From c7f4e2c6f9d72246b73f7e1f4a4171a03aec41f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 12 Oct 2017 12:06:34 +0200 Subject: [PATCH 01/11] change api for easier use (only header file!!! WIP) --- TinyFrame.c | 4 +- TinyFrame.h | 107 +++++++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/TinyFrame.c b/TinyFrame.c index 9ea3d4c..4debca1 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -44,7 +44,7 @@ static struct TinyFrameStruct { /* Parser state */ enum TFState state; - int parser_timeout_ticks; + unsigned int parser_timeout_ticks; TF_ID id; //!< Incoming packet ID TF_LEN len; //!< Payload length uint8_t data[TF_MAX_PAYLOAD]; //!< Data byte buffer @@ -542,7 +542,7 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, outbuff[pos++] = b; \ xtra; \ } - + #define _NOOP() #define WRITENUM(type, num) WRITENUM_BASE(type, num, _NOOP()) #define WRITENUM_CKSUM(type, num) WRITENUM_BASE(type, num, CKSUM_ADD(cksum, b)) diff --git a/TinyFrame.h b/TinyFrame.h index 03672f6..fa3a98e 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -108,7 +108,14 @@ // Bytes added to TF_MAX_PAYLOAD for the send buffer size. -#define TF_OVERHEAD_BYTES (1+sizeof(TF_ID)+sizeof(TF_LEN)+sizeof(TF_CKSUM)+sizeof(TF_TYPE)+sizeof(TF_CKSUM)) +#define TF_OVERHEAD_BYTES \ + (1*TF_USE_SOF_BYTE + \ + sizeof(TF_ID) + \ + sizeof(TF_LEN) + \ + sizeof(TF_CKSUM) + \ + sizeof(TF_TYPE) + \ + sizeof(TF_CKSUM) \ + ) //endregion @@ -129,42 +136,58 @@ typedef enum { TF_MASTER = 1 } TF_PEER; +/** Data structure for sending / receiving messages */ +typedef struct { + TF_ID frame_id, // message ID + bool is_response, // internal flag, set when using the Respond function. frame_id is then kept unchanged. + TF_TYPE type, // received or sent message type + const uint8_t *data, // buffer of received data or data to send. NULL = listener timed out, free userdata! + TF_LEN len, // length of the buffer + void *userdata // here's a place for custom data; this data will be + // stored with the listener +} TF_MSG; + +/** + * Clear message struct + */ +static inline void TF_ClearMsg(TF_MSG *msg) +{ + msg->frame_id = 0; + msg->is_response = 0; + msg->type = 0; + msg->data = NULL; + msg->len = 0; + msg->userdata = NULL; +} + /** * TinyFrame Type Listener callback + * * @param frame_id - ID of the received frame + * @param type - type field from the message * @param data - byte buffer with the application data * @param len - number of bytes in the buffer * @return true if the frame was consumed */ -typedef bool (*TF_LISTENER)(TF_ID frame_id, TF_TYPE type, const uint8_t *data, TF_LEN len); +typedef bool (*TF_LISTENER)(TF_MSG *msg); /** * Initialize the TinyFrame engine. * This can also be used to completely reset it (removing all listeners etc) + * * @param peer_bit - peer bit to use for self */ void TF_Init(TF_PEER peer_bit); /** * Reset the frame parser state machine. + * This does not affect registered listeners. */ void TF_ResetParser(void); -/** - * Accept incoming bytes & parse frames - * @param buffer - byte buffer to process - * @param count - nr of bytes in the buffer - */ -void TF_Accept(const uint8_t *buffer, size_t count); - -/** - * Accept a single incoming byte - * @param c - a received char - */ -void TF_AcceptChar(uint8_t c); - /** * Register a frame type listener. + * * @param frame_type - frame ID to listen for * @param cb - callback * @return slot index (for removing), or TF_ERROR (-1) @@ -173,12 +196,14 @@ bool TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb); /** * Remove a listener by the message ID it's registered for + * * @param frame_id - the frame we're listening for */ bool TF_RemoveIdListener(TF_ID frame_id); /** * Register a frame type listener. + * * @param frame_type - frame type to listen for * @param cb - callback * @return slot index (for removing), or TF_ERROR (-1) @@ -187,12 +212,14 @@ bool TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb); /** * Remove a listener by type. + * * @param type - the type it's registered for */ bool TF_RemoveTypeListener(TF_TYPE type); /** * Register a generic listener. + * * @param cb - callback * @return slot index (for removing), or TF_ERROR (-1) */ @@ -200,6 +227,7 @@ bool TF_AddGenericListener(TF_LISTENER cb); /** * Remove a generic listener by function pointer + * * @param cb - callback function to remove */ bool TF_RemoveGenericListener(TF_LISTENER cb); @@ -207,50 +235,35 @@ bool TF_RemoveGenericListener(TF_LISTENER cb); /** * Send a frame, and optionally attach an ID listener. * - * @param type - message type - * @param data - data to send (can be NULL if 'data_len' is 0) - * @param data_len - nr of bytes to send - * @param listener - listener waiting for the response - * @param id_ptr - store the ID here, NULL to don't store. - * The ID may be used to unbind the listener after a timeout. + * @param msg - message struct. ID is stored in the frame_id field + * @param listener - listener waiting for the response (can be NULL) + * @param timeout - listener expiry time in ticks * @return success */ -bool TF_Send(TF_TYPE type, const uint8_t *data, TF_LEN data_len, - TF_LISTENER listener, - TF_ID *id_ptr); +bool TF_Send(TF_MSG *msg, TF_LISTENER listener, unsigned int timeout); /** - * Like TF_Send(), but no data, just the type + * Send a response to a received message. + * + * @param msg - message struct. ID is read from frame_id + * @return success */ -bool TF_Send0(TF_TYPE type, TF_LISTENER listener, TF_ID *id_ptr); +bool TF_Respond(TF_MSG *msg); /** - * Like TF_Send(), but with just 1 data byte - */ -bool TF_Send1(TF_TYPE type, uint8_t b1, - TF_LISTENER listener, - TF_ID *id_ptr); -/** - * Like TF_Send(), but with just 2 data bytes + * Accept incoming bytes & parse frames + * + * @param buffer - byte buffer to process + * @param count - nr of bytes in the buffer */ -bool TF_Send2(TF_TYPE type, uint8_t b1, uint8_t b2, - TF_LISTENER listener, - TF_ID *id_ptr); +void TF_Accept(const uint8_t *buffer, size_t count); /** - * Send a response to a received message. + * Accept a single incoming byte * - * @param type - message type. If an ID listener is waiting for this response, - * then 'type' can be used to pass additional information. - * Otherwise, 'type' can be used to handle the message using a TypeListener. - * @param data - data to send - * @param data_len - nr of bytes to send - * @param frame_id - ID of the response frame (re-use ID from the original message) - * @return success + * @param c - a received char */ -bool TF_Respond(TF_TYPE type, - const uint8_t *data, TF_LEN data_len, - TF_ID frame_id); +void TF_AcceptChar(uint8_t c); /** * 'Write bytes' function that sends data to UART From b6532962a4134c0f3461d92ad57d28fd6032dec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 12 Oct 2017 16:25:05 +0200 Subject: [PATCH 02/11] updated C code, added timeouts etc, not tested! --- TinyFrame.c | 407 ++++++++++++++++++++++++++++------------------------ TinyFrame.h | 34 +++-- 2 files changed, 241 insertions(+), 200 deletions(-) diff --git a/TinyFrame.c b/TinyFrame.c index 4debca1..b93ea10 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -20,9 +20,12 @@ enum TFState { TFState_DATA_CKSUM //!< Wait for Checksum }; -typedef struct _IdListener_struct { +typedef struct _IdListener_struct_ { TF_ID id; TF_LISTENER fn; + unsigned int timeout; // nr of ticks remaining to disable this listener + unsigned int timeout_max; // the original timeout is stored here + void *userdata; } IdListener; typedef struct _TypeListener_struct_ { @@ -37,17 +40,17 @@ typedef struct _GenericListener_struct_ { /** * Frame parser internal state */ -static struct TinyFrameStruct { +static struct TinyFrameInstance { /* Own state */ TF_PEER peer_bit; //!< Own peer bit (unqiue to avoid msg ID clash) TF_ID next_id; //!< Next frame / frame chain ID /* Parser state */ enum TFState state; - unsigned int parser_timeout_ticks; + TF_TICKS parser_timeout_ticks; TF_ID id; //!< Incoming packet ID TF_LEN len; //!< Payload length - uint8_t data[TF_MAX_PAYLOAD]; //!< Data byte buffer + uint8_t data[TF_MAX_PAYLOAD_RX]; //!< Data byte buffer size_t rxi; //!< Byte counter TF_CKSUM cksum; //!< Checksum calculated of the data stream TF_CKSUM ref_cksum; //!< Reference checksum read from the message @@ -61,133 +64,136 @@ static struct TinyFrameStruct { TypeListener type_listeners[TF_MAX_TYPE_LST]; GenericListener generic_listeners[TF_MAX_GEN_LST]; + // Those counters are used to optimize look-up times. + // They point to the highest used slot number, + // or close to it, depending on the removal order. size_t count_id_lst; size_t count_type_lst; size_t count_generic_lst; // Buffer for building frames - uint8_t sendbuf[TF_MAX_PAYLOAD + TF_OVERHEAD_BYTES]; + uint8_t sendbuf[TF_MAX_PAYLOAD_TX + TF_OVERHEAD_BYTES]; // TODO generate and send frames without a buffer } tf; //region Checksums #if TF_CKSUM_TYPE == 0 -// NONE -#define CKSUM_RESET(cksum) -#define CKSUM_ADD(cksum, byte) -#define CKSUM_FINALIZE(cksum) + // NONE + #define CKSUM_RESET(cksum) + #define CKSUM_ADD(cksum, byte) + #define CKSUM_FINALIZE(cksum) #elif TF_CKSUM_TYPE == 8 -// ~XOR -#define CKSUM_RESET(cksum) do { cksum = 0; } while (0) -#define CKSUM_ADD(cksum, byte) do { cksum ^= byte; } while(0) -#define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) + // ~XOR + #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) + #define CKSUM_ADD(cksum, byte) do { cksum ^= byte; } while(0) + #define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) #elif TF_CKSUM_TYPE == 16 -/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ -static const uint16_t crc16_table[256] = { - 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, - 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, - 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, - 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, - 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, - 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, - 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, - 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, - 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, - 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, - 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, - 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, - 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, - 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, - 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, - 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, - 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, - 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, - 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, - 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, - 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, - 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, - 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, - 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, - 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, - 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, - 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, - 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, - 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, - 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, - 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, - 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 -}; - -static inline uint16_t crc16_byte(uint16_t cksum, const uint8_t byte) -{ - return (cksum >> 8) ^ crc16_table[(cksum ^ byte) & 0xff]; -} + /** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ + static const uint16_t crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + }; + + static inline uint16_t crc16_byte(uint16_t cksum, const uint8_t byte) + { + return (cksum >> 8) ^ crc16_table[(cksum ^ byte) & 0xff]; + } -#define CKSUM_RESET(cksum) do { cksum = 0; } while (0) -#define CKSUM_ADD(cksum, byte) do { cksum = crc16_byte(cksum, byte); } while(0) -#define CKSUM_FINALIZE(cksum) + #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) + #define CKSUM_ADD(cksum, byte) do { cksum = crc16_byte(cksum, byte); } while(0) + #define CKSUM_FINALIZE(cksum) #elif TF_CKSUM_TYPE == 32 -static const uint32_t crc32_table[] = { /* CRC polynomial 0xedb88320 */ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -static inline uint32_t crc32_byte(uint32_t cksum, const uint8_t byte) -{ - return (crc32_table[((cksum) ^ ((uint8_t)byte)) & 0xff] ^ ((cksum) >> 8)); -} + static const uint32_t crc32_table[] = { /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + + static inline uint32_t crc32_byte(uint32_t cksum, const uint8_t byte) + { + return (crc32_table[((cksum) ^ ((uint8_t)byte)) & 0xff] ^ ((cksum) >> 8)); + } -#define CKSUM_RESET(cksum) do { cksum = (TF_CKSUM)0xFFFFFFFF; } while (0) -#define CKSUM_ADD(cksum, byte) do { cksum = crc32_byte(cksum, byte); } while(0) -#define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) + #define CKSUM_RESET(cksum) do { cksum = (TF_CKSUM)0xFFFFFFFF; } while (0) + #define CKSUM_ADD(cksum, byte) do { cksum = crc32_byte(cksum, byte); } while(0) + #define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) #endif @@ -204,13 +210,17 @@ void _TF_FN TF_Init(TF_PEER peer_bit) //region Listeners -bool _TF_FN TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb) +bool _TF_FN TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout) { size_t i; + IdListener *lst; for (i = 0; i < TF_MAX_ID_LST; i++) { - if (tf.id_listeners[i].fn == NULL) { - tf.id_listeners[i].fn = cb; - tf.id_listeners[i].id = frame_id; + lst = &tf.id_listeners[i]; + if (lst->fn == NULL) { + lst->fn = cb; + lst->id = msg->frame_id; + lst->userdata = msg->userdata; + lst->timeout_max = lst->timeout = timeout; if (i >= tf.count_id_lst) { tf.count_id_lst = i + 1; } @@ -223,10 +233,12 @@ bool _TF_FN TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb) bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) { size_t i; + TypeListener *lst; for (i = 0; i < TF_MAX_TYPE_LST; i++) { - if (tf.type_listeners[i].fn == NULL) { - tf.type_listeners[i].fn = cb; - tf.type_listeners[i].type = frame_type; + lst = &tf.type_listeners[i]; + if (lst->fn == NULL) { + lst->fn = cb; + lst->type = frame_type; if (i >= tf.count_type_lst) { tf.count_type_lst = i + 1; } @@ -239,9 +251,11 @@ bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) { size_t i; + GenericListener *lst; for (i = 0; i < TF_MAX_GEN_LST; i++) { - if (tf.generic_listeners[i].fn == NULL) { - tf.generic_listeners[i].fn = cb; + lst = &tf.generic_listeners[i]; + if (lst->fn == NULL) { + lst->fn = cb; if (i >= tf.count_generic_lst) { tf.count_generic_lst = i + 1; } @@ -254,10 +268,11 @@ bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) { size_t i; + IdListener *lst; for (i = 0; i < tf.count_id_lst; i++) { - if (tf.id_listeners[i].fn != NULL - && tf.id_listeners[i].id == frame_id) { - tf.id_listeners[i].fn = NULL; + lst = &tf.id_listeners[i]; + if (lst->fn != NULL && lst->id == frame_id) { + lst->fn = NULL; if (i == tf.count_id_lst - 1) { tf.count_id_lst--; } @@ -270,10 +285,11 @@ bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) { size_t i; + TypeListener *lst; for (i = 0; i < tf.count_type_lst; i++) { - if (tf.type_listeners[i].fn != NULL - && tf.type_listeners[i].type == type) { - tf.type_listeners[i].fn = NULL; + lst = &tf.type_listeners[i]; + if (lst->fn != NULL && lst->type == type) { + lst->fn = NULL; if (i == tf.count_type_lst - 1) { tf.count_type_lst--; } @@ -286,9 +302,11 @@ bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) { size_t i; + GenericListener *lst; for (i = 0; i < tf.count_generic_lst; i++) { - if (tf.generic_listeners[i].fn == cb) { - tf.generic_listeners[i].fn = NULL; + lst = &tf.generic_listeners[i]; + if (lst->fn == cb) { + lst->fn = NULL; if (i == tf.count_generic_lst - 1) { tf.count_generic_lst--; } @@ -299,9 +317,20 @@ bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) } /** Handle a message that was just collected & verified by the parser */ -static void _TF_FN TF_HandleReceivedMessage(TF_ID frame_id, TF_TYPE type, uint8_t *data, TF_LEN data_len) +static void _TF_FN TF_HandleReceivedMessage(void) { size_t i; + IdListener *ilst; + TypeListener *tlst; + GenericListener *glst; + + // Prepare message object + TF_MSG msg; + msg.frame_id = tf.id; + msg.is_response = false; + msg.type = tf.type; + msg.data = tf.data; + msg.len = tf.len; // Any listener can consume the message (return true), // or let someone else handle it. @@ -311,28 +340,28 @@ static void _TF_FN TF_HandleReceivedMessage(TF_ID frame_id, TF_TYPE type, uint8_ // ID listeners first for (i = 0; i < tf.count_id_lst; i++) { - if (tf.id_listeners[i].fn && (tf.id_listeners[i].id == frame_id)) { - if (tf.id_listeners[i].fn(frame_id, type, data, data_len)) { - return; - } + ilst = &tf.id_listeners[i]; + if (ilst->fn && ilst->id == frame_id) { + msg.userdata = ilst->userdata; + if (ilst->fn(&msg)) return; } } + msg.userdata = NULL; + // clean up for the following listeners that don't use userdata // Type listeners for (i = 0; i < tf.count_type_lst; i++) { - if (tf.type_listeners[i].fn && (tf.type_listeners[i].type == type)) { - if (tf.type_listeners[i].fn(frame_id, type, data, data_len)) { - return; - } + tlst = &tf.type_listeners[i]; + if (tlst->fn && tlst->type == type) { + if (tlst->fn(&msg)) return; } } // Generic listeners for (i = 0; i < tf.count_generic_lst; i++) { - if (tf.generic_listeners[i].fn) { - if (tf.generic_listeners[i].fn(frame_id, type, data, data_len)) { - return; - } + glst = &tf.generic_listeners[i]; + if (glst->fn) { + if (glst->fn(&msg)) return; } } } @@ -369,7 +398,7 @@ static void _TF_FN TF_ParsBeginFrame(void) { void _TF_FN TF_AcceptChar(unsigned char c) { - // Timeout - clear + // Parser timeout - clear if (tf.parser_timeout_ticks >= TF_PARSER_TIMEOUT_TICKS) { TF_ResetParser(); } @@ -436,7 +465,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) } if (tf.len == 0) { - TF_HandleReceivedMessage(tf.id, tf.type, NULL, 0); + TF_HandleReceivedMessage(); TF_ResetParser(); break; } @@ -465,7 +494,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) if (tf.rxi == tf.len) { #if TF_CKSUM_TYPE == 0 // All done - TF_HandleReceivedMessage(tf.id, tf.type, tf.data, tf.len); + TF_HandleReceivedMessage(); TF_ResetParser(); #else // Enter DATA_CKSUM state @@ -481,7 +510,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) // Check the header checksum against the computed value CKSUM_FINALIZE(tf.cksum); if (!tf.discard_data && tf.cksum == tf.ref_cksum) { - TF_HandleReceivedMessage(tf.id, tf.type, tf.data, tf.len); + TF_HandleReceivedMessage(); } TF_ResetParser(); @@ -503,7 +532,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) * @param use_expl_id - whether to use the previous param * @return nr of bytes in outbuff used by the frame, TF_ERROR (-1) on failure */ -static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, +static inline int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, TF_TYPE type, const uint8_t *data, TF_LEN data_len, TF_ID explicit_id, bool use_expl_id) @@ -584,73 +613,73 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, return pos; } -bool _TF_FN TF_Send(TF_TYPE type, - const uint8_t *payload, TF_LEN payload_len, - TF_LISTENER listener, - TF_ID *id_ptr) +bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) { - TF_ID msgid = 0; int len; - len = TF_Compose(tf.sendbuf, &msgid, type, payload, payload_len, 0, false); + len = TF_Compose(tf.sendbuf, + &msg->frame_id, + msg->type, + msg->data, + msg->len, + msg->frame_id, + msg->is_response); + if (len == TF_ERROR) return false; - if (listener) TF_AddIdListener(msgid, listener); - if (id_ptr) *id_ptr = msgid; + if (listener) TF_AddIdListener(msg->frame_id, listener); TF_WriteImpl((const uint8_t *) tf.sendbuf, (TF_LEN)len); return true; } // Like TF_Send, but with explicit frame ID -bool _TF_FN TF_Respond(TF_TYPE type, - const uint8_t *data, TF_LEN data_len, - TF_ID frame_id) -{ - int len; - len = TF_Compose(tf.sendbuf, NULL, type, data, data_len, frame_id, true); - if (len == TF_ERROR) return false; - - TF_WriteImpl(tf.sendbuf, (TF_LEN)len); - return true; -} - -/** - * Like TF_Send(), but with no data - */ -bool _TF_FN TF_Send0(TF_TYPE type, - TF_LISTENER listener, - TF_ID *id_ptr) +bool _TF_FN TF_Respond(TF_MSG *msg, bool renew) { - return TF_Send(type, NULL, 0, listener, id_ptr); -} + msg->is_response = true; + bool suc = TF_Send(msg, NULL, 0); -/** - * Like TF_Send(), but with just 1 data byte - */ -bool _TF_FN TF_Send1(TF_TYPE type, uint8_t b1, - TF_LISTENER listener, - TF_ID *id_ptr) -{ - unsigned char b[] = {b1}; - return TF_Send(type, b, 1, listener, id_ptr); + if (suc && renew) TF_RenewIdListener(msg->frame_id); + return suc; } -/** - * Like TF_Send(), but with just 2 data bytes - */ -bool _TF_FN TF_Send2(TF_TYPE type, uint8_t b1, uint8_t b2, - TF_LISTENER listener, - TF_ID *id_ptr) +bool _TF_FN TF_RenewIdListener(TF_ID id) { - unsigned char b[] = {b1, b2}; - return TF_Send(type, b, 2, listener, id_ptr); + IdListener *lst; + for (i = 0; i < tf.count_id_lst; i++) { + lst = &tf.id_listeners[i]; + if (lst->fn && lst->id == id) { + lst->timeout = lst->timeout_max; + return true; + } + } + return false; } /** Timebase hook - for timeouts */ void _TF_FN TF_Tick(void) { + int i; + TF_MSG msg; + IdListener *lst; + + // increment parser timeout (timeout is handled when receiving next byte) if (tf.parser_timeout_ticks < TF_PARSER_TIMEOUT_TICKS) { tf.parser_timeout_ticks++; } + + // decrement and expire ID listeners + for (i = 0; i < tf.count_id_lst; i++) { + lst = &tf.id_listeners[i]; + if (lst->fn && lst->timeout > 0) { + if (--lst->timeout != 0) continue; + + // Notify listener about timeout + msg.userdata = lst->userdata; + msg.data = NULL; // this is a signal that listener should clean up + + lst->fn(msg); + lst->fn = NULL; // Discard listener + } + } } diff --git a/TinyFrame.h b/TinyFrame.h index fa3a98e..a27ea97 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -14,7 +14,8 @@ // Maximum send / receive payload size (static buffers size) // Larger payloads will be rejected. -#define TF_MAX_PAYLOAD 1024 +#define TF_MAX_PAYLOAD_RX 1024 +#define TF_MAX_PAYLOAD_TX 1024 // --- Listener counts - determine sizes of the static slot tables --- @@ -57,6 +58,7 @@ //------------------------- End of user config ------------------------------ +typedef unsigned int TF_TICKS; //region Resolve data types @@ -138,12 +140,12 @@ typedef enum { /** Data structure for sending / receiving messages */ typedef struct { - TF_ID frame_id, // message ID - bool is_response, // internal flag, set when using the Respond function. frame_id is then kept unchanged. - TF_TYPE type, // received or sent message type - const uint8_t *data, // buffer of received data or data to send. NULL = listener timed out, free userdata! - TF_LEN len, // length of the buffer - void *userdata // here's a place for custom data; this data will be + TF_ID frame_id; // message ID + bool is_response; // internal flag, set when using the Respond function. frame_id is then kept unchanged. + TF_TYPE type; // received or sent message type + const uint8_t *data; // buffer of received data or data to send. NULL = listener timed out, free userdata! + TF_LEN len; // length of the buffer + void *userdata; // here's a place for custom data; this data will be // stored with the listener } TF_MSG; @@ -188,11 +190,12 @@ void TF_ResetParser(void); /** * Register a frame type listener. * - * @param frame_type - frame ID to listen for + * @param msg - message (contains frame_id and userdata) * @param cb - callback + * @param timeout - timeout in ticks to auto-remove the listener (0 = keep forever) * @return slot index (for removing), or TF_ERROR (-1) */ -bool TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb); +bool TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout); /** * Remove a listener by the message ID it's registered for @@ -240,15 +243,24 @@ bool TF_RemoveGenericListener(TF_LISTENER cb); * @param timeout - listener expiry time in ticks * @return success */ -bool TF_Send(TF_MSG *msg, TF_LISTENER listener, unsigned int timeout); +bool TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout); /** * Send a response to a received message. * * @param msg - message struct. ID is read from frame_id + * @param renew - renew the listener timeout (waiting for more data) * @return success */ -bool TF_Respond(TF_MSG *msg); +bool TF_Respond(TF_MSG *msg, bool renew); + +/** + * Renew ID listener timeout + * + * @param id - listener ID to renew + * @return true if listener was found and renewed + */ +bool TF_RenewIdListener(TF_ID id); /** * Accept incoming bytes & parse frames From b89f458c19d81c29ba5dedc3ea59240fcb703f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 13 Oct 2017 11:14:20 +0200 Subject: [PATCH 03/11] fixed bugz --- TinyFrame.c | 17 +++++++++-------- TinyFrame.h | 2 +- test.c | 39 +++++++++++++++++++++++++-------------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/TinyFrame.c b/TinyFrame.c index b93ea10..55fc727 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -40,7 +40,7 @@ typedef struct _GenericListener_struct_ { /** * Frame parser internal state */ -static struct TinyFrameInstance { +static struct TinyFrameStruct { /* Own state */ TF_PEER peer_bit; //!< Own peer bit (unqiue to avoid msg ID clash) TF_ID next_id; //!< Next frame / frame chain ID @@ -341,7 +341,7 @@ static void _TF_FN TF_HandleReceivedMessage(void) // ID listeners first for (i = 0; i < tf.count_id_lst; i++) { ilst = &tf.id_listeners[i]; - if (ilst->fn && ilst->id == frame_id) { + if (ilst->fn && ilst->id == msg.frame_id) { msg.userdata = ilst->userdata; if (ilst->fn(&msg)) return; } @@ -352,7 +352,7 @@ static void _TF_FN TF_HandleReceivedMessage(void) // Type listeners for (i = 0; i < tf.count_type_lst; i++) { tlst = &tf.type_listeners[i]; - if (tlst->fn && tlst->type == type) { + if (tlst->fn && tlst->type == msg.type) { if (tlst->fn(&msg)) return; } } @@ -476,7 +476,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) CKSUM_RESET(tf.cksum); // Start collecting the payload - if (tf.len >= TF_MAX_PAYLOAD) { + if (tf.len >= TF_MAX_PAYLOAD_RX) { // ERROR - frame too long. Consume, but do not store. tf.discard_data = true; } @@ -546,7 +546,7 @@ static inline int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, CKSUM_RESET(cksum); // sanitize len - if (data_len > TF_MAX_PAYLOAD) { + if (data_len > TF_MAX_PAYLOAD_TX) { return TF_ERROR; } @@ -626,7 +626,7 @@ bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) if (len == TF_ERROR) return false; - if (listener) TF_AddIdListener(msg->frame_id, listener); + if (listener) TF_AddIdListener(msg, listener, timeout); TF_WriteImpl((const uint8_t *) tf.sendbuf, (TF_LEN)len); return true; @@ -644,6 +644,7 @@ bool _TF_FN TF_Respond(TF_MSG *msg, bool renew) bool _TF_FN TF_RenewIdListener(TF_ID id) { + size_t i; IdListener *lst; for (i = 0; i < tf.count_id_lst; i++) { lst = &tf.id_listeners[i]; @@ -658,7 +659,7 @@ bool _TF_FN TF_RenewIdListener(TF_ID id) /** Timebase hook - for timeouts */ void _TF_FN TF_Tick(void) { - int i; + size_t i; TF_MSG msg; IdListener *lst; @@ -677,7 +678,7 @@ void _TF_FN TF_Tick(void) msg.userdata = lst->userdata; msg.data = NULL; // this is a signal that listener should clean up - lst->fn(msg); + lst->fn(&msg); lst->fn = NULL; // Discard listener } } diff --git a/TinyFrame.h b/TinyFrame.h index a27ea97..11be373 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -139,7 +139,7 @@ typedef enum { } TF_PEER; /** Data structure for sending / receiving messages */ -typedef struct { +typedef struct _TF_MSG_STRUCT_ { TF_ID frame_id; // message ID bool is_response; // internal flag, set when using the Respond function. frame_id is then kept unchanged. TF_TYPE type; // received or sent message type diff --git a/test.c b/test.c index e41dc4f..2ec775e 100644 --- a/test.c +++ b/test.c @@ -3,6 +3,8 @@ #include #include "TinyFrame.h" +typedef unsigned char* pu8; + static void dumpFrame(const uint8_t *buff, TF_LEN len); /** @@ -20,19 +22,21 @@ void TF_WriteImpl(const uint8_t *buff, TF_LEN len) } /** An example listener function */ -bool myListener(TF_ID frame_id, TF_TYPE type, const uint8_t *buff, TF_LEN len) +bool myListener(TF_MSG *msg) { printf("\033[33mRX frame\n" " type: %02Xh\n" " data: \"%.*s\"\n" " len: %u\n" - " id: %Xh\033[0m\n", type, len, buff, len, frame_id); + " id: %Xh\033[0m\n", + msg->type, msg->len, msg->data, msg->len, msg->frame_id); return true; } -bool testIdListener(TF_ID frame_id, TF_TYPE type, const uint8_t *buff, TF_LEN len) +bool testIdListener(TF_MSG *msg) { - printf("OK - ID Listener triggered for msg (type %02X, id %Xh)!", type, frame_id); + printf("OK - ID Listener triggered for msg (type %02X, id %Xh)!", + msg->type, msg->frame_id); return true; } @@ -44,20 +48,27 @@ void main(void) printf("------ Simulate sending a message --------\n"); - TF_Send(0x22, (unsigned char*)"Hello TinyFrame", 16, NULL, NULL); + TF_MSG msg; + TF_ClearMsg(&msg); + msg.type = 0x22; + msg.data = (pu8)"Hello TinyFrame"; + msg.len = 16; + TF_Send(&msg, NULL, 0); const char *longstr = "Lorem ipsum dolor sit amet."; - TF_Send(0x33, (unsigned char*)longstr, (TF_LEN)(strlen(longstr)+1), NULL, NULL); - - TF_Send(0x44, (unsigned char*)"Hello2", 7, NULL, NULL); - - TF_Send0(0xF0, NULL, NULL); - - TF_Send1(0xF1, 'Q', NULL, NULL); + msg.type = 0x33; + msg.data = (pu8)longstr; + msg.len = strlen(longstr)+1; // add the null byte + TF_Send(&msg, NULL, 0); - TF_Send2(0xF2, 'A', 'Z', NULL, NULL); + msg.type = 0x44; + msg.data = (pu8)"Hello2"; + msg.len = 7; + TF_Send(&msg, NULL, 0); - TF_Send0(0x77, testIdListener, NULL); + msg.len = 0; + msg.type = 0x77; + TF_Send(&msg, testIdListener, 0); } // helper func for testing From d1aec88f23aa5a40cd70e51aab3ebed81779c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 18:18:20 +0200 Subject: [PATCH 04/11] did some cleaning --- Makefile | 2 +- TinyFrame.c | 145 +++++++++++++++++++++++++++++++++------------------- TinyFrame.h | 15 +++--- test.c | 9 ++-- 4 files changed, 107 insertions(+), 64 deletions(-) diff --git a/Makefile b/Makefile index 0124af5..259b362 100644 --- a/Makefile +++ b/Makefile @@ -7,4 +7,4 @@ debug: tf.bin gdb -q -ex run ./tf.bin tf.bin: test.c TinyFrame.c TinyFrame.h - gcc -Os --std=gnu89 -Wall -Wno-main -Wno-unused -Wextra test.c TinyFrame.c -I. -o tf.bin + gcc -O0 -ggdb --std=gnu89 -Wall -Wno-main -Wextra test.c TinyFrame.c -I. -o tf.bin diff --git a/TinyFrame.c b/TinyFrame.c index 55fc727..ad76c00 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -23,8 +23,8 @@ enum TFState { typedef struct _IdListener_struct_ { TF_ID id; TF_LISTENER fn; - unsigned int timeout; // nr of ticks remaining to disable this listener - unsigned int timeout_max; // the original timeout is stored here + TF_COUNT timeout; // nr of ticks remaining to disable this listener + TF_COUNT timeout_max; // the original timeout is stored here void *userdata; } IdListener; @@ -51,7 +51,7 @@ static struct TinyFrameStruct { TF_ID id; //!< Incoming packet ID TF_LEN len; //!< Payload length uint8_t data[TF_MAX_PAYLOAD_RX]; //!< Data byte buffer - size_t rxi; //!< Byte counter + TF_LEN rxi; //!< Field size byte counter TF_CKSUM cksum; //!< Checksum calculated of the data stream TF_CKSUM ref_cksum; //!< Reference checksum read from the message TF_TYPE type; //!< Collected message type number @@ -67,9 +67,9 @@ static struct TinyFrameStruct { // Those counters are used to optimize look-up times. // They point to the highest used slot number, // or close to it, depending on the removal order. - size_t count_id_lst; - size_t count_type_lst; - size_t count_generic_lst; + TF_COUNT count_id_lst; + TF_COUNT count_type_lst; + TF_COUNT count_generic_lst; // Buffer for building frames uint8_t sendbuf[TF_MAX_PAYLOAD_TX + TF_OVERHEAD_BYTES]; // TODO generate and send frames without a buffer @@ -210,19 +210,66 @@ void _TF_FN TF_Init(TF_PEER peer_bit) //region Listeners +/** + * Notify callback about ID listener demise & clean it + * + * @param lst - listener to clean + */ +static void _TF_FN cleanup_id_listener(TF_COUNT i, IdListener *lst) +{ + TF_MSG msg; + if (lst->fn == NULL) return; + + msg.userdata = lst->userdata; + msg.data = NULL; // this is a signal that the listener should clean up + lst->fn(&msg); + lst->fn = NULL; // Discard listener + + if (i == tf.count_id_lst - 1) { + tf.count_id_lst--; + } +} + +/** + * Clean up Type listener + * + * @param lst - listener to clean + */ +static inline void _TF_FN cleanup_type_listener(TF_COUNT i, TypeListener *lst) +{ + lst->fn = NULL; // Discard listener + if (i == tf.count_type_lst - 1) { + tf.count_type_lst--; + } +} + +/** + * Clean up Generic listener + * + * @param lst - listener to clean + */ +static inline void _TF_FN cleanup_generic_listener(TF_COUNT i, GenericListener *lst) +{ + lst->fn = NULL; // Discard listener + if (i == tf.count_generic_lst - 1) { + tf.count_generic_lst--; + } +} + bool _TF_FN TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout) { - size_t i; + TF_COUNT i; IdListener *lst; for (i = 0; i < TF_MAX_ID_LST; i++) { lst = &tf.id_listeners[i]; + // test for empty slot if (lst->fn == NULL) { lst->fn = cb; lst->id = msg->frame_id; lst->userdata = msg->userdata; lst->timeout_max = lst->timeout = timeout; if (i >= tf.count_id_lst) { - tf.count_id_lst = i + 1; + tf.count_id_lst = (TF_COUNT) (i + 1); } return true; } @@ -232,15 +279,16 @@ bool _TF_FN TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout) bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) { - size_t i; + TF_COUNT i; TypeListener *lst; for (i = 0; i < TF_MAX_TYPE_LST; i++) { lst = &tf.type_listeners[i]; + // test for empty slot if (lst->fn == NULL) { lst->fn = cb; lst->type = frame_type; if (i >= tf.count_type_lst) { - tf.count_type_lst = i + 1; + tf.count_type_lst = (TF_COUNT) (i + 1); } return true; } @@ -250,14 +298,15 @@ bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) { - size_t i; + TF_COUNT i; GenericListener *lst; for (i = 0; i < TF_MAX_GEN_LST; i++) { lst = &tf.generic_listeners[i]; + // test for empty slot if (lst->fn == NULL) { lst->fn = cb; if (i >= tf.count_generic_lst) { - tf.count_generic_lst = i + 1; + tf.count_generic_lst = (TF_COUNT) (i + 1); } return true; } @@ -267,15 +316,13 @@ bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) { - size_t i; + TF_COUNT i; IdListener *lst; for (i = 0; i < tf.count_id_lst; i++) { lst = &tf.id_listeners[i]; + // test if live & matching if (lst->fn != NULL && lst->id == frame_id) { - lst->fn = NULL; - if (i == tf.count_id_lst - 1) { - tf.count_id_lst--; - } + cleanup_id_listener(i, lst); return true; } } @@ -284,15 +331,13 @@ bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) { - size_t i; + TF_COUNT i; TypeListener *lst; for (i = 0; i < tf.count_type_lst; i++) { lst = &tf.type_listeners[i]; + // test if live & matching if (lst->fn != NULL && lst->type == type) { - lst->fn = NULL; - if (i == tf.count_type_lst - 1) { - tf.count_type_lst--; - } + cleanup_type_listener(i, lst); return true; } } @@ -301,15 +346,13 @@ bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) { - size_t i; + TF_COUNT i; GenericListener *lst; for (i = 0; i < tf.count_generic_lst; i++) { lst = &tf.generic_listeners[i]; + // test if live & matching if (lst->fn == cb) { - lst->fn = NULL; - if (i == tf.count_generic_lst - 1) { - tf.count_generic_lst--; - } + cleanup_generic_listener(i, lst); return true; } } @@ -319,7 +362,7 @@ bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) /** Handle a message that was just collected & verified by the parser */ static void _TF_FN TF_HandleReceivedMessage(void) { - size_t i; + TF_COUNT i; IdListener *ilst; TypeListener *tlst; GenericListener *glst; @@ -342,8 +385,9 @@ static void _TF_FN TF_HandleReceivedMessage(void) for (i = 0; i < tf.count_id_lst; i++) { ilst = &tf.id_listeners[i]; if (ilst->fn && ilst->id == msg.frame_id) { - msg.userdata = ilst->userdata; + msg.userdata = ilst->userdata; // pass userdata pointer to the callback if (ilst->fn(&msg)) return; + ilst->userdata = msg.userdata; // put it back (may have changed the pointer or set to NULL) } } msg.userdata = NULL; @@ -530,24 +574,25 @@ void _TF_FN TF_AcceptChar(unsigned char c) * @param len - payload size in bytes * @param explicit_id - ID to use in the frame (8-bit) * @param use_expl_id - whether to use the previous param - * @return nr of bytes in outbuff used by the frame, TF_ERROR (-1) on failure + * @return nr of bytes in outbuff used by the frame, 0 on failure */ -static inline int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, +static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, TF_TYPE type, const uint8_t *data, TF_LEN data_len, TF_ID explicit_id, bool use_expl_id) { - int i; + char si; // signed small int + TF_LEN i; uint8_t b; TF_ID id; TF_CKSUM cksum; - int pos = 0; + size_t pos = 0; // can be needed to grow larger than TF_LEN CKSUM_RESET(cksum); // sanitize len if (data_len > TF_MAX_PAYLOAD_TX) { - return TF_ERROR; + return 0; } // Gen ID @@ -566,8 +611,8 @@ static inline int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, // DRY helper for writing a multi-byte variable to the buffer #define WRITENUM_BASE(type, num, xtra) \ - for (i = sizeof(type)-1; i>=0; i--) { \ - b = (uint8_t)(num >> (i*8) & 0xFF); \ + for (si = sizeof(type)-1; si>=0; si--) { \ + b = (uint8_t)(num >> (si*8) & 0xFF); \ outbuff[pos++] = b; \ xtra; \ } @@ -615,7 +660,7 @@ static inline int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) { - int len; + size_t len; len = TF_Compose(tf.sendbuf, &msg->frame_id, msg->type, @@ -624,11 +669,11 @@ bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) msg->frame_id, msg->is_response); - if (len == TF_ERROR) return false; + if (len == 0) return false; if (listener) TF_AddIdListener(msg, listener, timeout); - TF_WriteImpl((const uint8_t *) tf.sendbuf, (TF_LEN)len); + TF_WriteImpl((const uint8_t *) tf.sendbuf, len); return true; } @@ -644,11 +689,12 @@ bool _TF_FN TF_Respond(TF_MSG *msg, bool renew) bool _TF_FN TF_RenewIdListener(TF_ID id) { - size_t i; + TF_COUNT i; IdListener *lst; for (i = 0; i < tf.count_id_lst; i++) { lst = &tf.id_listeners[i]; - if (lst->fn && lst->id == id) { + // test if live & matching + if (lst->fn != NULL && lst->id == id) { lst->timeout = lst->timeout_max; return true; } @@ -659,8 +705,7 @@ bool _TF_FN TF_RenewIdListener(TF_ID id) /** Timebase hook - for timeouts */ void _TF_FN TF_Tick(void) { - size_t i; - TF_MSG msg; + TF_COUNT i; IdListener *lst; // increment parser timeout (timeout is handled when receiving next byte) @@ -671,15 +716,11 @@ void _TF_FN TF_Tick(void) // decrement and expire ID listeners for (i = 0; i < tf.count_id_lst; i++) { lst = &tf.id_listeners[i]; - if (lst->fn && lst->timeout > 0) { - if (--lst->timeout != 0) continue; - - // Notify listener about timeout - msg.userdata = lst->userdata; - msg.data = NULL; // this is a signal that listener should clean up - - lst->fn(&msg); - lst->fn = NULL; // Discard listener + if (!lst->fn || lst->timeout == 0) continue; + // count down... + if (--lst->timeout == 0) { + // Listener has expired + cleanup_id_listener(i, lst); } } } diff --git a/TinyFrame.h b/TinyFrame.h index 11be373..4db7258 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -56,9 +56,14 @@ // Value of the SOF byte (if TF_USE_SOF_BYTE == 1) #define TF_SOF_BYTE 0x01 +// used for timeout tick counters - should be large enough for all used timeouts +typedef uint16_t TF_TICKS; + +// used in loops iterating over listeners +typedef uint8_t TF_COUNT; + //------------------------- End of user config ------------------------------ -typedef unsigned int TF_TICKS; //region Resolve data types @@ -123,9 +128,6 @@ typedef unsigned int TF_TICKS; //--------------------------------------------------------------------------- -// Return value indicating error state -#define TF_ERROR -1 - // Type-dependent masks for bit manipulation in the ID field #define TF_ID_MASK (TF_ID)(((TF_ID)1 << (sizeof(TF_ID)*8 - 1)) - 1) #define TF_ID_PEERBIT (TF_ID)((TF_ID)1 << ((sizeof(TF_ID)*8) - 1)) @@ -145,8 +147,7 @@ typedef struct _TF_MSG_STRUCT_ { TF_TYPE type; // received or sent message type const uint8_t *data; // buffer of received data or data to send. NULL = listener timed out, free userdata! TF_LEN len; // length of the buffer - void *userdata; // here's a place for custom data; this data will be - // stored with the listener + void *userdata; // here's a place for custom data; this data will be stored with the listener } TF_MSG; /** @@ -282,7 +283,7 @@ void TF_AcceptChar(uint8_t c); * * ! Implement this in your application code ! */ -extern void TF_WriteImpl(const uint8_t *buff, TF_LEN len); +extern void TF_WriteImpl(const uint8_t *buff, size_t len); /** * This function should be called periodically. diff --git a/test.c b/test.c index 2ec775e..e128839 100644 --- a/test.c +++ b/test.c @@ -11,7 +11,7 @@ static void dumpFrame(const uint8_t *buff, TF_LEN len); * This function should be defined in the application code. * It implements the lowest layer - sending bytes to UART (or other) */ -void TF_WriteImpl(const uint8_t *buff, TF_LEN len) +void TF_WriteImpl(const uint8_t *buff, size_t len) { printf("--------------------\n"); printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n"); @@ -42,23 +42,24 @@ bool testIdListener(TF_MSG *msg) void main(void) { + TF_MSG msg; + const char *longstr = "Lorem ipsum dolor sit amet."; + // Set up the TinyFrame library TF_Init(TF_MASTER); // 1 = master, 0 = slave TF_AddGenericListener(myListener); printf("------ Simulate sending a message --------\n"); - TF_MSG msg; TF_ClearMsg(&msg); msg.type = 0x22; msg.data = (pu8)"Hello TinyFrame"; msg.len = 16; TF_Send(&msg, NULL, 0); - const char *longstr = "Lorem ipsum dolor sit amet."; msg.type = 0x33; msg.data = (pu8)longstr; - msg.len = strlen(longstr)+1; // add the null byte + msg.len = (TF_LEN) (strlen(longstr)+1); // add the null byte TF_Send(&msg, NULL, 0); msg.type = 0x44; From 01c8ab7f9069babd104557498d091915860ec120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 18:28:27 +0200 Subject: [PATCH 05/11] oops checksums didnt work --- TinyFrame.c | 40 +++++++++++++++++++++------------------- TinyFrame.h | 13 +++++++++---- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/TinyFrame.c b/TinyFrame.c index ad76c00..cf8cb4d 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -23,8 +23,8 @@ enum TFState { typedef struct _IdListener_struct_ { TF_ID id; TF_LISTENER fn; - TF_COUNT timeout; // nr of ticks remaining to disable this listener - TF_COUNT timeout_max; // the original timeout is stored here + TF_TICKS timeout; // nr of ticks remaining to disable this listener + TF_TICKS timeout_max; // the original timeout is stored here void *userdata; } IdListener; @@ -77,21 +77,21 @@ static struct TinyFrameStruct { //region Checksums -#if TF_CKSUM_TYPE == 0 +#if TF_CKSUM_TYPE == TF_CKSUM_NONE // NONE #define CKSUM_RESET(cksum) #define CKSUM_ADD(cksum, byte) #define CKSUM_FINALIZE(cksum) -#elif TF_CKSUM_TYPE == 8 +#elif TF_CKSUM_TYPE == TF_CKSUM_XOR // ~XOR #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) #define CKSUM_ADD(cksum, byte) do { cksum ^= byte; } while(0) #define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) -#elif TF_CKSUM_TYPE == 16 +#elif TF_CKSUM_TYPE == TF_CKSUM_CRC16 /** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ static const uint16_t crc16_table[256] = { @@ -138,7 +138,7 @@ static struct TinyFrameStruct { #define CKSUM_ADD(cksum, byte) do { cksum = crc16_byte(cksum, byte); } while(0) #define CKSUM_FINALIZE(cksum) -#elif TF_CKSUM_TYPE == 32 +#elif TF_CKSUM_TYPE == TF_CKSUM_CRC32 static const uint32_t crc32_table[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -191,9 +191,9 @@ static struct TinyFrameStruct { return (crc32_table[((cksum) ^ ((uint8_t)byte)) & 0xff] ^ ((cksum) >> 8)); } - #define CKSUM_RESET(cksum) do { cksum = (TF_CKSUM)0xFFFFFFFF; } while (0) - #define CKSUM_ADD(cksum, byte) do { cksum = crc32_byte(cksum, byte); } while(0) - #define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) + #define CKSUM_RESET(cksum) do { (cksum) = (TF_CKSUM)0xFFFFFFFF; } while (0) + #define CKSUM_ADD(cksum, byte) do { (cksum) = crc32_byte(cksum, byte); } while(0) + #define CKSUM_FINALIZE(cksum) do { (cksum) = (TF_CKSUM)~(cksum); } while(0) #endif @@ -486,7 +486,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) case TFState_TYPE: CKSUM_ADD(tf.cksum, c); COLLECT_NUMBER(tf.type, TF_TYPE) { - #if TF_CKSUM_TYPE == 0 + #if TF_CKSUM_TYPE == TF_CKSUM_NONE tf.state = TFState_DATA; tf.rxi = 0; #else @@ -536,7 +536,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) } if (tf.rxi == tf.len) { - #if TF_CKSUM_TYPE == 0 + #if TF_CKSUM_TYPE == TF_CKSUM_NONE // All done TF_HandleReceivedMessage(); TF_ResetParser(); @@ -581,13 +581,15 @@ static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, const uint8_t *data, TF_LEN data_len, TF_ID explicit_id, bool use_expl_id) { - char si; // signed small int - TF_LEN i; - uint8_t b; - TF_ID id; - TF_CKSUM cksum; + char si = 0; // signed small int + TF_LEN i = 0; + uint8_t b = 0; + TF_ID id = 0; + TF_CKSUM cksum = 0; size_t pos = 0; // can be needed to grow larger than TF_LEN + (void)cksum; + CKSUM_RESET(cksum); // sanitize len @@ -633,7 +635,7 @@ static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, WRITENUM_CKSUM(TF_LEN, data_len); WRITENUM_CKSUM(TF_TYPE, type); - #if TF_CKSUM_TYPE != 0 + #if TF_CKSUM_TYPE != TF_CKSUM_NONE CKSUM_FINALIZE(cksum); WRITENUM(TF_CKSUM, cksum); #endif @@ -649,7 +651,7 @@ static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, CKSUM_ADD(cksum, b); } - #if TF_CKSUM_TYPE != 0 + #if TF_CKSUM_TYPE != TF_CKSUM_NONE CKSUM_FINALIZE(cksum); WRITENUM(TF_CKSUM, cksum); #endif @@ -705,7 +707,7 @@ bool _TF_FN TF_RenewIdListener(TF_ID id) /** Timebase hook - for timeouts */ void _TF_FN TF_Tick(void) { - TF_COUNT i; + TF_COUNT i = 0; IdListener *lst; // increment parser timeout (timeout is handled when receiving next byte) diff --git a/TinyFrame.h b/TinyFrame.h index 4db7258..90678ae 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -49,7 +49,12 @@ #define TF_TYPE_BYTES 1 // Select checksum type (0 = none, 8 = ~XOR, 16 = CRC16 0x8005, 32 = CRC32) -#define TF_CKSUM_TYPE 16 +#define TF_CKSUM_NONE 0 +#define TF_CKSUM_XOR 8 +#define TF_CKSUM_CRC16 16 +#define TF_CKSUM_CRC32 32 + +#define TF_CKSUM_TYPE TF_CKSUM_CRC16 // Use a SOF byte to mark the start of a frame #define TF_USE_SOF_BYTE 1 @@ -100,13 +105,13 @@ typedef uint8_t TF_COUNT; #endif -#if TF_CKSUM_TYPE == 8 || TF_CKSUM_TYPE == 0 +#if TF_CKSUM_TYPE == TF_CKSUM_XOR || TF_CKSUM_TYPE == TF_CKSUM_NONE // ~XOR (if 0, still use 1 byte - it won't be used) typedef uint8_t TF_CKSUM; -#elif TF_CKSUM_TYPE == 16 +#elif TF_CKSUM_TYPE == TF_CKSUM_CRC16 // CRC16 typedef uint16_t TF_CKSUM; -#elif TF_CKSUM_TYPE == 32 +#elif TF_CKSUM_TYPE == TF_CKSUM_CRC32 // CRC32 typedef uint32_t TF_CKSUM; #else From e89ca3a6cbf6fd2c2250af563dfb7a1bf800450e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 18:32:21 +0200 Subject: [PATCH 06/11] some cleaning --- TinyFrame.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/TinyFrame.h b/TinyFrame.h index 90678ae..270233f 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -20,11 +20,11 @@ // --- Listener counts - determine sizes of the static slot tables --- // Frame ID listeners (wait for response / multi-part message) -#define TF_MAX_ID_LST 20 +#define TF_MAX_ID_LST 10 // Frame Type listeners (wait for frame with a specific first payload byte) -#define TF_MAX_TYPE_LST 20 +#define TF_MAX_TYPE_LST 10 // Generic listeners (fallback if no other listener catches it) -#define TF_MAX_GEN_LST 4 +#define TF_MAX_GEN_LST 5 // Timeout for receiving & parsing a frame // ticks = number of calls to TF_Tick() @@ -147,12 +147,12 @@ typedef enum { /** Data structure for sending / receiving messages */ typedef struct _TF_MSG_STRUCT_ { - TF_ID frame_id; // message ID - bool is_response; // internal flag, set when using the Respond function. frame_id is then kept unchanged. - TF_TYPE type; // received or sent message type - const uint8_t *data; // buffer of received data or data to send. NULL = listener timed out, free userdata! - TF_LEN len; // length of the buffer - void *userdata; // here's a place for custom data; this data will be stored with the listener + TF_ID frame_id; //!< message ID + bool is_response; //!< internal flag, set when using the Respond function. frame_id is then kept unchanged. + TF_TYPE type; //!< received or sent message type + const uint8_t *data; //!< buffer of received data or data to send. NULL = listener timed out, free userdata! + TF_LEN len; //!< length of the buffer + void *userdata; //!< here's a place for custom data; this data will be stored with the listener } TF_MSG; /** From 46883a9baa361720d5270679b23d30bddce9f0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 22:40:53 +0200 Subject: [PATCH 07/11] kinda working demo --- .gitignore | 1 + CMakeLists.txt | 16 ++- Makefile | 10 -- TF_Config.example.h | 70 +++++++++++++ TinyFrame.c | 57 +++++++++-- TinyFrame.h | 90 +++++------------ demo/demo.c | 197 +++++++++++++++++++++++++++++++++++++ demo/demo.h | 20 ++++ demo/hello/Makefile | 17 ++++ demo/hello/TF_Config.h | 25 +++++ demo/hello/master.c | 38 +++++++ demo/hello/slave.c | 29 ++++++ demo/test/Makefile | 11 +++ demo/test/TF_Config.h | 25 +++++ test.c => demo/test/test.c | 42 ++------ demo/utils.c | 32 ++++++ demo/utils.h | 15 +++ 17 files changed, 578 insertions(+), 117 deletions(-) delete mode 100644 Makefile create mode 100644 TF_Config.example.h create mode 100644 demo/demo.c create mode 100644 demo/demo.h create mode 100644 demo/hello/Makefile create mode 100644 demo/hello/TF_Config.h create mode 100644 demo/hello/master.c create mode 100644 demo/hello/slave.c create mode 100644 demo/test/Makefile create mode 100644 demo/test/TF_Config.h rename test.c => demo/test/test.c (55%) create mode 100644 demo/utils.c create mode 100644 demo/utils.h diff --git a/.gitignore b/.gitignore index 6dc0790..be999a8 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ *.i*86 *.x86_64 *.hex +*.bin # Debug files *.dSYM/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fbd81f..b644369 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,20 @@ project(tf) set(CMAKE_CXX_STANDARD GNU89) set(SOURCE_FILES - test.c + demo/test/test.c + demo/test/TF_Config.h + demo/hello/master.c + demo/hello/slave.c + demo/hello/TF_Config.h + demo/demo.c + demo/demo.h TinyFrame.c - TinyFrame.h) + TinyFrame.h + TF_Config.example.h + demo/utils.c + demo/utils.h + ) + +include_directories(demo/test) add_executable(tf ${SOURCE_FILES}) diff --git a/Makefile b/Makefile deleted file mode 100644 index 259b362..0000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -build: tf.bin - -run: tf.bin - ./tf.bin - -debug: tf.bin - gdb -q -ex run ./tf.bin - -tf.bin: test.c TinyFrame.c TinyFrame.h - gcc -O0 -ggdb --std=gnu89 -Wall -Wno-main -Wextra test.c TinyFrame.c -I. -o tf.bin diff --git a/TF_Config.example.h b/TF_Config.example.h new file mode 100644 index 0000000..edbd372 --- /dev/null +++ b/TF_Config.example.h @@ -0,0 +1,70 @@ +// +// Rename to TF_Config.h +// + +#ifndef TF_CONFIG_H +#define TF_CONFIG_H + +#include +//#include // when using with esphttpd + +//----------------------------- FRAME FORMAT --------------------------------- +// The format can be adjusted to fit your particular application needs + +// If the connection is reliable, you can disable the SOF byte and checksums. +// That can save up to 9 bytes of overhead. + +// ,-----+----+-----+------+------------+- - - -+------------, +// | SOF | ID | LEN | TYPE | HEAD_CKSUM | DATA | PLD_CKSUM | +// | 1 | ? | ? | ? | ? | ... | ? | <- size (bytes) +// '-----+----+-----+------+------------+- - - -+------------' + +// !!! BOTH SIDES MUST USE THE SAME SETTINGS !!! + +// Adjust sizes as desired (1,2,4) +#define TF_ID_BYTES 1 +#define TF_LEN_BYTES 2 +#define TF_TYPE_BYTES 1 + +// Checksum type +//#define TF_CKSUM_TYPE TF_CKSUM_NONE +//#define TF_CKSUM_TYPE TF_CKSUM_XOR +#define TF_CKSUM_TYPE TF_CKSUM_CRC16 +//#define TF_CKSUM_TYPE TF_CKSUM_CRC32 + +// Use a SOF byte to mark the start of a frame +#define TF_USE_SOF_BYTE 1 +// Value of the SOF byte (if TF_USE_SOF_BYTE == 1) +#define TF_SOF_BYTE 0x01 + +//----------------------- PLATFORM COMPATIBILITY ---------------------------- + +// used for timeout tick counters - should be large enough for all used timeouts +typedef uint16_t TF_TICKS; + +// used in loops iterating over listeners +typedef uint8_t TF_COUNT; + +//----------------------------- PARAMETERS ---------------------------------- + +// Maximum send / receive payload size (static buffers size) +// Larger payloads will be rejected. +#define TF_MAX_PAYLOAD_RX 1024 +#define TF_MAX_PAYLOAD_TX 1024 + +// --- Listener counts - determine sizes of the static slot tables --- + +// Frame ID listeners (wait for response / multi-part message) +#define TF_MAX_ID_LST 10 +// Frame Type listeners (wait for frame with a specific first payload byte) +#define TF_MAX_TYPE_LST 10 +// Generic listeners (fallback if no other listener catches it) +#define TF_MAX_GEN_LST 5 + +// Timeout for receiving & parsing a frame +// ticks = number of calls to TF_Tick() +#define TF_PARSER_TIMEOUT_TICKS 10 + +//------------------------- End of user config ------------------------------ + +#endif //TF_CONFIG_H diff --git a/TinyFrame.c b/TinyFrame.c index cf8cb4d..b8af068 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -1,6 +1,7 @@ //--------------------------------------------------------------------------- #include "TinyFrame.h" #include +//#include "demo/utils.h" //--------------------------------------------------------------------------- // Compatibility with ESP8266 SDK @@ -87,9 +88,9 @@ static struct TinyFrameStruct { #elif TF_CKSUM_TYPE == TF_CKSUM_XOR // ~XOR - #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) - #define CKSUM_ADD(cksum, byte) do { cksum ^= byte; } while(0) - #define CKSUM_FINALIZE(cksum) do { cksum = (TF_CKSUM)~cksum; } while(0) + #define CKSUM_RESET(cksum) do { (cksum) = 0; } while (0) + #define CKSUM_ADD(cksum, byte) do { (cksum) ^= (byte); } while(0) + #define CKSUM_FINALIZE(cksum) do { (cksum) = (TF_CKSUM)~cksum; } while(0) #elif TF_CKSUM_TYPE == TF_CKSUM_CRC16 @@ -134,8 +135,8 @@ static struct TinyFrameStruct { return (cksum >> 8) ^ crc16_table[(cksum ^ byte) & 0xff]; } - #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) - #define CKSUM_ADD(cksum, byte) do { cksum = crc16_byte(cksum, byte); } while(0) + #define CKSUM_RESET(cksum) do { (cksum) = 0; } while (0) + #define CKSUM_ADD(cksum, byte) do { (cksum) = crc16_byte((cksum), (byte)); } while(0) #define CKSUM_FINALIZE(cksum) #elif TF_CKSUM_TYPE == TF_CKSUM_CRC32 @@ -375,6 +376,8 @@ static void _TF_FN TF_HandleReceivedMessage(void) msg.data = tf.data; msg.len = tf.len; + //dumpFrameInfo(&msg); + // Any listener can consume the message (return true), // or let someone else handle it. @@ -385,6 +388,7 @@ static void _TF_FN TF_HandleReceivedMessage(void) for (i = 0; i < tf.count_id_lst; i++) { ilst = &tf.id_listeners[i]; if (ilst->fn && ilst->id == msg.frame_id) { + msg.renew = false; msg.userdata = ilst->userdata; // pass userdata pointer to the callback if (ilst->fn(&msg)) return; ilst->userdata = msg.userdata; // put it back (may have changed the pointer or set to NULL) @@ -561,6 +565,12 @@ void _TF_FN TF_AcceptChar(unsigned char c) } break; } + + // we get here after finishing HEAD, if no data are to be received - handle and clear + if (tf.len == 0 && tf.state == TFState_DATA) { + TF_HandleReceivedMessage(); + TF_ResetParser(); + } } /** @@ -660,7 +670,36 @@ static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, return pos; } -bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) +// send without listener +bool _TF_FN TF_Send(TF_MSG *msg) +{ + return TF_Query(msg, NULL, 0); +} + +// send without listener and struct +bool _TF_FN TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len) +{ + TF_MSG msg; + TF_ClearMsg(&msg); + msg.type = type; + msg.data = data; + msg.len = len; + return TF_Send(&msg); +} + +// send without listener and struct +bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LISTENER listener, TF_TICKS timeout) +{ + TF_MSG msg; + TF_ClearMsg(&msg); + msg.type = type; + msg.data = data; + msg.len = len; + return TF_Query(&msg, listener, timeout); +} + +// send with listener +bool _TF_FN TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) { size_t len; len = TF_Compose(tf.sendbuf, @@ -680,12 +719,12 @@ bool _TF_FN TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) } // Like TF_Send, but with explicit frame ID -bool _TF_FN TF_Respond(TF_MSG *msg, bool renew) +bool _TF_FN TF_Respond(TF_MSG *msg) { msg->is_response = true; - bool suc = TF_Send(msg, NULL, 0); + bool suc = TF_Send(msg); - if (suc && renew) TF_RenewIdListener(msg->frame_id); + if (suc && msg->renew) TF_RenewIdListener(msg->frame_id); return suc; } diff --git a/TinyFrame.h b/TinyFrame.h index 270233f..1ada271 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -5,70 +5,15 @@ #include // for uint8_t etc #include // for bool #include // for NULL -//#include "messages.h" // for your message IDs (enum or defines) -//#include // when using with esphttpd //--------------------------------------------------------------------------- - -//----------------------------- PARAMETERS ---------------------------------- - -// Maximum send / receive payload size (static buffers size) -// Larger payloads will be rejected. -#define TF_MAX_PAYLOAD_RX 1024 -#define TF_MAX_PAYLOAD_TX 1024 - -// --- Listener counts - determine sizes of the static slot tables --- - -// Frame ID listeners (wait for response / multi-part message) -#define TF_MAX_ID_LST 10 -// Frame Type listeners (wait for frame with a specific first payload byte) -#define TF_MAX_TYPE_LST 10 -// Generic listeners (fallback if no other listener catches it) -#define TF_MAX_GEN_LST 5 - -// Timeout for receiving & parsing a frame -// ticks = number of calls to TF_Tick() -#define TF_PARSER_TIMEOUT_TICKS 10 - -//----------------------------- FRAME FORMAT --------------------------------- -// The format can be adjusted to fit your particular application needs - -// If the connection is reliable, you can disable the SOF byte and checksums. -// That can save up to 9 bytes of overhead. - -// ,-----+----+-----+------+------------+- - - -+------------, -// | SOF | ID | LEN | TYPE | HEAD_CKSUM | DATA | PLD_CKSUM | -// | 1 | ? | ? | ? | ? | ... | ? | <- size (bytes) -// '-----+----+-----+------+------------+- - - -+------------' - -// !!! BOTH SIDES MUST USE THE SAME SETTINGS !!! - -// Adjust sizes as desired (1,2,4) -#define TF_ID_BYTES 1 -#define TF_LEN_BYTES 2 -#define TF_TYPE_BYTES 1 - // Select checksum type (0 = none, 8 = ~XOR, 16 = CRC16 0x8005, 32 = CRC32) -#define TF_CKSUM_NONE 0 -#define TF_CKSUM_XOR 8 +#define TF_CKSUM_NONE 0 +#define TF_CKSUM_XOR 8 #define TF_CKSUM_CRC16 16 #define TF_CKSUM_CRC32 32 -#define TF_CKSUM_TYPE TF_CKSUM_CRC16 - -// Use a SOF byte to mark the start of a frame -#define TF_USE_SOF_BYTE 1 -// Value of the SOF byte (if TF_USE_SOF_BYTE == 1) -#define TF_SOF_BYTE 0x01 - -// used for timeout tick counters - should be large enough for all used timeouts -typedef uint16_t TF_TICKS; - -// used in loops iterating over listeners -typedef uint8_t TF_COUNT; - -//------------------------- End of user config ------------------------------ - +#include //region Resolve data types @@ -153,6 +98,7 @@ typedef struct _TF_MSG_STRUCT_ { const uint8_t *data; //!< buffer of received data or data to send. NULL = listener timed out, free userdata! TF_LEN len; //!< length of the buffer void *userdata; //!< here's a place for custom data; this data will be stored with the listener + bool renew; //!< Renew the ID listener - if using timeout } TF_MSG; /** @@ -161,11 +107,12 @@ typedef struct _TF_MSG_STRUCT_ { static inline void TF_ClearMsg(TF_MSG *msg) { msg->frame_id = 0; - msg->is_response = 0; + msg->is_response = false; msg->type = 0; msg->data = NULL; msg->len = 0; msg->userdata = NULL; + msg->renew = false; } /** @@ -241,6 +188,24 @@ bool TF_AddGenericListener(TF_LISTENER cb); */ bool TF_RemoveGenericListener(TF_LISTENER cb); +/** + * Send a frame, no listener + * + * @param msg - message struct. ID is stored in the frame_id field + * @return success + */ +bool TF_Send(TF_MSG *msg); + +/** + * Like TF_Send, but without the struct + */ +bool TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len); + +/** + * Like TF_Query, but without the struct + */ +bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LISTENER listener, TF_TICKS timeout); + /** * Send a frame, and optionally attach an ID listener. * @@ -249,16 +214,15 @@ bool TF_RemoveGenericListener(TF_LISTENER cb); * @param timeout - listener expiry time in ticks * @return success */ -bool TF_Send(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout); +bool TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout); /** * Send a response to a received message. * - * @param msg - message struct. ID is read from frame_id - * @param renew - renew the listener timeout (waiting for more data) + * @param msg - message struct. ID is read from frame_id. set ->renew to reset listener timeout * @return success */ -bool TF_Respond(TF_MSG *msg, bool renew); +bool TF_Respond(TF_MSG *msg); /** * Renew ID listener timeout diff --git a/demo/demo.c b/demo/demo.c new file mode 100644 index 0000000..9a5c95b --- /dev/null +++ b/demo/demo.c @@ -0,0 +1,197 @@ +// +// Created by MightyPork on 2017/10/15. +// + +// http://www.thegeekstuff.com/2011/12/c-socket-programming/?utm_source=feedburner + +#include "demo.h" + +#include +#include +#include +#include +#include +#include + +volatile int sockfd = -1; +volatile bool conn_disband = false; + +void demo_disconn(void) +{ + conn_disband = true; + if (sockfd >= 0) close(sockfd); +} + +void TF_WriteImpl(const uint8_t *buff, size_t len) +{ + printf("--------------------\n"); + printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n"); + dumpFrame(buff, len); + + if (sockfd != -1) { + write(sockfd, buff, len); + } else { + printf("\nNo peer!\n"); + } +} + +static bool demo_client(void) +{ + pid_t childPID; + ssize_t n = 0; + uint8_t recvBuff[1024]; + struct sockaddr_in serv_addr; + + printf("\n--- STARTING CLIENT! ---\n"); + + memset(recvBuff, '0', sizeof(recvBuff)); + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("\n Error : Could not create socket \n"); + return false; + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { + printf("\n inet_pton error occured\n"); + return false; + } + + if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + printf("\n Error : Connect Failed \n"); + perror("PERROR "); + return false; + } + + childPID = fork(); + if (childPID >= 0) { // fork was successful + if (childPID == 0) {// child process + printf("\n Child Process \n"); + + while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { + dumpFrame(recvBuff, (size_t) n); + TF_Accept(recvBuff, (size_t) n); + } + printf("\n End read \n"); + + if (n < 0) { + printf("\n Read error \n"); + } + + printf("\n Close sock \n"); + close(sockfd); + sockfd = -1; + + return true; + } + else { //Parent process + printf("\n Parent process \n"); + + return true; + } + } + else { // fork failed + printf("\n Fork failed!!!!!! \n"); + return false; + } +} + +static bool demo_server(void) +{ + pid_t childPID; + ssize_t n; + int listenfd = 0; + uint8_t recvBuff[1024]; + struct sockaddr_in serv_addr; + int option; + + printf("\n--- STARTING SERVER! ---\n"); + + listenfd = socket(AF_INET, SOCK_STREAM, 0); + memset(&serv_addr, '0', sizeof(serv_addr)); + + option = 1; + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(PORT); + + if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + perror("Failed to bind "); + return false; + } + + if (listen(listenfd, 10) < 0) { + perror("Failed to listen "); + return false; + } + + childPID = fork(); + if (childPID >= 0) { // fork was successful + if (childPID == 0) {// child process + printf("\n Child Process \n"); + + while (1) { + printf("\nWaiting for client...\n"); + sockfd = accept(listenfd, (struct sockaddr *) NULL, NULL); + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option)); + printf("\nClient connected\n"); + conn_disband = false; + + while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { + printf("...read %ld\n", n); + dumpFrame(recvBuff, n); + TF_Accept(recvBuff, (size_t) n); + } + + if (n < 0) { + printf("\n Read error \n"); + } + + printf("Closing socket\n"); + close(sockfd); + sockfd = -1; + } + + return true; + } + else { //Parent process + printf("\n Parent process \n"); + + return true; + } + } + else { // fork failed + printf("\n Fork failed!!!!!! \n"); + return false; + } +} + +void signal_handler(int sig) +{ + (void)sig; + printf("Shutting down..."); + demo_disconn(); + exit(0); +} + +void demo_init(TF_PEER peer) +{ + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); + + bool suc; + if (peer == TF_MASTER) { + suc = demo_client(); + } else { + suc = demo_server(); + } + + if (!suc) { + signal_handler(9); + } +} diff --git a/demo/demo.h b/demo/demo.h new file mode 100644 index 0000000..0b64d61 --- /dev/null +++ b/demo/demo.h @@ -0,0 +1,20 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#ifndef TF_DEMO_H +#define TF_DEMO_H + +#include +#include "../TinyFrame.h" +#include "utils.h" + +#define PORT 9798 + +/** Init server - DOES NOT init TinyFrame! */ +void demo_init(TF_PEER peer); + +/** Disconnect client from the server - claled by a server-side callback */ +void demo_disconn(void); + +#endif //TF_DEMO_H diff --git a/demo/hello/Makefile b/demo/hello/Makefile new file mode 100644 index 0000000..6c3e627 --- /dev/null +++ b/demo/hello/Makefile @@ -0,0 +1,17 @@ +CFILES=../demo.c ../utils.c ../../TinyFrame.c +INCLDIRS=-I. -I.. -I../.. +CFLAGS=-O0 -ggdb --std=gnu99 -Wno-main -Wall -Wextra $(CFILES) $(INCLDIRS) + +build: master.bin slave.bin + +master: master.bin + ./master.bin + +slave: slave.bin + ./slave.bin + +master.bin: master.c $(CFILES) + gcc master.c $(CFLAGS) -o master.bin + +slave.bin: slave.c $(CFILES) + gcc slave.c $(CFLAGS) -o slave.bin diff --git a/demo/hello/TF_Config.h b/demo/hello/TF_Config.h new file mode 100644 index 0000000..ea34ae6 --- /dev/null +++ b/demo/hello/TF_Config.h @@ -0,0 +1,25 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#ifndef TF_CONFIG_H +#define TF_CONFIG_H + +#include + +#define TF_ID_BYTES 1 +#define TF_LEN_BYTES 2 +#define TF_TYPE_BYTES 1 +#define TF_CKSUM_TYPE TF_CKSUM_CRC32 +#define TF_USE_SOF_BYTE 1 +#define TF_SOF_BYTE 0x01 +typedef uint16_t TF_TICKS; +typedef uint8_t TF_COUNT; +#define TF_MAX_PAYLOAD_RX 1024 +#define TF_MAX_PAYLOAD_TX 1024 +#define TF_MAX_ID_LST 10 +#define TF_MAX_TYPE_LST 10 +#define TF_MAX_GEN_LST 5 +#define TF_PARSER_TIMEOUT_TICKS 10 + +#endif //TF_CONFIG_H diff --git a/demo/hello/master.c b/demo/hello/master.c new file mode 100644 index 0000000..3c64960 --- /dev/null +++ b/demo/hello/master.c @@ -0,0 +1,38 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#include +#include +#include +#include "../../TinyFrame.h" +#include "../demo.h" + +bool testIdListener(TF_MSG *msg) +{ + printf("testIdListener()\n"); + dumpFrameInfo(msg); + return true; +} + +bool testGenericListener(TF_MSG *msg) +{ + printf("testGenericListener()\n"); + dumpFrameInfo(msg); + return true; +} + +int main(void) +{ + TF_Init(TF_MASTER); + TF_AddGenericListener(testGenericListener); + + demo_init(TF_MASTER); + + TF_SendSimple(1, (pu8)"Ahoj", 5); + TF_SendSimple(1, (pu8)"Hello", 6); + + TF_QuerySimple(1, (pu8)"Query!", 6, testIdListener, 0); + + while(1) usleep(10); +} diff --git a/demo/hello/slave.c b/demo/hello/slave.c new file mode 100644 index 0000000..1f1f873 --- /dev/null +++ b/demo/hello/slave.c @@ -0,0 +1,29 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#include +#include "../../TinyFrame.h" +#include "../demo.h" +#include +#include + +bool helloListener(TF_MSG *msg) +{ + printf("helloListener()\n"); + dumpFrameInfo(msg); + msg->data = (const uint8_t *) "jak se mas?"; + msg->len = (TF_LEN) strlen((const char *) msg->data); + TF_Respond(msg); + return true; +} + +int main(void) +{ + TF_Init(TF_SLAVE); + TF_AddTypeListener(1, helloListener); + + demo_init(TF_SLAVE); + printf("MAIN PROCESS CONTINUES...\n"); + while(1) usleep(10); +} diff --git a/demo/test/Makefile b/demo/test/Makefile new file mode 100644 index 0000000..118c385 --- /dev/null +++ b/demo/test/Makefile @@ -0,0 +1,11 @@ +CFILES=../utils.c ../../TinyFrame.c +INCLDIRS=-I. -I.. -I../.. +CFLAGS=-O0 -ggdb --std=gnu99 -Wno-main -Wall -Wextra $(CFILES) $(INCLDIRS) + +run: test.bin + ./test.bin + +build: test.bin + +test.bin: test.c $(CFILES) + gcc test.c $(CFLAGS) -o test.bin diff --git a/demo/test/TF_Config.h b/demo/test/TF_Config.h new file mode 100644 index 0000000..306b833 --- /dev/null +++ b/demo/test/TF_Config.h @@ -0,0 +1,25 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#ifndef TF_CONFIG_H +#define TF_CONFIG_H + +#include + +#define TF_ID_BYTES 1 +#define TF_LEN_BYTES 2 +#define TF_TYPE_BYTES 1 +#define TF_CKSUM_TYPE TF_CKSUM_CRC16 +#define TF_USE_SOF_BYTE 1 +#define TF_SOF_BYTE 0x01 +typedef uint16_t TF_TICKS; +typedef uint8_t TF_COUNT; +#define TF_MAX_PAYLOAD_RX 1024 +#define TF_MAX_PAYLOAD_TX 1024 +#define TF_MAX_ID_LST 10 +#define TF_MAX_TYPE_LST 10 +#define TF_MAX_GEN_LST 5 +#define TF_PARSER_TIMEOUT_TICKS 10 + +#endif //TF_CONFIG_H diff --git a/test.c b/demo/test/test.c similarity index 55% rename from test.c rename to demo/test/test.c index e128839..dc686cd 100644 --- a/test.c +++ b/demo/test/test.c @@ -1,11 +1,8 @@ #include -#include #include -#include "TinyFrame.h" +#include "../../TinyFrame.h" +#include "../utils.h" -typedef unsigned char* pu8; - -static void dumpFrame(const uint8_t *buff, TF_LEN len); /** * This function should be defined in the application code. @@ -24,19 +21,14 @@ void TF_WriteImpl(const uint8_t *buff, size_t len) /** An example listener function */ bool myListener(TF_MSG *msg) { - printf("\033[33mRX frame\n" - " type: %02Xh\n" - " data: \"%.*s\"\n" - " len: %u\n" - " id: %Xh\033[0m\n", - msg->type, msg->len, msg->data, msg->len, msg->frame_id); + dumpFrameInfo(msg); return true; } bool testIdListener(TF_MSG *msg) { - printf("OK - ID Listener triggered for msg (type %02X, id %Xh)!", - msg->type, msg->frame_id); + printf("OK - ID Listener triggered for msg!\n"); + dumpFrameInfo(msg); return true; } @@ -55,35 +47,19 @@ void main(void) msg.type = 0x22; msg.data = (pu8)"Hello TinyFrame"; msg.len = 16; - TF_Send(&msg, NULL, 0); + TF_Send(&msg); msg.type = 0x33; msg.data = (pu8)longstr; msg.len = (TF_LEN) (strlen(longstr)+1); // add the null byte - TF_Send(&msg, NULL, 0); + TF_Send(&msg); msg.type = 0x44; msg.data = (pu8)"Hello2"; msg.len = 7; - TF_Send(&msg, NULL, 0); + TF_Send(&msg); msg.len = 0; msg.type = 0x77; - TF_Send(&msg, testIdListener, 0); -} - -// helper func for testing -static void dumpFrame(const uint8_t *buff, TF_LEN len) -{ - int i; - for(i = 0; i < len; i++) { - printf("%3u \033[34m%02X\033[0m", buff[i], buff[i]); - if (buff[i] >= 0x20 && buff[i] < 127) { - printf(" %c", buff[i]); - } else { - printf(" \033[31m.\033[0m"); - } - printf("\n"); - } - printf("--- end of frame ---\n"); + TF_Query(&msg, testIdListener, 0); } diff --git a/demo/utils.c b/demo/utils.c new file mode 100644 index 0000000..8c2c891 --- /dev/null +++ b/demo/utils.c @@ -0,0 +1,32 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#include "utils.h" +#include + +// helper func for testing +void dumpFrame(const uint8_t *buff, size_t len) +{ + size_t i; + for(i = 0; i < len; i++) { + printf("%3u \033[34m%02X\033[0m", buff[i], buff[i]); + if (buff[i] >= 0x20 && buff[i] < 127) { + printf(" %c", buff[i]); + } else { + printf(" \033[31m.\033[0m"); + } + printf("\n"); + } + printf("--- end of frame ---\n"); +} + +void dumpFrameInfo(TF_MSG *msg) +{ + printf("\033[33mRX frame\n" + " type: %02Xh\n" + " data: \"%.*s\"\n" + " len: %u\n" + " id: %Xh\033[0m\n", + msg->type, msg->len, msg->data, msg->len, msg->frame_id); +} diff --git a/demo/utils.h b/demo/utils.h new file mode 100644 index 0000000..06c4af5 --- /dev/null +++ b/demo/utils.h @@ -0,0 +1,15 @@ +// +// Created by MightyPork on 2017/10/15. +// + +#ifndef TF_UTILS_H +#define TF_UTILS_H + +#include +#include "../TinyFrame.h" + +typedef unsigned char* pu8; +void dumpFrame(const uint8_t *buff, size_t len); +void dumpFrameInfo(TF_MSG *msg); + +#endif //TF_UTILS_H From 8415f15c99c72efbbdc71910901202f3ab35399a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 23:19:39 +0200 Subject: [PATCH 08/11] demo works ... --- demo/demo.c | 141 ++++++++++++++++++++------------------------ demo/hello/master.c | 2 +- demo/hello/slave.c | 12 +++- demo/utils.c | 2 +- 4 files changed, 77 insertions(+), 80 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index 9a5c95b..41c10e3 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -6,6 +6,10 @@ #include "demo.h" +#define _GNU_SOURCE +#define __USE_GNU +#include + #include #include #include @@ -35,9 +39,10 @@ void TF_WriteImpl(const uint8_t *buff, size_t len) } } -static bool demo_client(void) +static int demo_client(void* unused) { - pid_t childPID; + (void)unused; + ssize_t n = 0; uint8_t recvBuff[1024]; struct sockaddr_in serv_addr; @@ -66,42 +71,29 @@ static bool demo_client(void) return false; } - childPID = fork(); - if (childPID >= 0) { // fork was successful - if (childPID == 0) {// child process - printf("\n Child Process \n"); - - while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { - dumpFrame(recvBuff, (size_t) n); - TF_Accept(recvBuff, (size_t) n); - } - printf("\n End read \n"); + printf("\n Child Process \n"); - if (n < 0) { - printf("\n Read error \n"); - } - - printf("\n Close sock \n"); - close(sockfd); - sockfd = -1; - - return true; - } - else { //Parent process - printf("\n Parent process \n"); - - return true; - } - } - else { // fork failed - printf("\n Fork failed!!!!!! \n"); - return false; + while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0) { + dumpFrame(recvBuff, (size_t) n); + TF_Accept(recvBuff, (size_t) n); } +// printf("\n End read \n"); +// +// if (n < 0) { +// printf("\n Read error \n"); +// } +// +// printf("\n Close sock \n"); +// close(sockfd); +// sockfd = -1; +// +// return true; + return 0; } -static bool demo_server(void) +static int demo_server(void* unused) { - pid_t childPID; + (void)unused; ssize_t n; int listenfd = 0; uint8_t recvBuff[1024]; @@ -121,54 +113,37 @@ static bool demo_server(void) serv_addr.sin_port = htons(PORT); if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - perror("Failed to bind "); - return false; + perror("Failed to bind"); + return 1; } if (listen(listenfd, 10) < 0) { - perror("Failed to listen "); - return false; + perror("Failed to listen"); + return 1; } - childPID = fork(); - if (childPID >= 0) { // fork was successful - if (childPID == 0) {// child process - printf("\n Child Process \n"); - - while (1) { - printf("\nWaiting for client...\n"); - sockfd = accept(listenfd, (struct sockaddr *) NULL, NULL); - setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option)); - printf("\nClient connected\n"); - conn_disband = false; - - while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { - printf("...read %ld\n", n); - dumpFrame(recvBuff, n); - TF_Accept(recvBuff, (size_t) n); - } - - if (n < 0) { - printf("\n Read error \n"); - } - - printf("Closing socket\n"); - close(sockfd); - sockfd = -1; - } - - return true; + while (1) { + printf("\nWaiting for client...\n"); + sockfd = accept(listenfd, (struct sockaddr *) NULL, NULL); + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option)); + printf("\nClient connected\n"); + conn_disband = false; + + while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { + printf("...read %ld\n", n); + dumpFrame(recvBuff, n); + TF_Accept(recvBuff, (size_t) n); } - else { //Parent process - printf("\n Parent process \n"); - return true; + if (n < 0) { + printf("\n Read error \n"); } + + printf("Closing socket\n"); + close(sockfd); + sockfd = -1; } - else { // fork failed - printf("\n Fork failed!!!!!! \n"); - return false; - } + return 0; } void signal_handler(int sig) @@ -176,7 +151,7 @@ void signal_handler(int sig) (void)sig; printf("Shutting down..."); demo_disconn(); - exit(0); + exit(sig); } void demo_init(TF_PEER peer) @@ -184,14 +159,26 @@ void demo_init(TF_PEER peer) signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); - bool suc; + int retc; + void *stack = malloc(8192); + if (stack == NULL) { + perror("Oh fuck"); + signal_handler(9); + return; + } + + printf("Starting %s...\n", peer == TF_MASTER ? "MASTER" : "SLAVE"); if (peer == TF_MASTER) { - suc = demo_client(); + retc = clone(&demo_client, (char *)stack+8192, CLONE_VM|CLONE_FILES, 0); } else { - suc = demo_server(); + retc = clone(&demo_server, (char *)stack+8192, CLONE_VM|CLONE_FILES, 0); } - if (!suc) { + if (retc == 0) { + perror("Clone fail"); signal_handler(9); + return; } + + printf("Thread started\n"); } diff --git a/demo/hello/master.c b/demo/hello/master.c index 3c64960..581fa42 100644 --- a/demo/hello/master.c +++ b/demo/hello/master.c @@ -32,7 +32,7 @@ int main(void) TF_SendSimple(1, (pu8)"Ahoj", 5); TF_SendSimple(1, (pu8)"Hello", 6); - TF_QuerySimple(1, (pu8)"Query!", 6, testIdListener, 0); + TF_QuerySimple(2, (pu8)"Query!", 6, testIdListener, 0); while(1) usleep(10); } diff --git a/demo/hello/slave.c b/demo/hello/slave.c index 1f1f873..e178e73 100644 --- a/demo/hello/slave.c +++ b/demo/hello/slave.c @@ -12,9 +12,18 @@ bool helloListener(TF_MSG *msg) { printf("helloListener()\n"); dumpFrameInfo(msg); - msg->data = (const uint8_t *) "jak se mas?"; + return true; +} + +bool replyListener(TF_MSG *msg) +{ + printf("replyListener()\n"); + dumpFrameInfo(msg); + msg->data = (const uint8_t *) "response to query"; msg->len = (TF_LEN) strlen((const char *) msg->data); TF_Respond(msg); + + TF_SendSimple(77, (const uint8_t *) "NAZDAR", 7); return true; } @@ -22,6 +31,7 @@ int main(void) { TF_Init(TF_SLAVE); TF_AddTypeListener(1, helloListener); + TF_AddTypeListener(2, replyListener); demo_init(TF_SLAVE); printf("MAIN PROCESS CONTINUES...\n"); diff --git a/demo/utils.c b/demo/utils.c index 8c2c891..c79297f 100644 --- a/demo/utils.c +++ b/demo/utils.c @@ -10,7 +10,7 @@ void dumpFrame(const uint8_t *buff, size_t len) { size_t i; for(i = 0; i < len; i++) { - printf("%3u \033[34m%02X\033[0m", buff[i], buff[i]); + printf("%3u \033[94m%02X\033[0m", buff[i], buff[i]); if (buff[i] >= 0x20 && buff[i] < 127) { printf(" %c", buff[i]); } else { From 87d1841fc8e8721bca18cf2b94b07a1011490388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 15 Oct 2017 23:30:25 +0200 Subject: [PATCH 09/11] demo tweaks ... --- demo/demo.c | 23 +++++++++-------------- demo/demo.h | 3 +++ demo/hello/TF_Config.h | 2 +- demo/hello/master.c | 5 +---- demo/hello/slave.c | 5 +---- demo/utils.c | 6 +++--- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index 41c10e3..503e382 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -28,9 +28,9 @@ void demo_disconn(void) void TF_WriteImpl(const uint8_t *buff, size_t len) { - printf("--------------------\n"); - printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n"); + printf("\033[32m--- TX %ld bytes ---\033[0m\n", len); dumpFrame(buff, len); + usleep(1000); if (sockfd != -1) { write(sockfd, buff, len); @@ -74,20 +74,10 @@ static int demo_client(void* unused) printf("\n Child Process \n"); while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0) { + printf("\033[36m--- RX %ld bytes ---\033[0m\n", n); dumpFrame(recvBuff, (size_t) n); TF_Accept(recvBuff, (size_t) n); } -// printf("\n End read \n"); -// -// if (n < 0) { -// printf("\n Read error \n"); -// } -// -// printf("\n Close sock \n"); -// close(sockfd); -// sockfd = -1; -// -// return true; return 0; } @@ -130,7 +120,7 @@ static int demo_server(void* unused) conn_disband = false; while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) { - printf("...read %ld\n", n); + printf("\033[36m--- RX %ld bytes ---\033[0m\n", n); dumpFrame(recvBuff, n); TF_Accept(recvBuff, (size_t) n); } @@ -154,6 +144,11 @@ void signal_handler(int sig) exit(sig); } +void demo_sleep(void) +{ + while(1) usleep(10); +} + void demo_init(TF_PEER peer) { signal(SIGTERM, signal_handler); diff --git a/demo/demo.h b/demo/demo.h index 0b64d61..d5292f4 100644 --- a/demo/demo.h +++ b/demo/demo.h @@ -11,6 +11,9 @@ #define PORT 9798 +/** Sleep and wait for ^C */ +void demo_sleep(void); + /** Init server - DOES NOT init TinyFrame! */ void demo_init(TF_PEER peer); diff --git a/demo/hello/TF_Config.h b/demo/hello/TF_Config.h index ea34ae6..306b833 100644 --- a/demo/hello/TF_Config.h +++ b/demo/hello/TF_Config.h @@ -10,7 +10,7 @@ #define TF_ID_BYTES 1 #define TF_LEN_BYTES 2 #define TF_TYPE_BYTES 1 -#define TF_CKSUM_TYPE TF_CKSUM_CRC32 +#define TF_CKSUM_TYPE TF_CKSUM_CRC16 #define TF_USE_SOF_BYTE 1 #define TF_SOF_BYTE 0x01 typedef uint16_t TF_TICKS; diff --git a/demo/hello/master.c b/demo/hello/master.c index 581fa42..5bffbf6 100644 --- a/demo/hello/master.c +++ b/demo/hello/master.c @@ -3,9 +3,6 @@ // #include -#include -#include -#include "../../TinyFrame.h" #include "../demo.h" bool testIdListener(TF_MSG *msg) @@ -34,5 +31,5 @@ int main(void) TF_QuerySimple(2, (pu8)"Query!", 6, testIdListener, 0); - while(1) usleep(10); + demo_sleep(); } diff --git a/demo/hello/slave.c b/demo/hello/slave.c index e178e73..200b3e2 100644 --- a/demo/hello/slave.c +++ b/demo/hello/slave.c @@ -3,9 +3,7 @@ // #include -#include "../../TinyFrame.h" #include "../demo.h" -#include #include bool helloListener(TF_MSG *msg) @@ -34,6 +32,5 @@ int main(void) TF_AddTypeListener(2, replyListener); demo_init(TF_SLAVE); - printf("MAIN PROCESS CONTINUES...\n"); - while(1) usleep(10); + demo_sleep(); } diff --git a/demo/utils.c b/demo/utils.c index c79297f..3454cbf 100644 --- a/demo/utils.c +++ b/demo/utils.c @@ -18,15 +18,15 @@ void dumpFrame(const uint8_t *buff, size_t len) } printf("\n"); } - printf("--- end of frame ---\n"); + printf("--- end of frame ---\n\n"); } void dumpFrameInfo(TF_MSG *msg) { - printf("\033[33mRX frame\n" + printf("\033[33mFrame info\n" " type: %02Xh\n" " data: \"%.*s\"\n" " len: %u\n" - " id: %Xh\033[0m\n", + " id: %Xh\033[0m\n\n", msg->type, msg->len, msg->data, msg->len, msg->frame_id); } From 4ad1f09f733d1e5044700f481de046a024d9470a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 16 Oct 2017 00:29:43 +0200 Subject: [PATCH 10/11] great cleaning --- TinyFrame.c | 88 ++++++++++++++++++++++++++++++--------------- TinyFrame.h | 39 +++++++++++--------- demo/demo.c | 52 +++++++++++++++++++++++---- demo/demo.h | 4 +-- demo/hello/master.c | 8 ++--- demo/hello/slave.c | 14 +++++--- demo/test/test.c | 10 +++--- demo/utils.c | 2 +- demo/utils.h | 13 ++++++- 9 files changed, 161 insertions(+), 69 deletions(-) diff --git a/TinyFrame.c b/TinyFrame.c index b8af068..dac526b 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -23,7 +23,7 @@ enum TFState { typedef struct _IdListener_struct_ { TF_ID id; - TF_LISTENER fn; + TF_Listener fn; TF_TICKS timeout; // nr of ticks remaining to disable this listener TF_TICKS timeout_max; // the original timeout is stored here void *userdata; @@ -31,11 +31,11 @@ typedef struct _IdListener_struct_ { typedef struct _TypeListener_struct_ { TF_TYPE type; - TF_LISTENER fn; + TF_Listener fn; } TypeListener; typedef struct _GenericListener_struct_ { - TF_LISTENER fn; + TF_Listener fn; } GenericListener; /** @@ -43,7 +43,7 @@ typedef struct _GenericListener_struct_ { */ static struct TinyFrameStruct { /* Own state */ - TF_PEER peer_bit; //!< Own peer bit (unqiue to avoid msg ID clash) + TF_Peer peer_bit; //!< Own peer bit (unqiue to avoid msg ID clash) TF_ID next_id; //!< Next frame / frame chain ID /* Parser state */ @@ -201,7 +201,7 @@ static struct TinyFrameStruct { //endregion -void _TF_FN TF_Init(TF_PEER peer_bit) +void _TF_FN TF_Init(TF_Peer peer_bit) { // Zero it out memset(&tf, 0, sizeof(struct TinyFrameStruct)); @@ -211,6 +211,11 @@ void _TF_FN TF_Init(TF_PEER peer_bit) //region Listeners +static void _TF_FN renew_id_listener(IdListener *lst) +{ + lst->timeout = lst->timeout_max; +} + /** * Notify callback about ID listener demise & clean it * @@ -218,12 +223,16 @@ void _TF_FN TF_Init(TF_PEER peer_bit) */ static void _TF_FN cleanup_id_listener(TF_COUNT i, IdListener *lst) { - TF_MSG msg; + TF_Msg msg; if (lst->fn == NULL) return; - msg.userdata = lst->userdata; - msg.data = NULL; // this is a signal that the listener should clean up - lst->fn(&msg); + // Make user clean up their data - only if not NULL + if (lst->userdata != NULL) { + msg.userdata = lst->userdata; + msg.data = NULL; // this is a signal that the listener should clean up + lst->fn(&msg); // return value is ignored here - use TF_STAY or TF_CLOSE + } + lst->fn = NULL; // Discard listener if (i == tf.count_id_lst - 1) { @@ -257,7 +266,7 @@ static inline void _TF_FN cleanup_generic_listener(TF_COUNT i, GenericListener * } } -bool _TF_FN TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout) +bool _TF_FN TF_AddIdListener(TF_Msg *msg, TF_Listener cb, TF_TICKS timeout) { TF_COUNT i; IdListener *lst; @@ -278,7 +287,7 @@ bool _TF_FN TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout) return false; } -bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) +bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_Listener cb) { TF_COUNT i; TypeListener *lst; @@ -297,7 +306,7 @@ bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) return false; } -bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) +bool _TF_FN TF_AddGenericListener(TF_Listener cb) { TF_COUNT i; GenericListener *lst; @@ -345,7 +354,7 @@ bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) return false; } -bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) +bool _TF_FN TF_RemoveGenericListener(TF_Listener cb) { TF_COUNT i; GenericListener *lst; @@ -367,9 +376,10 @@ static void _TF_FN TF_HandleReceivedMessage(void) IdListener *ilst; TypeListener *tlst; GenericListener *glst; + TF_Result res; // Prepare message object - TF_MSG msg; + TF_Msg msg; msg.frame_id = tf.id; msg.is_response = false; msg.type = tf.type; @@ -388,10 +398,19 @@ static void _TF_FN TF_HandleReceivedMessage(void) for (i = 0; i < tf.count_id_lst; i++) { ilst = &tf.id_listeners[i]; if (ilst->fn && ilst->id == msg.frame_id) { - msg.renew = false; msg.userdata = ilst->userdata; // pass userdata pointer to the callback - if (ilst->fn(&msg)) return; + res = ilst->fn(&msg); ilst->userdata = msg.userdata; // put it back (may have changed the pointer or set to NULL) + + if (res != TF_NEXT) { + if (res == TF_CLOSE) { + cleanup_id_listener(i, ilst); + } + else if (res == TF_RENEW) { + renew_id_listener(ilst); + } + return; + } } } msg.userdata = NULL; @@ -401,7 +420,14 @@ static void _TF_FN TF_HandleReceivedMessage(void) for (i = 0; i < tf.count_type_lst; i++) { tlst = &tf.type_listeners[i]; if (tlst->fn && tlst->type == msg.type) { - if (tlst->fn(&msg)) return; + res = tlst->fn(&msg); + + if (res != TF_NEXT) { + if (res == TF_CLOSE) { + cleanup_type_listener(i, tlst); + } + return; + } } } @@ -409,7 +435,14 @@ static void _TF_FN TF_HandleReceivedMessage(void) for (i = 0; i < tf.count_generic_lst; i++) { glst = &tf.generic_listeners[i]; if (glst->fn) { - if (glst->fn(&msg)) return; + res = glst->fn(&msg); + + if (res != TF_NEXT) { + if (res == TF_CLOSE) { + cleanup_generic_listener(i, glst); + } + return; + } } } } @@ -671,7 +704,7 @@ static inline size_t _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, } // send without listener -bool _TF_FN TF_Send(TF_MSG *msg) +bool _TF_FN TF_Send(TF_Msg *msg) { return TF_Query(msg, NULL, 0); } @@ -679,7 +712,7 @@ bool _TF_FN TF_Send(TF_MSG *msg) // send without listener and struct bool _TF_FN TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len) { - TF_MSG msg; + TF_Msg msg; TF_ClearMsg(&msg); msg.type = type; msg.data = data; @@ -688,9 +721,9 @@ bool _TF_FN TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len) } // send without listener and struct -bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LISTENER listener, TF_TICKS timeout) +bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout) { - TF_MSG msg; + TF_Msg msg; TF_ClearMsg(&msg); msg.type = type; msg.data = data; @@ -699,7 +732,7 @@ bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LIS } // send with listener -bool _TF_FN TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) +bool _TF_FN TF_Query(TF_Msg *msg, TF_Listener listener, TF_TICKS timeout) { size_t len; len = TF_Compose(tf.sendbuf, @@ -719,13 +752,10 @@ bool _TF_FN TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout) } // Like TF_Send, but with explicit frame ID -bool _TF_FN TF_Respond(TF_MSG *msg) +bool _TF_FN TF_Respond(TF_Msg *msg) { msg->is_response = true; - bool suc = TF_Send(msg); - - if (suc && msg->renew) TF_RenewIdListener(msg->frame_id); - return suc; + return TF_Send(msg); } bool _TF_FN TF_RenewIdListener(TF_ID id) @@ -736,7 +766,7 @@ bool _TF_FN TF_RenewIdListener(TF_ID id) lst = &tf.id_listeners[i]; // test if live & matching if (lst->fn != NULL && lst->id == id) { - lst->timeout = lst->timeout_max; + renew_id_listener(lst); return true; } } diff --git a/TinyFrame.h b/TinyFrame.h index 1ada271..c724a24 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -87,8 +87,15 @@ /** Peer bit enum (used for init) */ typedef enum { TF_SLAVE = 0, - TF_MASTER = 1 -} TF_PEER; + TF_MASTER, +} TF_Peer; + +typedef enum { + TF_NEXT = 0, //!< Not handled, let other listeners handle it + TF_STAY = 1, //!< Handled, stay + TF_RENEW = 2, //!< Handled, stay, renew - useful only with listener timeout + TF_CLOSE = 3, //!< Handled, remove self +} TF_Result; /** Data structure for sending / receiving messages */ typedef struct _TF_MSG_STRUCT_ { @@ -98,13 +105,12 @@ typedef struct _TF_MSG_STRUCT_ { const uint8_t *data; //!< buffer of received data or data to send. NULL = listener timed out, free userdata! TF_LEN len; //!< length of the buffer void *userdata; //!< here's a place for custom data; this data will be stored with the listener - bool renew; //!< Renew the ID listener - if using timeout -} TF_MSG; +} TF_Msg; /** * Clear message struct */ -static inline void TF_ClearMsg(TF_MSG *msg) +static inline void TF_ClearMsg(TF_Msg *msg) { msg->frame_id = 0; msg->is_response = false; @@ -112,7 +118,6 @@ static inline void TF_ClearMsg(TF_MSG *msg) msg->data = NULL; msg->len = 0; msg->userdata = NULL; - msg->renew = false; } /** @@ -122,9 +127,9 @@ static inline void TF_ClearMsg(TF_MSG *msg) * @param type - type field from the message * @param data - byte buffer with the application data * @param len - number of bytes in the buffer - * @return true if the frame was consumed + * @return listener result */ -typedef bool (*TF_LISTENER)(TF_MSG *msg); +typedef TF_Result (*TF_Listener)(TF_Msg *msg); /** * Initialize the TinyFrame engine. @@ -132,7 +137,7 @@ typedef bool (*TF_LISTENER)(TF_MSG *msg); * * @param peer_bit - peer bit to use for self */ -void TF_Init(TF_PEER peer_bit); +void TF_Init(TF_Peer peer_bit); /** * Reset the frame parser state machine. @@ -148,7 +153,7 @@ void TF_ResetParser(void); * @param timeout - timeout in ticks to auto-remove the listener (0 = keep forever) * @return slot index (for removing), or TF_ERROR (-1) */ -bool TF_AddIdListener(TF_MSG *msg, TF_LISTENER cb, TF_TICKS timeout); +bool TF_AddIdListener(TF_Msg *msg, TF_Listener cb, TF_TICKS timeout); /** * Remove a listener by the message ID it's registered for @@ -164,7 +169,7 @@ bool TF_RemoveIdListener(TF_ID frame_id); * @param cb - callback * @return slot index (for removing), or TF_ERROR (-1) */ -bool TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb); +bool TF_AddTypeListener(TF_TYPE frame_type, TF_Listener cb); /** * Remove a listener by type. @@ -179,14 +184,14 @@ bool TF_RemoveTypeListener(TF_TYPE type); * @param cb - callback * @return slot index (for removing), or TF_ERROR (-1) */ -bool TF_AddGenericListener(TF_LISTENER cb); +bool TF_AddGenericListener(TF_Listener cb); /** * Remove a generic listener by function pointer * * @param cb - callback function to remove */ -bool TF_RemoveGenericListener(TF_LISTENER cb); +bool TF_RemoveGenericListener(TF_Listener cb); /** * Send a frame, no listener @@ -194,7 +199,7 @@ bool TF_RemoveGenericListener(TF_LISTENER cb); * @param msg - message struct. ID is stored in the frame_id field * @return success */ -bool TF_Send(TF_MSG *msg); +bool TF_Send(TF_Msg *msg); /** * Like TF_Send, but without the struct @@ -204,7 +209,7 @@ bool TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len); /** * Like TF_Query, but without the struct */ -bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LISTENER listener, TF_TICKS timeout); +bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout); /** * Send a frame, and optionally attach an ID listener. @@ -214,7 +219,7 @@ bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_LISTENER l * @param timeout - listener expiry time in ticks * @return success */ -bool TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout); +bool TF_Query(TF_Msg *msg, TF_Listener listener, TF_TICKS timeout); /** * Send a response to a received message. @@ -222,7 +227,7 @@ bool TF_Query(TF_MSG *msg, TF_LISTENER listener, TF_TICKS timeout); * @param msg - message struct. ID is read from frame_id. set ->renew to reset listener timeout * @return success */ -bool TF_Respond(TF_MSG *msg); +bool TF_Respond(TF_Msg *msg); /** * Renew ID listener timeout diff --git a/demo/demo.c b/demo/demo.c index 503e382..4b234ff 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -2,10 +2,9 @@ // Created by MightyPork on 2017/10/15. // -// http://www.thegeekstuff.com/2011/12/c-socket-programming/?utm_source=feedburner - #include "demo.h" +// those magic defines are needed so we can use clone() #define _GNU_SOURCE #define __USE_GNU #include @@ -20,15 +19,24 @@ volatile int sockfd = -1; volatile bool conn_disband = false; +/** + * Close socket + */ void demo_disconn(void) { conn_disband = true; if (sockfd >= 0) close(sockfd); } +/** + * Demo WriteImpl - send stuff to our peer + * + * @param buff + * @param len + */ void TF_WriteImpl(const uint8_t *buff, size_t len) { - printf("\033[32m--- TX %ld bytes ---\033[0m\n", len); + printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n"); dumpFrame(buff, len); usleep(1000); @@ -39,6 +47,13 @@ void TF_WriteImpl(const uint8_t *buff, size_t len) } } + +/** + * Client bg thread + * + * @param unused + * @return unused + */ static int demo_client(void* unused) { (void)unused; @@ -81,6 +96,12 @@ static int demo_client(void* unused) return 0; } +/** + * Server bg thread + * + * @param unused + * @return unused + */ static int demo_server(void* unused) { (void)unused; @@ -136,20 +157,36 @@ static int demo_server(void* unused) return 0; } -void signal_handler(int sig) +/** + * Trap - clean up + * + * @param sig - signal that caused this + */ +static void signal_handler(int sig) { (void)sig; printf("Shutting down..."); demo_disconn(); - exit(sig); + + exit(sig); // pass the signal through - this is nonstandard behavior but useful for debugging } +/** + * Sleaping Beauty's fave function + */ void demo_sleep(void) { while(1) usleep(10); } -void demo_init(TF_PEER peer) +/** + * Start the background thread + * + * Slave is started first and doesn't normally init transactions - but it could + * + * @param peer what peer we are + */ +void demo_init(TF_Peer peer) { signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); @@ -163,6 +200,9 @@ void demo_init(TF_PEER peer) } printf("Starting %s...\n", peer == TF_MASTER ? "MASTER" : "SLAVE"); + + // CLONE_VM --- share heap + // CLONE_FILES --- share stdout and stderr if (peer == TF_MASTER) { retc = clone(&demo_client, (char *)stack+8192, CLONE_VM|CLONE_FILES, 0); } else { diff --git a/demo/demo.h b/demo/demo.h index d5292f4..4caa068 100644 --- a/demo/demo.h +++ b/demo/demo.h @@ -15,9 +15,9 @@ void demo_sleep(void); /** Init server - DOES NOT init TinyFrame! */ -void demo_init(TF_PEER peer); +void demo_init(TF_Peer peer); -/** Disconnect client from the server - claled by a server-side callback */ +/** Disconnect client from the server - can be called by a server-side callback */ void demo_disconn(void); #endif //TF_DEMO_H diff --git a/demo/hello/master.c b/demo/hello/master.c index 5bffbf6..22e5d58 100644 --- a/demo/hello/master.c +++ b/demo/hello/master.c @@ -5,18 +5,18 @@ #include #include "../demo.h" -bool testIdListener(TF_MSG *msg) +TF_Result testIdListener(TF_Msg *msg) { printf("testIdListener()\n"); dumpFrameInfo(msg); - return true; + return TF_CLOSE; } -bool testGenericListener(TF_MSG *msg) +TF_Result testGenericListener(TF_Msg *msg) { printf("testGenericListener()\n"); dumpFrameInfo(msg); - return true; + return TF_STAY; } int main(void) diff --git a/demo/hello/slave.c b/demo/hello/slave.c index 200b3e2..3493bd1 100644 --- a/demo/hello/slave.c +++ b/demo/hello/slave.c @@ -6,14 +6,14 @@ #include "../demo.h" #include -bool helloListener(TF_MSG *msg) +TF_Result helloListener(TF_Msg *msg) { printf("helloListener()\n"); dumpFrameInfo(msg); - return true; + return TF_STAY; } -bool replyListener(TF_MSG *msg) +TF_Result replyListener(TF_Msg *msg) { printf("replyListener()\n"); dumpFrameInfo(msg); @@ -21,8 +21,14 @@ bool replyListener(TF_MSG *msg) msg->len = (TF_LEN) strlen((const char *) msg->data); TF_Respond(msg); + // unsolicted reply - will not be handled + msg->data = (const uint8_t *) "SPAM"; + msg->len = 5; + TF_Respond(msg); + + // unrelated message TF_SendSimple(77, (const uint8_t *) "NAZDAR", 7); - return true; + return TF_STAY; } int main(void) diff --git a/demo/test/test.c b/demo/test/test.c index dc686cd..90c9371 100644 --- a/demo/test/test.c +++ b/demo/test/test.c @@ -19,22 +19,22 @@ void TF_WriteImpl(const uint8_t *buff, size_t len) } /** An example listener function */ -bool myListener(TF_MSG *msg) +TF_Result myListener(TF_Msg *msg) { dumpFrameInfo(msg); - return true; + return TF_STAY; } -bool testIdListener(TF_MSG *msg) +TF_Result testIdListener(TF_Msg *msg) { printf("OK - ID Listener triggered for msg!\n"); dumpFrameInfo(msg); - return true; + return TF_CLOSE; } void main(void) { - TF_MSG msg; + TF_Msg msg; const char *longstr = "Lorem ipsum dolor sit amet."; // Set up the TinyFrame library diff --git a/demo/utils.c b/demo/utils.c index 3454cbf..2454c2c 100644 --- a/demo/utils.c +++ b/demo/utils.c @@ -21,7 +21,7 @@ void dumpFrame(const uint8_t *buff, size_t len) printf("--- end of frame ---\n\n"); } -void dumpFrameInfo(TF_MSG *msg) +void dumpFrameInfo(TF_Msg *msg) { printf("\033[33mFrame info\n" " type: %02Xh\n" diff --git a/demo/utils.h b/demo/utils.h index 06c4af5..f45a807 100644 --- a/demo/utils.h +++ b/demo/utils.h @@ -8,8 +8,19 @@ #include #include "../TinyFrame.h" +/** pointer to unsigned char */ typedef unsigned char* pu8; + +/** + * Dump a binary frame as hex, dec and ASCII + */ void dumpFrame(const uint8_t *buff, size_t len); -void dumpFrameInfo(TF_MSG *msg); + +/** + * Dump message metadata (not the content) + * + * @param msg + */ +void dumpFrameInfo(TF_Msg *msg); #endif //TF_UTILS_H From 95a7c89b9823de8054279e7f60ea7ab4f01c94f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 16 Oct 2017 00:46:30 +0200 Subject: [PATCH 11/11] improved api and updated readme --- README.md | 91 +++++++++++++-------------------------------- TinyFrame.c | 3 +- TinyFrame.h | 2 +- demo/hello/master.c | 2 +- demo/hello/slave.c | 2 +- 5 files changed, 30 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 0cea476..a483312 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,14 @@ UDP packets. If you find a good use for it, please let me know so I can add it h Frames can be protected by a checksum (~XOR, CRC16 or CRC32) and contain a unique ID field which can be used for chaining related messages. The highest bit -of the generated IDs is different for each peer to avoid collisions. +of the generated IDs is different in each peer to avoid collisions. Peers are functionally equivalent and can send messages to each other -(the names "master" and "slave" are used only for convenience). +(the names "master" and "slave" are used only for convenience and have special meaning +in the demos). The library lets you register listeners (callback functions) to wait for (1) any frame, (2) -a particular frame Type, or (3) a specific message ID. This lets you easily implement asynchronous -communication. +a particular frame Type, or (3) a specific message ID. This high-level API lets you +easily implement various async communication patterns. ## Frame structure @@ -50,24 +51,20 @@ DATA_CKSUM .. checksum, implemented as XOR of all preceding bytes in the message - Both peers must include the library with the same parameters (configured at the top of the header file) - Start by calling `TF_Init()` with `TF_MASTER` or `TF_SLAVE` as the argument - Implement `TF_WriteImpl()` - declared at the bottom of the header file as `extern`. - This function is used by `TF_Send()` to write bytes to your UART (or other physical layer). + This function is used by `TF_Send()` and others to write bytes to your UART (or other physical layer). Presently, always a full frame is sent to this function. -- If you wish to use `TF_PARSER_TIMEOUT_TICKS`, periodically call `TF_Tick()`. The period - determines the length of 1 tick. This is used to time-out the parser in case it gets stuck - in a bad state (such as receiving a partial frame). +- If you wish to use timeouts, periodically call `TF_Tick()`. The calling period determines + the length of 1 tick. This is used to time-out the parser in case it gets stuck + in a bad state (such as receiving a partial frame) and can also time-out ID listeners. - Bind Type or Generic listeners using `TF_AddTypeListener()` or `TF_AddGenericListener()`. -- Send a message using `TF_Send()` or the other Send functions. - If you provide a listener callback (function pointer) to the function, - the listener will be added as an ID listener and wait for a response. +- Send a message using `TF_Send()`, `TF_Query()`, `TF_SendSimple()`, `TF_QuerySimple()`. + Query functions take a listener callback (function pointer)that will be added as + an ID listener and wait for a response. - To reply to a message (when your listener gets called), use `TF_Respond()` - with the same frame_id as in the received message. -- Remove the ID listener using `TF_RemoveIdListener()` when it's no longer - needed. (Same for other listener types.) The slot count is limited. -- If the listener function returns `false`, some other listener will get - a chance to handle it + with the msg boject you received, replacing the `data` pointer (and `len`) with response. - Manually reset the parser using `TF_ResetParser()` -### The concept of listeners +### Message listeners Listeners are callback functions that are called by TinyFrame when a message which they can handle is received. @@ -78,52 +75,14 @@ There are 3 listener types: - Type listeners - Generic listeners -They handle the message in this order, and if they decide not to handle it, they can return `false` -and let it be handled by some other listener, or discarded. - -### Implementing "synchronous query" - -Sometimes it's necessary to send a message and wait for a response to arrive. - -One (not too pretty) way to do this is using a global variable - pseudocode: - -```c -#define MSG_PING 42 - -static volatile bool got_response = false; - -/** ID listener */ -static bool onResponse(TF_ID frame_id, TF_TYPE type, const uint8_t *data, TF_LEN len) -{ - // ... Do something ... - // (eg. copy data to a global variable) - - got_response = true; - return true; -} - -bool syncQuery(void) -{ - TF_ID id; - // Send our request, and bind an ID listener - got_response = false; - TF_Send0(MSG_PING, onResponse, &id); // Send0 sends zero bytes of data, just TYPE - - // the ID is now in `id` so we can remove the listener after a timeout - - // Wait for the response - bool suc = true; - while (!got_response) { - //delay() - if (/*timeout*/) { - TF_RemoveIdListener(id); // free the listener slot - return false; - } - } - - // ... Do something with the received data? ... - // (can be passed from the listener using a global variable) - - return true; -} -``` +Listeners return an enum constant based on what should be done next - remove the listener, +keep it, renew it's timeout, or let some other listener handle the message. + +### Examples + +You'll find various examples in the `demo/` folder. Each example has it's own Makefile, +read it to see what options are available. + +The demos are written for Linux, using sockets and `clone()` for background processing. +They try to simulate real TinyFrame behavior in an embedded system with asynchronous +Rx and Tx. If you can't run the demos, the source files are still good as examples. diff --git a/TinyFrame.c b/TinyFrame.c index dac526b..2a54faf 100644 --- a/TinyFrame.c +++ b/TinyFrame.c @@ -721,13 +721,14 @@ bool _TF_FN TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len) } // send without listener and struct -bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout) +bool _TF_FN TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout, void *userdata) { TF_Msg msg; TF_ClearMsg(&msg); msg.type = type; msg.data = data; msg.len = len; + msg.userdata = userdata; return TF_Query(&msg, listener, timeout); } diff --git a/TinyFrame.h b/TinyFrame.h index c724a24..0ba0c77 100644 --- a/TinyFrame.h +++ b/TinyFrame.h @@ -209,7 +209,7 @@ bool TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len); /** * Like TF_Query, but without the struct */ -bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout); +bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout, void *userdata); /** * Send a frame, and optionally attach an ID listener. diff --git a/demo/hello/master.c b/demo/hello/master.c index 22e5d58..04066a7 100644 --- a/demo/hello/master.c +++ b/demo/hello/master.c @@ -29,7 +29,7 @@ int main(void) TF_SendSimple(1, (pu8)"Ahoj", 5); TF_SendSimple(1, (pu8)"Hello", 6); - TF_QuerySimple(2, (pu8)"Query!", 6, testIdListener, 0); + TF_QuerySimple(2, (pu8)"Query!", 6, testIdListener, 0, NULL); demo_sleep(); } diff --git a/demo/hello/slave.c b/demo/hello/slave.c index 3493bd1..714f455 100644 --- a/demo/hello/slave.c +++ b/demo/hello/slave.c @@ -21,7 +21,7 @@ TF_Result replyListener(TF_Msg *msg) msg->len = (TF_LEN) strlen((const char *) msg->data); TF_Respond(msg); - // unsolicted reply - will not be handled + // unsolicited reply - will not be handled by the ID listener, which is already gone msg->data = (const uint8_t *) "SPAM"; msg->len = 5; TF_Respond(msg);