Just a small test for frames and serial (RS232) communication, with ideas from http://eli.thegreenplace.net/2009/08/20/frames-and-protocols-for-the-serial-port-in-python/

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
janwesterkamp
Date:
Wed May 02 06:01:00 2012 +0000
Commit message:

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
parser.c Show annotated file Show diff for this revision Revisions of this file
parser.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 566fc5f530fe main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed May 02 06:01:00 2012 +0000
@@ -0,0 +1,103 @@
+#include "mbed.h"
+#include "parser.h"
+#include "string"
+#include "list"
+
+Serial pc(USBTX, USBRX);    // initialize RS232 via USB
+
+DigitalOut prg_activity_led(LED1);     // some LED to show activity
+DigitalOut rx_activity_led(LED2);
+DigitalOut tx_activity_led(LED3);
+DigitalOut message_led(LED4);
+
+// we need some storage for the messages we want to send and receive
+string singleSendMessageBuffer;
+string singleReceiveMessageBuffer;
+// and a buffer for those messages, until they are processed
+list<string> sendMessagesBuffer;
+list<string> receiveMessagesBuffer;
+
+
+// Interupt Routine to read in data from serial port
+void Rx_interrupt() {
+    rx_activity_led=!rx_activity_led;
+    // Loop just in case more than one character is in UART's receive FIFO buffer
+    while (pc.readable()) {
+        char c = pc.getc();
+        unwrap_protocol(&c, &singleReceiveMessageBuffer, &receiveMessagesBuffer);
+        // pc.putc(c); // echo
+    }
+    return;
+}
+
+
+// Interupt Routine to write out data to serial port
+void Tx_interrupt() {
+    char c;
+    int finished = WRAP_SEND;
+    int messageAvailable = !sendMessagesBuffer.empty();
+
+    tx_activity_led=!tx_activity_led;
+
+    // Loop to fill more than one character in UART's transmit FIFO buffer
+    while (  pc.writeable() && messageAvailable && (finished == WRAP_SEND)) {
+        finished = wrap_protocol( &c, &singleSendMessageBuffer, &sendMessagesBuffer );
+        if (finished != WRAP_ABORT)
+            pc.putc(c);
+    }
+
+    //tx_activity_led=0;
+    return;
+}
+
+
+int main() {
+
+    string sendString;
+
+    pc.baud(115200);        // other high speed: 921600
+
+    // Setup a serial interrupt function to receive data
+    pc.attach(&Rx_interrupt, Serial::RxIrq);
+    // Setup a serial interrupt function to transmit data
+    pc.attach(&Tx_interrupt, Serial::TxIrq);
+    // enable interrupt
+    NVIC_EnableIRQ(UART1_IRQn);
+
+    set_time(0);            // needed to initialize rtc
+
+    while (1) {
+        prg_activity_led = !prg_activity_led;       // toggle LED
+        time_t seconds = time(NULL);    // get current time
+
+        //printf("Time as a string = %s\r\n", ctime(&seconds));
+
+        if (!receiveMessagesBuffer.empty()) {
+            //pc.printf("\r\nMessage: %s\r\n", receiveMessagesBuffer.front().c_str());
+
+            sendString = "Message '";
+            sendString += receiveMessagesBuffer.front().c_str();
+            sendString += "' received at ";
+            sendString += ctime(&seconds);
+            sendString += "\r";
+
+            sendMessagesBuffer.push_back(sendString);
+            receiveMessagesBuffer.pop_front();
+
+        } else {
+            //sendString = "Hallo Welt!\r\n";
+            sendString = ctime(&seconds);
+            sendString += "\r";
+            sendMessagesBuffer.push_back(sendString);
+        }
+        
+        
+        // trigger sending interrupt
+        char c;
+        int finished = wrap_protocol( &c, &singleSendMessageBuffer, &sendMessagesBuffer );
+        if (finished != WRAP_ABORT)
+            pc.putc(c);
+
+        wait(1); // wait and don't flood the RS232
+    }
+}
diff -r 000000000000 -r 566fc5f530fe mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed May 02 06:01:00 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479
diff -r 000000000000 -r 566fc5f530fe parser.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.c	Wed May 02 06:01:00 2012 +0000
@@ -0,0 +1,113 @@
+/*
+ *
+ */
+
+#include "mbed.h"
+#include "parser.h"
+
+int wrap_protocol(char *c, string *message, list<string> *messages, char header, char footer, char dle ) {
+
+    static int state = 0;
+    static int dle_state = 0;
+    static int index;
+    static int size;
+
+
+    switch (state) {
+        case 0: // start sending a header if there is a valid message available
+            if (!messages->empty()) {
+                *message =  messages->front();
+                messages->pop_front();      // now that we have the message, delete it from the list
+                index = 0;                  // initialize sending the actual message
+                size = message->size();
+                state = 1;
+                *c = header;
+                return WRAP_SEND;
+            }
+            return WRAP_ABORT;
+
+        case 1:
+            if ((size == 0) || (index==size)) {
+                *c = footer;
+                state = 0;
+                return WRAP_FINISHED;
+            }
+
+            *c = (*message)[index];
+
+            if ( dle_state == 1 ) {
+                dle_state = 0;
+                index++;
+                return WRAP_SEND;
+            }
+
+            if ( (*c == header) || (*c == footer) || (*c == dle) ) {
+                dle_state = 1;
+                *c = dle;
+                return WRAP_SEND;
+            }
+
+            index++;
+            return WRAP_SEND;
+    }
+
+    // if we reach this point, something went wrong!
+    return WRAP_ABORT;
+}
+
+void unwrap_protocol(char *c, string *buffer, list<string> *messages, unsigned int max_message_size,
+                     unsigned int max_messages, char header, char footer, char dle ) {
+
+    // these are needed for the internal state of the function
+    // they are also the reaseon, why this function can only be used in exactly one location
+    // i.e. the interrupt routine for receiving characters from the RS232
+    static int state = 0;
+    static int dle_state = 0;
+
+    switch (state) {
+        case 0:
+            if (*c == header) {
+                message_led=!message_led;
+                state = 1;
+            }
+            return;
+
+        case 1:
+            if (*c== header && dle_state==0) {
+                // new header that is not escaped will set e new message start
+                buffer->clear();
+                return;
+            }
+            if (*c == footer && dle_state==0 ) {
+                // a frame end is only a frame end, if the footer is not escaped
+                messages->push_back( *buffer );
+                buffer->clear();
+                state = 0;
+                message_led=!message_led;
+                return;
+            }
+
+            // check length of buffer; clear, if too large; restart search for header!
+            if (buffer->length() > max_message_size) {
+                // prevent buffer overflows if someone is flooding us with characters
+                buffer->clear();
+                state=0;
+                return;
+            }
+
+            if (*c == dle && dle_state==0) {
+                // the next character is "escaped" and is part of the message
+                dle_state = 1;
+                return;
+            }
+
+            // probably the easiest and quickest way of resetting the dle_state
+            dle_state = 0;
+
+            // in all other cases, we found a new character and append it to the buffer
+            *buffer += *c;
+    }
+}
+
+
+
diff -r 000000000000 -r 566fc5f530fe parser.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.h	Wed May 02 06:01:00 2012 +0000
@@ -0,0 +1,32 @@
+/*
+ *
+ */
+
+#ifndef _PARSER_H_
+#define _PARSER_H_
+
+#include "string"
+#include "list"
+
+#define WRAP_SEND   1
+#define WRAP_ABORT  2
+#define WRAP_FINISHED  3
+
+#define HEADER_CHAR 'A'
+#define FOOTER_CHAR 'B'
+#define DLE_CHAR '+'
+
+void unwrap_protocol(char *, string *buffer, list<string> *messages,
+                     unsigned int max_message_size = 255, unsigned int max_message = 5,
+                     char header=HEADER_CHAR, char footer=FOOTER_CHAR, char dle=DLE_CHAR);
+
+
+int wrap_protocol(char *c, string *buffer, list<string> *messages,
+                   char header=HEADER_CHAR, char footer=FOOTER_CHAR, char dle=DLE_CHAR);
+
+
+// these have to be declared somewhere else for consistency
+extern DigitalOut message_led;
+
+
+#endif