An RTOS-friendly Serial interface Its primary benefit is that it never hogs the CPU. An amusing alternative to the traditional ring-bufferd interrupt-serviced systems, it uses short mbed-rtos queues to buffer characters to and from the UART, and a thread to service the transmitter. Short interrupt service routines enqueue received characters and signal the transmit thread when the transmitter is available. WARNING: Do not create RTOS-Serial objects before the RTOS is running! Put them inside your main() block or another function, not in the global initialization.

Dependents:   Test_RDM880_rfid_reader

Revision:
12:be7883573c91
Parent:
11:bc067b42f8e0
Child:
13:2fb32235253c
--- a/rtos_serial.cpp	Thu Oct 24 05:34:47 2013 +0000
+++ b/rtos_serial.cpp	Thu Oct 24 17:30:52 2013 +0000
@@ -28,25 +28,18 @@
  */
 #include "rtos_serial.h"
 
+#define START_THREAD 0x80
+
 RTOS_Serial::RTOS_Serial(PinName tx, PinName rx, const char *name)
- : Serial(tx, rx, name)
+ : RawSerial(tx, rx), name(name),
+   _tx_thread(&RTOS_Serial::threadStarter, (void *) this,
+                    osPriorityNormal, RTOS_SERIAL_TX_THREAD_STACK_SIZE)
 {
     uart_number = get_index();
     const PinName leds[] = {LED1,LED2,LED3,LED4};
     ledp = new DigitalOut(leds[uart_number]);
-#ifdef RTOS_SERIAL_TX_THREAD
-    tx_emitter_threadp = new Thread(tx_emitter, (void *) this,
-                    osPriorityNormal, RTOS_SERIAL_TX_THREAD_STACK_SIZE);
-#endif
-//    rx_isr_pFP = attach(this, &RTOS_Serial::rx_isr, RxIrq);
-//    tx_isr_pFP = attach(this, &RTOS_Serial::tx_isr, TxIrq);    
-    attach(this, &RTOS_Serial::rx_isr, RxIrq);
-    attach(this, &RTOS_Serial::tx_isr, TxIrq);    
-#ifdef RTOS_SERIAL_TX_THREAD
-    tx_emitter_threadp->signal_set(0x01);   // "prime the pump" of the tx-ready signals
-#else
-    Serial::_putc('*'); //DEBUG
-#endif
+    for (int i=0; i<1; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5);
+    _tx_thread.signal_set(START_THREAD);
 }
 
 #if 0
@@ -64,8 +57,8 @@
     std::printf("returned %d]", b); std::fflush(stdout);
 #endif
 #ifdef RTOS_SERIAL_TX_THREAD
-    tx_emitter_threadp->terminate();
-    std::printf("[tx_emitter_thread 0x%x terminated]", tx_emitter_threadp); std::fflush(stdout);
+    _tx_thread.terminate();
+    std::printf("[tx_emitter_thread 0x%x terminated]", &_tx_thread); std::fflush(stdout);
     delete tx_emitter_threadp;
     std::printf("[tx_emitter_threadp deleted]"); std::fflush(stdout);
 #endif
@@ -100,7 +93,7 @@
 }
 
 int RTOS_Serial::parent_putc(int c) {
-    return Serial::_putc(c);
+    return RawSerial::putc(c);
 }
 
 int RTOS_Serial::getc() {
@@ -117,31 +110,31 @@
 }
 
 void RTOS_Serial::rx_isr(){
-    rx_q.put((int *) _getc());  // returns immediately even if queue was full
+    rx_q.put((int *) RawSerial::getc());  // returns immediately even if queue was full
 }
 
 void RTOS_Serial::tx_isr(){
-#ifdef RTOS_SERIAL_TX_THREAD
-    tx_emitter_threadp->signal_set(0x1);
-#else
-    osEvent evt;
-    evt = tx_q.get();   // BUG: This will wait forever in ISR!
-    if (evt.status == osEventMessage) {
-        *ledp = 1;
-        parent_putc(evt.value.v);
-        *ledp = 0;
-    } /*else {
-        std::printf("\r\nRTOS_Serial::tx_emitter() evt.status %d\n", evt.status);
-    }*/
-#endif
+    _tx_thread.signal_set(0x1);
 }
 
-#ifdef RTOS_SERIAL_TX_THREAD
-// tx_emitter is a class method
+
+void RTOS_Serial::threadStarter(void const *p) {
+    RTOS_Serial *instance = (RTOS_Serial*)p;
+    instance->_tx_thread.signal_set(0x01);   // "prime the pump" of the tx-ready signals
+    instance->tx_emitter(instance);
+}
+
 void RTOS_Serial::tx_emitter(void const *argument){
     RTOS_Serial *sp = (RTOS_Serial *) argument;
     osEvent evt;
     //osStatus status;
+    _tx_thread.signal_wait(START_THREAD);
+    for (int i=0; i<2; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5);
+    attach(this, &RTOS_Serial::rx_isr, RxIrq);
+    for (int i=0; i<3; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5);
+    attach(this, &RTOS_Serial::tx_isr, TxIrq);    
+    for (int i=0; i<4; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5);
+
     while(true){
         evt = sp->tx_q.get();
         if (evt.status == osEventMessage) {
@@ -163,4 +156,3 @@
         *(sp->ledp) = 0;
     }
 }
-#endif