@ -1,6 +1,6 @@
//---------------------------------------------------------------------------
# include "TinyFrame.h"
# include <malloc.h>
# include <stdlib.h> // - for malloc() if dynamic constructor is used
//---------------------------------------------------------------------------
// Compatibility with ESP8266 SDK
@ -10,144 +10,213 @@
# define _TF_FN
# endif
// Helper macros
# define TF_MAX(a, b) ((a)>(b)?(a):(b))
# define TF_MIN(a, b) ((a)<(b)?(a):(b))
# define TF_TRY(func) do { if(!(func)) return false; } while (0)
// 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))
# if !TF_USE_MUTEX
// Not thread safe lock implementation, used if user did not provide a better one.
// This is less reliable than a real mutex, but will catch most bugs caused by
// inappropriate use fo the API.
/** Claim the TX interface before composing and sending a frame */
static bool TF_ClaimTx ( TinyFrame * tf ) {
if ( tf - > soft_lock ) {
TF_Error ( " TF already locked for tx! " ) ;
return false ;
}
tf - > soft_lock = true ;
return true ;
}
// TODO It would be nice to have per-instance configurable checksum types, but that would
// mandate configurable field sizes unless we use u32 everywhere (and possibly shorten
// it when encoding to the buffer). I don't really like this idea so much. -MP
/** Free the TX interface after composing and sending a frame */
static void TF_ReleaseTx ( TinyFrame * tf )
{
tf - > soft_lock = false ;
}
# endif
//region Checksums
# if TF_CKSUM_TYPE == TF_CKSUM_NONE
// NONE
# define CKSUM_RESET(cksum)
# define CKSUM_ADD(cksum, byte)
# define CKSUM_FINALIZE(cksum)
static TF_CKSUM TF_CksumStart ( void )
{ return 0 ; }
static TF_CKSUM TF_CksumAdd ( TF_CKSUM cksum , uint8_t byte )
{ return cksum ; }
static TF_CKSUM TF_CksumEnd ( TF_CKSUM cksum )
{ return cksum ; }
# 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)
static TF_CKSUM TF_CksumStart ( void )
{ return 0 ; }
static TF_CKSUM TF_CksumAdd ( TF_CKSUM cksum , uint8_t byte )
{ return cksum ^ byte ; }
static TF_CKSUM TF_CksumEnd ( TF_CKSUM cksum )
{ return ( TF_CKSUM ) ~ cksum ; }
# elif TF_CKSUM_TYPE == TF_CKSUM_CRC8
static inline uint8_t crc8_bits ( uint8_t data )
{
uint8_t crc = 0 ;
if ( data & 1 ) crc ^ = 0x5e ;
if ( data & 2 ) crc ^ = 0xbc ;
if ( data & 4 ) crc ^ = 0x61 ;
if ( data & 8 ) crc ^ = 0xc2 ;
if ( data & 0x10 ) crc ^ = 0x9d ;
if ( data & 0x20 ) crc ^ = 0x23 ;
if ( data & 0x40 ) crc ^ = 0x46 ;
if ( data & 0x80 ) crc ^ = 0x8c ;
return crc ;
}
static TF_CKSUM TF_CksumStart ( void )
{ return 0 ; }
static TF_CKSUM TF_CksumAdd ( TF_CKSUM cksum , uint8_t byte )
{ return crc8_bits ( byte ^ cksum ) ; }
static TF_CKSUM TF_CksumEnd ( TF_CKSUM cksum )
{ return cksum ; }
# elif TF_CKSUM_TYPE == TF_CKSUM_CRC16
// TODO try to replace with an algorithm
/** 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)
// TODO try to replace with an algorithm
/** 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 TF_CKSUM TF_CksumStart ( void )
{ return 0 ; }
static TF_CKSUM TF_CksumAdd ( TF_CKSUM cksum , uint8_t byte )
{ return ( cksum > > 8 ) ^ crc16_table [ ( cksum ^ byte ) & 0xff ] ; }
static TF_CKSUM TF_CksumEnd ( TF_CKSUM cksum )
{ return cksum ; }
# elif TF_CKSUM_TYPE == TF_CKSUM_CRC32
// TODO try to replace with an algorithm
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)
// TODO try to replace with an algorithm
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 TF_CKSUM TF_CksumStart ( void )
{ return ( TF_CKSUM ) 0xFFFFFFFF ; }
static TF_CKSUM TF_CksumAdd ( TF_CKSUM cksum , uint8_t byte )
{ return crc32_table [ ( ( cksum ) ^ ( ( uint8_t ) byte ) ) & 0xff ] ^ ( ( cksum ) > > 8 ) ; }
static TF_CKSUM TF_CksumEnd ( TF_CKSUM cksum )
{ return ( TF_CKSUM ) ~ cksum ; }
# endif
# define CKSUM_RESET(cksum) do { (cksum) = TF_CksumStart(); } while (0)
# define CKSUM_ADD(cksum, byte) do { (cksum) = TF_CksumAdd((cksum), (byte)); } while (0)
# define CKSUM_FINALIZE(cksum) do { (cksum) = TF_CksumEnd((cksum)); } while (0)
//endregion
//region Init
/** Init with a user-allocated buffer */
void _TF_FN TF_InitStatic ( TinyFrame * tf , TF_Peer peer_bit )
bool _TF_FN TF_InitStatic ( TinyFrame * tf , TF_Peer peer_bit )
{
if ( tf = = NULL ) return ;
if ( tf = = NULL ) {
TF_Error ( " TF_InitStatic() failed, tf is null. " ) ;
return false ;
}
// Zero it out, keeping user config
uint32_t usertag = tf - > usertag ;
@ -159,12 +228,18 @@ void _TF_FN TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit)
tf - > userdata = userdata ;
tf - > peer_bit = peer_bit ;
return true ;
}
/** Init with malloc */
TinyFrame * _TF_FN TF_Init ( TF_Peer peer_bit )
{
TinyFrame * tf = malloc ( sizeof ( TinyFrame ) ) ;
if ( ! tf ) {
TF_Error ( " TF_Init() failed, out of memory. " ) ;
return NULL ;
}
TF_InitStatic ( tf , peer_bit ) ;
return tf ;
}
@ -176,6 +251,9 @@ void TF_DeInit(TinyFrame *tf)
free ( tf ) ;
}
//endregion Init
//region Listeners
/** Reset ID listener's timeout to the original value */
@ -191,7 +269,7 @@ static void _TF_FN cleanup_id_listener(TinyFrame *tf, TF_COUNT i, struct TF_IdLi
if ( lst - > fn = = NULL ) return ;
// Make user clean up their data - only if not NULL
if ( lst - > userdata ! = NULL ) {
if ( lst - > userdata ! = NULL | | lst - > userdata2 ! = NULL ) {
msg . userdata = lst - > userdata ;
msg . userdata2 = lst - > userdata2 ;
msg . data = NULL ; // this is a signal that the listener should clean up
@ -444,12 +522,33 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf)
TF_Error ( " Unhandled message, type %d " , ( int ) msg . type ) ;
}
/** Externally renew an ID listener */
bool _TF_FN TF_RenewIdListener ( TinyFrame * tf , TF_ID id )
{
TF_COUNT i ;
struct TF_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 ;
}
}
TF_Error ( " Renew listener: not found (id %d) " , ( int ) id ) ;
return false ;
}
//endregion Listeners
//region Parser
/** Handle a received byte buffer */
void _TF_FN TF_Accept ( TinyFrame * tf , const uint8_t * buffer , size_t count )
void _TF_FN TF_Accept ( TinyFrame * tf , const uint8_t * buffer , uint32 _t count )
{
size_t i ;
uint32 _t i ;
for ( i = 0 ; i < count ; i + + ) {
TF_AcceptChar ( tf , buffer [ i ] ) ;
}
@ -586,8 +685,8 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c)
if ( tf - > rxi = = tf - > len ) {
# if TF_CKSUM_TYPE == TF_CKSUM_NONE
// All done
TF_HandleReceivedMessage ( ) ;
TF_ResetParser ( ) ;
TF_HandleReceivedMessage ( tf ) ;
TF_ResetParser ( tf ) ;
# else
// Enter DATA_CKSUM state
tf - > state = TFState_DATA_CKSUM ;
@ -614,18 +713,17 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c)
break ;
}
//@formatter:on
// we get here after finishing HEAD, if no data are to be received - handle and clear
// TODO verify - this seems unreachable under normal circumstances
if ( tf - > len = = 0 & & tf - > state = = TFState_DATA ) {
TF_HandleReceivedMessage ( tf ) ;
TF_ResetParser ( tf ) ;
}
}
//endregion Parser
//region Compose and send
// Helper macros for the Compose functions
// use variables: si - signed int, b - byte, outbuff - target buffer, pos - count of bytes in buffer
/**
* Write a number to the output buffer .
*
@ -669,15 +767,15 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c)
* @ param msg - message written to the buffer
* @ return nr of bytes in outbuff used by the frame , 0 on failure
*/
static inline size _t _TF_FN TF_ComposeHead ( TinyFrame * tf , uint8_t * outbuff , TF_Msg * msg )
static inline uint32 _t _TF_FN TF_ComposeHead ( TinyFrame * tf , uint8_t * outbuff , TF_Msg * msg )
{
int8_t si = 0 ; // signed small int
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
uint32 _t pos = 0 ;
( void ) cksum ;
( void ) cksum ; // suppress "unused" warning if checksums are disabled
CKSUM_RESET ( cksum ) ;
@ -724,13 +822,13 @@ static inline size_t _TF_FN TF_ComposeHead(TinyFrame *tf, uint8_t *outbuff, TF_M
* @ param cksum - checksum variable , used for all calls to TF_ComposeBody . Must be reset before first use ! ( CKSUM_RESET ( cksum ) ; )
* @ return nr of bytes in outbuff used
*/
static size _t _TF_FN TF_ComposeBody ( uint8_t * outbuff ,
static inline uint32 _t _TF_FN TF_ComposeBody ( uint8_t * outbuff ,
const uint8_t * data , TF_LEN data_len ,
TF_CKSUM * cksum )
{
TF_LEN i = 0 ;
uint8_t b = 0 ;
size _t pos = 0 ;
uint32 _t pos = 0 ;
for ( i = 0 ; i < data_len ; i + + ) {
b = data [ i ] ;
@ -748,11 +846,11 @@ static size_t _TF_FN TF_ComposeBody(uint8_t *outbuff,
* @ param cksum - checksum variable used for the body
* @ return nr of bytes in outbuff used
*/
static size _t _TF_FN TF_ComposeTail ( uint8_t * outbuff , TF_CKSUM * cksum )
static inline uint32 _t _TF_FN TF_ComposeTail ( uint8_t * outbuff , TF_CKSUM * cksum )
{
int8_t si = 0 ; // signed small int
uint8_t b = 0 ;
size _t pos = 0 ;
uint32 _t pos = 0 ;
# if TF_CKSUM_TYPE != TF_CKSUM_NONE
CKSUM_FINALIZE ( * cksum ) ;
@ -762,60 +860,109 @@ static size_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
}
/**
* Send a messag e
* Begin building and sending a fram e
*
* @ param tf - instance
* @ param msg - message object
* @ param listener - ID listener , or NULL
* @ param timeout - listener timeout , 0 is non e
* @ return true if sent
* @ param msg - message to send
* @ param listener - response listener or NULL
* @ param timeout - listener timeout ticks , 0 = indefinit e
* @ return success ( mutex claimed and listener added , if any )
*/
static bool _TF_FN TF_SendFrame ( TinyFrame * tf , TF_Msg * msg , TF_Listener listener , TF_TICKS timeout )
static bool _TF_FN TF_SendFrame_Begin ( TinyFrame * tf , TF_Msg * msg , TF_Listener listener , TF_TICKS timeout )
{
size_t len = 0 ;
size_t remain = 0 ;
size_t sent = 0 ;
TF_CKSUM cksum = 0 ;
TF_TRY ( TF_ClaimTx ( tf ) ) ;
TF_ClaimTx ( tf ) ;
tf - > tx_pos = ( uint32_t ) TF_ComposeHead ( tf , tf - > sendbuf , msg ) ; // frame ID is incremented here if it's not a response
tf - > tx_len = msg - > len ;
len = TF_ComposeHead ( tf , tf - > sendbuf , msg ) ;
if ( listener ) TF_AddIdListener ( tf , msg , listener , timeout ) ;
if ( listener ) {
TF_TRY ( TF_AddIdListener ( tf , msg , listener , timeout ) ) ;
}
CKSUM_RESET ( cksum ) ;
CKSUM_RESET ( tf - > tx_cksum ) ;
return true ;
}
/**
* Build and send a part ( or all ) of a frame body .
* Caution : this does not check the total length against the length specified in the frame head
*
* @ param tf - instance
* @ param buff - bytes to write
* @ param length - count
*/
static void _TF_FN TF_SendFrame_Chunk ( TinyFrame * tf , const uint8_t * buff , uint32_t length )
{
uint32_t remain ;
uint32_t chunk ;
uint32_t sent = 0 ;
remain = msg - > len ;
remain = length ;
while ( remain > 0 ) {
size_t chunk = TF_MIN ( TF_SENDBUF_LEN - len , remain ) ;
len + = TF_ComposeBody ( tf - > sendbuf + len , msg - > data + sent , ( TF_LEN ) chunk , & cksum ) ;
// Write what can fit in the tx buffer
chunk = TF_MIN ( TF_SENDBUF_LEN - tf - > tx_pos , remain ) ;
tf - > tx_pos + = TF_ComposeBody ( tf - > sendbuf + tf - > tx_pos , buff + sent , ( TF_LEN ) chunk , & tf - > tx_cksum ) ;
remain - = chunk ;
sent + = chunk ;
// Flush if the buffer is full and we have more to send
if ( remain > 0 & & len = = TF_SENDBUF_LEN ) {
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , len ) ;
len = 0 ;
// Flush if the buffer is full
if ( tf - > tx_pos = = TF_SENDBUF_LEN ) {
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , tf - > tx_pos ) ;
tf - > tx_pos = 0 ;
}
}
}
/**
* End a multi - part frame . This sends the checksum and releases mutex .
*
* @ param tf - instance
*/
static void _TF_FN TF_SendFrame_End ( TinyFrame * tf )
{
// Checksum only if message had a body
if ( msg - > len > 0 ) {
if ( tf - > tx_ len > 0 ) {
// Flush if checksum wouldn't fit in the buffer
if ( TF_SENDBUF_LEN - len < sizeof ( TF_CKSUM ) ) {
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , len ) ;
len = 0 ;
if ( TF_SENDBUF_LEN - tf - > tx_pos < sizeof ( TF_CKSUM ) ) {
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , tf - > tx_pos ) ;
tf - > tx_pos = 0 ;
}
// Add checksum, flush what remains to be sent
len + = TF_ComposeTail ( tf - > sendbuf + len , & cksum ) ;
tf - > tx_pos + = TF_ComposeTail ( tf - > sendbuf + tf - > tx_pos , & tf - > tx_ cksum) ;
}
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , len ) ;
TF_WriteImpl ( tf , ( const uint8_t * ) tf - > sendbuf , tf - > tx_pos ) ;
TF_ReleaseTx ( tf ) ;
}
/**
* Send a message
*
* @ param tf - instance
* @ param msg - message object
* @ param listener - ID listener , or NULL
* @ param timeout - listener timeout , 0 is none
* @ return true if sent
*/
static bool _TF_FN TF_SendFrame ( TinyFrame * tf , TF_Msg * msg , TF_Listener listener , TF_TICKS timeout )
{
TF_TRY ( TF_SendFrame_Begin ( tf , msg , listener , timeout ) ) ;
if ( msg - > len = = 0 | | msg - > data ! = NULL ) {
// Send the payload and checksum only if we're not starting a multi-part frame.
// A multi-part frame is identified by passing NULL to the data field and setting the length.
// User then needs to call those functions manually
TF_SendFrame_Chunk ( tf , msg - > data , msg - > len ) ;
TF_SendFrame_End ( tf ) ;
}
return true ;
}
//endregion Compose and send
//region Sending API funcs
/** send without listener */
bool _TF_FN TF_Send ( TinyFrame * tf , TF_Msg * msg )
{
@ -857,28 +1004,56 @@ bool _TF_FN TF_Respond(TinyFrame *tf, TF_Msg *msg)
return TF_Send ( tf , msg ) ;
}
/** Externally renew an ID listener */
bool _TF_FN TF_RenewIdListener ( TinyFrame * tf , TF_ID id )
//endregion Sending API funcs
//region Sending API funcs - multipart
bool _TF_FN TF_Send_Multipart ( TinyFrame * tf , TF_Msg * msg )
{
TF_COUNT i ;
struct TF_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 ;
}
}
msg - > data = NULL ;
return TF_Send ( tf , msg ) ;
}
TF_Error ( " Renew listener: not found (id %d) " , ( int ) id ) ;
return false ;
bool _TF_FN TF_SendSimple_Multipart ( TinyFrame * tf , TF_TYPE type , TF_LEN len )
{
return TF_SendSimple ( tf , type , NULL , len ) ;
}
bool _TF_FN TF_QuerySimple_Multipart ( TinyFrame * tf , TF_TYPE type , TF_LEN len , TF_Listener listener , TF_TICKS timeout )
{
return TF_QuerySimple ( tf , type , NULL , len , listener , timeout ) ;
}
bool _TF_FN TF_Query_Multipart ( TinyFrame * tf , TF_Msg * msg , TF_Listener listener , TF_TICKS timeout )
{
msg - > data = NULL ;
return TF_Query ( tf , msg , listener , timeout ) ;
}
void _TF_FN TF_Respond_Multipart ( TinyFrame * tf , TF_Msg * msg )
{
msg - > data = NULL ;
TF_Respond ( tf , msg ) ;
}
void _TF_FN TF_Multipart_Payload ( TinyFrame * tf , const uint8_t * buff , uint32_t length )
{
TF_SendFrame_Chunk ( tf , buff , length ) ;
}
void _TF_FN TF_Multipart_Close ( TinyFrame * tf )
{
TF_SendFrame_End ( tf ) ;
}
//endregion Sending API funcs - multipart
/** Timebase hook - for timeouts */
void _TF_FN TF_Tick ( TinyFrame * tf )
{
TF_COUNT i = 0 ;
TF_COUNT i ;
struct TF_IdListener_ * lst ;
// increment parser timeout (timeout is handled when receiving next byte)
@ -898,19 +1073,3 @@ void _TF_FN TF_Tick(TinyFrame *tf)
}
}
}
/** Default impl for claiming write mutex; can be specific to the instance */
void __attribute__ ( ( weak ) ) TF_ClaimTx ( TinyFrame * tf )
{
( void ) tf ;
// do nothing
}
/** Default impl for releasing write mutex; can be specific to the instance */
void __attribute__ ( ( weak ) ) TF_ReleaseTx ( TinyFrame * tf )
{
( void ) tf ;
// do nothing
}