First class data visualization and communication library with embedded devices. Code is maintained at github.com/Overdrivr/Telemetry
Dependents: telemetry_car_demo telemetry_demo_FRDM-TFC telemetry_example_01 telemetry_indexed_data_demo ... more
Revision 5:cd94bb58e096, committed 2016-03-09
- Comitter:
- Overdrivr
- Date:
- Wed Mar 09 12:15:13 2016 +0000
- Parent:
- 4:8e3de1a314e1
- Child:
- 6:f5e1b079bffd
- Commit message:
- Release 1.0.3. See changelog here https://github.com/Overdrivr/Telemetry/releases/tag/1.0.3
Changed in this revision
--- a/Telemetry.cpp Mon Feb 22 17:55:46 2016 +0000 +++ b/Telemetry.cpp Wed Mar 09 12:15:13 2016 +0000 @@ -1,5 +1,5 @@ -#include "Telemetry.h" - +#include "Telemetry.hpp" +#include "c_api/telemetry_core.h" #include "BufferedSerial.h" static BufferedSerial pc(USBTX, USBRX); @@ -38,7 +38,17 @@ pc.baud(bauds); } -void Telemetry::pub(const char * topic, char * msg) +void Telemetry::begin(uint32_t bauds) +{ + pc.baud(bauds); +} + +TM_transport * Telemetry::get_transport() +{ + return &transport; +} + +void Telemetry::pub(const char * topic, const char * msg) { publish(topic,msg); } @@ -81,52 +91,10 @@ void Telemetry::sub(void (*callback)(TM_state * s, TM_msg * m), TM_state* userData) { - set_state(userData); - subscribe(callback); + subscribe(callback,userData); } void Telemetry::update() { update_telemetry(0); } -/* -uint32_t cast(TM_msg * m, char * buf, size_t bufSize) -{ - return emplace(m,buf,bufSize); -} - -uint32_t cast_u8(TM_msg * m, uint8_t * dst) -{ - return emplace_u8(m,dst); -} - -uint32_t cast_u16(TM_msg * m, uint16_t * dst) -{ - return emplace_u16(m,dst); -} - -uint32_t cast_u32(TM_msg * m, uint32_t * dst) -{ - return emplace_u32(m,dst); -} - -uint32_t cast_i8(TM_msg * m, int8_t * dst) -{ - return emplace_i8(m,dst); -} - -uint32_t cast_i16(TM_msg * m, int16_t * dst) -{ - return emplace_i16(m,dst); -} - -uint32_t cast_i32(TM_msg * m, int32_t * dst) -{ - return emplace_i32(m,dst); -} - -uint32_t cast_f32(TM_msg * m, float * dst) -{ - return emplace_f32(m,dst); -} -*/
--- a/Telemetry.h Mon Feb 22 17:55:46 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -#include "c_api/telemetry.h" - -class Telemetry -{ - public: - Telemetry(uint32_t bauds = 9600); - // Need different names from C API otherwise calling a method will call - // this method again and again - void pub(const char * topic, char * msg); - void pub_u8(const char * topic, uint8_t msg); - void pub_u16(const char * topic, uint16_t msg); - void pub_u32(const char * topic, uint32_t msg); - void pub_i8(const char * topic, int8_t msg); - void pub_i16(const char * topic, int16_t msg); - void pub_i32(const char * topic, int32_t msg); - void pub_f32(const char * topic, float msg); - - void sub(void (*callback)(TM_state * s, TM_msg * m), TM_state* userData); - - void update(); - - private: - TM_transport transport; -}; -/* -uint32_t cast(TM_msg * m, char * buf, size_t bufSize); -uint32_t cast_u8(TM_msg * m, uint8_t * dst); -uint32_t cast_u16(TM_msg * m, uint16_t * dst); -uint32_t cast_u32(TM_msg * m, uint32_t * dst); -uint32_t cast_i8(TM_msg * m, int8_t * dst); -uint32_t cast_i16(TM_msg * m, int16_t * dst); -uint32_t cast_i32(TM_msg * m, int32_t * dst); -uint32_t cast_f32(TM_msg * m, float * dst); -*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Telemetry.hpp Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,42 @@ +#ifndef TELEMETRY_HPP_ +#define TELEMETRY_HPP_ + +#include "telemetry_config.h" + +#ifdef TELEMETRY_ARDUINO_DISTRIBUTION +#include "telemetry_utils.h" +#else +#include "c_api/telemetry_utils.h" +#endif + +class Telemetry +{ + public: +#ifdef TELEMETRY_ARDUINO_DISTRIBUTION + Telemetry(); +#else + Telemetry(uint32_t bauds = 9600); +#endif + + void begin(uint32_t bauds = 9600); + + TM_transport * get_transport(); + + void pub(const char * topic, const char * msg); + void pub_u8(const char * topic, uint8_t msg); + void pub_u16(const char * topic, uint16_t msg); + void pub_u32(const char * topic, uint32_t msg); + void pub_i8(const char * topic, int8_t msg); + void pub_i16(const char * topic, int16_t msg); + void pub_i32(const char * topic, int32_t msg); + void pub_f32(const char * topic, float msg); + + void sub(void (*callback)(TM_state * s, TM_msg * m), TM_state* userData); + + void update(); + + private: + TM_transport transport; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/crc16.c Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,34 @@ +#include "crc16.h" + +uint16_t crc16(uint8_t* data, uint32_t len) +{ + uint16_t rem = 0; + uint16_t i=0; + for(i = 0 ; i < len ; i++) + { + rem = crc16_recursive(data[i],rem); + } + return rem; + } + +uint16_t crc16_recursive(uint8_t byte, uint16_t remainder) +{ + uint16_t n = 16; + + remainder = remainder ^ (byte << (n-8)); + uint16_t j = 0; + for(j = 1 ; j < 8 ; j++) + { + if(remainder & 0x8000) + { + remainder = (remainder << 1) ^ 0x1021; + } + else + { + remainder = remainder << 1; + } + remainder &= 0xffff; + } + + return remainder; +}
--- a/c_api/crc16.cpp Mon Feb 22 17:55:46 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -#include "crc16.h" - -uint16_t crc16(uint8_t* data, uint32_t len) -{ - uint16_t rem = 0; - for(uint16_t i = 0 ; i < len ; i++) - { - rem = crc16_recursive(data[i],rem); - } - return rem; - } - -uint16_t crc16_recursive(uint8_t byte, uint16_t remainder) -{ - uint16_t n = 16; - - remainder = remainder ^ (byte << (n-8)); - - for(uint16_t j = 1 ; j < 8 ; j++) - { - if(remainder & 0x8000) - { - remainder = (remainder << 1) ^ 0x1021; - } - else - { - remainder = remainder << 1; - } - remainder &= 0xffff; - } - - return remainder; -}
--- a/c_api/crc16.h Mon Feb 22 17:55:46 2016 +0000 +++ b/c_api/crc16.h Wed Mar 09 12:15:13 2016 +0000 @@ -8,4 +8,4 @@ uint16_t crc16(uint8_t * data, uint32_t lenght); uint16_t crc16_recursive(uint8_t byte, uint16_t remainder); -#endif \ No newline at end of file +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/framing.c Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,183 @@ +#include "framing.h" + +typedef enum _state +{ + IDLE, // No incoming frame is in process + ESCAPING, // incoming frame in process, next character to be escaped + ACTIVE // frame in process +} _state ; + +typedef struct storage storage; +struct storage +{ + uint8_t * ptr; + uint32_t size; + uint32_t cursor; + +}; + +static storage incomingStorage; +static storage outgoingStorage; + +int8_t safe_append(storage * s, uint8_t byte); + +static uint8_t SOF_; +static uint8_t EOF_; +static uint8_t ESC_; + +static _state incoming_state; + +void (*on_incoming_frame_cb)(uint8_t * storage, uint32_t occupiedSize); +void (*on_error_cb)(int32_t errCode); + +void initialize_framing() +{ + incomingStorage.ptr = NULL; + outgoingStorage.ptr = NULL; + + incomingStorage.size = 0; + outgoingStorage.size = 0; + + incomingStorage.cursor = 0; + incomingStorage.cursor = 0; + + SOF_ = 0xF7; + EOF_ = 0x7F; + ESC_ = 0x7D; + + incoming_state = IDLE; +} + +void outgoing_storage(uint8_t * buf, uint32_t bufSize) +{ + outgoingStorage.ptr = buf; + outgoingStorage.size = bufSize; +} + +void begin() +{ + if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) + return; + + outgoingStorage.cursor = 0; + + // Should not fail + safe_append(&outgoingStorage,SOF_); +} + +void append(uint8_t byte) +{ + if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) + return; + + // byte == to flag, need to escape it + if(byte == SOF_ || byte == EOF_ || byte == ESC_) + { + if(!safe_append(&outgoingStorage,ESC_)) + return; + } + + if(!safe_append(&outgoingStorage,byte)) + return; +} + +void append2(uint16_t twobytes) +{ + uint8_t * ptr = (uint8_t*)(&twobytes); + append(ptr[0]); + append(ptr[1]); +} + +void append4(uint32_t fourbytes) +{ + uint8_t * ptr = (uint8_t*)(&fourbytes); + append(ptr[0]); + append(ptr[1]); + append(ptr[2]); + append(ptr[3]); +} + +uint32_t end() +{ + if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) + return 0; + + if(!safe_append(&outgoingStorage,EOF_)) + return 0; + + return outgoingStorage.cursor; +} + +void incoming_storage(uint8_t * buf, uint32_t bufSize) +{ + incomingStorage.ptr = buf; + incomingStorage.size = bufSize; +} + +void set_on_incoming_frame(void (*callback)(uint8_t * storage, uint32_t occupiedSize)) +{ + on_incoming_frame_cb = callback; +} + +void set_on_incoming_error(void (*callback)(int32_t errCode)) +{ + on_error_cb = callback; +} + +void feed(uint8_t byte) +{ + if(incomingStorage.size == 0 || incomingStorage.ptr == NULL) + return; + + if(incoming_state == ESCAPING) + { + if(!safe_append(&incomingStorage,byte)) + { + incoming_state = IDLE; + return; + } + incoming_state = ACTIVE; + return; + } + + if(byte == SOF_) + { + incoming_state = ACTIVE; + incomingStorage.cursor = 0; + return; + } + + if(incoming_state == ACTIVE) + { + if(byte == EOF_) + { + incoming_state = IDLE; + on_incoming_frame_cb(incomingStorage.ptr, incomingStorage.cursor); + } + // Escape next character + else if(byte == ESC_) + { + incoming_state = ESCAPING; + } + else + { + if(!safe_append(&incomingStorage,byte)) + { + incoming_state = IDLE; + return; + } + incoming_state = ACTIVE; + } + } +} + +int8_t safe_append(storage * s, uint8_t byte) +{ + // Not enough space for 1 more character + if(s->cursor + 1 >= s->size) + return 0; + + s->ptr[s->cursor++] = byte; + + return 1; +}
--- a/c_api/framing.cpp Mon Feb 22 17:55:46 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,183 +0,0 @@ -#include "framing.h" - -typedef enum _state -{ - IDLE, // No incoming frame is in process - ESCAPING, // incoming frame in process, next character to be escaped - ACTIVE // frame in process -} _state ; - -typedef struct storage storage; -struct storage -{ - uint8_t * ptr; - uint32_t size; - uint32_t cursor; - -}; - -static storage incomingStorage; -static storage outgoingStorage; - -int8_t safe_append(storage * s, uint8_t byte); - -static uint8_t SOF_; -static uint8_t EOF_; -static uint8_t ESC_; - -static _state incoming_state; - -void (*on_incoming_frame_cb)(uint8_t * storage, uint32_t occupiedSize); -void (*on_error_cb)(int32_t errCode); - -void initialize_framing() -{ - incomingStorage.ptr = NULL; - outgoingStorage.ptr = NULL; - - incomingStorage.size = 0; - outgoingStorage.size = 0; - - incomingStorage.cursor = 0; - incomingStorage.cursor = 0; - - SOF_ = 0xF7; - EOF_ = 0x7F; - ESC_ = 0x7D; - - incoming_state = IDLE; -} - -void outgoing_storage(uint8_t * buf, uint32_t bufSize) -{ - outgoingStorage.ptr = buf; - outgoingStorage.size = bufSize; -} - -void begin() -{ - if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) - return; - - outgoingStorage.cursor = 0; - - // Should not fail - safe_append(&outgoingStorage,SOF_); -} - -void append(uint8_t byte) -{ - if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) - return; - - // byte == to flag, need to escape it - if(byte == SOF_ || byte == EOF_ || byte == ESC_) - { - if(!safe_append(&outgoingStorage,ESC_)) - return; - } - - if(!safe_append(&outgoingStorage,byte)) - return; -} - -void append2(uint16_t twobytes) -{ - uint8_t * ptr = (uint8_t*)(&twobytes); - append(ptr[0]); - append(ptr[1]); -} - -void append4(uint32_t fourbytes) -{ - uint8_t * ptr = (uint8_t*)(&fourbytes); - append(ptr[0]); - append(ptr[1]); - append(ptr[2]); - append(ptr[3]); -} - -uint32_t end() -{ - if(outgoingStorage.size == 0 || outgoingStorage.ptr == NULL) - return 0; - - if(!safe_append(&outgoingStorage,EOF_)) - return 0; - - return outgoingStorage.cursor; -} - -void incoming_storage(uint8_t * buf, uint32_t bufSize) -{ - incomingStorage.ptr = buf; - incomingStorage.size = bufSize; -} - -void set_on_incoming_frame(void (*callback)(uint8_t * storage, uint32_t occupiedSize)) -{ - on_incoming_frame_cb = callback; -} - -void set_on_incoming_error(void (*callback)(int32_t errCode)) -{ - on_error_cb = callback; -} - -void feed(uint8_t byte) -{ - if(incomingStorage.size == 0 || incomingStorage.ptr == NULL) - return; - - if(incoming_state == ESCAPING) - { - if(!safe_append(&incomingStorage,byte)) - { - incoming_state = IDLE; - return; - } - incoming_state = ACTIVE; - return; - } - - if(byte == SOF_) - { - incoming_state = ACTIVE; - incomingStorage.cursor = 0; - return; - } - - if(incoming_state == ACTIVE) - { - if(byte == EOF_) - { - incoming_state = IDLE; - on_incoming_frame_cb(incomingStorage.ptr, incomingStorage.cursor); - } - // Escape next character - else if(byte == ESC_) - { - incoming_state = ESCAPING; - } - else - { - if(!safe_append(&incomingStorage,byte)) - { - incoming_state = IDLE; - return; - } - incoming_state = ACTIVE; - } - } -} - -int8_t safe_append(storage * s, uint8_t byte) -{ - // Not enough space for 1 more character - if(s->cursor + 1 >= s->size) - return 0; - - s->ptr[s->cursor++] = byte; - - return 1; -}
--- a/c_api/telemetry.cpp Mon Feb 22 17:55:46 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -#include "telemetry.h" -#include "framing.h" -#include "crc16.h" -#include "string.h" - -static TM_state * statePtr; -static TM_transport * transportPtr; -static uint8_t incomingBuffer[INCOMING_BUFFER_SIZE]; -static uint8_t outgoingBuffer[OUTGOING_BUFFER_SIZE]; -static char topicBuffer[TOPIC_BUFFER_SIZE]; - -static void (*userCallback)(TM_state * s, TM_msg * m); - -uint16_t header(TM_type type); -uint16_t topic(const char * topic, uint16_t crc); -uint16_t payload(const void * payload, uint32_t size, uint16_t crc); -void frame(const char * t, TM_type type, const void * data, uint32_t datasize); -void send(void * buf, uint32_t size); -void on_incoming_frame(uint8_t * storage, uint32_t size); -void on_incoming_error(int32_t errCode); -void emptyCallback(TM_state * s, TM_msg * m); - -void init_telemetry(TM_transport * t) -{ - statePtr = NULL; - transportPtr = t; - userCallback = emptyCallback; - - // Setup framing - initialize_framing(); - incoming_storage(incomingBuffer,INCOMING_BUFFER_SIZE); - outgoing_storage(outgoingBuffer, OUTGOING_BUFFER_SIZE); - set_on_incoming_frame(on_incoming_frame); - set_on_incoming_error(on_incoming_error); -} - -uint32_t emplace(TM_msg* m, char * buf, size_t bufSize) -{ - if(m->type != TM_string) - return 0; - - uint32_t size = m->size; - - if(bufSize - 1 < size) - size = bufSize - 1; - - strncpy(buf, (char*)(m->buffer), size); - buf[size] = '\0'; - - return 1; -} - -uint32_t emplace_u8(TM_msg* m, uint8_t* dst) -{ - if(m->type != TM_uint8) - return 0; - - memcpy(dst,m->buffer,1); - return 1; -} - -uint32_t emplace_u16(TM_msg* m, uint16_t* dst) -{ - if(m->type != TM_uint16) - return 0; - - memcpy(dst,m->buffer,2); - return 1; -} - -uint32_t emplace_u32(TM_msg* m, uint32_t* dst) -{ - if(m->type != TM_uint32) - return 0; - - memcpy(dst,m->buffer,4); - return 1; -} - -uint32_t emplace_i8(TM_msg* m, int8_t* dst) -{ - if(m->type != TM_int8) - return 0; - - memcpy(dst,m->buffer,1); - return 1; -} - -uint32_t emplace_i16(TM_msg* m, int16_t* dst) -{ - if(m->type != TM_int16) - return 0; - - memcpy(dst,m->buffer,2); - return 1; -} - -uint32_t emplace_i32(TM_msg* m, int32_t* dst) -{ - if(m->type != TM_int32) - return 0; - - memcpy(dst,m->buffer,4); - return 1; -} - -uint32_t emplace_f32(TM_msg* m, float* dst) -{ - if(m->type != TM_float32) - return 0; - - memcpy(dst,m->buffer,4); - return 1; -} - -void publish(const char * t, char * msg) -{ - frame(t,TM_string,msg,strlen(msg)); -} - -void publish_u8(const char * t, uint8_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_uint8,ptr,1); -} - -void publish_u16(const char * t, uint16_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_uint16,ptr,2); -} - -void publish_u32(const char * t, uint32_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_uint32,ptr,4); -} - -void publish_i8(const char * t, int8_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_int8,ptr,1); -} - -void publish_i16(const char * t, int16_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_int16,ptr,2); -} - -void publish_i32(const char * t, int32_t msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_int32,ptr,4); -} - -void publish_f32(const char * t, float msg) -{ - void * ptr = (void *)(&msg); - frame(t,TM_float32,ptr,4); -} - -void set_state(TM_state * s) -{ - statePtr = s; -} - -void subscribe(void (*callback)(TM_state* s, TM_msg* m)) -{ - userCallback = callback; -} - -void update_telemetry(float elapsedTime) -{ - // If user forgot to define transport by calling init_telemetry, abort - if(!transportPtr) - return; - - uint32_t amount = transportPtr->readable(); - - for(uint32_t i = 0 ; i < amount ; i++) - { - uint8_t c; - transportPtr->read(&c,1); - feed(c); - } -} - -uint16_t header(TM_type type) -{ - // header data - uint16_t h = type; - uint8_t * ptr = (uint8_t*)(&h); - - // add data to frame - append2(h); - - // compute crc and return it - return crc16(ptr, 2); -} - -uint16_t topic(const char * t, uint16_t crc) -{ - const uint8_t * ptr = (uint8_t*)t; - for(uint32_t i = 0 ; i < strlen(t) ; i++) - { - // TODO : Replace with Huffman compression - append(ptr[i]); - crc = crc16_recursive(ptr[i], crc); - } - // Add NULL character - append(0); - return crc16_recursive(0,crc); -} - -uint16_t payload(const void * p, uint32_t size, uint16_t crc) -{ - const uint8_t * ptr = (uint8_t*)p; - for(uint32_t i = 0 ; i < size ; i++) - { - append(ptr[i]); - crc = crc16_recursive(ptr[i], crc); - } - return crc; -} - -void frame(const char * t, TM_type type, const void * data, uint32_t datasize) -{ - // start new frame - begin(); - - // header - uint16_t crc = header(type); - - // topic - crc = topic(t, crc); - - // payload - crc = payload(data, datasize, crc); - - // crc - append2(crc); - - // complete frame - uint32_t bytesAmount = end(); - - // send data - send(outgoingBuffer, bytesAmount); -} - -void send(void * buf, uint32_t size) -{ - // If user forgot to define transport by calling init_telemetry, abort - if(!transportPtr) - return; - - if(transportPtr->writeable() && size > 0) - { - transportPtr->write(outgoingBuffer, size); - } -} - -void on_incoming_frame(uint8_t * storage, uint32_t size) -{ - if(size < 2) - return; - // Read header - uint16_t head; - uint8_t * ptr; - ptr = (uint8_t*)(&head); - memcpy(ptr,storage,2); - - // Read topic - uint32_t cursor = 2; - uint32_t topicSize = 0; - while(cursor < size) - { - if(storage[cursor] == 0) - break; - topicSize++; - cursor++; - } - - if(topicSize == 0) - return; - - // payload = total - header - topic - /0 - crc - int32_t payloadSize = size - 2 - topicSize - 1 - 2; - - if(payloadSize <= 0) - return; - - // Check crc - uint16_t expected_crc = crc16(storage, size-2); - uint16_t rcv_crc; - ptr = (uint8_t*)(&rcv_crc); - memcpy(ptr,storage+size-2,2); - - if(expected_crc != rcv_crc) - return; - - // Store topic - char * t = (char*)(storage); - strcpy(topicBuffer, t + 2); - - // ptr to beginning of payload - ptr = (uint8_t*)(storage) + (uint32_t)(2 + topicSize + 1); - - TM_msg packet; - packet.topic = topicBuffer; - packet.type = (TM_type)head; - packet.buffer = (void *)(ptr); - packet.size = (uint32_t)payloadSize; - - // Call callback - userCallback(statePtr,&packet); -} - -void on_incoming_error(int32_t errCode) -{ - // TODO : Error management -} - -void emptyCallback(TM_state * s, TM_msg * m) -{ - // Called only if the user forgot to subscribe a callback -}
--- a/c_api/telemetry.h Mon Feb 22 17:55:46 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -#ifndef TELEMETRY_H_ -#define TELEMETRY_H_ - -#include "stddef.h" -#include "stdint.h" - -#define INCOMING_BUFFER_SIZE 128 -#define OUTGOING_BUFFER_SIZE 128 -#define TOPIC_BUFFER_SIZE 64 - -// Forward declaration of user state -typedef struct TM_state TM_state; - -// Enumeration of supported message payloads -enum TM_type { - TM_float32 = 0, - TM_uint8 = 1, - TM_uint16 = 2, - TM_uint32 = 3, - TM_int8 = 4, - TM_int16 = 5, - TM_int32 = 6, - TM_string = 7 -}; -typedef enum TM_type TM_type; - -// Data structure for received messages -typedef struct TM_msg TM_msg; -struct TM_msg { - TM_type type; - char * topic; - void * buffer; - uint32_t size; -}; - -// Data structure for holding transport interface -typedef struct TM_transport TM_transport; -struct TM_transport { - int32_t (*read)(void * buf, uint32_t sizeToRead); - int32_t (*readable)(); - int32_t (*write)(void * buf, uint32_t sizeToWrite); - int32_t (*writeable)(); -}; - -void init_telemetry(TM_transport * t); - -// Decodes TM_msg buffer and emplaces its value into dst -// Returns 0 if decoding was successful -uint32_t emplace(TM_msg * m, char * buf, size_t bufSize); -uint32_t emplace_u8(TM_msg * m, uint8_t * dst); -uint32_t emplace_u16(TM_msg * m, uint16_t * dst); -uint32_t emplace_u32(TM_msg * m, uint32_t * dst); -uint32_t emplace_i8(TM_msg * m, int8_t * dst); -uint32_t emplace_i16(TM_msg * m, int16_t * dst); -uint32_t emplace_i32(TM_msg * m, int32_t * dst); -uint32_t emplace_f32(TM_msg * m, float * dst); - -void publish(const char * topic, char * msg); -void publish_u8(const char * topic, uint8_t msg); -void publish_u16(const char * topic, uint16_t msg); -void publish_u32(const char * topic, uint32_t msg); -void publish_i8(const char * topic, int8_t msg); -void publish_i16(const char * topic, int16_t msg); -void publish_i32(const char * topic, int32_t msg); -void publish_f32(const char * topic, float msg); - -void set_state(TM_state * s); - -void subscribe(void (*callback)(TM_state * s, TM_msg * m)); - -void update_telemetry(float elapsedTime); - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/telemetry_core.c Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,245 @@ +#include "telemetry_core.h" +#include "framing.h" +#include "crc16.h" + +static TM_state * statePtr; +static TM_transport * transportPtr; +static uint8_t incomingBuffer[INCOMING_BUFFER_SIZE]; +static uint8_t outgoingBuffer[OUTGOING_BUFFER_SIZE]; +static char topicBuffer[TOPIC_BUFFER_SIZE]; + +static void (*userCallback)(TM_state * s, TM_msg * m); + +uint16_t header(TM_type type); +uint16_t topic(const char * topic, uint16_t crc); +uint16_t payload(const void * payload, uint32_t size, uint16_t crc); +void frame(const char * t, TM_type type, const void * data, uint32_t datasize); +void send(void * buf, uint32_t size); +void on_incoming_frame(uint8_t * storage, uint32_t size); +void on_incoming_error(int32_t errCode); +void emptyCallback(TM_state * s, TM_msg * m); + +void init_telemetry(TM_transport * t) +{ + statePtr = NULL; + transportPtr = t; + userCallback = emptyCallback; + + // Setup framing + initialize_framing(); + incoming_storage(incomingBuffer,INCOMING_BUFFER_SIZE); + outgoing_storage(outgoingBuffer, OUTGOING_BUFFER_SIZE); + set_on_incoming_frame(on_incoming_frame); + set_on_incoming_error(on_incoming_error); +} + +void publish(const char * t, const char * msg) +{ + frame(t,TM_string,msg,strlen(msg)); +} + +void publish_u8(const char * t, uint8_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_uint8,ptr,1); +} + +void publish_u16(const char * t, uint16_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_uint16,ptr,2); +} + +void publish_u32(const char * t, uint32_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_uint32,ptr,4); +} + +void publish_i8(const char * t, int8_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_int8,ptr,1); +} + +void publish_i16(const char * t, int16_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_int16,ptr,2); +} + +void publish_i32(const char * t, int32_t msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_int32,ptr,4); +} + +void publish_f32(const char * t, float msg) +{ + void * ptr = (void *)(&msg); + frame(t,TM_float32,ptr,4); +} + +void subscribe(void (*callback)(TM_state* s, TM_msg* m), TM_state * s) +{ + statePtr = s; + userCallback = callback; +} + +void update_telemetry(float elapsedTime) +{ + // If user forgot to define transport by calling init_telemetry, abort + if(!transportPtr) + return; + + uint32_t amount = transportPtr->readable(); + uint32_t i = 0 ; + for(i = 0 ; i < amount ; i++) + { + uint8_t c; + transportPtr->read(&c,1); + feed(c); + } +} + +uint16_t header(TM_type type) +{ + // header data + uint16_t h = type; + uint8_t * ptr = (uint8_t*)(&h); + + // add data to frame + append2(h); + + // compute crc and return it + return crc16(ptr, 2); +} + +uint16_t topic(const char * t, uint16_t crc) +{ + const uint8_t * ptr = (uint8_t*)t; + uint32_t i = 0 ; + for(i = 0 ; i < strlen(t) ; i++) + { + // TODO : Replace with Huffman compression + append(ptr[i]); + crc = crc16_recursive(ptr[i], crc); + } + // Add NULL character + append(0); + return crc16_recursive(0,crc); +} + +uint16_t payload(const void * p, uint32_t size, uint16_t crc) +{ + const uint8_t * ptr = (uint8_t*)p; + uint32_t i = 0 ; + for(i = 0 ; i < size ; i++) + { + append(ptr[i]); + crc = crc16_recursive(ptr[i], crc); + } + return crc; +} + +void frame(const char * t, TM_type type, const void * data, uint32_t datasize) +{ + // start new frame + begin(); + + // header + uint16_t crc = header(type); + + // topic + crc = topic(t, crc); + + // payload + crc = payload(data, datasize, crc); + + // crc + append2(crc); + + // complete frame + uint32_t bytesAmount = end(); + + // send data + send(outgoingBuffer, bytesAmount); +} + +void send(void * buf, uint32_t size) +{ + // If user forgot to define transport by calling init_telemetry, abort + if(!transportPtr) + return; + + if(transportPtr->writeable() && size > 0) + { + transportPtr->write(outgoingBuffer, size); + } +} + +void on_incoming_frame(uint8_t * storage, uint32_t size) +{ + if(size < 2) + return; + // Read header + uint16_t head; + uint8_t * ptr; + ptr = (uint8_t*)(&head); + memcpy(ptr,storage,2); + + // Read topic + uint32_t cursor = 2; + uint32_t topicSize = 0; + while(cursor < size) + { + if(storage[cursor] == 0) + break; + topicSize++; + cursor++; + } + + if(topicSize == 0) + return; + + // payload = total - header - topic - /0 - crc + int32_t payloadSize = size - 2 - topicSize - 1 - 2; + + if(payloadSize <= 0) + return; + + // Check crc + uint16_t expected_crc = crc16(storage, size-2); + uint16_t rcv_crc; + ptr = (uint8_t*)(&rcv_crc); + memcpy(ptr,storage+size-2,2); + + if(expected_crc != rcv_crc) + return; + + // Store topic + char * t = (char*)(storage); + strcpy(topicBuffer, t + 2); + + // ptr to beginning of payload + ptr = (uint8_t*)(storage) + (uint32_t)(2 + topicSize + 1); + + TM_msg packet; + packet.topic = topicBuffer; + packet.type = (TM_type)head; + packet.buffer = (void *)(ptr); + packet.size = (uint32_t)payloadSize; + + // Call callback + userCallback(statePtr,&packet); +} + +void on_incoming_error(int32_t errCode) +{ + // TODO : Error management +} + +void emptyCallback(TM_state * s, TM_msg * m) +{ + // Called only if the user forgot to subscribe a callback +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/telemetry_core.h Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,29 @@ +#ifndef TELEMETRY_CORE_H_ +#define TELEMETRY_CORE_H_ + +#include "stddef.h" +#include "stdint.h" +#include "telemetry_utils.h" + +#define INCOMING_BUFFER_SIZE 128 +#define OUTGOING_BUFFER_SIZE 128 +#define TOPIC_BUFFER_SIZE 64 + +void init_telemetry(TM_transport * t); + +void publish(const char * topic, const char * msg); +void publish_u8(const char * topic, uint8_t msg); +void publish_u16(const char * topic, uint16_t msg); +void publish_u32(const char * topic, uint32_t msg); +void publish_i8(const char * topic, int8_t msg); +void publish_i16(const char * topic, int16_t msg); +void publish_i32(const char * topic, int32_t msg); +void publish_f32(const char * topic, float msg); + +// subscribe a function to be called everytime a frame is received +// second argument is a data structure that you can implement to access your program data inside the function +void subscribe(void (*callback)(TM_state * s, TM_msg * m), TM_state * s); + +void update_telemetry(float elapsedTime); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/telemetry_utils.c Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,160 @@ +#include "telemetry_utils.h" + +uint32_t emplace(TM_msg* m, char * buf, size_t bufSize) +{ + if(m->type != TM_string) + return 0; + + uint32_t size = m->size; + + if(bufSize - 1 < size) + size = bufSize - 1; + + strncpy(buf, (char*)(m->buffer), size); + buf[size] = '\0'; + + return 1; +} + +uint32_t emplace_u8(TM_msg* m, uint8_t* dst) +{ + if(m->type != TM_uint8) + return 0; + + memcpy(dst,m->buffer,1); + return 1; +} + +uint32_t emplace_u16(TM_msg* m, uint16_t* dst) +{ + if(m->type != TM_uint16) + return 0; + + memcpy(dst,m->buffer,2); + return 1; +} + +uint32_t emplace_u32(TM_msg* m, uint32_t* dst) +{ + if(m->type != TM_uint32) + return 0; + + memcpy(dst,m->buffer,4); + return 1; +} + +uint32_t emplace_i8(TM_msg* m, int8_t* dst) +{ + if(m->type != TM_int8) + return 0; + + memcpy(dst,m->buffer,1); + return 1; +} + +uint32_t emplace_i16(TM_msg* m, int16_t* dst) +{ + if(m->type != TM_int16) + return 0; + + memcpy(dst,m->buffer,2); + return 1; +} + +uint32_t emplace_i32(TM_msg* m, int32_t* dst) +{ + if(m->type != TM_int32) + return 0; + + memcpy(dst,m->buffer,4); + return 1; +} + +uint32_t emplace_f32(TM_msg* m, float* dst) +{ + if(m->type != TM_float32) + return 0; + + memcpy(dst,m->buffer,4); + return 1; +} + +uint32_t match(TM_msg * m, const char * topicToMatch) +{ + if(strcmp(m->topic,topicToMatch) == 0) + return 1; + + return 0; +} + +uint32_t fullmatch(TM_msg * m, const char * topicToMatch, TM_type typeToMatch) +{ + if(strcmp(m->topic,topicToMatch) == 0 && m->type == typeToMatch) + return 1; + + return 0; +} + +uint32_t update(TM_msg * msg, const char *topic, char *var, size_t bufSize) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace(msg, var, bufSize); + + return 0; +} + +uint32_t update_u8(TM_msg * msg, const char *topic, uint8_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_u8(msg, var); + + return 0; +} + +uint32_t update_u16(TM_msg * msg, const char *topic, uint16_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_u16(msg, var); + + return 0; +} + +uint32_t update_u32(TM_msg * msg, const char *topic, uint32_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_u32(msg, var); + + return 0; +} + +uint32_t update_i8(TM_msg * msg, const char *topic, int8_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_i8(msg, var); + + return 0; +} + +uint32_t update_i16(TM_msg * msg, const char *topic, int16_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_i16(msg, var); + + return 0; +} + +uint32_t update_i32(TM_msg * msg, const char *topic, int32_t *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_i32(msg, var); + + return 0; +} + +uint32_t update_f32(TM_msg * msg, const char *topic, float *var) +{ + if(strcmp(topic,msg->topic) == 0) + return emplace_f32(msg, var); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/telemetry_utils.h Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,75 @@ +#ifndef TELEMETRY_UTILS_H_ +#define TELEMETRY_UTILS_H_ + +#include "stddef.h" +#include "stdint.h" +#include "string.h" + +// Forward declaration of user state +typedef struct TM_state TM_state; + +// Enumeration of supported message payloads +enum TM_type { + TM_float32 = 0, + TM_uint8 = 1, + TM_uint16 = 2, + TM_uint32 = 3, + TM_int8 = 4, + TM_int16 = 5, + TM_int32 = 6, + TM_string = 7 +}; + +typedef enum TM_type TM_type; + + +// Data structure for received messages +typedef struct TM_msg TM_msg; +struct TM_msg { + TM_type type; + char * topic; + void * buffer; + uint32_t size; +}; + +// Data structure for holding transport interface +typedef struct TM_transport TM_transport; +struct TM_transport { + int32_t (*read)(void * buf, uint32_t sizeToRead); + int32_t (*readable)(); + int32_t (*write)(void * buf, uint32_t sizeToWrite); + int32_t (*writeable)(); +}; + +// Decodes TM_msg buffer and emplaces its value into dst +// Returns 1 (true) if decoding was successful +uint32_t emplace(TM_msg * m, char * buf, size_t bufSize); +uint32_t emplace_u8(TM_msg * m, uint8_t * dst); +uint32_t emplace_u16(TM_msg * m, uint16_t * dst); +uint32_t emplace_u32(TM_msg * m, uint32_t * dst); +uint32_t emplace_i8(TM_msg * m, int8_t * dst); +uint32_t emplace_i16(TM_msg * m, int16_t * dst); +uint32_t emplace_i32(TM_msg * m, int32_t * dst); +uint32_t emplace_f32(TM_msg * m, float * dst); + +// Returns 1 if topicToMatch matches m->topic +// 0 otherwise +uint32_t match(TM_msg * m, const char * topicToMatch); + +// Returns 1 if topicToMatch matches m->topic and typeToMatch matches m->type, +// 0 otherwise +uint32_t fullmatch(TM_msg * m, const char * topicToMatch, TM_type typeToMatch); + +// Decodes TM_msg buffer and update its value into dst if matching topic +// Returns 1 (true) if decoding was successful +uint32_t update(TM_msg * msg, const char *topic, char *var, size_t bufSize); +uint32_t update_u8(TM_msg * msg, const char *topic, uint8_t *var); +uint32_t update_u16(TM_msg * msg, const char *topic, uint16_t *var); +uint32_t update_u32(TM_msg * msg, const char *topic, uint32_t *var); +uint32_t update_i8(TM_msg * msg, const char *topic, int8_t *var); +uint32_t update_i16(TM_msg * msg, const char *topic, int16_t *var); +uint32_t update_i32(TM_msg * msg, const char *topic, int32_t *var); +uint32_t update_f32(TM_msg * msg, const char *topic, float *var); + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c_api/telemetry_version.h Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,8 @@ +#ifndef TELEMETRY_VERSION_H_ +#define TELEMETRY_VERSION_H_ + +#define TELEMETRY_VERSION_MAJOR 1 +#define TELEMETRY_VERSION_MINOR 0 +#define TELEMETRY_VERSION_PATCH 3 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telemetry_config.h Wed Mar 09 12:15:13 2016 +0000 @@ -0,0 +1,6 @@ +#ifndef TELEMETRY_CONFIG_H_ +#define TELEMETRY_CONFIG_H_ + +#define TELEMETRY_MBED_DISTRIBUTION + +#endif