协议数据处理流程

2023-11-16

总体流程

在两个设备对接通讯时都会用到协议处理的功能,将接受的协议数据接收到后解包后得到传输的内容,下面写一下轮询方式的流程处理过程

	PushToComFIFO(RecBuffer,BufLen);
	if(GetDataFromComFIFO(ComStr))
	{
		Command_Class(ComStr);
	}
转存
解出对应协议格式
解出协议信息内容
接收到的数据
缓冲处理数组
待处理的协议包
结束

上面就是协议处理的整体框架,先将从硬件接口上接收到的数据(RecBuffer)根据长度(BufLen)放入到处理缓冲中(ComFIFO),然后从缓冲数据中读出需要的符合协议规则的数据包(ComStr),最后在对得到的数据包解析,读出其中包含的内容。如果该硬件接口接收的数据中包含不同地协议格式,可以根据设置不同的GetDataFromComFIFO返回值判断之后进行哪个协议解包。如下:

 switch(ComType)
 {
	case CMD_7D7E:
		Command_Class_7D7E(ComStr);
		break;
	case CMD_$RN:
		Command_Class_$RN(ComStr);
		break;
	default;break;
}

数据放入缓冲

PushToComFIFO(RecBuffer,BufLen);

将数据放入缓冲的作用主要是为了方便组包,因为接口收到的数据有可能不是完整的一包数据,通过写指针(FIFOWritePos)可以将多次接收的数据顺序的放在同一个缓冲数组中,其中FIFO_SIZE为缓冲数组长度

