A library to send and receive packets over serial, uses MODSERIAL

Dependents:   SimpleSerialProtocolExample SerialFileReceiver

Codec.h

Committer:
p3p
Date:
2014-09-18
Revision:
2:43794e0b738f
Child:
3:5caff50e14a7

File content as of revision 2:43794e0b738f:

#ifndef SIMPLE_SERIAL_PROTOCOL_CODEC
#define SIMPLE_SERIAL_PROTOCOL_CODEC

#include "Ringbuffer.h"
#include "Packet.h"

namespace SimpleSerialProtocol {

class ICodec {
public:
    ICodec(){}
    virtual ~ICodec(){}
    virtual bool encode(Packet* packet, RingBuffer* buffer) = 0;
    virtual void decode(Packet* packet, char data) = 0;
    virtual uint32_t getStreamErrors() = 0;
    virtual uint32_t getPacketErrors() = 0;
};

class Codec: public ICodec {
public:
    Codec(){
        state = PACKET_STARTA;
        header_read = 0;
        data_read = 0;
        stream_errors = 0;
        packet_errors = 0;
    }
    virtual ~Codec(){}
    
    virtual uint32_t getStreamErrors() {
        return stream_errors;
    }
    virtual uint32_t getPacketErrors() {
        return packet_errors;    
    }
    
    virtual bool encode(Packet* packet, RingBuffer* buffer){
        if (packet!=0) {
            
            if((buffer->size() - buffer->available()) < packet->_size + 4){
                return false;    
            }
            
            buffer->write(255);
            buffer->write(127);
            buffer->write(packet->_size);
            for (int i = 0; i < packet->_size; i++) {
                 buffer->write(packet->_data[i]);
            }
            buffer->write(checksum(packet));
            
            return true;
            
        }
        return 0;
    }
    
    virtual void decode(Packet* packet, char data){
        switch (state) {
            case PACKET_STARTA:
                if(data == PACKET_BYTE1){
                    state = PACKET_STARTB;
                }
                break;
                
            case PACKET_STARTB:
                if(data == PACKET_BYTE2){
                    state = HEADER_RECEIVE;
                } else {
                    state = PACKET_STARTA;
                    stream_errors ++; 
                }
                break;

            case HEADER_RECEIVE:
                header[header_read++] = data;
                if(header_read == PACKET_HEADER_SIZE){
                    packet->_size = header[0];
                    state = DATA_RECEIVE;
                }
                break;

            case DATA_RECEIVE:
                if (data_read < packet->_size) {
                    packet->_data[data_read++] = data;
                    if (data_read == packet->_size) {
                        state = DATA_VALIDATE;
                    }
                } else {
                    state = PACKET_STARTA;
                    header_read = 0;
                    data_read = 0;
                }
                break;

            case DATA_VALIDATE:
                packet->_type = packet->_data[0];
                packet->_checksum = data;
                if (checksum(packet) == packet->_checksum) {
                    packet->_valid = true;
                } else {
                    packet_errors ++;    
                }
                state = PACKET_STARTA;
                header_read = 0;
                data_read = 0;
                break;

            default:
                state = PACKET_STARTA;
                header_read = 0;
                data_read = 0;
                break;
        }
    }
    
    virtual uint16_t checksum(Packet* packet){
        uint8_t tmp_checksum = 16;
        for (int i = 0; i < packet->_size; i++) {
            tmp_checksum ^= packet->_data[i];
        }
        return tmp_checksum;
    }
    
    
    enum {
        PACKET_STARTA,
        PACKET_STARTB,
        HEADER_RECEIVE,
        DATA_RECEIVE,
        DATA_VALIDATE,
    };
    
    enum {
        PACKET_BYTE1 = 255,
        PACKET_BYTE2 = 127,
        PACKET_HEADER_SIZE = 1, 
    };
    
    uint8_t state;
    char header[PACKET_HEADER_SIZE];
    uint8_t header_read; 
    uint32_t data_read;
    uint32_t stream_errors;
    uint32_t packet_errors;
    
};
    
}

#endif