一、设计思想

  任何通信协议的实现都是基于状态机的设计思想,就是来了一串数据判断是是干啥的在调用相应的处理函数只不过高手一般采用回调处理。

  • 如果你熟悉了回调、源码里的状态机的实现又可以理解,那么恭喜你已经掌握了通信协议的实现方法。
  •   如果你可以从源妈里体会到分层的设计思想,那么恭喜你已经触碰到了架构师的门槛。

  本系列文章就是通过对FreeModeBus源码进行解析来掌握以上技能。

二、ModBus协议简介以及状态机的实现

  为啥把ModBus协议简介与状态机的实现放在一起呢??? 

  状态机编写当然是基于通信协议标准。

  如果通信数据格式、功能码、处理流程都搞不清楚,你编出来的状态机也是你“个人版的通信协议标准”,与符合ModBus通信协议标准的设备也是通信不上的。

1、  ModBus  设备间通信处理流程如下:

  •   主设备向从设备发送请求
  •   从设备分析并处理主设备的请求,然后向主设备发送结果
  •   如果出现任何差错,从设备将返回一个异常功能码

这里不对ModBus协议进行过多介绍,网上有很多资料。但有个疑点还是有必要搞清楚。在ModbusTCP里什么是主站(主设备)?什么是从站(从设备)??

我相信会有人不假思索地说主站不就是服务器,从站不就是客户端码???

 哈哈,如果你仔细读了  ModBus  设备间通信处理流程的话,你可以搞懂的。俺老李就不老生常谈了。

2、状态机的实现解析

  首先从网上下载modbus协议源码文件,打开文件夹如下:

  

首先使用Source Insight编辑器打开mb.c文件(一般重要的文件放在工程的根目录下相相当于main函数,这个和人类的编程习惯有关)。

   打开之后。嗯分析文件之前先说下状态机,状态机的运行是要轮询poll是否建立modbus通信、判断通信数据是接收请求还是请求响应。

注意关键字poll在编辑器的左下角找到带有poll的函数。

就是eMBPoll函数,这里面就有实现设备间Modbus通信状态机源代码以及相应的简单注释如下所示:

   /* Check if the protocol stack is ready. */
//判断协议栈硬件环境有没有准备。好比如ModBusTCP协议里基于W5500以太网芯片的初始化,sockt通信建立提供TCP服务。
if( eMBState != STATE_ENABLED )
{
return MB_EILLSTATE;
} /* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
    //通过xMBPortEventGet函数处理如果有事件发生得到状态机的状态值并赋值给eEvent,
    //然后通过switch语句运行状态机调用相应函数进行处理,当然这里用了函数指针、回调。
if( xMBPortEventGet( &eEvent ) == TRUE )
{
      //
switch ( eEvent )
{
case EV_READY:
break; case EV_FRAME_RECEIVED:
eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
if( eStatus == MB_ENOERR )
{
/* Check if the frame is for us. If not ignore the frame. */
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
{
( void )xMBPortEventPost( EV_EXECUTE );
}
}
break; case EV_EXECUTE:
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
eException = MB_EX_ILLEGAL_FUNCTION;
for( i = ; i < MB_FUNC_HANDLERS_MAX; i++ )
{
/* No more function handlers registered. Abort. */
if( xFuncHandlers[i].ucFunctionCode == )
{
break;
}
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
{
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
break;
}
} /* If the request was not sent to the broadcast address we
* return a reply. */
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
{
if( eException != MB_EX_NONE )
{
/* An exception occured. Build an error frame. */
usLength = ;
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
ucMBFrame[usLength++] = eException;
}
if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
{
vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
}
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
}
break; case EV_FRAME_SENT:
break;
}
}

从程序源码里面解析框架图如下:

大家可以根据上图理解状态机的结构框架,本文解析到此结束。关于相关在状态机里面怎么回调相关处理函数的下章解析。

FreeModBus源码解析(1)---开篇的更多相关文章

  1. SuperSocket源码解析之开篇

    一 简介 官方介绍:SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架.你无须了解如何使用 Socket, 如何维护 Socket 连接和 S ...

  2. SuperSocket源码解析之开篇 (转)

    一 简介 官方介绍:SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架.你无须了解如何使用 Socket, 如何维护 Socket 连接和 S ...

  3. Spring源码解析系列汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...

  4. Maven 依赖调解源码解析(一):开篇

    本文是系列文章<Maven 源码解析:依赖调解是如何实现的?>第一篇,主要做个开头介绍.并为后续的实验做一些准备.系列文章总目录参见:https://www.cnblogs.com/xia ...

  5. jQuery整体架构源码解析(转载)

    jQuery整体架构源码解析 最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性, ...

  6. 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析

    前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表).接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持 ...

  7. jQuery整体架构源码解析

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  8. 顺序线性表 ---- ArrayList 源码解析及实现原理分析

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...

  9. .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...

随机推荐

  1. rest framework-分页-长期维护

    ###############  分页组件   ############### # 分页组件 # # django也有分页,rest framework也有分页,但是没有页面这个概念了, # 这个分页 ...

  2. vue2.0学习之动画

    下载animate.css <transition name="v"> <div class="content">需要做动画的内容< ...

  3. KVC解析

    •  阅读  valueForKey (总体规划,先找相关方法,再找相关变量) 1.先是找相关方法,如果方法找不到 2.那么去判断 1 2 3 + (BOOL)accessInstanceVariab ...

  4. Offer垂青于有准备的人——微软亚洲研究院实习生们的就业分享

    编者按:一年一度的"求职大战"又拉开了序幕,如何在求职中掌握主动,更好地展现自己,最后抓住Offer?且听微软亚洲研究院三位实习生慢慢道来,Offer总会垂青于有准备的人. 廖振, ...

  5. 在CentOS安装CMake (CentOS7 64位适用)

    在CentOS安装CMake 转自:http://www.cnblogs.com/mophee/archive/2013/03/19/2969456.html 一.环境描述 1.系统:CentOS 6 ...

  6. java中的锁——列队同步器

    队列同步器 队列同步器(AbstractQueuedSynchronizer)为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量.事件,等等)提供一个框架.此类的设计目标是成为依 ...

  7. jenkins配置搭建环境

    1.安装及运行 (1)下载 http://updates.jenkins-ci.org/latest/jenkins.war (2)运行 两种运行方式:一种是基于tomcat.Jdk启动,一种是基于D ...

  8. SpringMVC学习笔记五:HandlerExceptionResolver异常处理

    继承HandlerExceptionResolver自定义异常处理器 控制器ExceptionController.java package com.orange.controller; import ...

  9. haproxy笔记之六:负载均衡MySQL服务的配置示例

    #--------------------------------------------------------------------- # Global settings #---------- ...

  10. 省A类竞赛二等奖--村先游项目VUE前端重构

    村先游--省二竞赛项目VUE重构 源码地址: 重构前的(前端+后台):https://github.com/Archer-Fang/cunxianyou 重构前的(前端):https://github ...