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

相关文章

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

深度解析Python yfinance的核心功能和高级用法

《深度解析Pythonyfinance的核心功能和高级用法》yfinance是一个功能强大且易于使用的Python库,用于从YahooFinance获取金融数据,本教程将深入探讨yfinance的核... 目录yfinance 深度解析教程 (python)1. 简介与安装1.1 什么是 yfinance?

Python脚本轻松实现检测麦克风功能

《Python脚本轻松实现检测麦克风功能》在进行音频处理或开发需要使用麦克风的应用程序时,确保麦克风功能正常是非常重要的,本文将介绍一个简单的Python脚本,能够帮助我们检测本地麦克风的功能,需要的... 目录轻松检测麦克风功能脚本介绍一、python环境准备二、代码解析三、使用方法四、知识扩展轻松检测麦

Java实现TXT文件导入功能的详细步骤

《Java实现TXT文件导入功能的详细步骤》在实际开发中,很多应用场景需要将用户上传的TXT文件进行解析,并将文件中的数据导入到数据库或其他存储系统中,本文将演示如何用Java实现一个基本的TXT文件... 目录前言1. 项目需求分析2. 示例文件格式3. 实现步骤3.1. 准备数据库(假设使用 mysql

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Springboot项目登录校验功能实现

《Springboot项目登录校验功能实现》本文介绍了Web登录校验的重要性,对比了Cookie、Session和JWT三种会话技术,分析其优缺点,并讲解了过滤器与拦截器的统一拦截方案,推荐使用JWT... 目录引言一、登录校验的基本概念二、HTTP协议的无状态性三、会话跟android踪技术1. Cook

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC