libmodbus源码分析(3)从机(服务端)功能源码分析

2023-10-10 05:40

本文主要是介绍libmodbus源码分析(3)从机(服务端)功能源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    在上一篇文章《libmodbus源码分析(2)主机(客户端)功能源码分析》 从 主机的角度 分析了 源码,本文以 从机(服务器)的角度分析一下源码。同样的,我们以 modbus rtu 协议的 4x区保持寄存器功能进行举例说明。

   我们简单的写一下 modbus rtu 下 响应客户端(主机)读4x 区保持寄存器的伪代码流程:

int main(void)
{modbus_t *ctx;modbus_mapping_t *mb_mapping;uint8_t *query;/* 创建并初始化 modbus_t 指针 */ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1);/* 设定本机设备地址 */modbus_set_slave(ctx, SERVER_ID);/* 用于接收主机消息的 缓存申请 */query = malloc(MODBUS_RTU_MAX_ADU_LENGTH);/* 0x、1x、3x、4x共4个区 寄存器的 缓存申请 */mb_mapping = modbus_mapping_new_start_address(UT_BITS_ADDRESS, UT_BITS_NB,UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX,UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB);/* 根据自己需要 填充 4个区 寄存器内容,这一部分可以在另外一个单独线程中,循环刷新寄存器值*/while(1){/* 等待接收主机读,直到 读到 指令,会阻塞*/do{rc = modbus_receive(ctx, query);}while(rc == 0);/* 根据接收到的主机 指令 query 内容,自动的回复 主机想要的 数据包 */rc = modbus_reply(ctx, query, rc, mb_mapping);}/* libmodbus 退出后,释放、关闭相关资源 */modbus_mapping_free(mb_mapping);free(query);/* For RTU */modbus_close(ctx);modbus_free(ctx);
}

     上述代码中,大部分都是很容易理解的,modbus_receive 函数就是在上一篇文章中已经进行了分析,这里就不再赘述了,它最终是调用 _modbus_receive_msg 函数, 它采用 select 接收机制,而且当作为 从机使用时, select 的超时时间设定为 空,

 if (msg_type == MSG_INDICATION) {/* Wait for a message, we don't know when the message will be* received */p_tv = NULL;}

  这就意味着该函数会“阻塞“等待接收,直到有数据可接收,所以在写程序的时候,需要注意,可以考虑在一个单独线程中使用。

 接下来,我们就分析一下 modbus_repley 函数的实现:

 

这里,我们再看看一下,libmodbus 是如何 知道主机要读那些寄存器,并且如何将主机想读的寄存器内容筛选打包的,源码如下:

case MODBUS_FC_READ_HOLDING_REGISTERS:case MODBUS_FC_READ_INPUT_REGISTERS: {/* 保持寄存器 or 输入寄存器判断 */unsigned int is_input = (function == MODBUS_FC_READ_INPUT_REGISTERS);/* modbus 寄存器区 首地址 获取 */int start_registers = is_input ? mb_mapping->start_input_registers : mb_mapping->start_registers;/* modbus 寄存器区 寄存器总数量,比如 4x区寄存器数量 */int nb_registers = is_input ? mb_mapping->nb_input_registers : mb_mapping->nb_registers;/* 对应区 寄存器 缓存 首地址 */uint16_t *tab_registers = is_input ? mb_mapping->tab_input_registers : mb_mapping->tab_registers;/* 调试,没用 */const char * const name = is_input ? "read_input_registers" : "read_registers";/* 筛选出 主机想要读的 寄存器 数量 */int nb = (req[offset + 3] << 8) + req[offset + 4];/* The mapping can be shifted to reduce memory consumption and itdoesn't always start at address zero. *//* 计算出 主机要读的 寄存器起始地址 在 modbus 寄存器缓存中的 偏移地址 */int mapping_address = address - start_registers;/* 主机发送命令中的 首地址、寄存器数量大小 合法性判断 */if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {rsp_length = response_exception(ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,"Illegal nb of values %d in %s (max %d)\n",nb, name, MODBUS_MAX_READ_REGISTERS);} else if (mapping_address < 0 || (mapping_address + nb) > nb_registers) {rsp_length = response_exception(ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,"Illegal data address 0x%0X in %s\n",mapping_address < 0 ? address : address + nb, name);} else {/* 根据前面的 计算,将对应区的寄存器 数据从 modbus 缓存 拷贝到 rsp(回复给主机的数* 据帧包) */int i;rsp_length = ctx->backend->build_response_basis(&sft, rsp);rsp[rsp_length++] = nb << 1;for (i = mapping_address; i < mapping_address + nb; i++) {rsp[rsp_length++] = tab_registers[i] >> 8;rsp[rsp_length++] = tab_registers[i] & 0xFF;}}}break;

 

 

这篇关于libmodbus源码分析(3)从机(服务端)功能源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/178349

相关文章

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

最好用的WPF加载动画功能

《最好用的WPF加载动画功能》当开发应用程序时,提供良好的用户体验(UX)是至关重要的,加载动画作为一种有效的沟通工具,它不仅能告知用户系统正在工作,还能够通过视觉上的吸引力来增强整体用户体验,本文给... 目录前言需求分析高级用法综合案例总结最后前言当开发应用程序时,提供良好的用户体验(UX)是至关重要

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步