Void PushToComFIFO(uint8_tDataBuffer[],conset int DataBufsize)`
{
	static int i;
	for(i=0;i<DataBufsize;i++)
	{
		ComFIFO[FIFOWritePos++]=DataBuffer[i];
		if(FIFOWritePos>=FIFO_SIZE)
		{
			FIFOWritePos=0;
		}
	}
}

从数据缓冲中解包协议格式-读缓冲

GetDataFromComFIFO(ComStr);

通过判断读指针和写指针是否在同一位置,得知数据缓冲中是否有待处理数据,并将该数据放入DataBuffer中依次传给Get_XXX_Msg函数判断是否符合协议格式,直到待处理数据全部处理完毕。

bool GetDataFromComFIFO(uint8_t* DataBuffer)
{
	static int sync =false;
	static int DataIndex =0;
 	while(FIFOReadPos!=FIFOWritePos)
	{
		DataBuffer[DataIndex ]=ComFIFO[ReadIndex++];
		if(FIFOReadPos>=FIFO_SIZE)
		{
			FIFOReadPos=0;
		}
		if(Get_XXX_Msg(&sync,&DataIndex ,DataBuffer)}
		{
			DataIndex =0;
			return ture;
		}
	}
	return false;

}

从数据缓冲中解包协议格式-协议格式解析

Get_XXX_Msg(&sync,&DataIndex ,DataBuffer)

函数先判断是否符合协议包头,在检测到包头后会将检测状态标志p_sync置位,该值从外部传入可以防止多处调用造成的逻辑错误。之后
就会判断是否到包尾部位置,过程中判断DataBuffer数组长度
p_DataIndex是否超定义长度,防止数组溢出。检测到尾部后下面函数就得到了$G…* 格式的协议包DataBuffer,同时状态标志清零并返回Get_XXX_Msg函数的协议获取状态ture。

bool Get_XXX_Msg(int* p_sync,int* p_DataIndex ,uint8_t DataBuffer)
{
	
	if(*p_sync||((*p_DataIndex==0)&&(DataBuffer[0]=="$")||(*p_DataIndex==1)&&(DataBuffer[1]=="G")))
	{
		*p_DataIndex++;
		if(*p_DataIndex>=2)
		{
			*p_sync=ture;
		}
	}
	if(*p_DataIndex>=255)
	{
		*p_DataIndex=0;
		*p_sync=false;
	}
	if(*p_sync&&(DataIndex(*p_DataIndex-1)=="*"))
	{
		*p_sync=false;
		return ture;
	}
}
else
{
	*p_sync=false;
	if(*p_DataIndex==1)
	{
		*p_DataIndex=1;
	}
	else
	{
		*p_DataIndex=0;
	}
}

如果协议有校验位需要校验可以在协议格式解析中加入校验计算或获得协议包后再在进行校验,校验方式按协议要求进行校验

 if(Get_XXX_Msg(&sync,&DataIndex ,DataBuffer)}
 {
		DataIndex =0;
			//校验
		if(Check(DataBuffer))
		return ture;
}

有的协议没有包尾通过包长度来代替包尾检测确定结束协议帧检测,但这个一般有校验过程,需要在检测协议的同时进行校验

另外在传输Hex协议时为了防止协议内容干扰到包头包尾的判断,通常会将协议内容和包头尾一样的字节进行转义,比如7E转义位7D 5E、7D转义位7D 5D 在接收数据时就要将该数据转义回来
接收完数据数对DataBuffer进行重新处理
发送端如果有校验位一般都是先校验再转义发送,所以接收方需要先转义后才能进行校验计算。

for(i=0,n=0;i<DataIndex;i++,n++)
{
	if((DataBuffer[i]==0x7D)&&(DataBuffer[i+1]==0x5E))
	{
		DataBuffer[n]=0x7E;
		i++;
	}
	else if((DataBuffer[i]==0x7D)&&(DataBuffer[i+1]==0x5D))
	{
		DataBuffer[n]=0x7D;
		i++;
	}
	else
	{
		DataBuffer[n]=DataBuffer[i];
	}
	if(Check(DataBuffer))
	{
		return ture;
	}
}

从协议包格式中解出内容信息

Command_Class(ComStr);

按照不同的协议规则,在处理上也有不同地处理方式,ASCII协议时可以使用如下函数,其中GetSubItem函数为取数的具体方法。
在得到cBufOut后有的需要进行转换得到要求的数据,比如使用atoi、atof、 sscanf、strtol等函数得到包含的数据,Num1、Num2.

void Command_Class(uint8_t *Buffer)
{
	char Status = 0;
	char cBufOut[256];
	
	Status = GetSubItem(Buffer, strlen(Buffer),3,cBufOut);
	if(Status)
	{
		Num1 = atof(cBufOut);
	}
	Status = GetSubItem(Buffer, strlen(Buffer),4,cBufOut);
	if(Status)
	{
		Num2 = atof(cBufOut);
	}
}

GetSubItem(Buffer, strlen(Buffer),3,cBufOut);

该函数功能是报文数据区域数据提取,根据具体协议用来分隔数据内容的方式实现读取Buffer相应分割区域的内容到cBufOut,如下代码内容是解析通过“,”分隔内容的代码,3表示第3块分隔的区域如"$Gxxx,xxx,123,…"其中123为解出的数据被传递给cBufOut。
或者在下面代码中if (Buffer[i] == (char)(’,’) || Buffer[i] == (char)(’
’))更改分隔方式。
另外按照协议需求更改,如以下代码表示只接收数字和相应符号的ASCII字节,如不要求数据格式可去掉该限制选择。
if((cBufOut[j] == ‘+’)||(cBufOut[j] == ‘-’)||(cBufOut[j] == ‘.’)||((cBufOut[j]>= 0x30)&&(cBufOut[j]<= 0x39)))


char GetSubItem(const char Buffer[], const int BufferSize, const int ItemIndex, uint8_t cBufOut[])
{
	int i,j;
	int CommCnt = 0;
	int CommaPoint = -1;
	int PreCommaPoint = -1;
	int BufOutSize;
	if (ItemIndex == 1)
	{
		return 0;
	}
	if (cBufOut == 0)
	{
		return 0;
	}
	if (Buffer == 0)
	{
		return 0;
	}
	for (i=0; i<BufferSize; i++)
	{
		if (Buffer[i] == (char)(',') || Buffer[i] == (char)('*'))
		{
			CommCnt++;
			if (CommCnt == ItemIndex)
			{
				CommaPoint = i;
				BufOutSize = CommaPoint-PreCommaPoint-1;
				if(BufOutSize>20)
				{
					BufOutSize = 20;
				}
				if (BufOutSize > 0)
				{
					strncpy(cBufOut, Buffer+PreCommaPoint+1, BufOutSize);
					cBufOut[BufOutSize] = '\0';
					for(j=0; j< BufOutSize; j++)
					{
						if((cBufOut[j] == '+')||(cBufOut[j] == '-')||(cBufOut[j] == '.')||((cBufOut[j]>= 0x30)&&(cBufOut[j]<= 0x39)))						
						{
							j = j;
						}else
						{
							return 0;
						}	
					}					
					return 1;
				}
				else
					return 0;				
			}
			else
			{
				PreCommaPoint = i;
			}			
		}
	}
	return 0;
}

Hex协议大部分的协议是按固定的位置进行解析的,直接按位置分隔信息内容,或是也有一些按照ASCII码协议分隔方法进行处理

以上代码环境 :keil+c+stm32。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协议数据处理流程 的相关文章

随机推荐

  • python快速实现简易双重弹力球小游戏

    完整代码如下 from tkinter import import random import time Creating the window window Tk window title Bounce window geometry 6
  • STM32HAL 移植MultiButton小巧简单事件驱动型按键驱动框架(裸机版本)

    目录 概述 一 使用方法 特性 按键事件 Examples 二 STM32CubeMx配置 三 Examples 四 运行结果 五 总结 概述 本篇文章介绍如何使用STM32移植 MultiButton开源框架 引用官网简述如下 Multi
  • 日志审计-syslog日志外发

    一 Linux 主机日志 不同的 Linux 版本 syslog 服务名可能为 syslog 也可能为 rsyslog 以下以 syslog 为例说明 Linux 主机所有的日志文件一般都在 var log 下 默认只是不记录 FTP 的
  • antdpro5.2.0项目开卷

    一 下载antdpro antdpro官网 刚开始想的是去github上下载项目 发现下载出来的版本是6 0 0版本 安装完依赖启动项目 左侧的菜单不出来 用react developer tools工具看 是因为左侧的菜单没有渲染出来 身
  • R语言第十一讲 决策树与随机森林

    概念 决策树主要有树的回归和分类方法 这些方法主要根据分层和分割 的方式将预测变量空间划分为一系列简单区域 对某个给定待预测的观 测值 用它所属区域中训练集的平均值或众数对其进行预测 基于树的方法简便且易于解释 但预测准确性通常较低 如图所
  • Mybatis之choose (when, otherwise)标签

    choose when otherwise 标签 有时候我们并不想应用所有的条件 而只是想从多个选项中选择一个 而使用if标签时 只要test中的表达式为 true 就会执行 if 标签中的条件 MyBatis 提供了 choose 元素
  • idea 导出文件附带文件目录结构

    安装这个插件
  • Linux学习记录之命令

    1 显示 跳转行号的基本操作 vi 文件名 打开文件后 如果要显示所有行号 使用 set nu 如果要显示当前行号 使用 nu 如果要跳转到指定行 使用 行号 例如 跳转到第10行 使用 10
  • OpenPie上榜2022年源自中国值得关注的20家新锐全球化科技品牌

    2022年6月25日 EqualOcean盘点了2022年源自中国值得关注的20家新锐全球化科技品牌 拓数派 OpenPie 成为了数据计算领域领先全球的佼佼者 OpenPie是以 Data Computing for New Discov
  • 1.3 OC与OD门(硬件基础系列)

    针对设计过程的问题 欢迎各位留言评论或群内讨论 1 3 OC与OD门 1 3 1 简介 OC Open Collector 门又叫集电极开路门 主要针对的是BJT电路 图1 21 OC门 OD Open Drain 门又叫漏极开路门 主要针
  • express中简单的使用token

    首先安装需要的插件 创建一个js文件 导入express const exprss require express 创建web服务器 const app exprss 生成token const jwt require jsonwebtok
  • 35道SpringBoot面试题及答案

    Spring Boot 是微服务中最好的 Java 框架 我们建议你能够成为一名 Spring Boot 的专家 本文精选了三十五个常见的Spring Boot知识点 祝你一臂之力 问题一 Spring Boot Spring MVC 和
  • AODV按需路由协议

    一 详细解释 AODV Ad hoc On demand Distance Vector Routing 是一种按需路由协议 当一个节点需要给网络中的其他节点传送信息时 如果没有到达目标节点的路由 则必须先以多播的形式发出RREQ 路由请求
  • Windows Server 2008多路径 I/O 概述

    面向高可用性的多路径支持 Windows Server 2008 包括许多将运行 Windows 服务器级操作系统的计算机与存储区域网络 SAN 设备连接起来的增强功能 集成的多路径 I O MPIO 支持是为基于 Windows 的服务器
  • 升专家需要具备的6个能力!

    阅读本文大概需要2min 文 强哥 图 强哥 未经授权禁止转载 高级开发和初级开发的区别并不只有工作经验的差异 可以说如果只凭经验丰富 那还不够高级开发的标准 互联网企业一般对于技术岗都有清晰的晋升体系和对应的能力图谱 有些人可能因为某些原
  • struct结构体占内存字节数

    昨天写了一个结构体demo 心血来潮打印struct所占内存字节数 struct student char name 20 char sex int num float score 3 void print 你猜猜是多少个字节数呢 对于ch
  • PCL拼接点云数据

    1 将两个点云拼接成一个点云 1 1 输入和输出 输入 两个相同点格式的点云比如pcl PointCloud
  • JSP include能包含html页面吗?

    转自 JSP include能包含html页面吗 jsp简介 JSP全称是Java Server Pages 是一种动态网页技术 JSP其实就是在html中插入了java代码和JSP标签之后形成的文件 文件名以 jsp结尾 其实JSP就是一
  • 输入网址后,会经历哪几个步骤

    1 面试官问输入网址后 会经历哪几个步骤 DNS HTTPS TCP 就知道这两个 DNS解析 TCP连接 发送http请求 HTTP请求报文的方法是 get 如果浏览器存储了该域名下的 Cookies 那么会把 Cookies放入 HTT
  • 协议数据处理流程

    数据处理流程 总体流程 数据放入缓冲 PushToComFIFO RecBuffer BufLen 从数据缓冲中解包协议格式 读缓冲 GetDataFromComFIFO ComStr 从数据缓冲中解包协议格式 协议格式解析 Get XXX