Buffered Serial Port Driver for RTOS

Dependents:   nucleo_cannonball PiballNeoController

Buffered Serial Port Driver for RTOS

  • ISR driven, ring buffered IO operation
  • IO operations are idle waiting, don't waste time in RTOS :D
  • Can use external buffers
  • Based on mbed RawSerial

Example

SerialDriver Example

#include "SerialDriver.h"

SerialDriver pc(USBTX, USBRX);

int main()
{
    // setup serial port
    pc.baud(9600);
    
    // print some text
    pc.puts("This is just a string.\r\n");
    pc.printf("But this is a %s with integer %i and float %f.\r\n", "formatted text", 123, 0.456f);
    
    // now lets behave like a null modem 
    while(1)
       pc.putc(pc.getc());
}

Look at the API Documentation for more Examples.

Dependencies

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Import librarymbed-rtos

Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard.

If you find a bug, please help me to fix it. Send me a message. You can help me a lot: Write a demo program that causes the bug reproducible.

Committer:
BlazeX
Date:
Fri Oct 23 13:49:19 2015 +0000
Revision:
4:a41e47716932
Parent:
3:ea9719695b6a
Child:
5:cb9007ef1a30
BETA update.
; Trying to make SerialDriver compatible with KL25Z and KL46Z. Test at your own risk.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
BlazeX 0:cd0d79be0c1a 1 #include "SerialDriver.h"
BlazeX 0:cd0d79be0c1a 2
BlazeX 0:cd0d79be0c1a 3 SerialDriver::SerialDriver(PinName txPin, PinName rxPin, int txBufferLength_, int rxBufferLength_, unsigned char * txBuffer_, unsigned char * rxBuffer_)
BlazeX 0:cd0d79be0c1a 4 : SerialBase(txPin, rxPin), semTxBufferFull(0), semRxBufferEmpty(0)
BlazeX 0:cd0d79be0c1a 5 {
BlazeX 0:cd0d79be0c1a 6 // check buffer length
BlazeX 0:cd0d79be0c1a 7 txBufferLength= txBufferLength_;
BlazeX 0:cd0d79be0c1a 8 if(txBufferLength <= 1)
BlazeX 0:cd0d79be0c1a 9 error("TX buffer length must be > 1 !");
BlazeX 0:cd0d79be0c1a 10
BlazeX 0:cd0d79be0c1a 11 rxBufferLength= rxBufferLength_;
BlazeX 0:cd0d79be0c1a 12 if(rxBufferLength <= 1)
BlazeX 0:cd0d79be0c1a 13 error("RX buffer length must be > 1 !");
BlazeX 0:cd0d79be0c1a 14
BlazeX 0:cd0d79be0c1a 15 // take or allocate buffer
BlazeX 0:cd0d79be0c1a 16 txBuffer= txBuffer_;
BlazeX 0:cd0d79be0c1a 17 if(txBuffer == NULL)
BlazeX 0:cd0d79be0c1a 18 {
BlazeX 0:cd0d79be0c1a 19 txBuffer= new unsigned char[txBufferLength];
BlazeX 0:cd0d79be0c1a 20 if(txBuffer == NULL)
BlazeX 0:cd0d79be0c1a 21 error("Cannot allocate TX buffer!");
BlazeX 0:cd0d79be0c1a 22 }
BlazeX 0:cd0d79be0c1a 23
BlazeX 0:cd0d79be0c1a 24 rxBuffer= rxBuffer_;
BlazeX 0:cd0d79be0c1a 25 if(rxBuffer == NULL)
BlazeX 0:cd0d79be0c1a 26 {
BlazeX 0:cd0d79be0c1a 27 rxBuffer= new unsigned char[rxBufferLength];
BlazeX 0:cd0d79be0c1a 28 if(rxBuffer == NULL)
BlazeX 0:cd0d79be0c1a 29 error("Cannot allocate RX buffer!");
BlazeX 0:cd0d79be0c1a 30 }
BlazeX 0:cd0d79be0c1a 31
BlazeX 0:cd0d79be0c1a 32
BlazeX 0:cd0d79be0c1a 33 // reset cursors
BlazeX 0:cd0d79be0c1a 34 txIn= txOut= 0;
BlazeX 0:cd0d79be0c1a 35 rxIn= rxOut= 0;
BlazeX 0:cd0d79be0c1a 36 txCount= rxCount= 0;
BlazeX 0:cd0d79be0c1a 37
BlazeX 3:ea9719695b6a 38 // reset drop counters
BlazeX 3:ea9719695b6a 39 numTxDrops= 0;
BlazeX 3:ea9719695b6a 40 numRxDrops= 0;
BlazeX 3:ea9719695b6a 41
BlazeX 0:cd0d79be0c1a 42 // attach interrupt routines
BlazeX 0:cd0d79be0c1a 43 attach(this, &SerialDriver::onTxIrq, TxIrq);
BlazeX 0:cd0d79be0c1a 44 attach(this, &SerialDriver::onRxIrq, RxIrq);
BlazeX 4:a41e47716932 45
BlazeX 4:a41e47716932 46 // we need tx interrupt not yet
BlazeX 4:a41e47716932 47 disableTxInterrupt();
BlazeX 0:cd0d79be0c1a 48 }
BlazeX 0:cd0d79be0c1a 49
BlazeX 0:cd0d79be0c1a 50 int SerialDriver::putc(int c, unsigned int timeoutMs)
BlazeX 0:cd0d79be0c1a 51 {
BlazeX 0:cd0d79be0c1a 52 // critical section, isr could modify cursors
BlazeX 0:cd0d79be0c1a 53 disableTxInterrupt();
BlazeX 0:cd0d79be0c1a 54
BlazeX 0:cd0d79be0c1a 55 if(isTxBufferFull())
BlazeX 0:cd0d79be0c1a 56 {
BlazeX 0:cd0d79be0c1a 57 // wait for free space
BlazeX 0:cd0d79be0c1a 58 while(semTxBufferFull.wait(0) > 0); // clear semaphore
BlazeX 0:cd0d79be0c1a 59 enableTxInterrupt();
BlazeX 0:cd0d79be0c1a 60
BlazeX 0:cd0d79be0c1a 61 // let isr work
BlazeX 0:cd0d79be0c1a 62 semTxBufferFull.wait(timeoutMs);
BlazeX 0:cd0d79be0c1a 63
BlazeX 0:cd0d79be0c1a 64 disableTxInterrupt();
BlazeX 0:cd0d79be0c1a 65 if(isTxBufferFull()) // still full? drop byte!
BlazeX 0:cd0d79be0c1a 66 {
BlazeX 3:ea9719695b6a 67 numTxDrops++;
BlazeX 0:cd0d79be0c1a 68 enableTxInterrupt();
BlazeX 0:cd0d79be0c1a 69 return 0;
BlazeX 0:cd0d79be0c1a 70 }
BlazeX 0:cd0d79be0c1a 71 }
BlazeX 0:cd0d79be0c1a 72
BlazeX 0:cd0d79be0c1a 73 // write this byte to tx buffer
BlazeX 0:cd0d79be0c1a 74 txBuffer[txIn]= (unsigned char)c;
BlazeX 0:cd0d79be0c1a 75 txIn= (txIn+1) % txBufferLength;
BlazeX 0:cd0d79be0c1a 76 txCount++;
BlazeX 0:cd0d79be0c1a 77
BlazeX 0:cd0d79be0c1a 78 // its over, isr can come
BlazeX 0:cd0d79be0c1a 79 enableTxInterrupt();
BlazeX 0:cd0d79be0c1a 80
BlazeX 0:cd0d79be0c1a 81 // Let's write (isr will check writeability itself)
BlazeX 0:cd0d79be0c1a 82 onTxIrq();
BlazeX 0:cd0d79be0c1a 83
BlazeX 0:cd0d79be0c1a 84 return 1;
BlazeX 0:cd0d79be0c1a 85 }
BlazeX 0:cd0d79be0c1a 86
BlazeX 0:cd0d79be0c1a 87 void SerialDriver::onTxIrq()
BlazeX 0:cd0d79be0c1a 88 {
BlazeX 0:cd0d79be0c1a 89 // prevent fire another TxIrq now
BlazeX 0:cd0d79be0c1a 90 disableTxInterrupt();
BlazeX 0:cd0d79be0c1a 91
BlazeX 0:cd0d79be0c1a 92 // write as long as you can
BlazeX 0:cd0d79be0c1a 93 bool wasFull= isTxBufferFull();
BlazeX 4:a41e47716932 94 bool wasEmpty= isTxBufferEmtpy();
BlazeX 4:a41e47716932 95 while(SerialBase::writeable() && !wasEmpty)
BlazeX 0:cd0d79be0c1a 96 {
BlazeX 0:cd0d79be0c1a 97 // take byte from tx buffer and put it out
BlazeX 0:cd0d79be0c1a 98 SerialBase::_base_putc(txBuffer[txOut]);
BlazeX 0:cd0d79be0c1a 99 txOut= (txOut+1) % txBufferLength;
BlazeX 0:cd0d79be0c1a 100 txCount--;
BlazeX 0:cd0d79be0c1a 101 }
BlazeX 0:cd0d79be0c1a 102
BlazeX 0:cd0d79be0c1a 103 if(wasFull && !isTxBufferFull()) // more bytes can come
BlazeX 0:cd0d79be0c1a 104 semTxBufferFull.release();
BlazeX 0:cd0d79be0c1a 105
BlazeX 0:cd0d79be0c1a 106 // ok, let's wait for next writability
BlazeX 4:a41e47716932 107 // if the is something to send,
BlazeX 4:a41e47716932 108 // else we need tx interrupt not yet
BlazeX 4:a41e47716932 109 if(wasEmpty);
BlazeX 4:a41e47716932 110 enableTxInterrupt();
BlazeX 0:cd0d79be0c1a 111 }
BlazeX 0:cd0d79be0c1a 112
BlazeX 0:cd0d79be0c1a 113
BlazeX 0:cd0d79be0c1a 114 int SerialDriver::getc(unsigned int timeoutMs)
BlazeX 0:cd0d79be0c1a 115 {
BlazeX 0:cd0d79be0c1a 116 // Let's read (isr will check readability itself)
BlazeX 0:cd0d79be0c1a 117 onRxIrq();
BlazeX 0:cd0d79be0c1a 118
BlazeX 0:cd0d79be0c1a 119 // critical section, isr could modify cursors
BlazeX 0:cd0d79be0c1a 120 disableRxInterrupt();
BlazeX 0:cd0d79be0c1a 121
BlazeX 0:cd0d79be0c1a 122 if(isRxBufferEmpty())
BlazeX 0:cd0d79be0c1a 123 {
BlazeX 0:cd0d79be0c1a 124 // wait for new byte
BlazeX 0:cd0d79be0c1a 125 while(semRxBufferEmpty.wait(0) > 0); // clear semaphore
BlazeX 0:cd0d79be0c1a 126 enableRxInterrupt();
BlazeX 0:cd0d79be0c1a 127
BlazeX 0:cd0d79be0c1a 128 // let isr work
BlazeX 0:cd0d79be0c1a 129 semRxBufferEmpty.wait(timeoutMs);
BlazeX 0:cd0d79be0c1a 130
BlazeX 0:cd0d79be0c1a 131 disableRxInterrupt();
BlazeX 0:cd0d79be0c1a 132 if(isRxBufferEmpty()) // still empty? nothing received!
BlazeX 0:cd0d79be0c1a 133 {
BlazeX 0:cd0d79be0c1a 134 enableRxInterrupt();
BlazeX 0:cd0d79be0c1a 135 return -1;
BlazeX 0:cd0d79be0c1a 136 }
BlazeX 0:cd0d79be0c1a 137 }
BlazeX 0:cd0d79be0c1a 138
BlazeX 0:cd0d79be0c1a 139 // get byte from rx buffer
BlazeX 0:cd0d79be0c1a 140 int c= (int)rxBuffer[rxOut];
BlazeX 0:cd0d79be0c1a 141 rxOut= (rxOut+1) % rxBufferLength;
BlazeX 0:cd0d79be0c1a 142 rxCount--;
BlazeX 0:cd0d79be0c1a 143
BlazeX 0:cd0d79be0c1a 144 // its over, isr can come
BlazeX 0:cd0d79be0c1a 145 enableRxInterrupt();
BlazeX 0:cd0d79be0c1a 146
BlazeX 0:cd0d79be0c1a 147 return c;
BlazeX 0:cd0d79be0c1a 148 }
BlazeX 0:cd0d79be0c1a 149
BlazeX 0:cd0d79be0c1a 150 void SerialDriver::onRxIrq()
BlazeX 0:cd0d79be0c1a 151 {
BlazeX 0:cd0d79be0c1a 152 // prevent fire another RxIrq now
BlazeX 0:cd0d79be0c1a 153 disableRxInterrupt();
BlazeX 0:cd0d79be0c1a 154
BlazeX 0:cd0d79be0c1a 155 // read as long as you can
BlazeX 0:cd0d79be0c1a 156 bool wasEmpty= isRxBufferEmpty();
BlazeX 0:cd0d79be0c1a 157 while(SerialBase::readable())
BlazeX 0:cd0d79be0c1a 158 {
BlazeX 0:cd0d79be0c1a 159 // get byte and store it to the RX buffer
BlazeX 0:cd0d79be0c1a 160 int c= SerialBase::_base_getc();
BlazeX 0:cd0d79be0c1a 161 if(!isRxBufferFull())
BlazeX 0:cd0d79be0c1a 162 {
BlazeX 0:cd0d79be0c1a 163 rxBuffer[rxIn]= (unsigned char)c;
BlazeX 0:cd0d79be0c1a 164 rxIn= (rxIn+1) % rxBufferLength;
BlazeX 0:cd0d79be0c1a 165 rxCount++;
BlazeX 3:ea9719695b6a 166 }
BlazeX 3:ea9719695b6a 167 else // drop byte :(
BlazeX 3:ea9719695b6a 168 numRxDrops++;
BlazeX 0:cd0d79be0c1a 169 }
BlazeX 0:cd0d79be0c1a 170
BlazeX 0:cd0d79be0c1a 171 if(wasEmpty && !isRxBufferEmpty()) // more bytes can go
BlazeX 0:cd0d79be0c1a 172 semRxBufferEmpty.release();
BlazeX 0:cd0d79be0c1a 173
BlazeX 0:cd0d79be0c1a 174 // ok, let's wait for next readability
BlazeX 0:cd0d79be0c1a 175 enableRxInterrupt();
BlazeX 0:cd0d79be0c1a 176 }
BlazeX 0:cd0d79be0c1a 177
BlazeX 0:cd0d79be0c1a 178
BlazeX 0:cd0d79be0c1a 179 int SerialDriver::write(const unsigned char * buffer, const unsigned int length, bool block)
BlazeX 0:cd0d79be0c1a 180 {
BlazeX 0:cd0d79be0c1a 181 // try to put all bytes
BlazeX 0:cd0d79be0c1a 182 for(int i= 0; i < length; i++)
BlazeX 0:cd0d79be0c1a 183 if(!putc(buffer[i], block ? osWaitForever : 0))
BlazeX 0:cd0d79be0c1a 184 return i; // putc failed, but already put i bytes
BlazeX 0:cd0d79be0c1a 185
BlazeX 0:cd0d79be0c1a 186 return length; // put all bytes
BlazeX 0:cd0d79be0c1a 187 }
BlazeX 0:cd0d79be0c1a 188
BlazeX 0:cd0d79be0c1a 189 int SerialDriver::read(unsigned char * buffer, const unsigned int length, bool block)
BlazeX 0:cd0d79be0c1a 190 {
BlazeX 0:cd0d79be0c1a 191 // try to get all bytes
BlazeX 0:cd0d79be0c1a 192 int c;
BlazeX 0:cd0d79be0c1a 193 for(int i= 0; i < length; i++)
BlazeX 0:cd0d79be0c1a 194 {
BlazeX 0:cd0d79be0c1a 195 c= getc(block ? osWaitForever : 0);
BlazeX 0:cd0d79be0c1a 196 if(c < 0)
BlazeX 0:cd0d79be0c1a 197 return i; // getc failed, but already got i bytes
BlazeX 0:cd0d79be0c1a 198 buffer[i]= (unsigned char)c;
BlazeX 0:cd0d79be0c1a 199 }
BlazeX 0:cd0d79be0c1a 200
BlazeX 0:cd0d79be0c1a 201 return length; // got all bytes
BlazeX 0:cd0d79be0c1a 202 }
BlazeX 0:cd0d79be0c1a 203
BlazeX 0:cd0d79be0c1a 204
BlazeX 0:cd0d79be0c1a 205 int SerialDriver::puts(const char * str, bool block)
BlazeX 0:cd0d79be0c1a 206 {
BlazeX 0:cd0d79be0c1a 207 // the same as write, but get length from strlen
BlazeX 0:cd0d79be0c1a 208 const int len= strlen(str);
BlazeX 0:cd0d79be0c1a 209 return write((const unsigned char *)str, len, block);
BlazeX 0:cd0d79be0c1a 210 }
BlazeX 0:cd0d79be0c1a 211
BlazeX 0:cd0d79be0c1a 212 int SerialDriver::printf(const char * format, ...)
BlazeX 0:cd0d79be0c1a 213 {
BlazeX 0:cd0d79be0c1a 214 // Parts of this are copied from mbed RawSerial ;)
BlazeX 0:cd0d79be0c1a 215 std::va_list arg;
BlazeX 0:cd0d79be0c1a 216 va_start(arg, format);
BlazeX 0:cd0d79be0c1a 217
BlazeX 0:cd0d79be0c1a 218 int length= vsnprintf(NULL, 0, format, arg);
BlazeX 0:cd0d79be0c1a 219 char *temp = new char[length + 1];
BlazeX 4:a41e47716932 220 if(temp == NULL)
BlazeX 4:a41e47716932 221 return 0; // I can't work like this!
BlazeX 0:cd0d79be0c1a 222 vsprintf(temp, format, arg);
BlazeX 0:cd0d79be0c1a 223 puts(temp, true);
BlazeX 0:cd0d79be0c1a 224 delete[] temp;
BlazeX 0:cd0d79be0c1a 225
BlazeX 0:cd0d79be0c1a 226 va_end(arg);
BlazeX 0:cd0d79be0c1a 227 return length;
BlazeX 0:cd0d79be0c1a 228 }
BlazeX 0:cd0d79be0c1a 229
BlazeX 3:ea9719695b6a 230 // still thinking of XTN