报文格式:
字段 | 长度(字节) | 说明 |
STX | 1 | 开始控制字符 0x02 |
数据长度 | 2 | 传输时需要转换成INTEL序(高字节在前)数据体部分长度。最大允许值为:4096 |
数据体 | 不定 | 由数据长度决定 |
校验字节 | 1 | 校验字节是报文中除通信控制字符之外所有数据的校验和 |
ETX | 1 | 结束控制字符 0x03 |
断帧和连帧处理:
通过宏BROKEN_FRAME可以控制断帧测试或是连帧测试 ,代码中有详细注释说明
#include <stdio.h>
#include <string.h>
#include <stdint.h>
//最大缓存区
#define MAX_BUFFER_SIZE 4096
//帧格式
typedef struct {
unsigned char start;
unsigned short length;
unsigned char data[MAX_BUFFER_SIZE/4];
unsigned char checksum;
unsigned char end;
} Frame;
//定义缓存区和缓存区当前索引
unsigned char buffer[MAX_BUFFER_SIZE];
int bufferIndex = 0;
//打印hex数据
void print_mesg(char *head, unsigned char *data, int len)
{
printf("%s", head);
for(int i=0; i<len; i++)
{
printf("%02X ",data[i]);
}
printf("\n");
}
/**
* 返回单字节校验和
*/
unsigned char GetCheckSum(unsigned char *data, uint32_t data_size)
{
int i = 0;
uint32_t temp = 0;
uint8_t sum = 0;
for(i = 0;i<data_size;i++)
{
temp += *(data+i);
}
sum = temp&0xff;
return sum;
}
//接收数据处理
void processFrame(Frame frame) {
// 在这里处理接收到的帧数据
// 可以根据具体需求对数据进行解密、校验等操作
// 例如,可以打印数据体内容
print_mesg("Received data:", frame.data, frame.length);
}
//接收数据放到缓存区
void addToBuffer(unsigned char *data, int data_len) {
// 将帧数据添加到缓存区
if((bufferIndex+data_len) > MAX_BUFFER_SIZE)
{
bufferIndex = 0;
memset(buffer, 0, MAX_BUFFER_SIZE);
return;
}
memcpy(&buffer[bufferIndex],data, data_len);
bufferIndex += data_len;
}
//解析帧
void parseFrame(unsigned char* data, int length) {
printf("length=%d\n",length);
print_mesg("Received:", data, length);
Frame frame;
memset(&frame, 0, sizeof(Frame));
addToBuffer(data, length);
int dataIndex = 0;
while (bufferIndex > 5) {
if (buffer[dataIndex] != 0x02) {
// 数据起始标志错误,丢弃当前帧
dataIndex++;
continue;
}
printf("dataIndex=%d\n",dataIndex);
if (bufferIndex - dataIndex < 5) {
// 数据长度不足,无法解析帧
break;
}
frame.start = buffer[dataIndex];
frame.length = (buffer[dataIndex + 1] << 8) | buffer[dataIndex + 2];
if (bufferIndex - dataIndex < frame.length + 5) {
// 数据长度不足,无法解析帧
break;
}
memcpy(frame.data, buffer + dataIndex + 3, frame.length);
frame.checksum = buffer[dataIndex + frame.length + 3];
frame.end = buffer[dataIndex + frame.length + 4];
// 检查校验和
unsigned char checksum = GetCheckSum(&buffer[dataIndex+1], frame.length+2);
printf("checksum:%02X\n",checksum);
printf("frame.checksum:%02X\n",frame.checksum);
printf("frame.end:%02X\n",frame.end);
print_mesg("data:", frame.data, frame.length);
if (checksum != frame.checksum || frame.end != 0x03) {
// 校验和或控制字符错误,丢弃帧
dataIndex++;
continue;
}
processFrame(frame);
dataIndex += frame.length + 5;
bufferIndex -= dataIndex;
memmove(buffer,buffer+dataIndex,bufferIndex);
dataIndex=0;
}
}
//是否断帧
#define BROKEN_FRAME 1
int main() {
//0xFF为干扰字符
unsigned char receivedData1[] = {0xFF,0x02, 0x00, 0x13, 0x10, 0x02, 0x00, 0x01, 0x32, 0x30, 0x32, 0x33, 0x31, 0x31, 0x30, 0x32, 0x31, 0x39, 0x35, 0x38, 0x30, 0x33, 0x02, 0xED, 0x03};
//0xFF为干扰字符
unsigned char receivedData2[] = {0x02, 0x00, 0x13, 0x10, 0x02, 0x00, 0x01, 0x32, 0x30, 0x32, 0x33, 0x31, 0x31, 0x30, 0x32, 0x31, 0x39, 0x35, 0x38, 0x30, 0x33, 0x02, 0xED, 0x03, 0xFF, 0x02, 0x00, 0x13, 0x50, 0x01, 0x00, 0x01, 0x62, 0x77, 0x74, 0x32, 0x31, 0x30, 0x38, 0x38, 0x32, 0x30, 0x34, 0x30, 0x31, 0x01, 0x00, 0xad, 0x03, 0x02, 0x00, 0x13, 0x50, 0x01, 0x00, 0x01, 0x62, 0x77, 0x74, 0x32, 0x31, 0x30, 0x38, 0x38, 0x32, 0x30, 0x34, 0x30, 0x31, 0x01, 0x00, 0xad, 0x03};
int receivedLength1 = sizeof(receivedData1) / sizeof(receivedData1[0]);
int receivedLength2 = sizeof(receivedData2) / sizeof(receivedData2[0]);
#if BROKEN_FRAME //断帧处理
parseFrame(receivedData1, receivedLength1-10);
parseFrame(receivedData1+receivedLength1-10, 5);
parseFrame(receivedData1+receivedLength1-5, 5);
#else //连帧处理
parseFrame(receivedData2, receivedLength2);
#endif
return 0;
}
如果不需要连帧处理,仅仅简单的断帧处理可参考下面博文