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

parser.c

Committer:
janwesterkamp
Date:
2012-05-02
Revision:
0:566fc5f530fe

File content as of revision 0:566fc5f530fe:

/*
 *
 */

#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;
    }
}