Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SerialDriver by
SerialDriver.cpp@4:3c0d0c37ad75, 2015-02-23 (annotated)
- Committer:
- rosterloh84
- Date:
- Mon Feb 23 13:06:32 2015 +0000
- Revision:
- 4:3c0d0c37ad75
- Parent:
- 3:ea9719695b6a
Added tx and rx overflow callback and message complete callback
Who changed what in which revision?
| User | Revision | Line number | New 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 | 0:cd0d79be0c1a | 45 | } |
| BlazeX | 0:cd0d79be0c1a | 46 | |
| BlazeX | 0:cd0d79be0c1a | 47 | int SerialDriver::putc(int c, unsigned int timeoutMs) |
| BlazeX | 0:cd0d79be0c1a | 48 | { |
| BlazeX | 0:cd0d79be0c1a | 49 | // critical section, isr could modify cursors |
| BlazeX | 0:cd0d79be0c1a | 50 | disableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 51 | |
| BlazeX | 0:cd0d79be0c1a | 52 | if(isTxBufferFull()) |
| BlazeX | 0:cd0d79be0c1a | 53 | { |
| BlazeX | 0:cd0d79be0c1a | 54 | // wait for free space |
| BlazeX | 0:cd0d79be0c1a | 55 | while(semTxBufferFull.wait(0) > 0); // clear semaphore |
| BlazeX | 0:cd0d79be0c1a | 56 | enableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 57 | |
| BlazeX | 0:cd0d79be0c1a | 58 | // let isr work |
| BlazeX | 0:cd0d79be0c1a | 59 | semTxBufferFull.wait(timeoutMs); |
| BlazeX | 0:cd0d79be0c1a | 60 | |
| BlazeX | 0:cd0d79be0c1a | 61 | disableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 62 | if(isTxBufferFull()) // still full? drop byte! |
| BlazeX | 0:cd0d79be0c1a | 63 | { |
| BlazeX | 3:ea9719695b6a | 64 | numTxDrops++; |
| BlazeX | 0:cd0d79be0c1a | 65 | enableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 66 | return 0; |
| BlazeX | 0:cd0d79be0c1a | 67 | } |
| BlazeX | 0:cd0d79be0c1a | 68 | } |
| BlazeX | 0:cd0d79be0c1a | 69 | |
| BlazeX | 0:cd0d79be0c1a | 70 | // write this byte to tx buffer |
| BlazeX | 0:cd0d79be0c1a | 71 | txBuffer[txIn]= (unsigned char)c; |
| BlazeX | 0:cd0d79be0c1a | 72 | txIn= (txIn+1) % txBufferLength; |
| BlazeX | 0:cd0d79be0c1a | 73 | txCount++; |
| BlazeX | 0:cd0d79be0c1a | 74 | |
| BlazeX | 0:cd0d79be0c1a | 75 | // its over, isr can come |
| BlazeX | 0:cd0d79be0c1a | 76 | enableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 77 | |
| BlazeX | 0:cd0d79be0c1a | 78 | // Let's write (isr will check writeability itself) |
| BlazeX | 0:cd0d79be0c1a | 79 | onTxIrq(); |
| BlazeX | 0:cd0d79be0c1a | 80 | |
| BlazeX | 0:cd0d79be0c1a | 81 | return 1; |
| BlazeX | 0:cd0d79be0c1a | 82 | } |
| BlazeX | 0:cd0d79be0c1a | 83 | |
| BlazeX | 0:cd0d79be0c1a | 84 | void SerialDriver::onTxIrq() |
| BlazeX | 0:cd0d79be0c1a | 85 | { |
| BlazeX | 0:cd0d79be0c1a | 86 | // prevent fire another TxIrq now |
| BlazeX | 0:cd0d79be0c1a | 87 | disableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 88 | |
| BlazeX | 0:cd0d79be0c1a | 89 | // write as long as you can |
| BlazeX | 0:cd0d79be0c1a | 90 | bool wasFull= isTxBufferFull(); |
| BlazeX | 0:cd0d79be0c1a | 91 | while(SerialBase::writeable() && !isTxBufferEmtpy()) |
| BlazeX | 0:cd0d79be0c1a | 92 | { |
| BlazeX | 0:cd0d79be0c1a | 93 | // take byte from tx buffer and put it out |
| BlazeX | 0:cd0d79be0c1a | 94 | SerialBase::_base_putc(txBuffer[txOut]); |
| BlazeX | 0:cd0d79be0c1a | 95 | txOut= (txOut+1) % txBufferLength; |
| BlazeX | 0:cd0d79be0c1a | 96 | txCount--; |
| BlazeX | 0:cd0d79be0c1a | 97 | } |
| BlazeX | 0:cd0d79be0c1a | 98 | |
| BlazeX | 0:cd0d79be0c1a | 99 | if(wasFull && !isTxBufferFull()) // more bytes can come |
| BlazeX | 0:cd0d79be0c1a | 100 | semTxBufferFull.release(); |
| BlazeX | 0:cd0d79be0c1a | 101 | |
| BlazeX | 0:cd0d79be0c1a | 102 | // ok, let's wait for next writability |
| BlazeX | 0:cd0d79be0c1a | 103 | enableTxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 104 | } |
| BlazeX | 0:cd0d79be0c1a | 105 | |
| BlazeX | 0:cd0d79be0c1a | 106 | |
| BlazeX | 0:cd0d79be0c1a | 107 | int SerialDriver::getc(unsigned int timeoutMs) |
| BlazeX | 0:cd0d79be0c1a | 108 | { |
| BlazeX | 0:cd0d79be0c1a | 109 | // Let's read (isr will check readability itself) |
| BlazeX | 0:cd0d79be0c1a | 110 | onRxIrq(); |
| BlazeX | 0:cd0d79be0c1a | 111 | |
| BlazeX | 0:cd0d79be0c1a | 112 | // critical section, isr could modify cursors |
| BlazeX | 0:cd0d79be0c1a | 113 | disableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 114 | |
| BlazeX | 0:cd0d79be0c1a | 115 | if(isRxBufferEmpty()) |
| BlazeX | 0:cd0d79be0c1a | 116 | { |
| BlazeX | 0:cd0d79be0c1a | 117 | // wait for new byte |
| BlazeX | 0:cd0d79be0c1a | 118 | while(semRxBufferEmpty.wait(0) > 0); // clear semaphore |
| BlazeX | 0:cd0d79be0c1a | 119 | enableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 120 | |
| BlazeX | 0:cd0d79be0c1a | 121 | // let isr work |
| BlazeX | 0:cd0d79be0c1a | 122 | semRxBufferEmpty.wait(timeoutMs); |
| BlazeX | 0:cd0d79be0c1a | 123 | |
| BlazeX | 0:cd0d79be0c1a | 124 | disableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 125 | if(isRxBufferEmpty()) // still empty? nothing received! |
| BlazeX | 0:cd0d79be0c1a | 126 | { |
| BlazeX | 0:cd0d79be0c1a | 127 | enableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 128 | return -1; |
| BlazeX | 0:cd0d79be0c1a | 129 | } |
| BlazeX | 0:cd0d79be0c1a | 130 | } |
| BlazeX | 0:cd0d79be0c1a | 131 | |
| BlazeX | 0:cd0d79be0c1a | 132 | // get byte from rx buffer |
| BlazeX | 0:cd0d79be0c1a | 133 | int c= (int)rxBuffer[rxOut]; |
| BlazeX | 0:cd0d79be0c1a | 134 | rxOut= (rxOut+1) % rxBufferLength; |
| BlazeX | 0:cd0d79be0c1a | 135 | rxCount--; |
| BlazeX | 0:cd0d79be0c1a | 136 | |
| BlazeX | 0:cd0d79be0c1a | 137 | // its over, isr can come |
| BlazeX | 0:cd0d79be0c1a | 138 | enableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 139 | |
| BlazeX | 0:cd0d79be0c1a | 140 | return c; |
| BlazeX | 0:cd0d79be0c1a | 141 | } |
| BlazeX | 0:cd0d79be0c1a | 142 | |
| BlazeX | 0:cd0d79be0c1a | 143 | void SerialDriver::onRxIrq() |
| BlazeX | 0:cd0d79be0c1a | 144 | { |
| BlazeX | 0:cd0d79be0c1a | 145 | // prevent fire another RxIrq now |
| BlazeX | 0:cd0d79be0c1a | 146 | disableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 147 | |
| BlazeX | 0:cd0d79be0c1a | 148 | // read as long as you can |
| BlazeX | 0:cd0d79be0c1a | 149 | bool wasEmpty= isRxBufferEmpty(); |
| BlazeX | 0:cd0d79be0c1a | 150 | while(SerialBase::readable()) |
| BlazeX | 0:cd0d79be0c1a | 151 | { |
| BlazeX | 0:cd0d79be0c1a | 152 | // get byte and store it to the RX buffer |
| BlazeX | 0:cd0d79be0c1a | 153 | int c= SerialBase::_base_getc(); |
| BlazeX | 0:cd0d79be0c1a | 154 | if(!isRxBufferFull()) |
| BlazeX | 0:cd0d79be0c1a | 155 | { |
| BlazeX | 0:cd0d79be0c1a | 156 | rxBuffer[rxIn]= (unsigned char)c; |
| BlazeX | 0:cd0d79be0c1a | 157 | rxIn= (rxIn+1) % rxBufferLength; |
| BlazeX | 0:cd0d79be0c1a | 158 | rxCount++; |
| rosterloh84 | 4:3c0d0c37ad75 | 159 | if ('\n' == c) { |
| rosterloh84 | 4:3c0d0c37ad75 | 160 | _callback_auto_detect.call(); |
| rosterloh84 | 4:3c0d0c37ad75 | 161 | } |
| BlazeX | 3:ea9719695b6a | 162 | } |
| rosterloh84 | 4:3c0d0c37ad75 | 163 | else { // drop byte :( |
| BlazeX | 3:ea9719695b6a | 164 | numRxDrops++; |
| rosterloh84 | 4:3c0d0c37ad75 | 165 | _callback_rx_overflow.call(); |
| rosterloh84 | 4:3c0d0c37ad75 | 166 | } |
| BlazeX | 0:cd0d79be0c1a | 167 | } |
| BlazeX | 0:cd0d79be0c1a | 168 | |
| BlazeX | 0:cd0d79be0c1a | 169 | if(wasEmpty && !isRxBufferEmpty()) // more bytes can go |
| BlazeX | 0:cd0d79be0c1a | 170 | semRxBufferEmpty.release(); |
| BlazeX | 0:cd0d79be0c1a | 171 | |
| BlazeX | 0:cd0d79be0c1a | 172 | // ok, let's wait for next readability |
| BlazeX | 0:cd0d79be0c1a | 173 | enableRxInterrupt(); |
| BlazeX | 0:cd0d79be0c1a | 174 | } |
| BlazeX | 0:cd0d79be0c1a | 175 | |
| BlazeX | 0:cd0d79be0c1a | 176 | |
| BlazeX | 0:cd0d79be0c1a | 177 | int SerialDriver::write(const unsigned char * buffer, const unsigned int length, bool block) |
| BlazeX | 0:cd0d79be0c1a | 178 | { |
| BlazeX | 0:cd0d79be0c1a | 179 | // try to put all bytes |
| BlazeX | 0:cd0d79be0c1a | 180 | for(int i= 0; i < length; i++) |
| BlazeX | 0:cd0d79be0c1a | 181 | if(!putc(buffer[i], block ? osWaitForever : 0)) |
| BlazeX | 0:cd0d79be0c1a | 182 | return i; // putc failed, but already put i bytes |
| BlazeX | 0:cd0d79be0c1a | 183 | |
| BlazeX | 0:cd0d79be0c1a | 184 | return length; // put all bytes |
| BlazeX | 0:cd0d79be0c1a | 185 | } |
| BlazeX | 0:cd0d79be0c1a | 186 | |
| BlazeX | 0:cd0d79be0c1a | 187 | int SerialDriver::read(unsigned char * buffer, const unsigned int length, bool block) |
| BlazeX | 0:cd0d79be0c1a | 188 | { |
| BlazeX | 0:cd0d79be0c1a | 189 | // try to get all bytes |
| BlazeX | 0:cd0d79be0c1a | 190 | int c; |
| BlazeX | 0:cd0d79be0c1a | 191 | for(int i= 0; i < length; i++) |
| BlazeX | 0:cd0d79be0c1a | 192 | { |
| BlazeX | 0:cd0d79be0c1a | 193 | c= getc(block ? osWaitForever : 0); |
| BlazeX | 0:cd0d79be0c1a | 194 | if(c < 0) |
| BlazeX | 0:cd0d79be0c1a | 195 | return i; // getc failed, but already got i bytes |
| BlazeX | 0:cd0d79be0c1a | 196 | buffer[i]= (unsigned char)c; |
| BlazeX | 0:cd0d79be0c1a | 197 | } |
| BlazeX | 0:cd0d79be0c1a | 198 | |
| BlazeX | 0:cd0d79be0c1a | 199 | return length; // got all bytes |
| BlazeX | 0:cd0d79be0c1a | 200 | } |
| BlazeX | 0:cd0d79be0c1a | 201 | |
| BlazeX | 0:cd0d79be0c1a | 202 | |
| BlazeX | 0:cd0d79be0c1a | 203 | int SerialDriver::puts(const char * str, bool block) |
| BlazeX | 0:cd0d79be0c1a | 204 | { |
| BlazeX | 0:cd0d79be0c1a | 205 | // the same as write, but get length from strlen |
| BlazeX | 0:cd0d79be0c1a | 206 | const int len= strlen(str); |
| BlazeX | 0:cd0d79be0c1a | 207 | return write((const unsigned char *)str, len, block); |
| BlazeX | 0:cd0d79be0c1a | 208 | } |
| BlazeX | 0:cd0d79be0c1a | 209 | |
| BlazeX | 0:cd0d79be0c1a | 210 | int SerialDriver::printf(const char * format, ...) |
| BlazeX | 0:cd0d79be0c1a | 211 | { |
| BlazeX | 0:cd0d79be0c1a | 212 | // Parts of this are copied from mbed RawSerial ;) |
| BlazeX | 0:cd0d79be0c1a | 213 | std::va_list arg; |
| BlazeX | 0:cd0d79be0c1a | 214 | va_start(arg, format); |
| BlazeX | 0:cd0d79be0c1a | 215 | |
| BlazeX | 0:cd0d79be0c1a | 216 | int length= vsnprintf(NULL, 0, format, arg); |
| BlazeX | 0:cd0d79be0c1a | 217 | char *temp = new char[length + 1]; |
| BlazeX | 0:cd0d79be0c1a | 218 | vsprintf(temp, format, arg); |
| BlazeX | 0:cd0d79be0c1a | 219 | puts(temp, true); |
| BlazeX | 0:cd0d79be0c1a | 220 | delete[] temp; |
| BlazeX | 0:cd0d79be0c1a | 221 | |
| BlazeX | 0:cd0d79be0c1a | 222 | va_end(arg); |
| BlazeX | 0:cd0d79be0c1a | 223 | return length; |
| BlazeX | 0:cd0d79be0c1a | 224 | } |
| BlazeX | 0:cd0d79be0c1a | 225 | |
| BlazeX | 3:ea9719695b6a | 226 | // still thinking of XTN |
