Experiment of serial command protocol
Dependencies: RingBuffer SerialInterfaceProtocol duinotech_16x2_LCD mbed
You can edit this area
Revision 4:658044ad7327, committed 2016-06-19
- Comitter:
- rba90
- Date:
- Sun Jun 19 01:39:39 2016 +0000
- Parent:
- 3:0c4aa3cec685
- Commit message:
- Create new library
Changed in this revision
--- a/CommandPacket.cpp Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -#include "CommandPacket.h" -#include "mbed.h" - -#define CHECKSUM_DEBUG - -uint8_t generate_checksum(uint8_t *data, uint8_t length, uint8_t offset) -{ - uint8_t s = 0; - - if (data) - { - // take the sum of all data bytes preceding checksum field - for(uint8_t i = 0; i < length; i++) - { - s += data[i + offset]; - } - - // calculate two's complement of the remainder - s = 0xff - s + 1; - } - - return s; -} - -uint8_t hexchar_to_uint8(uint8_t ch) -{ - uint8_t val = 0; - - if (ch >= '0' && ch <= '9') - { - val = ch - '0'; - } - else if (ch >= 'A' && ch <= 'F') - { - val = ch - 'A'; - val += 10; - } - else if (ch >= 'a' && ch <= 'f') - { - val = ch - 'a'; - val += 10; - } - - return val; -} - - -bool CommandPacket::verify() -{ - return checksum == generate_checksum(); -} - -CommandPacket::CommandPacket() -{ - // reset internal error number - errno = NO_ERROR; - - // set public variables - sflag = '<'; - command = 0x0; - length = 0x0; - memset(payload, 0x0, sizeof(payload)); - checksum = 0x0; - eflag = '>'; -} - -const char *CommandPacket::getErrorString() const -{ - return errorString[errno]; -} - -int CommandPacket::serialize(uint8_t *output) -{ - // create buffer for payload - uint8_t buffer[length * 2]; - memset(buffer, 0x0, sizeof(buffer)); - - for (int i = 0; i < length; i++) - { - sprintf((char *) (buffer + i * 2), "%02X", payload[i]); - } - - // assume the user provide output buffer large enough - sprintf((char *) output, "%c%02X%02X%s%02X%c", - sflag, - command, - length, - (char *) buffer, - generate_checksum(), - eflag - ); - - return length; -} - -uint8_t CommandPacket::generate_checksum() -{ - // checksum is defined by the sum of all characters between sflag and checksum field - uint8_t s = 0; - - // include command - s += command; - - // include length - s += length; - - // include payload - for (int i = 0; i < length; i++) - { - s += payload[i]; - } - - // calculate two's complement of the remainder - s = 0xff - s + 1; - - return s; -} - -
--- a/CommandPacket.h Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -#ifndef COMMAND_PACKET_H_ -#define COMMAND_PACKET_H_ - -#include "stdint.h" - -// command packet consists of following parts -// u4 sflag -// u8 command -// u8 length -// u8 payload[len] -// u8 checksum -// u4 eflag - -uint8_t generate_checksum(uint8_t *payload, uint8_t length, uint8_t offset=0); -uint8_t hexchar_to_uint8(uint8_t ch); -uint8_t uint8_to_hexchar(uint8_t data); - -static const char *errorString[16] = - { - "No Error", - "Invalid start flag", - "Invalid end flag", - "Invalid command", - "Invalid checksum" - }; - -static char errorCode[16] = { 0 }; - - -class CommandPacket -{ -public: - typedef enum - { - CP_SFLAG = '<', - CP_EFLAG = '>' - } CPFlag_t; - - typedef enum - { - NONE = 0, - SFLAG, - COMMAND_H, - COMMAND_L, - LENGTH_H, - LENGTH_L, - PAYLOAD_H, - PAYLOAD_L, - CHECKSUM_H, - CHECKSUM_L, - EFLAG - } State_t; - - typedef enum - { - NO_ERROR = 0, - INVALID_SFLAG_ERROR, - INVALID_EFLAG_ERROR, - INVALID_CMD_ERROR, - INVALID_CS_ERROR, - INVALID_EXEC_ERROR - } Error_t; - -public: - Error_t errno; - -public: - uint8_t sflag; - uint8_t command; - uint8_t length; - uint8_t payload[256 + 1]; // payload include terminator - uint8_t checksum; - uint8_t eflag; - -public: - CommandPacket(); - ~CommandPacket() {}; - - bool verify(); - const char *getErrorString() const; - int serialize(uint8_t *output); - uint8_t generate_checksum(); -}; - - - - -#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RingBuffer.lib Sun Jun 19 01:39:39 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/ENEL400/code/RingBuffer/#36b372831d9e
--- a/SerialInterfaceProtocol.cpp Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -#include "SerialInterfaceProtocol.h" - -// #define DEBUG_MESSAGE - -SerialInterfaceProtocol::SerialInterfaceProtocol(SerialBuffer_t *in, SerialBuffer_t *out) -{ - // assign input and output buffers - SerialInputBuffer = in; - SerialOutputBuffer = out; - - // init command vector table - for (int i = 0; i < SIP_CMD_VECTOR_TABLE_SZ; i++) - { - CommandVectorTable[i] = NULL; - } - - // init internal state machine - state = CommandPacket::NONE; - - // init internal state - isChecksumEnabled = true; -} - -SerialInterfaceProtocol::~SerialInterfaceProtocol() -{ - -} - -void SerialInterfaceProtocol::registerCommand(uint8_t command, callback_func f) -{ - CommandVectorTable[command] = f; -} - -void SerialInterfaceProtocol::deRegisterCommand(uint8_t command) -{ - CommandVectorTable[command] = NULL; -} - -int SerialInterfaceProtocol::execute(uint8_t *response, uint8_t *response_length) -{ - - // execute the command if it's already been registered - if (CommandVectorTable[PacketBuffer.command] != NULL) - { - return CommandVectorTable[PacketBuffer.command]( - PacketBuffer.payload, - PacketBuffer.length, - response, - response_length - ); - } - - printf("Callback function not registered\r\n"); - - return -1; -} - -int SerialInterfaceProtocol::assemble(uint8_t *response, uint8_t response_length) -{ - // prepare for packet buffer - PacketBuffer.sflag = CommandPacket::CP_SFLAG; - - PacketBuffer.command = 0xE0 | ((uint8_t) PacketBuffer.errno & 0x0f); - - PacketBuffer.length = response_length; - - memcpy(PacketBuffer.payload, response, response_length); - - PacketBuffer.checksum = PacketBuffer.generate_checksum(); - - PacketBuffer.eflag = CommandPacket::CP_EFLAG; - - - // serialize the packet - int total_len = PacketBuffer.length * 2 + 8; - uint8_t buffer[total_len]; - memset(buffer, 0x0, total_len); - - PacketBuffer.serialize(buffer); - - // add to ring buffer - for (int i = 0; i < total_len; i++) - { - SerialOutputBuffer->enqueue(buffer[i]); - } - - return 0; - -} - -void SerialInterfaceProtocol::poll() -{ - static uint8_t payload_counter = 0; - uint8_t response[SIP_MAX_RESP_LEN]; - uint8_t response_length; - - // fetch data from ring buffer - while (SerialInputBuffer->getCounter() > 0) - { - uint8_t ch; - ch = SerialInputBuffer->dequeue(); - - // reset state to keep sync - if (ch == CommandPacket::CP_SFLAG) - { - state = CommandPacket::SFLAG; - - // reset variable - payload_counter = 0; - memset(PacketBuffer.payload, 0x0, sizeof(PacketBuffer.payload)); - PacketBuffer.errno = CommandPacket::NO_ERROR; - } - - switch (state) - { - case CommandPacket::SFLAG: - PacketBuffer.sflag = ch; - state = CommandPacket::COMMAND_H; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::SFLAG: 0x%x\r\n", PacketBuffer.sflag); -#endif - break; - - case CommandPacket::COMMAND_H: - PacketBuffer.command = hexchar_to_uint8(ch) << 4; - state = CommandPacket::COMMAND_L; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::COMMAND_H: 0x%x\r\n", PacketBuffer.command); -#endif - break; - - case CommandPacket::COMMAND_L: - PacketBuffer.command |= (hexchar_to_uint8(ch) & 0x0f); - state = CommandPacket::LENGTH_H; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::COMMAND_L: 0x%x\r\n", PacketBuffer.command); -#endif - break; - - case CommandPacket::LENGTH_H: - PacketBuffer.length = hexchar_to_uint8(ch) << 4; - state = CommandPacket::LENGTH_L; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::LENGTH_H: 0x%x\r\n", PacketBuffer.length); -#endif - break; - - case CommandPacket::LENGTH_L: - PacketBuffer.length |= (hexchar_to_uint8(ch) & 0x0f); - if (PacketBuffer.length != 0) // if the length is not zero, then proceed to payload state - { - state = CommandPacket::PAYLOAD_H; - } - else // otherwise proceed to checksum state - { - state = CommandPacket::CHECKSUM_H; - } -#ifdef DEBUG_MESSAGE - printf("CommandPacket::LENGTH_L: 0x%x\r\n", PacketBuffer.length); -#endif - break; - - case CommandPacket::PAYLOAD_H: - PacketBuffer.payload[payload_counter] = hexchar_to_uint8(ch) << 4; // store higher 4 bits of payload - state = CommandPacket::PAYLOAD_L; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::PAYLOAD_H: 0x%x\r\n", PacketBuffer.payload[payload_counter]); -#endif - break; - - case CommandPacket::PAYLOAD_L: - PacketBuffer.payload[payload_counter++] |= (hexchar_to_uint8(ch) & 0x0f); // store lower 4 bits of payload - if (payload_counter < PacketBuffer.length) // append ch to payload until reach the length - { - state = CommandPacket::PAYLOAD_H; - } - else - { - state = CommandPacket::CHECKSUM_H; - } -#ifdef DEBUG_MESSAGE - printf("CommandPacket::PAYLOAD_L: 0x%x\r\n", PacketBuffer.payload[payload_counter - 1]); -#endif - break; - - case CommandPacket::CHECKSUM_H: - PacketBuffer.checksum = hexchar_to_uint8(ch) << 4; - state = CommandPacket::CHECKSUM_L; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::CHECKSUM_H: 0x%x\r\n", PacketBuffer.checksum); -#endif - break; - - case CommandPacket::CHECKSUM_L: - PacketBuffer.checksum |= (hexchar_to_uint8(ch) & 0x0f); - - // checksum can be turned off - if (isChecksumEnabled) - { - if (PacketBuffer.verify()) // checksum match - { - state = CommandPacket::EFLAG; - } - else // checksum mismatch - { - PacketBuffer.errno = CommandPacket::INVALID_CS_ERROR; - - // prepare for checksum error response - PacketBuffer.errno = CommandPacket::INVALID_CS_ERROR; - assemble(response, response_length); - - state = CommandPacket::NONE; - } - } - else - { - state = CommandPacket::EFLAG; - } - - -#ifdef DEBUG_MESSAGE - printf("CommandPacket::CHECKSUM_L: 0x%x\r\n", PacketBuffer.checksum); -#endif - break; - - case CommandPacket::EFLAG: - if (ch == CommandPacket::CP_EFLAG) - { - PacketBuffer.eflag = ch; - - // clear response and response length - response_length = 0; - memset(response, 0x0, sizeof(response)); - - // execute command - int ret = execute(response, &response_length); - - if (ret < 0) // command not registered - { - PacketBuffer.errno = CommandPacket::INVALID_CMD_ERROR; - } - else if (ret != 0) // error to execute - { - PacketBuffer.errno = CommandPacket::INVALID_EXEC_ERROR; - } - - assemble(response, response_length); - } - state = CommandPacket::NONE; -#ifdef DEBUG_MESSAGE - printf("CommandPacket::EFLAG: 0x%x\r\n", PacketBuffer.eflag); -#endif - break; - - case CommandPacket::NONE: - PacketBuffer.errno = CommandPacket::INVALID_SFLAG_ERROR; - - // TODO:: Execute error generator - PacketBuffer.errno = CommandPacket::INVALID_SFLAG_ERROR; - assemble(response, response_length); - -#ifdef DEBUG_MESSAGE - printf("CommandPacket::NONE\r\n"); -#endif - break; - - default: - break; - } - } -} - -void SerialInterfaceProtocol::disableChecksum() -{ - isChecksumEnabled = false; -} - -void SerialInterfaceProtocol::enableChecksum() -{ - isChecksumEnabled = true; -} \ No newline at end of file
--- a/SerialInterfaceProtocol.h Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -// SerialInterfaceProtocol (SIP) is a protocol which help to exchange -// information between host and slave devices -#ifndef SERIALINTERFACEPROTOCOL_H_ -#define SERIALINTERFACEPROTOCOL_H_ - -#include "mbed.h" -#include "stdint.h" -#include "CommandPacket.h" -#include "buffer.h" - -#define SIP_CMD_VECTOR_TABLE_SZ 256 -#define SIP_MAX_RESP_LEN 256 -#define SIP_MAX_PAYLOAD_LEN 256 - -typedef int (*callback_func)(uint8_t *payload, uint8_t payload_length, uint8_t *response, uint8_t *response_length); -typedef CircularBuffer<uint8_t> SerialBuffer_t; - -class SerialInterfaceProtocol -{ -public: - // namespace - -protected: - // internal variable - callback_func CommandVectorTable[SIP_CMD_VECTOR_TABLE_SZ]; - - // buffered interface - SerialBuffer_t *SerialInputBuffer; - SerialBuffer_t *SerialOutputBuffer; - CommandPacket PacketBuffer; - - // state machine - CommandPacket::State_t state; - - // internal state - bool isChecksumEnabled; - -protected: - // internal methods - int execute(uint8_t *response, uint8_t *response_length); - - int assemble(uint8_t *response, uint8_t response_length); - - -public: - // public methods - - // constructor - SerialInterfaceProtocol(SerialBuffer_t *in, SerialBuffer_t *out); - ~SerialInterfaceProtocol(); - - // member function - void poll(); - void registerCommand(uint8_t command, callback_func f); - void deRegisterCommand(uint8_t command); - - void disableChecksum(); - void enableChecksum(); - -}; - - - - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SerialInterfaceProtocol.lib Sun Jun 19 01:39:39 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/ENEL400/code/SerialInterfaceProtocol/#21e4e3afa5e6
--- a/buffer.cpp Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -#include "buffer.h" - -template <typename T> -CircularBuffer<T>::CircularBuffer(const uint32_t size) - :buffer_size(size) -{ - read_ptr = 0; - write_ptr = 0; - count = 0; - - // mutex lock - mux = false; - - // overflow - is_over_flow = false; - - // container - data = new T[buffer_size]; -} - -template <typename T> -CircularBuffer<T>::~CircularBuffer() -{ - delete[] data; -} - -template <typename T> -bool CircularBuffer<T>::isLocked() -{ - return mux; -} - -template <typename T> -void CircularBuffer<T>::lock() -{ - mux = true; -} - -template <typename T> -void CircularBuffer<T>::unlock() -{ - mux = false; -} - -template <typename T> -void CircularBuffer<T>::enqueue(T in) -{ - data[write_ptr++] = in; - write_ptr %= buffer_size; - - count++; -} - -template <typename T> -T CircularBuffer<T>::dequeue() -{ - T temp = data[read_ptr++]; - read_ptr %= buffer_size; - - count--; - return temp; -} - -template <typename T> -uint32_t CircularBuffer<T>::getReadPtr() -{ - return read_ptr; -} - -template <typename T> -uint32_t CircularBuffer<T>::getWritePtr() -{ - return write_ptr; -} - -template <typename T> -uint32_t CircularBuffer<T>::getCounter() -{ - return count; -} - -template <typename T> -bool CircularBuffer<T>::getOverFlow() -{ - return is_over_flow; -} - -template <typename T> -void CircularBuffer<T>::clearOverFlow() -{ - is_over_flow = false; -} - -template <typename T> -T CircularBuffer<T>::first() -{ - if (read_ptr > 0) - { - return data[read_ptr - 1]; - } - else - { - return data[read_ptr]; - } -} - -template <typename T> -T CircularBuffer<T>::last() -{ - if (write_ptr > 0) - { - return data[write_ptr - 1]; - } - else - { - return data[write_ptr]; - } -} - -template <typename T> -T CircularBuffer<T>::operator[](uint32_t idx) -{ - return data[idx]; -} - -// force compiler to create code for template -template class CircularBuffer<int>; -template class CircularBuffer<uint8_t>; -template class CircularBuffer<uint16_t>; -template class CircularBuffer<uint32_t>; \ No newline at end of file
--- a/buffer.h Thu Jun 16 03:52:01 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -#ifndef BUFFER_H_ -#define BUFFER_H_ - -#define DEFAULT_MAX_BUFFER_SZ 64 - -#include "stdint.h" - -template <typename T> -class CircularBuffer -{ -private: - const uint32_t buffer_size; - uint32_t read_ptr; - uint32_t write_ptr; - uint32_t count; - - // mutex lock - bool mux; - - // overflow - bool is_over_flow; - - // container - T *data; - - -public: - CircularBuffer(const uint32_t size=DEFAULT_MAX_BUFFER_SZ); - ~CircularBuffer(); - - // psudo mutex - bool isLocked(); - void lock(); - void unlock(); - - // enqueue and dequeue - void enqueue(T in); - T dequeue(); - - // pointer operation - uint32_t getReadPtr(); - uint32_t getWritePtr(); - uint32_t getCounter(); - - // overflow - bool getOverFlow(); - void clearOverFlow(); - - // operation - T first(); - T last(); - - // random access - T operator[](uint32_t idx); -}; - -#endif \ No newline at end of file