freemodbus的兼容性非常好,可以方便的在很多的平台进行移植,这与它的代码架构有很大的关系。
这里我们不考虑代码的移植过程,仅仅分析它的层次结构。
我认为,freemodbus协议实际上是分了三个层次的
1. 应用层(或者说暴露给应用层的接口):
接口定义全部在头文件mb.h中包含,在mb.c中实现。
包括了移植时不需要改动的部分(一些初始化,使能,poll等),还有需要修改或者说实现的部分(注册给定功能码对应的回调处理程序,寄存器相关操作等)。
而且在初始化中通过回调函数指向了第二层的函数接口,相当于为整个程序提供了统一的接口去访问第二层的函数,而不用考虑第二层的改变。
2. 协议(移植)层:
这一层体现了freemodbus的类型多样(RTU模式,ASCII模式,TCP模式等)
接口定义类型.h(mbrtu.h/mbascii.h)中包含,在对应的.c中实现。
目前看到的函数全部不用改动,可以直接调用。实现了具体的(RTU)初始化、开始、停止、接收处理、发送处理等部分功能。
此层函数直接调用物理层接口。
3. 物理层:
接口定义在mbport.h中定义,用户只需要根据平台的不同具体实现(初始化串口、初始化最小单位为50us的定时器、使能串口和定时器等)其定义的相关接口。具体位置的话,串口相关的基本操作在portserial.c中,定时器相关的在porttimer.c中,状态机在portevent.h中
4. 特殊点:
这里有一个地方比较特殊,就是接受和发送中断函数。实际上的接受和处理是在协议(移植)层定义并实现好的,但是清中断必须要下放到物理层来适配不同的平台。
所以freemodbus规定了接受中断和发送中断必须分别包括两个函数,这两个函数通过回调的形式最终指向的是协议移植层的接收处理和发送处理函数。接受中断处理函数和发送中断处理函数需要注册在本层(物理层)的串口初始化部分。
所以我认为 可以说freemodbus协议规定了中断处理函数的流程。
也可以说是freemodbus做好了中断处理函数,只是让用户在物理层帮忙清一下中断标志,如果需要其他操作也可以同时加入。
5. 总结:这个架构明显的分了三个层次,对应着用户移植的三种情况:
(1)业务:串口接收数据与业务完全分离,业务只需要调用接口,而不对串口的架构做任何的修改即可。
(2)切换协议:假设从RTU切换到ASCII,那么只需要在应用层接口中注册ASCii的回调即可完成,底层与业务无需修改。
(3)切换平台:以单片机为例,切换的时候仅需要把物理层的硬件实现重新适配,而不需要对上层做任何的改动。
那么其调用流程为:
应用->(调用)应用层的接口 -> (回调) 协议(移植)层函数->(调用)物理层接口
当然,这个协议远比我分析的复杂和具体,以后有时间和机会我还会继续学习和分析整理。