嵌入式系统通讯协议设计与应用 1.概述 本通讯协议主要参考TCP/IP协议的分层结构进行建模,主要为了解决嵌入式系统中通讯设备种类较多,网络结构多变使上层应用程序设计与硬件相关,没有统一的编程接口,不便于调试,不便于模块化的问题。
2.协议模型 本通讯协议被分为如图1-1所示的五层。各层的定义见表1-1
物理设备RS485驱动程序HDLC驱动程序应用程序1应用程序2其他通讯方式驱动程序
物理寄存器接口
双向缓冲双向缓冲双向缓冲
网络层协议发送任务队列接收任务队列
传输层协议
图1-1 层次名称 层次作用 对应类(基类) 物理层 提供物理层次的器件连接 无 数据链路层 通过对物理层寄存器的操作,按照传输要求对数据进行编码解码,实现点对点的数据流的传输及流量控制。 CDLL_BASE
网络层 通过统一接口访问“数据链路层”的数据缓冲,将含有网络层协议头的网络层包装入或取出数据缓冲,进行路由分析,最后转发或向上一层传输。 CNWK CNWK_MASTER (主板或单机使用)CNWK_SLAVE (子板使用) 传输层 对数据进行分包处理,将数据切割成较小的数据包,按照次序发送,对接收的数据包按照包头的信息重组数据包。并且提供发送数据的校验及重发超时任务。 CTPL_TASK
路由管理协议层 针对不同的应用配置管理设备的网络结构,映射硬件物理结构并查询、存储路由信息的服务。 CLINK 应用程序层 应用程序使用固定接口向“传输层”提交发送任务,并在数据到达以后进行处理及响应。 CAPP_BASE 表1-1
3.通讯程序的应用 3.1通过CLINK类的使用及配置协议 除了以上提到的五层网络模型以外,为了程序设计者能够方便的使用配置程序在协议开发包中还包含一个CLINK类,它继承于CTPL_TASK类(类图见注),通过继承这个类,调用它的接口开发者能够将程序员自己编写的“数据链路层“,和“应用程序层”动态配置到网络中,产生编程者所需要的网络配置。 本协议使用“网络层协议”,“传输层协议”作为实现网络功能的下层协议。在使用中应按照以下的步骤配置协议。 ① 新建一个类继承类CLINK。 ② 实例化数据链路层协议。(需自CDLL_BASE中派生) ③ 实例化应用程序层程序。(需自CAPP_BASE中派生) ④ 重载以下四个函数。 virtual BOOL OnAddDll(); 在此函数中使用 BOOL AddDll(CDLL_BASE *pcDllUnit, BYTE &uDllIndex); 函数添加用户编写的“数据链路层”协议 virtual BOOL OnMapUnit(); 在此函数中使用
BOOL MapModule(const BYTE uModule, const DLL_STRU sDllStru);
适用于主板或单机
BOOL MapPort(const BYTE uModule, const DLL_STRU sDllStru); BOOL SetDefaultPort(const BYTE uDefaultPort); BOOL SetMasterPort(const BYTE uMasterPort, BOOL bMaster); 适用于子板
virtual BOOL OnAddApp(); 在此中加入应用层程序 BOOL AddNetApp(CAPP_BASE *pcNetApp); virtual BOOL OnInitFinish() 通讯协议初始化完毕。
⑤ 在程序运行时可以使用如下接口改变路由及配置。 路由信息类:
函数体 函数定义 DWORD GetMyId(); 获得设备地址 void SetMyId(DWORD dwMyId); 设置设备地址 BOOL AddGroupRoute(const BYTE uGroup, const BYTE uModule, const BYTE uPort);
增加组路由(暂不支持)
BOOL DelGroupRoute(const BYTE uGroup); 删除组路由(暂不支持)
BOOL AddRoute(const DWORD dwNodeId, const BYTE uModule, const BYTE uPort = 0);
增加路由
BOOL DelRoute(const DWORD dwNodeId); 删除路由
void ClsRoute(); 删除所有路由 BOOL SaveRoute(); 存储路由 BOOL GetRouteInf(DWORD dwNodeId, BYTE &uModule, BYTE &uPort);
查询路由
DWORD GetRouteCount(); 获取路由数 DWORD GetRouteList(sNodeStru *psNodeStru); 获取整个路由表 3.2通讯程序的扩展编程 本通讯协议可以在任何层次上使用,以便各层的调试,及以后通讯设计的复用,以下将介绍使用的方法和一些接口。
3.2.1数据链路层 对发送缓冲 WORD Dll_GetOutputCount(const BYTE uBuffUnit); 发送缓冲中数据数
BOOL Dll_GetChar(const BYTE uBuffUnit, BYTE &uChar); 从发送缓冲中读出一个数据
BOOL Dll_GetChar(const BYTE uBuffUnitm, BYTE *puChar, WORD wCount); 从发送缓冲中读出多个数据
BOOL Dll_DelChar(const BYTE uBuffUnit, const WORD wCount = 1); 从发送缓冲删除数据
对接收缓冲 virtual void Dll_InputUpdate(const BYTE uBuffUnit) = 0; WORD Dll_GetInputRemainBuffCount(const BYTE uBuffUnit); 获得剩余的输入缓冲空间数
BOOL Dll_PutChar(const BYTE uBuffUnit ,const BYTE uChar); 送入一个字节
BOOL Dll_PutChar(const BYTE uBuffUnit ,BYTE *puChar, const WORD wCount = 1);
送入多个字节
void Dll_ValidInput(const BYTE uBuffUnit); 输入允许 与系统的接口 BOOL GetEnable (const BYTE uUnitCount); 获得端口是否被系统禁止
void SetEnable (const BYTE uUnitCount, const BOOL bEnable);
系统设置端口状态
BOOL GetActive (const BYTE uUnitCount); 获得端口是否可用
BYTE GetUnitCount(); 获得协议所分配的端口数 BOOL Init(); 手动初始化协议
3.2. 2 网络层 结构体定义 typedef struct { BYTE uDllIndex; uDllIndex; “数据链路层”索引 uDllUnit; BYTE uDllUnit; }DLL_STRU; “数据链路层”中的相对端
口号 typedef struct { DWORD dwSrId; BYTE uSrModule; DWORD dwDeId; BYTE uDeModule; BYTE uPort; BYTE uDelayTime; }NWK_OVERHEAD_STRU;
dwSrId;网络包源地址 uSrModule; 网络包源模块 dwDeId;网络包目的地址 uDeModule; 网络包目的模块 uPort;网络包目的端口
uDelayTime;网络包延时
typedef struct { NWK_OVERHEAD_STRU sOverhead; BYTE uMapUnit; BYTE uDataLength; BYTE *puData; }NWK_PG_STRU;
sOverhead;网络包头结构 uMapUnit;转发端口 uDataLength;数据长度 *puData;数据指针
发送一个网络包(本地) BOOL SendData (BYTE *puData, const BYTE uDataLength, const BYTE uDelayTime,const BYTE uDeModule, const BYTE uMapModule, const BYTE uMapPort, BYTE uSrModule = 0);
*puData 数据指针 uDataLength数据长度 uDelayTime数据延时初试值 uDeModule目标模块 uMapModule目标模块(内部映射)
uMapPort目标端口(内部映射) uSrModule(源端口(现阶段使用))
发送一个网络包(远程) BOOL SendData (BYTE *puData, const BYTE uDataLength, const BYTE uDelayTime,const DWORD dwDeId, const BYTE uDeModule, BYTE uSrModule = 0);
*puData 数据指针 uDataLength数据长度 uDelayTime数据延时初试值 dwDeId目标地址 uDeModule目标模块 uSrModule(源端口(现阶段使用))
接受到一个网络包(必须重载) virtual void GetValidFrame (const DLL_STRU &sLv1Port, NWK_PG_STRU sNwkPgStru) = 0;
网络层收到一个网络包
调用系统 BOOL SearchRoute(const DWORD dwNodeId, BYTE &uModule, BYTE &uPort); 查询路由表获得下电路入口