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/
Revision 0:566fc5f530fe, committed 2012-05-02
- Comitter:
- janwesterkamp
- Date:
- Wed May 02 06:01:00 2012 +0000
- Commit message:
Changed in this revision
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