PSM:协议状态机(Protocol State Machine),一款用于流式传输的数据协议解析组件

阅读: 评论:0

PSM:协议状态机(Protocol State Machine),一款用于流式传输的数据协议解析组件

PSM:协议状态机(Protocol State Machine),一款用于流式传输的数据协议解析组件

PSM:协议状态机(Protocol State Machine),一款用于流式传输的数据协议解析组件


介绍

PSM:Protocol State Machine,协议状态机。

一款用于流式传输的数据协议解析组件,可有效解决沾包、断帧问题。

PSM以回调函数的形式将完整的协议数据包抛到应用软件层,确保应用软件层收到的数据是一包完整的、有效的数据帧。

代码以纯C编写,可无缝在windows、linux、嵌入式单片机、嵌入式RTOS下应用。

代码下载:


使用场景

  • windows、linux下使用tcp、udp等流式传输协议
  • 嵌入式linux、单片机开发时,使用到了串口、SPI、IIC、USB、网络等进行收发不定长数据

协议的制定也是比较有规律的,一包完整的协议数据包的结构包含:包头、数据字段的长度、包尾等信息,或者只有协议包头后跟数据的形式,基于此特性,PSM由此而生。


使用介绍

PSM由psm_t这个结构体进行管理,该结构如下:

typedef struct psm psm_t;
struct psm
{uint8_t* buf;                     // 指向数据缓存uint32_t bufsize;                 // 数据缓存大小uint32_t wpos;                    // 写指针uint32_t rpos;                    // 读指针uint32_t match_start;             // 数据匹配索引psm_state_t state;                // 当前协议状态机的状态int (*recv_callback)(psm_t* psm, const void* buf, uint32_t len);  // 数据回调函数uint8_t  delimiter[4];             // 协议尾分隔符uint32_t delimiter_bytes;          // 协议尾分隔符长度uint32_t delimiter_index;          // 协议尾分隔符匹配索引uint8_t  identifier[4];            // 协议头标识符uint32_t identifier_bytes;         // 协议头标识符长度uint32_t identifier_index;         // 协议头标识符匹配索引uint32_t body_offset;              // 主体数据偏移地址uint32_t body_length;              // 主体数据长度uint32_t length_field_offset;                 // 长度字段偏移地址uint32_t length_field_bytes;                  // 长度字段所占字节数psm_unpack_coding_t length_field_coding;      // 长度字节编码方式void* arg;                                    // 可用于携带附加参数
};

PSM的移植也很简单,API如下:

int psm_recv(psm_t* psm, const void* buf, uint32_t len);
int psm_recv_byte(psm_t* psm, uint8_t c);
void psm_reset(psm_t* psm);
int psm_unpack(psm_t* psm);
  • psm_recv:数据接收函数,将接收到的数据存储于PSM中
  • psm_recv_byte:数据单字节接收函数,将接收到的数据存储于PSM中
  • psm_reset:重置PSM
  • psm_unpack:解析接收到的数据

移植时将psm_recv或psm_recv_byte放置于实际的数据接收位置进行数据接收,使用psm_unpack对收到的数据进行解析,psm_unpack解析成功后自动调用回调函数将完整的协议包抛到上层。

以单片机串口为例,将psm_recv_byte或psm_recv放置到串口接收中断中进行数据接收,在main函数中的死循环中轮训psm_unpack函数即可。

示例:


psm_t psm_usart =
{............
};void UART1_IRQHandler(void)
{static uint8_t RxData;...psm_recv_byte(&psm_usart, RxData);  // 接收一个字节...
}int main()
{.........while (1){psm_unpack(&psm_usart);  // 解析}
}

同时,也可将psm_unpack直接放置在串口接收中断中,由于此时数据是在串口中断中进行的数据解析,解析成功后会调用回调函数,所以在在回调函数中不可存在耗时操作。

示例:

void UART1_IRQHandler(void)
{static uint8_t RxData;...psm_recv_byte(&psm_usart, RxData);  // 接收一个字节psm_unpack(&psm_usart);  // 解析...
}

使用案例

示例1:以回车换行结尾的字符串形式

int recv_callback(psm_t * psm, const void* buf, uint32_t len)
{// 在此函数中对完整的数据包进行使用return 0;
}uint8_t buffer[512];psm_t psm =
{.buf                = buffer,.bufsize            = sizeof(buffer),.recv_callback      = recv_callback,.delimiter[0]       = 'r',  // 结束符第一个字节.delimiter[1]       = 'n',  // 结束符第二个字节.delimiter_bytes    = 2,     // 结束符大小
};
示例2:协议头形式

该协议结构一般为:

包头命令码数据长度CRCN字节数据

其中:包头 +命令码 +数据长度 +CRC组合成协议头,后跟实际的数据。

以包头、命令码、数据长度、CRC都为unsigned short类型,且包头为0XA1B0,PSM设置如下:

psm_t psm =
{.buf              = buffer,.bufsize          = sizeof(buffer),.recv_callback    = recv_callback,.identifier[0]    = 0XB0,  // 包头低字节.identifier[1]    = 0XA1,  // 包头高字节.identifier_bytes = 2,     // 包头的大小.length_field_bytes  = 2,  // 协议头中数据长度字段的大小.length_field_offset = 4,  // 协议头中数据长度字段的位置偏移.length_field_coding = PSM_UNPACK_ENCODE_BY_LITTEL_ENDIAN,   // 编码方式:小端.body_offset = 8,  // 主体数据的位置偏移
};
示例3:包头包尾形式

注:不支持相同字节的包头包尾,例如包头为0XAA、0XAA,包尾为0x55、0x55。

该协议结构一般为:

包头数据包尾

假设包头、包尾为unsigned short类型,且包头为0XAA、0X55、包尾为0X55、0XAA,PSM设置如下:

psm_t psm =
{.buf              = buffer,.bufsize          = sizeof(buffer),.recv_callback    = recv_callback,.identifier[0]    = 0XAA,  // 包头低字节.identifier[1]    = 0X55,  // 包头高字节.identifier_bytes = 2,     // 包头的大小.delimiter[0]     = 0X55,  // 包尾低字节.delimiter[1]     = 0XAA,  // 包尾高字节.delimiter_bytes  = 2,     // 包尾的大小
};

本文发布于:2024-01-29 09:52:37,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170649316214451.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:协议   组件   流式   数据   状态机
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23