一个简洁实用的基于字节的自定义通信协议。
/* Frame format definition */
typedef struct msg_frame
{
uint32_t head; /* Frame header */
uint8_t type; /* Device ID */
uint8_t cmd; /* Order code */
uint16_t code; /* Function code */
uint16_t datalen; /* Data length */
uint8_t data[MSG_FRAME_MAX_LEN]; /* Data storage area */
uint16_t chkval; /* Check value */
uint16_t tail; /* Frame end */
} msg_frame_t;
说明 | 帧头 | 设备 ID | 指令码 | 功能码 | 数据长度 | 数据存储区 | 校验值 | 帧尾 |
---|---|---|---|---|---|---|---|---|
变量名 | head | type | cmd | code | datalen | data | chkval | tail |
长度(Byte) | 4 | 1 | 1 | 2 | 2 | n | 2 | 2 |
数据存储区最大长度,单位为字节
。
#define MSG_FRAME_MAX_LEN 64
可处理有效数据最大长度,单位为字节
。
#define MSG_BUF_MAX_LEN 96
帧头:有效数据的开始。
#define MSG_FRAME_HEAD0 0xED
#define MSG_FRAME_HEAD1 0xB9
#define MSG_FRAME_HEAD2 0x55
#define MSG_FRAME_HEAD3 0xAA
设备 ID:设备种类、地址或者设备类型
uint8_t type;
指令码:对设备的造作命令,如 open、close、read、write 等。
uint8_t cmd;
功能码:对指令码的进一步说明。
uint16_t code;
数据长度:数据存储区中数据
的长度,单位为字节
。
uint16_t datalen;
数据存储区:用来存储要传输的数据。
uint8_t data[MSG_FRAME_MAX_LEN];
校验值:基于 CRC 校验(可自定义)。
static uint16_t mc_check_crc16(const uint8_t *data, uint8_t len)
{
uint16_t crc16 = 0xffff;
uint8_t state, i, j;
for(i = 0; i < len; i++ )
{
crc16 ^= data[i];
for( j = 0; j < 8; j++)
{
state = crc16 & 0x01;
crc16 >>= 1;
if(state)
{
crc16 ^= 0xa001;
}
}
}
return crc16;
}
帧尾:有效数据的结束。
#define MSG_FRAME_TAil0 0x5A
#define MSG_FRAME_TAil1 0xA5
数据解包
/* Packet decoding */
msg_pkg_t *unpkg_frame(const uint8_t *_msg_buf, const uint8_t size)
数据打包
/* Packet packaging */
msg_buf_t *pkg_frame(const msg_frame_t *_msg_pkg)
测试环境:Visual Studio 2022 IDE
测试代码:
void pkg_test_cmd(void)
{
kprintf("\r\n----- Packing and unpacking test begin -----\r\n");
msg_frame_t my_frame = { 0x01, 0x02, 0xabcd, 0x8,
{0x12, 0x34, 0x56,0x78, 0xab, 0xcd, 0xef, 0x5a} };
uint8_t my_buf[] = { 0xed, 0xb9, 0x55, 0xaa, 0x0a, 0x2c, 0x80, 0x00,
0x00, 0x04, 0x12, 0x34, 0xab, 0xcd, 0xe5, 0x50, 0x5a, 0xa5 };
msg_buf_t* msg_buf = pkg_frame(&my_frame);
msg_buf_print("frame to buffer test", msg_buf);
msg_pkg_t* msg_pkg = unpkg_frame(msg_buf->buf_ptr, msg_buf->buf_size);
msg_pkg_print("buffer to frame test", msg_pkg);
msg_pkg = unpkg_frame(my_buf, sizeof(my_buf) / sizeof(uint8_t));
msg_pkg_print("buffer to frame test", msg_pkg);
kprintf("\r\n---- Packing and unpacking test end ---- \r\n");
}
运行结果:
----- Packing and unpacking test begin -----
frame to buffer test
size (DEC): 22
data (HEX): ed b9 55 aa 01 02 ab cd 00 08 12 34 56 78 ab cd ef 5a 47 14 5a a5
state (DEC): 0
buffer to frame test
type (HEX): 01
cmd (HEX): 02
code (HEX): ab cd
datalen(DEC): 8
data: (HEX): 12 34 56 78 ab cd ef 5a
state: (DEC): 0
buffer to frame test
type (HEX): 0a
cmd (HEX): 2c
code (HEX): 80 00
datalen(DEC): 4
data: (HEX): 12 34 ab cd
state: (DEC): 0
---- Packing and unpacking test end ----
请按任意键继续. . .