Buffered Serial Port Driver for RTOS

Dependents:   nucleo_cannonball PiballNeoController

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SerialDriver.cpp Source File

SerialDriver.cpp

00001 #include "SerialDriver.h"
00002 
00003 SerialDriver::SerialDriver(PinName txPin, PinName rxPin, int txBufferLength_, int rxBufferLength_, unsigned char * txBuffer_, unsigned char * rxBuffer_)
00004     : RawSerial(txPin, rxPin), semTxBufferFull(0), semRxBufferEmpty(0)
00005 {    
00006     // check buffer length
00007     txBufferLength= txBufferLength_;
00008     if(txBufferLength <= 1)
00009         error("TX buffer length must be > 1 !");
00010         
00011     rxBufferLength= rxBufferLength_;
00012     if(rxBufferLength <= 1)
00013         error("RX buffer length must be > 1 !");
00014     
00015     // take or allocate buffer
00016     txBuffer= txBuffer_;
00017     if(txBuffer == NULL)
00018     {
00019         txBuffer= new unsigned char[txBufferLength];
00020         if(txBuffer == NULL)
00021             error("Cannot allocate TX buffer!");
00022     }
00023     
00024     rxBuffer= rxBuffer_;
00025     if(rxBuffer == NULL)
00026     {
00027         rxBuffer= new unsigned char[rxBufferLength];
00028         if(rxBuffer == NULL)
00029             error("Cannot allocate RX buffer!");
00030     }
00031         
00032     
00033     // reset cursors
00034     txIn= txOut= 0;
00035     rxIn= rxOut= 0;
00036     txCount= rxCount= 0;
00037     
00038     // reset drop counters
00039     numTxDrops= 0;
00040     numRxDrops= 0;
00041     
00042     // attach interrupt routines
00043     attach(this, &SerialDriver::onTxIrq, TxIrq);
00044     attach(this, &SerialDriver::onRxIrq, RxIrq);
00045     
00046     // we need tx interrupt not yet
00047     disableTxInterrupt();
00048 }
00049 
00050 int SerialDriver::putc(int c, unsigned int timeoutMs)
00051 {
00052     // critical section, isr could modify cursors
00053     disableTxInterrupt();
00054     
00055     if(isTxBufferFull())
00056     {
00057         // wait for free space
00058         while(semTxBufferFull.wait(0) > 0);    // clear semaphore
00059         enableTxInterrupt();
00060         
00061         // let isr work
00062         semTxBufferFull.wait(timeoutMs);
00063         
00064         disableTxInterrupt();
00065         if(isTxBufferFull()) // still full? drop byte!
00066         {
00067             numTxDrops++;
00068             enableTxInterrupt();
00069             return 0;
00070         }
00071     }
00072     
00073     // write this byte to tx buffer
00074     txBuffer[txIn]= (unsigned char)c;
00075     txIn= (txIn+1) % txBufferLength;
00076     txCount++;
00077     
00078     // its over, isr can come
00079     enableTxInterrupt();
00080         
00081     // Let's write (isr will check writeability itself)
00082     onTxIrq();
00083     
00084     return 1;
00085 }
00086 
00087 void SerialDriver::onTxIrq()
00088 {
00089     // prevent fire another TxIrq now
00090     disableTxInterrupt();
00091     
00092     // write as long as you can
00093     bool wasFull= isTxBufferFull();
00094     while(SerialBase::writeable() && !isTxBufferEmtpy())
00095     {
00096         // take byte from tx buffer and put it out
00097         SerialBase::_base_putc(txBuffer[txOut]);
00098         txOut= (txOut+1) % txBufferLength;
00099         txCount--;
00100     }
00101     
00102     if(wasFull && !isTxBufferFull())   // more bytes can come
00103         semTxBufferFull.release();
00104     
00105     // ok, let's wait for next writability,
00106     // if there is something to send,  
00107     // else we need tx interrupt not yet
00108     if(!isTxBufferEmtpy())
00109         enableTxInterrupt();
00110 }
00111 
00112 
00113 int SerialDriver::getc(unsigned int timeoutMs)
00114 {    
00115     // Let's read (isr will check readability itself)
00116     onRxIrq();
00117     
00118     // critical section, isr could modify cursors
00119     disableRxInterrupt();
00120     
00121     if(isRxBufferEmpty())
00122     {
00123         // wait for new byte
00124         while(semRxBufferEmpty.wait(0) > 0);    // clear semaphore
00125         enableRxInterrupt();
00126         
00127         // let isr work
00128         semRxBufferEmpty.wait(timeoutMs);
00129         
00130         disableRxInterrupt();
00131         if(isRxBufferEmpty()) // still empty? nothing received!
00132         {
00133             enableRxInterrupt();
00134             return -1;
00135         }
00136     }
00137     
00138     // get byte from rx buffer
00139     int c= (int)rxBuffer[rxOut];
00140     rxOut= (rxOut+1) % rxBufferLength;
00141     rxCount--;
00142     
00143     // its over, isr can come
00144     enableRxInterrupt();
00145     
00146     return c;
00147 }
00148 
00149 void SerialDriver::onRxIrq()
00150 {
00151     // prevent fire another RxIrq now
00152     disableRxInterrupt();
00153     
00154     // read as long as you can
00155     bool wasEmpty= isRxBufferEmpty();
00156     while(SerialBase::readable())
00157     {
00158         // get byte and store it to the RX buffer
00159         int c= SerialBase::_base_getc();
00160         if(!isRxBufferFull())
00161         {
00162             rxBuffer[rxIn]= (unsigned char)c;
00163             rxIn= (rxIn+1) % rxBufferLength;
00164             rxCount++;
00165         }
00166         else    // drop byte :(
00167             numRxDrops++;
00168     }
00169     
00170     if(wasEmpty && !isRxBufferEmpty())   // more bytes can go
00171         semRxBufferEmpty.release();
00172     
00173     // ok, let's wait for next readability
00174     enableRxInterrupt();
00175 }
00176 
00177 
00178 int SerialDriver::write(const unsigned char * buffer, const unsigned int length, bool block)
00179 {
00180     // try to put all bytes
00181     for(int i= 0; i < length; i++)
00182         if(!putc(buffer[i], block ? osWaitForever : 0))
00183             return i; // putc failed, but already put i bytes
00184     
00185     return length;  // put all bytes
00186 }
00187     
00188 int SerialDriver::read(unsigned char * buffer, const unsigned int length, bool block)
00189 {
00190     // try to get all bytes
00191     int c;
00192     for(int i= 0; i < length; i++)
00193     {
00194         c= getc(block ? osWaitForever : 0);
00195         if(c < 0)
00196             return i; // getc failed, but already got i bytes
00197         buffer[i]= (unsigned char)c;
00198     }
00199     
00200     return length;  // got all bytes
00201 }
00202 
00203 
00204 int SerialDriver::puts(const char * str, bool block)
00205 {
00206     // the same as write, but get length from strlen
00207     const int len= strlen(str);
00208     return write((const unsigned char *)str, len, block);
00209 }
00210 
00211 int SerialDriver::printf(const char * format, ...)
00212 {
00213     // Parts of this are copied from mbed RawSerial ;)
00214     std::va_list arg;
00215     va_start(arg, format);
00216     
00217     int length= vsnprintf(NULL, 0, format, arg);
00218     char *temp = new char[length + 1];
00219     if(temp == NULL)
00220         return 0;   // I can't work like this!    
00221 
00222     vsprintf(temp, format, arg);
00223     puts(temp, true);
00224     delete[] temp;
00225     
00226     va_end(arg);
00227     return length;
00228 } 
00229 
00230 // still thinking of XTN
00231