|  |  | @ -1,6 +1,7 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | //---------------------------------------------------------------------------
 |  |  |  | //---------------------------------------------------------------------------
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #include "TinyFrame.h" |  |  |  | #include "TinyFrame.h" | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <string.h> |  |  |  | #include <string.h> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //#include "demo/utils.h"
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //---------------------------------------------------------------------------
 |  |  |  | //---------------------------------------------------------------------------
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Compatibility with ESP8266 SDK
 |  |  |  | // Compatibility with ESP8266 SDK
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -20,18 +21,21 @@ enum TFState { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TFState_DATA_CKSUM    //!< Wait for Checksum
 |  |  |  | 	TFState_DATA_CKSUM    //!< Wait for Checksum
 | 
			
		
	
		
		
			
				
					
					|  |  |  | }; |  |  |  | }; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | typedef struct _IdListener_struct { |  |  |  | typedef struct _IdListener_struct_ { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	TF_ID id; |  |  |  | 	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; | 
			
		
	
		
		
			
				
					
					|  |  |  | } IdListener; |  |  |  | } IdListener; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | typedef struct _TypeListener_struct_ { |  |  |  | typedef struct _TypeListener_struct_ { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_TYPE type; |  |  |  | 	TF_TYPE type; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_LISTENER fn; |  |  |  | 	TF_Listener fn; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } TypeListener; |  |  |  | } TypeListener; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | typedef struct _GenericListener_struct_ { |  |  |  | typedef struct _GenericListener_struct_ { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_LISTENER fn; |  |  |  | 	TF_Listener fn; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } GenericListener; |  |  |  | } GenericListener; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /**
 |  |  |  | /**
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -39,16 +43,16 @@ typedef struct _GenericListener_struct_ { | 
			
		
	
		
		
			
				
					
					|  |  |  |  */ |  |  |  |  */ | 
			
		
	
		
		
			
				
					
					|  |  |  | static struct TinyFrameStruct { |  |  |  | static struct TinyFrameStruct { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/* Own state */ |  |  |  | 	/* 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
 |  |  |  | 	TF_ID next_id;          //!< Next frame / frame chain ID
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/* Parser state */ |  |  |  | 	/* Parser state */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	enum TFState state; |  |  |  | 	enum TFState state; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int parser_timeout_ticks; |  |  |  | 	TF_TICKS parser_timeout_ticks; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	TF_ID id;               //!< Incoming packet ID
 |  |  |  | 	TF_ID id;               //!< Incoming packet ID
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_LEN len;             //!< Payload length
 |  |  |  | 	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_LEN rxi;             //!< Field size byte counter
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	TF_CKSUM cksum;         //!< Checksum calculated of the data stream
 |  |  |  | 	TF_CKSUM cksum;         //!< Checksum calculated of the data stream
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_CKSUM ref_cksum;     //!< Reference checksum read from the message
 |  |  |  | 	TF_CKSUM ref_cksum;     //!< Reference checksum read from the message
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_TYPE type;           //!< Collected message type number
 |  |  |  | 	TF_TYPE type;           //!< Collected message type number
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -61,31 +65,34 @@ static struct TinyFrameStruct { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TypeListener type_listeners[TF_MAX_TYPE_LST]; |  |  |  | 	TypeListener type_listeners[TF_MAX_TYPE_LST]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	GenericListener generic_listeners[TF_MAX_GEN_LST]; |  |  |  | 	GenericListener generic_listeners[TF_MAX_GEN_LST]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	size_t count_id_lst; |  |  |  | 	// Those counters are used to optimize look-up times.
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	size_t count_type_lst; |  |  |  | 	// They point to the highest used slot number,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	size_t count_generic_lst; |  |  |  | 	// or close to it, depending on the removal order.
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_COUNT count_id_lst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_COUNT count_type_lst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_COUNT count_generic_lst; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Buffer for building frames
 |  |  |  | 	// 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; |  |  |  | } tf; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //region Checksums
 |  |  |  | //region Checksums
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #if TF_CKSUM_TYPE == 0 |  |  |  | #if TF_CKSUM_TYPE == TF_CKSUM_NONE | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// NONE
 |  |  |  | 	// NONE
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	#define CKSUM_RESET(cksum) |  |  |  | 	#define CKSUM_RESET(cksum) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	#define CKSUM_ADD(cksum, byte) |  |  |  | 	#define CKSUM_ADD(cksum, byte) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	#define CKSUM_FINALIZE(cksum) |  |  |  | 	#define CKSUM_FINALIZE(cksum) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #elif TF_CKSUM_TYPE == 8 |  |  |  | #elif TF_CKSUM_TYPE == TF_CKSUM_XOR | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// ~XOR
 |  |  |  | 	// ~XOR
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #define CKSUM_RESET(cksum) do { cksum = 0; } while (0) |  |  |  | 	#define CKSUM_RESET(cksum) do { (cksum) = 0; } while (0) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | #define CKSUM_ADD(cksum, byte) do { cksum ^= byte; } 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_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) */ |  |  |  | 	/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	static const uint16_t crc16_table[256] = { |  |  |  | 	static const uint16_t crc16_table[256] = { | 
			
		
	
	
		
		
			
				
					|  |  | @ -128,11 +135,11 @@ static inline uint16_t crc16_byte(uint16_t cksum, const uint8_t byte) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return (cksum >> 8) ^ crc16_table[(cksum ^ byte) & 0xff]; |  |  |  | 		return (cksum >> 8) ^ crc16_table[(cksum ^ byte) & 0xff]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #define CKSUM_RESET(cksum) do { cksum = 0; } 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_ADD(cksum, byte) do { (cksum) = crc16_byte((cksum), (byte)); } while(0) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	#define CKSUM_FINALIZE(cksum) |  |  |  | 	#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 */ |  |  |  | 	static const uint32_t crc32_table[] = { /* CRC polynomial 0xedb88320 */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, |  |  |  | 		0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | 
			
		
	
	
		
		
			
				
					|  |  | @ -185,16 +192,16 @@ static inline uint32_t crc32_byte(uint32_t cksum, const uint8_t byte) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return (crc32_table[((cksum) ^ ((uint8_t)byte)) & 0xff] ^ ((cksum) >> 8)); |  |  |  | 		return (crc32_table[((cksum) ^ ((uint8_t)byte)) & 0xff] ^ ((cksum) >> 8)); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #define CKSUM_RESET(cksum) do { cksum = (TF_CKSUM)0xFFFFFFFF; } 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_ADD(cksum, byte) do { (cksum) = crc32_byte(cksum, byte); } while(0) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | #define CKSUM_FINALIZE(cksum)  do { cksum = (TF_CKSUM)~cksum; } while(0) |  |  |  | 	#define CKSUM_FINALIZE(cksum)  do { (cksum) = (TF_CKSUM)~(cksum); } while(0) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #endif |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //endregion
 |  |  |  | //endregion
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void _TF_FN TF_Init(TF_PEER peer_bit) |  |  |  | void _TF_FN TF_Init(TF_Peer peer_bit) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Zero it out
 |  |  |  | 	// Zero it out
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	memset(&tf, 0, sizeof(struct TinyFrameStruct)); |  |  |  | 	memset(&tf, 0, sizeof(struct TinyFrameStruct)); | 
			
		
	
	
		
		
			
				
					|  |  | @ -204,15 +211,75 @@ void _TF_FN TF_Init(TF_PEER peer_bit) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //region Listeners
 |  |  |  | //region Listeners
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb) |  |  |  | static void _TF_FN renew_id_listener(IdListener *lst) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	size_t i; |  |  |  | 	lst->timeout = lst->timeout_max; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | /**
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  * 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; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	// 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) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		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) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_COUNT i; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	IdListener *lst; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = 0; i < TF_MAX_ID_LST; i++) { |  |  |  | 	for (i = 0; i < TF_MAX_ID_LST; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.id_listeners[i].fn == NULL) { |  |  |  | 		lst = &tf.id_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.id_listeners[i].fn = cb; |  |  |  | 		// test for empty slot
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.id_listeners[i].id = frame_id; |  |  |  | 		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) { |  |  |  | 			if (i >= tf.count_id_lst) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_id_lst = i + 1; |  |  |  | 				tf.count_id_lst = (TF_COUNT) (i + 1); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -220,15 +287,18 @@ bool _TF_FN TF_AddIdListener(TF_ID frame_id, TF_LISTENER cb) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return false; |  |  |  | 	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) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	size_t i; |  |  |  | 	TF_COUNT i; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TypeListener *lst; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = 0; i < TF_MAX_TYPE_LST; i++) { |  |  |  | 	for (i = 0; i < TF_MAX_TYPE_LST; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.type_listeners[i].fn == NULL) { |  |  |  | 		lst = &tf.type_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.type_listeners[i].fn = cb; |  |  |  | 		// test for empty slot
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.type_listeners[i].type = frame_type; |  |  |  | 		if (lst->fn == NULL) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			lst->fn = cb; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			lst->type = frame_type; | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (i >= tf.count_type_lst) { |  |  |  | 			if (i >= tf.count_type_lst) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_type_lst = i + 1; |  |  |  | 				tf.count_type_lst = (TF_COUNT) (i + 1); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -236,14 +306,17 @@ bool _TF_FN TF_AddTypeListener(TF_TYPE frame_type, TF_LISTENER cb) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return false; |  |  |  | 	return false; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_AddGenericListener(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++) { |  |  |  | 	for (i = 0; i < TF_MAX_GEN_LST; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.generic_listeners[i].fn == NULL) { |  |  |  | 		lst = &tf.generic_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.generic_listeners[i].fn = cb; |  |  |  | 		// test for empty slot
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (lst->fn == NULL) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			lst->fn = cb; | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (i >= tf.count_generic_lst) { |  |  |  | 			if (i >= tf.count_generic_lst) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_generic_lst = i + 1; |  |  |  | 				tf.count_generic_lst = (TF_COUNT) (i + 1); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -253,14 +326,13 @@ bool _TF_FN TF_AddGenericListener(TF_LISTENER cb) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) |  |  |  | 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++) { |  |  |  | 	for (i = 0; i < tf.count_id_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.id_listeners[i].fn != NULL |  |  |  | 		lst = &tf.id_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			&& tf.id_listeners[i].id == frame_id) { |  |  |  | 		// test if live & matching
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.id_listeners[i].fn = NULL; |  |  |  | 		if (lst->fn != NULL && lst->id == frame_id) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (i == tf.count_id_lst - 1) { |  |  |  | 			cleanup_id_listener(i, lst); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_id_lst--; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | @ -269,29 +341,28 @@ bool _TF_FN TF_RemoveIdListener(TF_ID frame_id) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_RemoveTypeListener(TF_TYPE type) |  |  |  | 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++) { |  |  |  | 	for (i = 0; i < tf.count_type_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.type_listeners[i].fn != NULL |  |  |  | 		lst = &tf.type_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			&& tf.type_listeners[i].type == type) { |  |  |  | 		// test if live & matching
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.type_listeners[i].fn = NULL; |  |  |  | 		if (lst->fn != NULL	&& lst->type == type) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (i == tf.count_type_lst - 1) { |  |  |  | 			cleanup_type_listener(i, lst); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_type_lst--; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return false; |  |  |  | 	return false; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) |  |  |  | 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++) { |  |  |  | 	for (i = 0; i < tf.count_generic_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.generic_listeners[i].fn == cb) { |  |  |  | 		lst = &tf.generic_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			tf.generic_listeners[i].fn = NULL; |  |  |  | 		// test if live & matching
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (i == tf.count_generic_lst - 1) { |  |  |  | 		if (lst->fn == cb) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				tf.count_generic_lst--; |  |  |  | 			cleanup_generic_listener(i, lst); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			return true; |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | @ -299,9 +370,23 @@ bool _TF_FN TF_RemoveGenericListener(TF_LISTENER cb) | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /** Handle a message that was just collected & verified by the parser */ |  |  |  | /** 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; |  |  |  | 	TF_COUNT i; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	IdListener *ilst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TypeListener *tlst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	GenericListener *glst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_Result res; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	// 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; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	//dumpFrameInfo(&msg);
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Any listener can consume the message (return true),
 |  |  |  | 	// Any listener can consume the message (return true),
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// or let someone else handle it.
 |  |  |  | 	// or let someone else handle it.
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -311,17 +396,36 @@ static void _TF_FN TF_HandleReceivedMessage(TF_ID frame_id, TF_TYPE type, uint8_ | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// ID listeners first
 |  |  |  | 	// ID listeners first
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = 0; i < tf.count_id_lst; i++) { |  |  |  | 	for (i = 0; i < tf.count_id_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.id_listeners[i].fn && (tf.id_listeners[i].id == frame_id)) { |  |  |  | 		ilst = &tf.id_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (tf.id_listeners[i].fn(frame_id, type, data, data_len)) { |  |  |  | 		if (ilst->fn && ilst->id == msg.frame_id) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			msg.userdata = ilst->userdata; // pass userdata pointer to the callback
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			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; |  |  |  | 				return; | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	msg.userdata = NULL; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	// clean up for the following listeners that don't use userdata
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Type listeners
 |  |  |  | 	// Type listeners
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = 0; i < tf.count_type_lst; i++) { |  |  |  | 	for (i = 0; i < tf.count_type_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.type_listeners[i].fn && (tf.type_listeners[i].type == type)) { |  |  |  | 		tlst = &tf.type_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (tf.type_listeners[i].fn(frame_id, type, data, data_len)) { |  |  |  | 		if (tlst->fn && tlst->type == msg.type) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			res = tlst->fn(&msg); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			if (res != TF_NEXT) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				if (res == TF_CLOSE) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					cleanup_type_listener(i, tlst); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				return; |  |  |  | 				return; | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -329,8 +433,14 @@ static void _TF_FN TF_HandleReceivedMessage(TF_ID frame_id, TF_TYPE type, uint8_ | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Generic listeners
 |  |  |  | 	// Generic listeners
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = 0; i < tf.count_generic_lst; i++) { |  |  |  | 	for (i = 0; i < tf.count_generic_lst; i++) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (tf.generic_listeners[i].fn) { |  |  |  | 		glst = &tf.generic_listeners[i]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			if (tf.generic_listeners[i].fn(frame_id, type, data, data_len)) { |  |  |  | 		if (glst->fn) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			res = glst->fn(&msg); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			if (res != TF_NEXT) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				if (res == TF_CLOSE) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					cleanup_generic_listener(i, glst); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				return; |  |  |  | 				return; | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -369,7 +479,7 @@ static void _TF_FN TF_ParsBeginFrame(void) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void _TF_FN TF_AcceptChar(unsigned char c) |  |  |  | void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Timeout - clear
 |  |  |  | 	// Parser timeout - clear
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if (tf.parser_timeout_ticks >= TF_PARSER_TIMEOUT_TICKS) { |  |  |  | 	if (tf.parser_timeout_ticks >= TF_PARSER_TIMEOUT_TICKS) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		TF_ResetParser(); |  |  |  | 		TF_ResetParser(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | @ -413,7 +523,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		case TFState_TYPE: |  |  |  | 		case TFState_TYPE: | 
			
		
	
		
		
			
				
					
					|  |  |  | 			CKSUM_ADD(tf.cksum, c); |  |  |  | 			CKSUM_ADD(tf.cksum, c); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			COLLECT_NUMBER(tf.type, TF_TYPE) { |  |  |  | 			COLLECT_NUMBER(tf.type, TF_TYPE) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				#if TF_CKSUM_TYPE == 0 |  |  |  | 				#if TF_CKSUM_TYPE == TF_CKSUM_NONE | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					tf.state = TFState_DATA; |  |  |  | 					tf.state = TFState_DATA; | 
			
		
	
		
		
			
				
					
					|  |  |  | 					tf.rxi = 0; |  |  |  | 					tf.rxi = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  | 				#else |  |  |  | 				#else | 
			
		
	
	
		
		
			
				
					|  |  | @ -436,7 +546,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if (tf.len == 0) { |  |  |  | 				if (tf.len == 0) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					TF_HandleReceivedMessage(tf.id, tf.type, NULL, 0); |  |  |  | 					TF_HandleReceivedMessage(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					TF_ResetParser(); |  |  |  | 					TF_ResetParser(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 					break; |  |  |  | 					break; | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
	
		
		
			
				
					|  |  | @ -447,7 +557,7 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 				CKSUM_RESET(tf.cksum); // Start collecting the payload
 |  |  |  | 				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.
 |  |  |  | 					// ERROR - frame too long. Consume, but do not store.
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 					tf.discard_data = true; |  |  |  | 					tf.discard_data = true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
	
		
		
			
				
					|  |  | @ -463,9 +573,9 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (tf.rxi == tf.len) { |  |  |  | 			if (tf.rxi == tf.len) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				#if TF_CKSUM_TYPE == 0 |  |  |  | 				#if TF_CKSUM_TYPE == TF_CKSUM_NONE | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					// All done
 |  |  |  | 					// All done
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 					TF_HandleReceivedMessage(tf.id, tf.type, tf.data, tf.len); |  |  |  | 					TF_HandleReceivedMessage(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					TF_ResetParser(); |  |  |  | 					TF_ResetParser(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 				#else |  |  |  | 				#else | 
			
		
	
		
		
			
				
					
					|  |  |  | 					// Enter DATA_CKSUM state
 |  |  |  | 					// Enter DATA_CKSUM state
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -481,13 +591,19 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				// Check the header checksum against the computed value
 |  |  |  | 				// Check the header checksum against the computed value
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 				CKSUM_FINALIZE(tf.cksum); |  |  |  | 				CKSUM_FINALIZE(tf.cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if (!tf.discard_data && tf.cksum == tf.ref_cksum) { |  |  |  | 				if (!tf.discard_data && tf.cksum == tf.ref_cksum) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					TF_HandleReceivedMessage(tf.id, tf.type, tf.data, tf.len); |  |  |  | 					TF_HandleReceivedMessage(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 				TF_ResetParser(); |  |  |  | 				TF_ResetParser(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			break; |  |  |  | 			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(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /**
 |  |  |  | /**
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -501,24 +617,27 @@ void _TF_FN TF_AcceptChar(unsigned char c) | 
			
		
	
		
		
			
				
					
					|  |  |  |  * @param len - payload size in bytes |  |  |  |  * @param len - payload size in bytes | 
			
		
	
		
		
			
				
					
					|  |  |  |  * @param explicit_id - ID to use in the frame (8-bit) |  |  |  |  * @param explicit_id - ID to use in the frame (8-bit) | 
			
		
	
		
		
			
				
					
					|  |  |  |  * @param use_expl_id - whether to use the previous param |  |  |  |  * @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 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, |  |  |  | 			      TF_TYPE type, | 
			
		
	
		
		
			
				
					
					|  |  |  | 				  const uint8_t *data, TF_LEN data_len, |  |  |  | 				  const uint8_t *data, TF_LEN data_len, | 
			
		
	
		
		
			
				
					
					|  |  |  | 				  TF_ID explicit_id, bool use_expl_id) |  |  |  | 				  TF_ID explicit_id, bool use_expl_id) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int i; |  |  |  | 	char si = 0; // signed small int
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	uint8_t b; |  |  |  | 	TF_LEN i = 0; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_ID id; |  |  |  | 	uint8_t b = 0; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_CKSUM cksum; |  |  |  | 	TF_ID id = 0; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	int pos = 0; |  |  |  | 	TF_CKSUM cksum = 0; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	size_t pos = 0; // can be needed to grow larger than TF_LEN
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	(void)cksum; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	CKSUM_RESET(cksum); |  |  |  | 	CKSUM_RESET(cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// sanitize len
 |  |  |  | 	// sanitize len
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if (data_len > TF_MAX_PAYLOAD) { |  |  |  | 	if (data_len > TF_MAX_PAYLOAD_TX) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		return TF_ERROR; |  |  |  | 		return 0; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Gen ID
 |  |  |  | 	// Gen ID
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -537,8 +656,8 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// DRY helper for writing a multi-byte variable to the buffer
 |  |  |  | 	// DRY helper for writing a multi-byte variable to the buffer
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #define WRITENUM_BASE(type, num, xtra) \ |  |  |  | #define WRITENUM_BASE(type, num, xtra) \ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for (i = sizeof(type)-1; i>=0; i--) { \
 |  |  |  | 	for (si = sizeof(type)-1; si>=0; si--) { \
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		b = (uint8_t)(num >> (i*8) & 0xFF); \
 |  |  |  | 		b = (uint8_t)(num >> (si*8) & 0xFF); \
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		outbuff[pos++] = b; \
 |  |  |  | 		outbuff[pos++] = b; \
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		xtra; \
 |  |  |  | 		xtra; \
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | @ -559,7 +678,7 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, | 
			
		
	
		
		
			
				
					
					|  |  |  | 	WRITENUM_CKSUM(TF_LEN, data_len); |  |  |  | 	WRITENUM_CKSUM(TF_LEN, data_len); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	WRITENUM_CKSUM(TF_TYPE, type); |  |  |  | 	WRITENUM_CKSUM(TF_TYPE, type); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	#if TF_CKSUM_TYPE != 0 |  |  |  | 	#if TF_CKSUM_TYPE != TF_CKSUM_NONE | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		CKSUM_FINALIZE(cksum); |  |  |  | 		CKSUM_FINALIZE(cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		WRITENUM(TF_CKSUM, cksum); |  |  |  | 		WRITENUM(TF_CKSUM, cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	#endif |  |  |  | 	#endif | 
			
		
	
	
		
		
			
				
					|  |  | @ -575,7 +694,7 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			CKSUM_ADD(cksum, b); |  |  |  | 			CKSUM_ADD(cksum, b); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		#if TF_CKSUM_TYPE != 0 |  |  |  | 		#if TF_CKSUM_TYPE != TF_CKSUM_NONE | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			CKSUM_FINALIZE(cksum); |  |  |  | 			CKSUM_FINALIZE(cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			WRITENUM(TF_CKSUM, cksum); |  |  |  | 			WRITENUM(TF_CKSUM, cksum); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		#endif |  |  |  | 		#endif | 
			
		
	
	
		
		
			
				
					|  |  | @ -584,73 +703,97 @@ static int _TF_FN TF_Compose(uint8_t *outbuff, TF_ID *id_ptr, | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return pos; |  |  |  | 	return pos; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_Send(TF_TYPE type, |  |  |  | // send without listener
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			 const uint8_t *payload, TF_LEN payload_len, |  |  |  | bool _TF_FN TF_Send(TF_Msg *msg) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 			 TF_LISTENER listener, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			 TF_ID *id_ptr) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_ID msgid = 0; |  |  |  | 	return TF_Query(msg, NULL, 0); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	int len; |  |  |  | } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	len = TF_Compose(tf.sendbuf, &msgid, type, payload, payload_len, 0, false); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if (len == TF_ERROR) return false; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if (listener) TF_AddIdListener(msgid, listener); |  |  |  | // send without listener and struct
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	if (id_ptr) *id_ptr = msgid; |  |  |  | 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); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_WriteImpl((const uint8_t *) tf.sendbuf, (TF_LEN)len); |  |  |  | // send without listener and struct
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	return true; |  |  |  | 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); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Like TF_Send, but with explicit frame ID
 |  |  |  | // send with listener
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_Respond(TF_TYPE type, |  |  |  | bool _TF_FN TF_Query(TF_Msg *msg, TF_Listener listener, TF_TICKS timeout) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				const uint8_t *data, TF_LEN data_len, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				TF_ID frame_id) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int len; |  |  |  | 	size_t len; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	len = TF_Compose(tf.sendbuf, NULL, type, data, data_len, frame_id, true); |  |  |  | 	len = TF_Compose(tf.sendbuf, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	if (len == TF_ERROR) return false; |  |  |  | 		             &msg->frame_id, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		             msg->type, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		             msg->data, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		             msg->len, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		             msg->frame_id, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		             msg->is_response); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	if (len == 0) return false; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	TF_WriteImpl(tf.sendbuf, (TF_LEN)len); |  |  |  | 	if (listener) TF_AddIdListener(msg, listener, timeout); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_WriteImpl((const uint8_t *) tf.sendbuf, len); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return true; |  |  |  | 	return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /**
 |  |  |  | // Like TF_Send, but with explicit frame ID
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |  * Like TF_Send(), but with no data |  |  |  | bool _TF_FN TF_Respond(TF_Msg *msg) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |  */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | bool _TF_FN TF_Send0(TF_TYPE type, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			  TF_LISTENER listener, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 			  TF_ID *id_ptr) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return TF_Send(type, NULL, 0, listener, id_ptr); |  |  |  | 	msg->is_response = true; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	return TF_Send(msg); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /**
 |  |  |  | bool _TF_FN TF_RenewIdListener(TF_ID id) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |  * 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}; |  |  |  | 	TF_COUNT i; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	return TF_Send(type, b, 1, listener, id_ptr); |  |  |  | 	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 == id) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			renew_id_listener(lst); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 	} | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | /**
 |  |  |  | 	return false; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |  * 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) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	unsigned char b[] = {b1, b2}; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return TF_Send(type, b, 2, listener, id_ptr); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /** Timebase hook - for timeouts */ |  |  |  | /** Timebase hook - for timeouts */ | 
			
		
	
		
		
			
				
					
					|  |  |  | void _TF_FN TF_Tick(void) |  |  |  | void _TF_FN TF_Tick(void) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	TF_COUNT i = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	IdListener *lst; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	// increment parser timeout (timeout is handled when receiving next byte)
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if (tf.parser_timeout_ticks < TF_PARSER_TIMEOUT_TICKS) { |  |  |  | 	if (tf.parser_timeout_ticks < 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) continue; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		// count down...
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (--lst->timeout == 0) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			// Listener has expired
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			cleanup_id_listener(i, lst); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | 
 |