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.
Diff: SerialDriver.h
- Revision:
- 0:cd0d79be0c1a
- Child:
- 3:ea9719695b6a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SerialDriver.h Wed Jan 14 16:30:14 2015 +0000 @@ -0,0 +1,173 @@ +/// @file SerialDriver.h +/// @brief RTOS compatible buffered Serial port driver +/// +/// Examples: +/// - @ref Example_printf.cpp +/// - @ref Example_Nullmodem.cpp +/// - @ref Example_Bridge.cpp +/// - @ref Example_Blocking.cpp +/// +/// +/// Dependencies: +/// - cstdarg +/// @see https://developer.mbed.org/users/mbed_official/code/mbed-rtos/ +/// @see https://developer.mbed.org/users/mbed_official/code/mbed/ + +#pragma once + +#include "mbed.h" +#include "rtos.h" +#include <cstdarg> + + +/// @class SerialDriver +/// @brief RTOS compatible buffered Serial port driver +/// +/// - Based on SerialBase. +/// - Can use external buffers. +/// - ISR driven, ring buffered IO operation +/// - Can Replace mbed RawSerial +/// - IO operations are idle waiting, don't waste time in RTOS :D +/// - Do not use attach methods for TxIrq or RxIrq! They are already in use. +class SerialDriver : public SerialBase +{ +protected: + // ring buffered rx/tx + unsigned char * txBuffer; + unsigned char * rxBuffer; + int txBufferLength, rxBufferLength; + + // ring buffer cursors + volatile int txIn, txOut; + volatile int rxIn, rxOut; + volatile int txCount, rxCount; + + // semaphores for timeout (used as signals) + Semaphore semTxBufferFull; // used by putc to wait + Semaphore semRxBufferEmpty; // used by getc to wait + + +public: + /// @brief Prepares ring buffer and irq + /// + /// If no buffer was set, the buffer gets allocated. + /// @param txPin TX PinName, e.g. USBTX + /// @param rxPin RX PinName, e.g. USBRX + /// @param txBufferLength_ size of TX buffer. Must be > 1! + /// @param rxBufferLength_ size of RX buffer. Must be > 1! + /// @param txBuffer_ TX buffer, if NULL, the buffer will be allocated + /// @param rxBuffer_ RX buffer, if NULL, the buffer will be allocated + SerialDriver(PinName txPin, PinName rxPin, int txBufferLength_= 256, int rxBufferLength_= 256, unsigned char * txBuffer_= NULL, unsigned char * rxBuffer_= NULL); + + + //////////////////////////////////////////////////////////////// + // Basic IO Operation + + /// @brief Put a byte to the TX buffer + /// + /// If the TX buffer is full, it waits the defined timeout. + /// Drops the byte, if TX buffer is still full after timeout. + /// @param c The byte to write + /// @param timeoutMs give TX buffer time to get writeable. + /// @return 1 - success, 0 - if TX Buffer was full all the time + int putc(int c, unsigned int timeoutMs= osWaitForever); + + + /// @brief Get a byte from the RX buffer + /// + /// If the RX buffer is empty, it waits the defined timeout. + /// @param timeoutMs give RX buffer time to get readable. + /// @return next byte from RX buffer or -1 after timeout. + int getc(unsigned int timeoutMs= osWaitForever); + + +protected: + //////////////////////////////////////////////////////////////// + // Interrupts + + // TX: Move data from txBuffer to SerialBase::putc + void onTxIrq(); // serial base port now writeable, lets put some bytes + + // RX: Move data from SerialBase::getc to rxBuffer + void onRxIrq(); // serial base port now readable, lets get some bytes + + // Enable / Disable + inline void disableTxInterrupt() { serial_irq_set(&_serial, (SerialIrq)TxIrq, 0); } + inline void enableTxInterrupt() { serial_irq_set(&_serial, (SerialIrq)TxIrq, 1); } + + inline void disableRxInterrupt() { serial_irq_set(&_serial, (SerialIrq)RxIrq, 0); } + inline void enableRxInterrupt() { serial_irq_set(&_serial, (SerialIrq)RxIrq, 1); } + + +public: + //////////////////////////////////////////////////////////////// + // Extended IO Operation + + /// @brief write a buck of bytes + /// + /// No timeout! To block, or not to block. That is the question. + /// @param buffer buck of bytes + /// @param length write how much bytes? + /// @param block idle wait for every @ref putc to complete + /// @return written bytes. For non block write it could be < length! + int write(const unsigned char * buffer, const unsigned int length, bool block= true); + + /// @brief read a buck of bytes + /// + /// No timeout! To block, or not to block. That is the question. + /// @param buffer buck of bytes + /// @param length read how much bytes? + /// @param block idle wait for every @ref getc to complete + /// @return read bytes. For non block read it could be < length! + int read(unsigned char * buffer, const unsigned int length, bool block= true); + + + /// @brief Write a string (without terminating null) + /// + /// For compatibility with mbed RawSerial + /// @param str null terminated string + /// @param block idle wait for every @ref putc to complete + /// @return written chars (without terminating null) + int puts(const char * str, bool block= true); + + /// @brief Print a formatted string. + /// + /// Idle blocking! + /// Dynamically allocates needed buffer. + /// @param format null terminated format string + /// @return written chars (without terminating null) + int printf(const char * format, ...); + + + //////////////////////////////////////////////////////////////// + // Buffer Infos + + /// @brief Checks if TX buffer is full + /// @return true - TX buffer is full, false - else + inline bool isTxBufferFull() { return txCount == txBufferLength; } + + /// @brief Checks if RX buffer is full + /// @return true - RX buffer is full, false - else + inline bool isRxBufferFull() { return rxCount == rxBufferLength; } + + /// @brief Checks if TX buffer is empty + /// @return true - TX buffer is empty, false - else + inline bool isTxBufferEmtpy() { return txCount == 0; } + + /// @brief Checks if RX buffer is empty + /// @return true - RX buffer is empty, false - else + inline bool isRxBufferEmpty() { return rxCount == 0; } + + + /// @brief Checks if TX buffer is writeable (= not full). + /// + /// For compatibility with mbed Serial. + /// @return true - TX buffer is writeable, false - else + inline bool writeable() { return !isTxBufferFull(); } + + /// @brief Checks if RX buffer is readable (= not empty). + /// + /// For compatibility with mbed Serial. + /// @return true - RX buffer is readable, false - else + inline bool readable() { return !isRxBufferEmpty(); } +};