Richard Osterloh / SerialDriver

Fork of SerialDriver by BlazeX .

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     : SerialBase(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 
00047 int SerialDriver::putc(int c, unsigned int timeoutMs)
00048 {
00049     // critical section, isr could modify cursors
00050     disableTxInterrupt();
00051     
00052     if(isTxBufferFull())
00053     {
00054         // wait for free space
00055         while(semTxBufferFull.wait(0) > 0);    // clear semaphore
00056         enableTxInterrupt();
00057         
00058         // let isr work
00059         semTxBufferFull.wait(timeoutMs);
00060         
00061         disableTxInterrupt();
00062         if(isTxBufferFull()) // still full? drop byte!
00063         {
00064             numTxDrops++;
00065             enableTxInterrupt();
00066             return 0;
00067         }
00068     }
00069     
00070     // write this byte to tx buffer
00071     txBuffer[txIn]= (unsigned char)c;
00072     txIn= (txIn+1) % txBufferLength;
00073     txCount++;
00074     
00075     // its over, isr can come
00076     enableTxInterrupt();
00077         
00078     // Let's write (isr will check writeability itself)
00079     onTxIrq();
00080     
00081     return 1;
00082 }
00083 
00084 void SerialDriver::onTxIrq()
00085 {
00086     // prevent fire another TxIrq now
00087     disableTxInterrupt();
00088     
00089     // write as long as you can
00090     bool wasFull= isTxBufferFull();
00091     while(SerialBase::writeable() && !isTxBufferEmtpy())
00092     {
00093         // take byte from tx buffer and put it out
00094         SerialBase::_base_putc(txBuffer[txOut]);
00095         txOut= (txOut+1) % txBufferLength;
00096         txCount--;
00097     }
00098     
00099     if(wasFull && !isTxBufferFull())   // more bytes can come
00100         semTxBufferFull.release();
00101     
00102     // ok, let's wait for next writability
00103     enableTxInterrupt();
00104 }
00105 
00106 
00107 int SerialDriver::getc(unsigned int timeoutMs)
00108 {    
00109     // Let's read (isr will check readability itself)
00110     onRxIrq();
00111     
00112     // critical section, isr could modify cursors
00113     disableRxInterrupt();
00114     
00115     if(isRxBufferEmpty())
00116     {
00117         // wait for new byte
00118         while(semRxBufferEmpty.wait(0) > 0);    // clear semaphore
00119         enableRxInterrupt();
00120         
00121         // let isr work
00122         semRxBufferEmpty.wait(timeoutMs);
00123         
00124         disableRxInterrupt();
00125         if(isRxBufferEmpty()) // still empty? nothing received!
00126         {
00127             enableRxInterrupt();
00128             return -1;
00129         }
00130     }
00131     
00132     // get byte from rx buffer
00133     int c= (int)rxBuffer[rxOut];
00134     rxOut= (rxOut+1) % rxBufferLength;
00135     rxCount--;
00136     
00137     // its over, isr can come
00138     enableRxInterrupt();
00139     
00140     return c;
00141 }
00142 
00143 void SerialDriver::onRxIrq()
00144 {
00145     // prevent fire another RxIrq now
00146     disableRxInterrupt();
00147     
00148     // read as long as you can
00149     bool wasEmpty= isRxBufferEmpty();
00150     while(SerialBase::readable())
00151     {
00152         // get byte and store it to the RX buffer
00153         int c= SerialBase::_base_getc();
00154         if(!isRxBufferFull())
00155         {
00156             rxBuffer[rxIn]= (unsigned char)c;
00157             rxIn= (rxIn+1) % rxBufferLength;
00158             rxCount++;
00159             if ('\n' == c) {
00160                 _callback_auto_detect.call();
00161             }
00162         }
00163         else {   // drop byte :(
00164             numRxDrops++;
00165             _callback_rx_overflow.call();
00166         }
00167     }
00168     
00169     if(wasEmpty && !isRxBufferEmpty())   // more bytes can go
00170         semRxBufferEmpty.release();
00171     
00172     // ok, let's wait for next readability
00173     enableRxInterrupt();
00174 }
00175 
00176 
00177 int SerialDriver::write(const unsigned char * buffer, const unsigned int length, bool block)
00178 {
00179     // try to put all bytes
00180     for(int i= 0; i < length; i++)
00181         if(!putc(buffer[i], block ? osWaitForever : 0))
00182             return i; // putc failed, but already put i bytes
00183     
00184     return length;  // put all bytes
00185 }
00186     
00187 int SerialDriver::read(unsigned char * buffer, const unsigned int length, bool block)
00188 {
00189     // try to get all bytes
00190     int c;
00191     for(int i= 0; i < length; i++)
00192     {
00193         c= getc(block ? osWaitForever : 0);
00194         if(c < 0)
00195             return i; // getc failed, but already got i bytes
00196         buffer[i]= (unsigned char)c;
00197     }
00198     
00199     return length;  // got all bytes
00200 }
00201 
00202 
00203 int SerialDriver::puts(const char * str, bool block)
00204 {
00205     // the same as write, but get length from strlen
00206     const int len= strlen(str);
00207     return write((const unsigned char *)str, len, block);
00208 }
00209 
00210 int SerialDriver::printf(const char * format, ...)
00211 {
00212     // Parts of this are copied from mbed RawSerial ;)
00213     std::va_list arg;
00214     va_start(arg, format);
00215     
00216     int length= vsnprintf(NULL, 0, format, arg);
00217     char *temp = new char[length + 1];
00218     vsprintf(temp, format, arg);
00219     puts(temp, true);
00220     delete[] temp;
00221     
00222     va_end(arg);
00223     return length;
00224 } 
00225 
00226 // still thinking of XTN