RTOS safe buffered serial driver
Fork of SerialDriver by
SerialDriver.h@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 | /// @file SerialDriver.h |
BlazeX | 0:cd0d79be0c1a | 2 | /// @brief RTOS compatible buffered Serial port driver |
BlazeX | 0:cd0d79be0c1a | 3 | /// |
BlazeX | 0:cd0d79be0c1a | 4 | /// Examples: |
BlazeX | 0:cd0d79be0c1a | 5 | /// - @ref Example_printf.cpp |
BlazeX | 0:cd0d79be0c1a | 6 | /// - @ref Example_Nullmodem.cpp |
BlazeX | 0:cd0d79be0c1a | 7 | /// - @ref Example_Bridge.cpp |
BlazeX | 0:cd0d79be0c1a | 8 | /// - @ref Example_Blocking.cpp |
BlazeX | 0:cd0d79be0c1a | 9 | /// |
BlazeX | 0:cd0d79be0c1a | 10 | /// |
BlazeX | 0:cd0d79be0c1a | 11 | /// Dependencies: |
BlazeX | 0:cd0d79be0c1a | 12 | /// - cstdarg |
BlazeX | 0:cd0d79be0c1a | 13 | /// @see https://developer.mbed.org/users/mbed_official/code/mbed-rtos/ |
BlazeX | 0:cd0d79be0c1a | 14 | /// @see https://developer.mbed.org/users/mbed_official/code/mbed/ |
BlazeX | 0:cd0d79be0c1a | 15 | |
BlazeX | 0:cd0d79be0c1a | 16 | #pragma once |
BlazeX | 0:cd0d79be0c1a | 17 | |
BlazeX | 0:cd0d79be0c1a | 18 | #include "mbed.h" |
BlazeX | 0:cd0d79be0c1a | 19 | #include "rtos.h" |
BlazeX | 0:cd0d79be0c1a | 20 | #include <cstdarg> |
BlazeX | 0:cd0d79be0c1a | 21 | |
BlazeX | 0:cd0d79be0c1a | 22 | |
BlazeX | 0:cd0d79be0c1a | 23 | /// @class SerialDriver |
BlazeX | 0:cd0d79be0c1a | 24 | /// @brief RTOS compatible buffered Serial port driver |
BlazeX | 0:cd0d79be0c1a | 25 | /// |
BlazeX | 0:cd0d79be0c1a | 26 | /// - Based on SerialBase. |
BlazeX | 0:cd0d79be0c1a | 27 | /// - Can use external buffers. |
BlazeX | 0:cd0d79be0c1a | 28 | /// - ISR driven, ring buffered IO operation |
BlazeX | 0:cd0d79be0c1a | 29 | /// - Can Replace mbed RawSerial |
BlazeX | 0:cd0d79be0c1a | 30 | /// - IO operations are idle waiting, don't waste time in RTOS :D |
BlazeX | 0:cd0d79be0c1a | 31 | /// - Do not use attach methods for TxIrq or RxIrq! They are already in use. |
BlazeX | 0:cd0d79be0c1a | 32 | class SerialDriver : public SerialBase |
BlazeX | 0:cd0d79be0c1a | 33 | { |
BlazeX | 0:cd0d79be0c1a | 34 | protected: |
BlazeX | 0:cd0d79be0c1a | 35 | // ring buffered rx/tx |
BlazeX | 0:cd0d79be0c1a | 36 | unsigned char * txBuffer; |
BlazeX | 0:cd0d79be0c1a | 37 | unsigned char * rxBuffer; |
BlazeX | 0:cd0d79be0c1a | 38 | int txBufferLength, rxBufferLength; |
BlazeX | 0:cd0d79be0c1a | 39 | |
BlazeX | 0:cd0d79be0c1a | 40 | // ring buffer cursors |
BlazeX | 0:cd0d79be0c1a | 41 | volatile int txIn, txOut; |
BlazeX | 0:cd0d79be0c1a | 42 | volatile int rxIn, rxOut; |
BlazeX | 0:cd0d79be0c1a | 43 | volatile int txCount, rxCount; |
BlazeX | 0:cd0d79be0c1a | 44 | |
BlazeX | 0:cd0d79be0c1a | 45 | // semaphores for timeout (used as signals) |
BlazeX | 0:cd0d79be0c1a | 46 | Semaphore semTxBufferFull; // used by putc to wait |
BlazeX | 0:cd0d79be0c1a | 47 | Semaphore semRxBufferEmpty; // used by getc to wait |
BlazeX | 0:cd0d79be0c1a | 48 | |
BlazeX | 3:ea9719695b6a | 49 | // drop counters |
BlazeX | 3:ea9719695b6a | 50 | volatile int numTxDrops, numRxDrops; |
BlazeX | 0:cd0d79be0c1a | 51 | |
rosterloh84 | 4:3c0d0c37ad75 | 52 | FunctionPointer _callback_rx_overflow; |
rosterloh84 | 4:3c0d0c37ad75 | 53 | FunctionPointer _callback_tx_overflow; |
rosterloh84 | 4:3c0d0c37ad75 | 54 | FunctionPointer _callback_auto_detect; |
rosterloh84 | 4:3c0d0c37ad75 | 55 | |
BlazeX | 0:cd0d79be0c1a | 56 | public: |
rosterloh84 | 4:3c0d0c37ad75 | 57 | enum IrqType { RxOvIrq = 0, TxOvIrq, RxAutoDetect}; |
rosterloh84 | 4:3c0d0c37ad75 | 58 | |
BlazeX | 0:cd0d79be0c1a | 59 | /// @brief Prepares ring buffer and irq |
BlazeX | 0:cd0d79be0c1a | 60 | /// |
BlazeX | 0:cd0d79be0c1a | 61 | /// If no buffer was set, the buffer gets allocated. |
BlazeX | 0:cd0d79be0c1a | 62 | /// @param txPin TX PinName, e.g. USBTX |
BlazeX | 0:cd0d79be0c1a | 63 | /// @param rxPin RX PinName, e.g. USBRX |
BlazeX | 0:cd0d79be0c1a | 64 | /// @param txBufferLength_ size of TX buffer. Must be > 1! |
BlazeX | 0:cd0d79be0c1a | 65 | /// @param rxBufferLength_ size of RX buffer. Must be > 1! |
BlazeX | 0:cd0d79be0c1a | 66 | /// @param txBuffer_ TX buffer, if NULL, the buffer will be allocated |
BlazeX | 0:cd0d79be0c1a | 67 | /// @param rxBuffer_ RX buffer, if NULL, the buffer will be allocated |
BlazeX | 0:cd0d79be0c1a | 68 | SerialDriver(PinName txPin, PinName rxPin, int txBufferLength_= 256, int rxBufferLength_= 256, unsigned char * txBuffer_= NULL, unsigned char * rxBuffer_= NULL); |
BlazeX | 0:cd0d79be0c1a | 69 | |
BlazeX | 0:cd0d79be0c1a | 70 | |
rosterloh84 | 4:3c0d0c37ad75 | 71 | void attach(IrqType irq, void (*function)(void)) { |
rosterloh84 | 4:3c0d0c37ad75 | 72 | if (irq == RxOvIrq) { |
rosterloh84 | 4:3c0d0c37ad75 | 73 | _callback_tx_overflow.attach( function ); |
rosterloh84 | 4:3c0d0c37ad75 | 74 | } else if (irq == TxOvIrq) { |
rosterloh84 | 4:3c0d0c37ad75 | 75 | _callback_tx_overflow.attach( function ); |
rosterloh84 | 4:3c0d0c37ad75 | 76 | } else if (irq == RxAutoDetect) { |
rosterloh84 | 4:3c0d0c37ad75 | 77 | _callback_auto_detect.attach( function ); |
rosterloh84 | 4:3c0d0c37ad75 | 78 | } //else { } |
rosterloh84 | 4:3c0d0c37ad75 | 79 | } |
rosterloh84 | 4:3c0d0c37ad75 | 80 | |
BlazeX | 0:cd0d79be0c1a | 81 | //////////////////////////////////////////////////////////////// |
BlazeX | 0:cd0d79be0c1a | 82 | // Basic IO Operation |
BlazeX | 0:cd0d79be0c1a | 83 | |
BlazeX | 0:cd0d79be0c1a | 84 | /// @brief Put a byte to the TX buffer |
BlazeX | 0:cd0d79be0c1a | 85 | /// |
BlazeX | 0:cd0d79be0c1a | 86 | /// If the TX buffer is full, it waits the defined timeout. |
BlazeX | 0:cd0d79be0c1a | 87 | /// Drops the byte, if TX buffer is still full after timeout. |
BlazeX | 0:cd0d79be0c1a | 88 | /// @param c The byte to write |
BlazeX | 0:cd0d79be0c1a | 89 | /// @param timeoutMs give TX buffer time to get writeable. |
BlazeX | 0:cd0d79be0c1a | 90 | /// @return 1 - success, 0 - if TX Buffer was full all the time |
BlazeX | 0:cd0d79be0c1a | 91 | int putc(int c, unsigned int timeoutMs= osWaitForever); |
BlazeX | 0:cd0d79be0c1a | 92 | |
BlazeX | 0:cd0d79be0c1a | 93 | |
BlazeX | 0:cd0d79be0c1a | 94 | /// @brief Get a byte from the RX buffer |
BlazeX | 0:cd0d79be0c1a | 95 | /// |
BlazeX | 0:cd0d79be0c1a | 96 | /// If the RX buffer is empty, it waits the defined timeout. |
BlazeX | 0:cd0d79be0c1a | 97 | /// @param timeoutMs give RX buffer time to get readable. |
BlazeX | 0:cd0d79be0c1a | 98 | /// @return next byte from RX buffer or -1 after timeout. |
BlazeX | 0:cd0d79be0c1a | 99 | int getc(unsigned int timeoutMs= osWaitForever); |
BlazeX | 0:cd0d79be0c1a | 100 | |
BlazeX | 0:cd0d79be0c1a | 101 | |
BlazeX | 0:cd0d79be0c1a | 102 | protected: |
BlazeX | 0:cd0d79be0c1a | 103 | //////////////////////////////////////////////////////////////// |
BlazeX | 0:cd0d79be0c1a | 104 | // Interrupts |
BlazeX | 0:cd0d79be0c1a | 105 | |
BlazeX | 0:cd0d79be0c1a | 106 | // TX: Move data from txBuffer to SerialBase::putc |
BlazeX | 0:cd0d79be0c1a | 107 | void onTxIrq(); // serial base port now writeable, lets put some bytes |
BlazeX | 0:cd0d79be0c1a | 108 | |
BlazeX | 0:cd0d79be0c1a | 109 | // RX: Move data from SerialBase::getc to rxBuffer |
BlazeX | 0:cd0d79be0c1a | 110 | void onRxIrq(); // serial base port now readable, lets get some bytes |
BlazeX | 0:cd0d79be0c1a | 111 | |
BlazeX | 0:cd0d79be0c1a | 112 | // Enable / Disable |
BlazeX | 0:cd0d79be0c1a | 113 | inline void disableTxInterrupt() { serial_irq_set(&_serial, (SerialIrq)TxIrq, 0); } |
BlazeX | 0:cd0d79be0c1a | 114 | inline void enableTxInterrupt() { serial_irq_set(&_serial, (SerialIrq)TxIrq, 1); } |
BlazeX | 0:cd0d79be0c1a | 115 | |
BlazeX | 0:cd0d79be0c1a | 116 | inline void disableRxInterrupt() { serial_irq_set(&_serial, (SerialIrq)RxIrq, 0); } |
BlazeX | 0:cd0d79be0c1a | 117 | inline void enableRxInterrupt() { serial_irq_set(&_serial, (SerialIrq)RxIrq, 1); } |
BlazeX | 0:cd0d79be0c1a | 118 | |
BlazeX | 0:cd0d79be0c1a | 119 | |
BlazeX | 0:cd0d79be0c1a | 120 | public: |
BlazeX | 0:cd0d79be0c1a | 121 | //////////////////////////////////////////////////////////////// |
BlazeX | 0:cd0d79be0c1a | 122 | // Extended IO Operation |
BlazeX | 0:cd0d79be0c1a | 123 | |
BlazeX | 0:cd0d79be0c1a | 124 | /// @brief write a buck of bytes |
BlazeX | 0:cd0d79be0c1a | 125 | /// |
BlazeX | 0:cd0d79be0c1a | 126 | /// No timeout! To block, or not to block. That is the question. |
BlazeX | 0:cd0d79be0c1a | 127 | /// @param buffer buck of bytes |
BlazeX | 0:cd0d79be0c1a | 128 | /// @param length write how much bytes? |
BlazeX | 0:cd0d79be0c1a | 129 | /// @param block idle wait for every @ref putc to complete |
BlazeX | 0:cd0d79be0c1a | 130 | /// @return written bytes. For non block write it could be < length! |
BlazeX | 0:cd0d79be0c1a | 131 | int write(const unsigned char * buffer, const unsigned int length, bool block= true); |
BlazeX | 0:cd0d79be0c1a | 132 | |
BlazeX | 0:cd0d79be0c1a | 133 | /// @brief read a buck of bytes |
BlazeX | 0:cd0d79be0c1a | 134 | /// |
BlazeX | 0:cd0d79be0c1a | 135 | /// No timeout! To block, or not to block. That is the question. |
BlazeX | 0:cd0d79be0c1a | 136 | /// @param buffer buck of bytes |
BlazeX | 0:cd0d79be0c1a | 137 | /// @param length read how much bytes? |
BlazeX | 0:cd0d79be0c1a | 138 | /// @param block idle wait for every @ref getc to complete |
BlazeX | 0:cd0d79be0c1a | 139 | /// @return read bytes. For non block read it could be < length! |
BlazeX | 0:cd0d79be0c1a | 140 | int read(unsigned char * buffer, const unsigned int length, bool block= true); |
BlazeX | 0:cd0d79be0c1a | 141 | |
BlazeX | 0:cd0d79be0c1a | 142 | |
BlazeX | 0:cd0d79be0c1a | 143 | /// @brief Write a string (without terminating null) |
BlazeX | 0:cd0d79be0c1a | 144 | /// |
BlazeX | 0:cd0d79be0c1a | 145 | /// For compatibility with mbed RawSerial |
BlazeX | 0:cd0d79be0c1a | 146 | /// @param str null terminated string |
BlazeX | 0:cd0d79be0c1a | 147 | /// @param block idle wait for every @ref putc to complete |
BlazeX | 0:cd0d79be0c1a | 148 | /// @return written chars (without terminating null) |
BlazeX | 0:cd0d79be0c1a | 149 | int puts(const char * str, bool block= true); |
BlazeX | 0:cd0d79be0c1a | 150 | |
BlazeX | 0:cd0d79be0c1a | 151 | /// @brief Print a formatted string. |
BlazeX | 0:cd0d79be0c1a | 152 | /// |
BlazeX | 0:cd0d79be0c1a | 153 | /// Idle blocking! |
BlazeX | 0:cd0d79be0c1a | 154 | /// Dynamically allocates needed buffer. |
BlazeX | 0:cd0d79be0c1a | 155 | /// @param format null terminated format string |
BlazeX | 0:cd0d79be0c1a | 156 | /// @return written chars (without terminating null) |
BlazeX | 0:cd0d79be0c1a | 157 | int printf(const char * format, ...); |
BlazeX | 0:cd0d79be0c1a | 158 | |
BlazeX | 0:cd0d79be0c1a | 159 | |
BlazeX | 0:cd0d79be0c1a | 160 | //////////////////////////////////////////////////////////////// |
BlazeX | 0:cd0d79be0c1a | 161 | // Buffer Infos |
BlazeX | 0:cd0d79be0c1a | 162 | |
BlazeX | 0:cd0d79be0c1a | 163 | /// @brief Checks if TX buffer is full |
BlazeX | 0:cd0d79be0c1a | 164 | /// @return true - TX buffer is full, false - else |
BlazeX | 0:cd0d79be0c1a | 165 | inline bool isTxBufferFull() { return txCount == txBufferLength; } |
BlazeX | 0:cd0d79be0c1a | 166 | |
BlazeX | 0:cd0d79be0c1a | 167 | /// @brief Checks if RX buffer is full |
BlazeX | 0:cd0d79be0c1a | 168 | /// @return true - RX buffer is full, false - else |
BlazeX | 0:cd0d79be0c1a | 169 | inline bool isRxBufferFull() { return rxCount == rxBufferLength; } |
BlazeX | 0:cd0d79be0c1a | 170 | |
BlazeX | 0:cd0d79be0c1a | 171 | /// @brief Checks if TX buffer is empty |
BlazeX | 0:cd0d79be0c1a | 172 | /// @return true - TX buffer is empty, false - else |
BlazeX | 0:cd0d79be0c1a | 173 | inline bool isTxBufferEmtpy() { return txCount == 0; } |
BlazeX | 0:cd0d79be0c1a | 174 | |
BlazeX | 0:cd0d79be0c1a | 175 | /// @brief Checks if RX buffer is empty |
BlazeX | 0:cd0d79be0c1a | 176 | /// @return true - RX buffer is empty, false - else |
BlazeX | 0:cd0d79be0c1a | 177 | inline bool isRxBufferEmpty() { return rxCount == 0; } |
BlazeX | 0:cd0d79be0c1a | 178 | |
BlazeX | 0:cd0d79be0c1a | 179 | |
BlazeX | 0:cd0d79be0c1a | 180 | /// @brief Checks if TX buffer is writeable (= not full). |
BlazeX | 0:cd0d79be0c1a | 181 | /// |
BlazeX | 0:cd0d79be0c1a | 182 | /// For compatibility with mbed Serial. |
BlazeX | 0:cd0d79be0c1a | 183 | /// @return true - TX buffer is writeable, false - else |
BlazeX | 0:cd0d79be0c1a | 184 | inline bool writeable() { return !isTxBufferFull(); } |
BlazeX | 0:cd0d79be0c1a | 185 | |
BlazeX | 0:cd0d79be0c1a | 186 | /// @brief Checks if RX buffer is readable (= not empty). |
BlazeX | 0:cd0d79be0c1a | 187 | /// |
BlazeX | 0:cd0d79be0c1a | 188 | /// For compatibility with mbed Serial. |
BlazeX | 0:cd0d79be0c1a | 189 | /// @return true - RX buffer is readable, false - else |
BlazeX | 0:cd0d79be0c1a | 190 | inline bool readable() { return !isRxBufferEmpty(); } |
BlazeX | 3:ea9719695b6a | 191 | |
BlazeX | 3:ea9719695b6a | 192 | |
BlazeX | 3:ea9719695b6a | 193 | /// @brief Returns number of dropped bytes that did not fit into TX buffer |
BlazeX | 3:ea9719695b6a | 194 | /// @return number of dropped tx bytes |
BlazeX | 3:ea9719695b6a | 195 | inline int getNumTxDrops() { return numTxDrops; } |
BlazeX | 3:ea9719695b6a | 196 | |
BlazeX | 3:ea9719695b6a | 197 | /// @brief Returns number of dropped bytes that did not fit into RX buffer |
BlazeX | 3:ea9719695b6a | 198 | /// @return number of dropped rx bytes |
BlazeX | 3:ea9719695b6a | 199 | inline int getNumRxDrops() { return numRxDrops; } |
BlazeX | 0:cd0d79be0c1a | 200 | }; |