C的一些算法技巧
一 数据分包与位字节计算:
modbus中m个位寄存器需要的字节数计算:
#define BytesForBitRegs(m) (total/8 + ((total%8)?1:0))
传输m个字节,每包/帧大小为n,则总共需要的包数
#define PackNum(total,single) (total/single + ((total%single)?1:0))或
PackNum = (total + (singleNum - 1))/singleNum ;
二 数据字节编码算法COBS,可用于串口通信
以modbus rtu通信为例,一般是3.5字符作为帧间隔区分,而使用COBS就不需要这样了,他是将范围 [0,255] 内的任意字节字符串转换为 [1,255] 范围内的字节。从数据中消除所有0,现在可以使用0来明确标记转换后数据的结束
1 #include <stddef.h> 2 #include <stdint.h> 3 #include <assert.h> 4 5 /** COBS encode data to buffer 6 @param data Pointer to input data to encode 7 @param length Number of bytes to encode 8 @param buffer Pointer to encoded output buffer 9 @return Encoded buffer length in bytes 10 @note Does not output delimiter byte 11 */ 12 size_t cobsEncode(const void *data, size_t length, uint8_t *buffer) 13 { 14 assert(data && buffer); 15 16 uint8_t *encode = buffer; // Encoded byte pointer 17 uint8_t *codep = encode++; // Output code pointer 18 uint8_t code = 1; // Code value 19 20 for (const uint8_t *byte = (const uint8_t *)data; length--; ++byte) 21 { 22 if (*byte) // Byte not zero, write it 23 *encode++ = *byte, ++code; 24 25 if (!*byte || code == 0xff) // Input is zero or block completed, restart 26 { 27 *codep = code, code = 1, codep = encode; 28 if (!*byte || length) 29 ++encode; 30 } 31 } 32 *codep = code; // Write final code value 33 34 return (size_t)(encode - buffer); 35 } 36 37 /** COBS decode data from buffer 38 @param buffer Pointer to encoded input bytes 39 @param length Number of bytes to decode 40 @param data Pointer to decoded output data 41 @return Number of bytes successfully decoded 42 @note Stops decoding if delimiter byte is found 43 */ 44 size_t cobsDecode(const uint8_t *buffer, size_t length, void *data) 45 { 46 assert(buffer && data); 47 48 const uint8_t *byte = buffer; // Encoded input byte pointer 49 uint8_t *decode = (uint8_t *)data; // Decoded output byte pointer 50 51 for (uint8_t code = 0xff, block = 0; byte < buffer + length; --block) 52 { 53 if (block) // Decode block byte 54 *decode++ = *byte++; 55 else 56 { 57 if (code != 0xff) // Encoded zero, write it 58 *decode++ = 0; 59 block = code = *byte++; // Next block length 60 if (!code) // Delimiter code found 61 break; 62 } 63 } 64 65 return (size_t)(decode - (uint8_t *)data); 66 }