G-CAMS-DATU/packages/agile_modbus-v1.1.2/doc/doxygen/output/index.html
2024-05-13 16:08:47 +08:00

394 lines
41 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.2"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Agile Modbus: Agile Modbus</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Agile Modbus<span id="projectnumber">&#160;1.1.2</span>
</div>
<div id="projectbrief">Lightweight modbus protocol stack.</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- 制作者 Doxygen 1.9.2 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search",'搜索','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
initMenu('',true,false,'search.php','搜索');
$(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('index.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">Agile Modbus </div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p ><a class="anchor" id="md_C__Users_25440_Desktop_stm32f407_atk_explorer_packages_agile_modbus_README"></a> </p>
<h1><a class="anchor" id="autotoc_md18"></a>
1、介绍</h1>
<p >Agile Modbus 即:轻量型 modbus 协议栈,满足用户任何场景下的使用需求。</p>
<p ><img src="./figures/ModbusProtocol.jpg" alt="ModbusProtocol" class="inline"/></p>
<ul>
<li><code>examples</code> 文件夹提供 PC 上的示例</li>
<li>MCU 上的示例查看 <a href="https://github.com/loogg/agile_modbus_mcu_demos">mcu_demos</a></li>
<li>在 AT32F437 上基于 RT-Thread 实现的支持 Modbus 固件升级的 Bootloader<a href="https://github.com/loogg/AT32F437_Boot">AT32F437_Boot</a></li>
<li>在 HPM6750 上基于 RT-Thread 实现的支持 Modbus 固件升级的 Bootloader<a href="https://github.com/loogg/HPM6750_Boot">HPM6750_Boot</a></li>
</ul>
<h2><a class="anchor" id="autotoc_md19"></a>
1.1、特性</h2>
<ol type="1">
<li>支持 rtu 及 tcp 协议,使用纯 C 开发,不涉及任何硬件接口,可在任何形式的硬件上直接使用。</li>
<li>由于其使用纯 C 开发、不涉及硬件,完全可以在串口上跑 tcp 协议,在网络上跑 rtu 协议。</li>
<li>支持符合 modbus 格式的自定义协议。</li>
<li>同时支持多主机和多从机。</li>
<li>使用简单,只需要将 rtu 或 tcp 句柄初始化好后,调用相应 API 进行组包和解包即可。</li>
</ol>
<h2><a class="anchor" id="autotoc_md20"></a>
1.2、目录结构</h2>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">名称 </th><th class="markdownTableHeadNone">说明 </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">doc </td><td class="markdownTableBodyNone">文档 </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">examples </td><td class="markdownTableBodyNone">例子 </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">figures </td><td class="markdownTableBodyNone">素材 </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">inc </td><td class="markdownTableBodyNone">头文件 </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">src </td><td class="markdownTableBodyNone">源代码 </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">util </td><td class="markdownTableBodyNone">提供简单实用的组件 </td></tr>
</table>
<h2><a class="anchor" id="autotoc_md21"></a>
1.3、许可证</h2>
<p >Agile Modbus 遵循 <code>Apache-2.0</code> 许可,详见 <code>LICENSE</code> 文件。</p>
<h1><a class="anchor" id="autotoc_md22"></a>
2、使用 Agile Modbus</h1>
<p >帮助文档请查看 <a href="./doc/doxygen/Agile_Modbus.chm">doc/doxygen/Agile_Modbus.chm</a></p>
<h2><a class="anchor" id="autotoc_md23"></a>
2.1、移植</h2>
<ul>
<li><p class="startli">用户需要实现硬件接口的 <code>发送数据</code><code>等待数据接收结束</code><code>清空接收缓存</code> 函数</p>
<p class="startli">对于 <code>等待数据接收结束</code>,提供如下几点思路:</p><ol type="1">
<li><p class="startli">通用方法</p>
<p class="startli">每隔 20 / 50 ms (该时间可根据波特率和硬件设置,这里只是给了参考值) 从硬件接口读取数据存放到缓冲区中并更新偏移,直到读取不到或缓冲区满,退出读取。</p>
<p class="startli">这对于裸机或操作系统都适用,操作系统可通过 <code>select</code><code>信号量</code> 方式完成阻塞。</p>
</li>
<li><p class="startli">串口 <code>DMA + IDLE</code> 中断方式</p>
<p class="startli">配置 <code>DMA + IDLE</code> 中断,在中断中使能标志,应用程序中判断该标志是否置位即可。</p>
<p class="startli">但该方案容易出问题,数据字节间稍微错开一点时间就不是一帧了。推荐第一种方案。</p>
</li>
</ol>
</li>
<li>主机:<ol type="1">
<li><code>agile_modbus_rtu_init</code> / <code>agile_modbus_tcp_init</code> 初始化 <code>RTU/TCP</code> 环境</li>
<li><code>agile_modbus_set_slave</code> 设置从机地址</li>
<li><code>清空接收缓存</code></li>
<li><code>agile_modbus_serialize_xxx</code> 打包请求数据</li>
<li><code>发送数据</code></li>
<li><code>等待数据接收结束</code></li>
<li><code>agile_modbus_deserialize_xxx</code> 解析响应数据</li>
<li>用户处理得到的数据</li>
</ol>
</li>
<li>从机:<ol type="1">
<li>实现 <code>agile_modbus_slave_callback_t</code> 类型回调函数</li>
<li><code>agile_modbus_rtu_init</code> / <code>agile_modbus_tcp_init</code> 初始化 <code>RTU/TCP</code> 环境</li>
<li><code>agile_modbus_set_slave</code> 设置从机地址</li>
<li><code>等待数据接收结束</code></li>
<li><code>agile_modbus_slave_handle</code> 处理请求数据</li>
<li><code>清空接收缓存</code> (可选)</li>
<li><code>发送数据</code></li>
</ol>
</li>
<li><p class="startli">特殊功能码</p>
<p class="startli">需要调用 <code>agile_modbus_set_compute_meta_length_after_function_cb</code><code>agile_modbus_set_compute_data_length_after_meta_cb</code> API 设置特殊功能码在主从模式下处理的回调。</p><ul>
<li><p class="startli"><code>agile_modbus_set_compute_meta_length_after_function_cb</code></p>
<p class="startli"><code>msg_type == AGILE_MODBUS_MSG_INDICATION</code>: 返回主机请求报文的数据元长度(uint8_t 类型),不是特殊功能码必须返回 0。</p>
<p class="startli"><code>msg_type == MSG_CONFIRMATION</code>: 返回从机响应报文的数据元长度(uint8_t 类型),不是特殊功能码必须返回 1。</p>
</li>
<li><p class="startli"><code>agile_modbus_set_compute_data_length_after_meta_cb</code></p>
<p class="startli"><code>msg_type == AGILE_MODBUS_MSG_INDICATION</code>: 返回主机请求报文数据元之后的数据长度,不是特殊功能码必须返回 0。</p>
<p class="startli"><code>msg_type == MSG_CONFIRMATION</code>: 返回从机响应报文数据元之后的数据长度,不是特殊功能码必须返回 0。</p>
</li>
</ul>
</li>
<li><p class="startli"><code>agile_modbus_rtu_init</code> / <code>agile_modbus_tcp_init</code></p>
<p class="startli">初始化 <code>RTU/TCP</code> 环境时需要用户传入 <code>发送缓冲区</code><code>接收缓冲区</code>,建议这两个缓冲区大小都为 <code>AGILE_MODBUS_MAX_ADU_LENGTH</code> (260) 字节。<code>特殊功能码</code> 情况用户根据协议自行决定。</p>
<p class="startli">但对于小内存 MCU这两个缓冲区也可以设置小所有 API 都会对缓冲区大小进行判断:</p>
<p class="startli">发送缓冲区设置:如果 <code>预期请求的数据长度</code><code>预期响应的数据长度</code> 大于 <code>设置的发送缓冲区大小</code>,返回异常。</p>
<p class="startli">接收缓冲区设置:如果 <code>主机请求的报文长度</code> 大于 <code>设置的接收缓冲区大小</code>,返回异常。这个是合理的,小内存 MCU 做从机肯定是需要对某些功能码做限制的。</p>
</li>
</ul>
<h2><a class="anchor" id="autotoc_md24"></a>
2.2、主机</h2>
<p ><code>2.1、移植</code></p>
<h2><a class="anchor" id="autotoc_md25"></a>
2.3、从机</h2>
<h3><a class="anchor" id="autotoc_md26"></a>
2.3.1、接口说明</h3>
<ul>
<li><p class="startli"><code>agile_modbus_slave_handle</code> 介绍</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> <a class="code hl_function" href="group___slave___operation___functions.html#ga9ddc38e7ac14384c02b07b8927165247">agile_modbus_slave_handle</a>(<a class="code hl_struct" href="structagile__modbus.html">agile_modbus_t</a> *ctx, <span class="keywordtype">int</span> msg_length, uint8_t slave_strict,</div>
<div class="line"> <a class="code hl_typedef" href="group___slave___exported___types.html#gae66e6077fe07d589d91121ac8874541a">agile_modbus_slave_callback_t</a> slave_cb, <span class="keyword">const</span> <span class="keywordtype">void</span> *slave_data, <span class="keywordtype">int</span> *frame_length)</div>
<div class="ttc" id="agroup___slave___exported___types_html_gae66e6077fe07d589d91121ac8874541a"><div class="ttname"><a href="group___slave___exported___types.html#gae66e6077fe07d589d91121ac8874541a">agile_modbus_slave_callback_t</a></div><div class="ttdeci">int(* agile_modbus_slave_callback_t)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)</div><div class="ttdoc">从机回调函数</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus_8h_source.html#l00251">agile_modbus.h:251</a></div></div>
<div class="ttc" id="agroup___slave___operation___functions_html_ga9ddc38e7ac14384c02b07b8927165247"><div class="ttname"><a href="group___slave___operation___functions.html#ga9ddc38e7ac14384c02b07b8927165247">agile_modbus_slave_handle</a></div><div class="ttdeci">int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict, agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length)</div><div class="ttdoc">从机数据处理</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus_8c_source.html#l01203">agile_modbus.c:1203</a></div></div>
<div class="ttc" id="astructagile__modbus_html"><div class="ttname"><a href="structagile__modbus.html">agile_modbus</a></div><div class="ttdoc">Agile Modbus 结构体</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus_8h_source.html#l00203">agile_modbus.h:203</a></div></div>
</div><!-- fragment --><p class="startli">msg_length: <code>等待数据接收结束</code> 后接收到的数据长度。</p>
<p class="startli">slave_strict: 从机地址严格性检查 (0: 不判断地址是否一致,由用户回调处理; 1: 地址必须一致,否则不会调用回调,也不打包响应数据)。</p>
<p class="startli">slave_cb: <code>agile_modbus_slave_callback_t</code> 类型回调函数,用户实现并传入。如果为 NULL所有功能码都能响应且为成功但寄存器数据依然为 0。</p>
<p class="startli">slave_data: 从机回调函数私有数据。</p>
<p class="startli">frame_length: 获取解析出的 modbus 数据帧长度。这个参数的意义在于:</p><ol type="1">
<li>尾部有脏数据: 仍能解析成功,并告诉用户真实的 modbus 帧长,用户可以进行处理</li>
<li>数据粘包: 数据由 <code>一帧完整的 modbus 数据 + 部分 modbus 数据帧</code> 组成,用户获得真实 modbus 帧长后,可以移除处理完的 modbus 数据帧,再次读取硬件接口数据与当前 <code>部分 modbus 数据帧</code> 组成新的一帧</li>
<li>该参数在 modbus 广播传输大数据时使用较多(如:自定义功能码广播升级固件),普通的从机响应都是一问一答式,只处理完整数据帧就行,建议在响应前执行 <code>清空接收缓存</code></li>
</ol>
</li>
<li><p class="startli"><code>agile_modbus_slave_callback_t</code> 介绍</p>
<div class="fragment"><div class="line"> </div>
<div class="line"><span class="keyword">typedef</span> int (*<a class="code hl_typedef" href="group___slave___exported___types.html#gae66e6077fe07d589d91121ac8874541a">agile_modbus_slave_callback_t</a>)(<a class="code hl_struct" href="structagile__modbus.html">agile_modbus_t</a> *ctx, <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__info.html">agile_modbus_slave_info</a> *slave_info, <span class="keyword">const</span> <span class="keywordtype">void</span> *data);</div>
<div class="ttc" id="astructagile__modbus__slave__info_html"><div class="ttname"><a href="structagile__modbus__slave__info.html">agile_modbus_slave_info</a></div><div class="ttdoc">Agile Modbus 从机信息结构体</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus_8h_source.html#l00232">agile_modbus.h:232</a></div></div>
</div><!-- fragment --><p class="startli"><code><a class="el" href="structagile__modbus__slave__info.html" title="Agile Modbus 从机信息结构体">agile_modbus_slave_info</a></code>:</p>
<p class="startli">sft: 包含从机地址和功能码属性,回调中可利用</p>
<p class="startli">rsp_length: 响应数据长度指针,回调中处理 <code>特殊功能码</code> 时需要更新其值,否则 <b>不准更改</b></p>
<p class="startli">address: 寄存器地址 (不是所有功能码都用到)</p>
<p class="startli">nb: 数目 (不是所有功能码都用到)</p>
<p class="startli">buf: 不同功能码需要使用的数据域 (不是所有功能码都用到)</p>
<p class="startli">send_index: 发送缓冲区当前索引 (不是所有功能码都用到)</p>
</li>
<li><code><a class="el" href="structagile__modbus__slave__info.html" title="Agile Modbus 从机信息结构体">agile_modbus_slave_info</a></code> 不同功能码使用<ul>
<li><p class="startli">AGILE_MODBUS_FC_READ_COILS、AGILE_MODBUS_FC_READ_DISCRETE_INPUTS</p>
<p class="startli">需要使用到 <code>address</code><code>nb</code><code>send_index</code> 属性,需要调用 <code>agile_modbus_slave_io_set</code> API 将 IO 数据存放到 <code>ctx-&gt;send_buf + send_index</code> 开始的数据区域。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_READ_HOLDING_REGISTERS、AGILE_MODBUS_FC_READ_INPUT_REGISTERS</p>
<p class="startli">需要使用到 <code>address</code><code>nb</code><code>send_index</code> 属性,需要调用 <code>agile_modbus_slave_register_set</code> API 将寄存器数据存放到 <code>ctx-&gt;send_buf + send_index</code> 开始的数据区域。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_WRITE_SINGLE_COIL、AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER</p>
<p class="startli">需要使用到 <code>address</code><code>buf</code> 属性,将 <code>buf</code> 强转为 <code>int *</code> 类型,获取值存放到寄存器中。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS</p>
<p class="startli">需要使用到 <code>address</code><code>nb</code><code>buf</code> 属性,需要调用 <code>agile_modbus_slave_io_get</code> API 获取要写入的 IO 数据。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS</p>
<p class="startli">需要使用到 <code>address</code><code>nb</code><code>buf</code> 属性,需要调用 <code>agile_modbus_slave_register_get</code> API 获取要写入的寄存器数据。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_MASK_WRITE_REGISTER</p>
<p class="startli">需要使用到 <code>address</code><code>buf</code> 属性,通过 <code>(buf[0] &lt;&lt; 8) + buf[1]</code> 获取 <code>and</code> 值,通过 <code>(buf[2] &lt;&lt; 8) + buf[3]</code> 获取 <code>or</code> 值。获取寄存器值 <code>data</code>,进行 <code>data = (data &amp; and) | (or &amp; (~and))</code> 操作更新 <code>data</code> 值,写入寄存器。</p>
</li>
<li><p class="startli">AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS</p>
<p class="startli">需要使用到 <code>address</code><code>buf</code><code>send_index</code> 属性,通过 <code>(buf[0] &lt;&lt; 8) + buf[1]</code> 获取要读取的寄存器数目,通过 <code>(buf[2] &lt;&lt; 8) + buf[3]</code> 获取要写入的寄存器地址,通过 <code>(buf[4] &lt;&lt; 8) + buf[5]</code> 获取要写入的寄存器数目。需要调用 <code>agile_modbus_slave_register_get</code> API 获取要写入的寄存器数据,调用 <code>agile_modbus_slave_register_set</code> API 将寄存器数据存放到 <code>ctx-&gt;send_buf + send_index</code> 开始的数据区域。</p>
</li>
<li><p class="startli">自定义功能码</p>
<p class="startli">需要使用到 <code>send_index</code><code>nb</code><code>buf</code> 属性,用户在回调中处理数据。</p>
<p class="startli">send_index: 发送缓冲区当前索引</p>
<p class="startli">nb: PUD - 1也就是 modbus 数据域长度</p>
<p class="startli">buf: modbus 数据域起始位置</p>
<p class="startli"><b>注意</b>: 用户在回调中往发送缓冲区填入数据后,需要更新 <code><a class="el" href="structagile__modbus__slave__info.html" title="Agile Modbus 从机信息结构体">agile_modbus_slave_info</a></code><code>rsp_length</code> 值。</p>
</li>
</ul>
</li>
</ul>
<h3><a class="anchor" id="autotoc_md27"></a>
2.3.2、简易从机接入接口</h3>
<p >Agile Modbus 提供了 <code>agile_modbus_slave_callback_t</code> 的一种实现方式,使用户能够简单方便接入。</p>
<p >使用示例可查看 <a href="./examples/slave">examples/slave</a></p>
<p >使用方式:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="agile__modbus_8h.html">agile_modbus.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;<a class="code" href="agile__modbus__slave__util_8h.html">agile_modbus_slave_util.h</a>&quot;</span></div>
<div class="line"> </div>
<div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structagile__modbus__slave__util.html">agile_modbus_slave_util_t</a> slave_util = {</div>
<div class="line"> <span class="comment">/* User implementation */</span></div>
<div class="line"> </div>
<div class="line">};</div>
<div class="line"> </div>
<div class="line"><a class="code hl_function" href="group___slave___operation___functions.html#ga9ddc38e7ac14384c02b07b8927165247">agile_modbus_slave_handle</a>(ctx, read_len, 0, <a class="code hl_function" href="group___s_l_a_v_e___u_t_i_l___exported___functions.html#ga6d7613fbda26c40a969df673cf9b8c5b">agile_modbus_slave_util_callback</a>, &amp;slave_util, NULL);</div>
<div class="ttc" id="aagile__modbus_8h_html"><div class="ttname"><a href="agile__modbus_8h.html">agile_modbus.h</a></div><div class="ttdoc">Agile Modbus 软件包通用头文件</div></div>
<div class="ttc" id="aagile__modbus__slave__util_8h_html"><div class="ttname"><a href="agile__modbus__slave__util_8h.html">agile_modbus_slave_util.h</a></div><div class="ttdoc">Agile Modbus 软件包提供的简易从机接入头文件</div></div>
<div class="ttc" id="agroup___s_l_a_v_e___u_t_i_l___exported___functions_html_ga6d7613fbda26c40a969df673cf9b8c5b"><div class="ttname"><a href="group___s_l_a_v_e___u_t_i_l___exported___functions.html#ga6d7613fbda26c40a969df673cf9b8c5b">agile_modbus_slave_util_callback</a></div><div class="ttdeci">int agile_modbus_slave_util_callback(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)</div><div class="ttdoc">从机回调函数</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8c_source.html#l00387">agile_modbus_slave_util.c:387</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html"><div class="ttname"><a href="structagile__modbus__slave__util.html">agile_modbus_slave_util</a></div><div class="ttdoc">从机功能结构体</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00048">agile_modbus_slave_util.h:48</a></div></div>
</div><!-- fragment --><ul>
<li><code>agile_modbus_slave_util_callback</code> 介绍<ul>
<li>Agile Modbus 提供的一种 <code>agile_modbus_slave_callback_t</code> 实现方式,需要 <code>agile_modbus_slave_util_t</code> 类型变量指针作为私有数据。</li>
<li>私有数据为 NULL所有功能码都能响应且为成功但寄存器数据依然为 0。</li>
</ul>
</li>
<li><p class="startli"><code>agile_modbus_slave_util_t</code> 介绍</p>
<div class="fragment"><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__util.html">agile_modbus_slave_util</a> {</div>
<div class="line"> <span class="keyword">const</span> <a class="code hl_struct" href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map_t</a> *<a class="code hl_variable" href="structagile__modbus__slave__util.html#adf60d2aacae135df7fb77f1fd567a0f3">tab_bits</a>; </div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util.html#a54d8cd5ea2ece03fc4748f857d433470">nb_bits</a>; </div>
<div class="line"> <span class="keyword">const</span> <a class="code hl_struct" href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map_t</a> *<a class="code hl_variable" href="structagile__modbus__slave__util.html#ab8dd5a6fa6cb534aa90460cf9a71ae6f">tab_input_bits</a>; </div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util.html#a81fb44a47ea6e8dc7eb190b87ddb6dc4">nb_input_bits</a>; </div>
<div class="line"> <span class="keyword">const</span> <a class="code hl_struct" href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map_t</a> *<a class="code hl_variable" href="structagile__modbus__slave__util.html#ae21eece6d89b5d46839496e9281108f8">tab_registers</a>; </div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util.html#ac7c7bd2cc1687ae7c291a054d3071114">nb_registers</a>; </div>
<div class="line"> <span class="keyword">const</span> <a class="code hl_struct" href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map_t</a> *<a class="code hl_variable" href="structagile__modbus__slave__util.html#a67c8df610dcb3f8dee4d32ed920f4886">tab_input_registers</a>; </div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util.html#a3c2c64bb74a0cab7f34f303fa3a37b31">nb_input_registers</a>; </div>
<div class="line"> int (*<a class="code hl_variable" href="structagile__modbus__slave__util.html#a134270ba34165c677e85490b2bb6719c">addr_check</a>)(<a class="code hl_struct" href="structagile__modbus.html">agile_modbus_t</a> *ctx, <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__info.html">agile_modbus_slave_info</a> *slave_info); </div>
<div class="line"> int (*<a class="code hl_variable" href="structagile__modbus__slave__util.html#a70de0b2f19492b188c99ba332e2b2ffa">special_function</a>)(<a class="code hl_struct" href="structagile__modbus.html">agile_modbus_t</a> *ctx, <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__info.html">agile_modbus_slave_info</a> *slave_info); </div>
<div class="line"> int (*<a class="code hl_variable" href="structagile__modbus__slave__util.html#abc6323db9d3873c30bee0e7efe96f4b8">done</a>)(<a class="code hl_struct" href="structagile__modbus.html">agile_modbus_t</a> *ctx, <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__info.html">agile_modbus_slave_info</a> *slave_info, <span class="keywordtype">int</span> ret); </div>
<div class="line">} <a class="code hl_typedef" href="group___s_l_a_v_e___u_t_i_l___exported___types.html#ga48cf733bea0cf7ad09b52b139348de50">agile_modbus_slave_util_t</a>;</div>
<div class="ttc" id="agroup___s_l_a_v_e___u_t_i_l___exported___types_html_ga48cf733bea0cf7ad09b52b139348de50"><div class="ttname"><a href="group___s_l_a_v_e___u_t_i_l___exported___types.html#ga48cf733bea0cf7ad09b52b139348de50">agile_modbus_slave_util_t</a></div><div class="ttdeci">struct agile_modbus_slave_util agile_modbus_slave_util_t</div><div class="ttdoc">从机功能结构体</div></div>
<div class="ttc" id="astructagile__modbus__slave__util__map_html"><div class="ttname"><a href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map</a></div><div class="ttdoc">从机寄存器映射结构体</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00038">agile_modbus_slave_util.h:38</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a134270ba34165c677e85490b2bb6719c"><div class="ttname"><a href="structagile__modbus__slave__util.html#a134270ba34165c677e85490b2bb6719c">agile_modbus_slave_util::addr_check</a></div><div class="ttdeci">int(* addr_check)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info)</div><div class="ttdoc">地址检查接口</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00057">agile_modbus_slave_util.h:57</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a3c2c64bb74a0cab7f34f303fa3a37b31"><div class="ttname"><a href="structagile__modbus__slave__util.html#a3c2c64bb74a0cab7f34f303fa3a37b31">agile_modbus_slave_util::nb_input_registers</a></div><div class="ttdeci">int nb_input_registers</div><div class="ttdoc">输入寄存器定义数组数目</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00056">agile_modbus_slave_util.h:56</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a54d8cd5ea2ece03fc4748f857d433470"><div class="ttname"><a href="structagile__modbus__slave__util.html#a54d8cd5ea2ece03fc4748f857d433470">agile_modbus_slave_util::nb_bits</a></div><div class="ttdeci">int nb_bits</div><div class="ttdoc">线圈寄存器定义数组数目</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00050">agile_modbus_slave_util.h:50</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a67c8df610dcb3f8dee4d32ed920f4886"><div class="ttname"><a href="structagile__modbus__slave__util.html#a67c8df610dcb3f8dee4d32ed920f4886">agile_modbus_slave_util::tab_input_registers</a></div><div class="ttdeci">const agile_modbus_slave_util_map_t * tab_input_registers</div><div class="ttdoc">输入寄存器定义数组</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00055">agile_modbus_slave_util.h:55</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a70de0b2f19492b188c99ba332e2b2ffa"><div class="ttname"><a href="structagile__modbus__slave__util.html#a70de0b2f19492b188c99ba332e2b2ffa">agile_modbus_slave_util::special_function</a></div><div class="ttdeci">int(* special_function)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info)</div><div class="ttdoc">特殊功能码处理接口</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00058">agile_modbus_slave_util.h:58</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_a81fb44a47ea6e8dc7eb190b87ddb6dc4"><div class="ttname"><a href="structagile__modbus__slave__util.html#a81fb44a47ea6e8dc7eb190b87ddb6dc4">agile_modbus_slave_util::nb_input_bits</a></div><div class="ttdeci">int nb_input_bits</div><div class="ttdoc">离散量输入寄存器定义数组数目</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00052">agile_modbus_slave_util.h:52</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_ab8dd5a6fa6cb534aa90460cf9a71ae6f"><div class="ttname"><a href="structagile__modbus__slave__util.html#ab8dd5a6fa6cb534aa90460cf9a71ae6f">agile_modbus_slave_util::tab_input_bits</a></div><div class="ttdeci">const agile_modbus_slave_util_map_t * tab_input_bits</div><div class="ttdoc">离散量输入寄存器定义数组</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00051">agile_modbus_slave_util.h:51</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_abc6323db9d3873c30bee0e7efe96f4b8"><div class="ttname"><a href="structagile__modbus__slave__util.html#abc6323db9d3873c30bee0e7efe96f4b8">agile_modbus_slave_util::done</a></div><div class="ttdeci">int(* done)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, int ret)</div><div class="ttdoc">处理结束接口</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00059">agile_modbus_slave_util.h:59</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_ac7c7bd2cc1687ae7c291a054d3071114"><div class="ttname"><a href="structagile__modbus__slave__util.html#ac7c7bd2cc1687ae7c291a054d3071114">agile_modbus_slave_util::nb_registers</a></div><div class="ttdeci">int nb_registers</div><div class="ttdoc">保持寄存器定义数组数目</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00054">agile_modbus_slave_util.h:54</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_adf60d2aacae135df7fb77f1fd567a0f3"><div class="ttname"><a href="structagile__modbus__slave__util.html#adf60d2aacae135df7fb77f1fd567a0f3">agile_modbus_slave_util::tab_bits</a></div><div class="ttdeci">const agile_modbus_slave_util_map_t * tab_bits</div><div class="ttdoc">线圈寄存器定义数组</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00049">agile_modbus_slave_util.h:49</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util_html_ae21eece6d89b5d46839496e9281108f8"><div class="ttname"><a href="structagile__modbus__slave__util.html#ae21eece6d89b5d46839496e9281108f8">agile_modbus_slave_util::tab_registers</a></div><div class="ttdeci">const agile_modbus_slave_util_map_t * tab_registers</div><div class="ttdoc">保持寄存器定义数组</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00053">agile_modbus_slave_util.h:53</a></div></div>
</div><!-- fragment --><ul>
<li><p class="startli">寄存器相关</p>
<p class="startli">用户需要实现 <code>bits</code><code>input_bits</code><code>registers</code><code>input_registers</code> 定义。如果某个寄存器定义为 NULL该寄存器对应的功能码能响应且为成功但寄存器数据都为 0。</p>
</li>
<li><p class="startli">接口调用过程</p>
<p class="startli"><img src="./figures/SlaveCallback.jpg" alt="SlaveCallback" class="inline"/></p>
</li>
</ul>
</li>
<li><p class="startli"><code><a class="el" href="structagile__modbus__slave__util__map.html" title="从机寄存器映射结构体">agile_modbus_slave_util_map</a></code> 介绍</p>
<div class="fragment"><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct </span><a class="code hl_struct" href="structagile__modbus__slave__util__map.html">agile_modbus_slave_util_map</a> {</div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util__map.html#a9b130b4a875dca0d63c31d81fbc8b0f1">start_addr</a>; </div>
<div class="line"> <span class="keywordtype">int</span> <a class="code hl_variable" href="structagile__modbus__slave__util__map.html#ace624a13ffd6380963e9173d6f8f4eb9">end_addr</a>; </div>
<div class="line"> int (*<a class="code hl_variable" href="structagile__modbus__slave__util__map.html#a7fd43329330824f98bdd5da3e8b8f170">get</a>)(<span class="keywordtype">void</span> *buf, <span class="keywordtype">int</span> bufsz); </div>
<div class="line"> int (*<a class="code hl_variable" href="structagile__modbus__slave__util__map.html#aeb703aff86edfb371edb56e0122d51ab">set</a>)(<span class="keywordtype">int</span> index, <span class="keywordtype">int</span> len, <span class="keywordtype">void</span> *buf, <span class="keywordtype">int</span> bufsz); </div>
<div class="line">} <a class="code hl_typedef" href="group___s_l_a_v_e___u_t_i_l___exported___types.html#ga704dafcb7fb13e228bfbf8744dd5a3f8">agile_modbus_slave_util_map_t</a>;</div>
<div class="ttc" id="agroup___s_l_a_v_e___u_t_i_l___exported___types_html_ga704dafcb7fb13e228bfbf8744dd5a3f8"><div class="ttname"><a href="group___s_l_a_v_e___u_t_i_l___exported___types.html#ga704dafcb7fb13e228bfbf8744dd5a3f8">agile_modbus_slave_util_map_t</a></div><div class="ttdeci">struct agile_modbus_slave_util_map agile_modbus_slave_util_map_t</div><div class="ttdoc">从机寄存器映射结构体</div></div>
<div class="ttc" id="astructagile__modbus__slave__util__map_html_a7fd43329330824f98bdd5da3e8b8f170"><div class="ttname"><a href="structagile__modbus__slave__util__map.html#a7fd43329330824f98bdd5da3e8b8f170">agile_modbus_slave_util_map::get</a></div><div class="ttdeci">int(* get)(void *buf, int bufsz)</div><div class="ttdoc">获取寄存器数据接口</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00041">agile_modbus_slave_util.h:41</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util__map_html_a9b130b4a875dca0d63c31d81fbc8b0f1"><div class="ttname"><a href="structagile__modbus__slave__util__map.html#a9b130b4a875dca0d63c31d81fbc8b0f1">agile_modbus_slave_util_map::start_addr</a></div><div class="ttdeci">int start_addr</div><div class="ttdoc">起始地址</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00039">agile_modbus_slave_util.h:39</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util__map_html_ace624a13ffd6380963e9173d6f8f4eb9"><div class="ttname"><a href="structagile__modbus__slave__util__map.html#ace624a13ffd6380963e9173d6f8f4eb9">agile_modbus_slave_util_map::end_addr</a></div><div class="ttdeci">int end_addr</div><div class="ttdoc">结束地址</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00040">agile_modbus_slave_util.h:40</a></div></div>
<div class="ttc" id="astructagile__modbus__slave__util__map_html_aeb703aff86edfb371edb56e0122d51ab"><div class="ttname"><a href="structagile__modbus__slave__util__map.html#aeb703aff86edfb371edb56e0122d51ab">agile_modbus_slave_util_map::set</a></div><div class="ttdeci">int(* set)(int index, int len, void *buf, int bufsz)</div><div class="ttdoc">设置寄存器数据接口</div><div class="ttdef"><b>Definition:</b> <a href="agile__modbus__slave__util_8h_source.html#l00042">agile_modbus_slave_util.h:42</a></div></div>
</div><!-- fragment --><ul>
<li><b>注意事项</b>:<ul>
<li>起始地址和结束地址决定的寄存器个数有限制。更改函数内部 <code>map_buf</code> 数组大小可使其变大。<ul>
<li>bit 寄存器 &lt; 250</li>
<li>register 寄存器 &lt; 125</li>
</ul>
</li>
<li>接口函数为 NULL寄存器对应的功能码能响应且为成功。</li>
</ul>
</li>
<li><p class="startli"><code>get</code> 接口</p>
<p class="startli">将地址域内的数据全部拷贝到 <code>buf</code> 中。</p>
</li>
<li><p class="startli"><code>set</code> 接口</p><ul>
<li><code>index</code>: 地址域内的偏移</li>
<li><code>len</code>: 长度</li>
</ul>
<p class="startli">根据 <code>index</code><code>len</code> 修改数据。</p>
</li>
</ul>
</li>
</ul>
<h2><a class="anchor" id="autotoc_md28"></a>
2.4、示例</h2>
<ul>
<li><a href="./examples">examples</a> 文件夹中提供 PC 上的示例,可以在 <code>WSL</code><code>Linux</code> 下编译运行。<ul>
<li>RTU / TCP 主机、从机的示例</li>
<li><p class="startli">特殊功能码的示例</p>
<p class="startli">RTU 点对点传输文件: 演示特殊功能码的使用方式</p>
<p class="startli">RTU 广播传输文件: 演示 <code>agile_modbus_slave_handle</code><code>frame_length</code> 的用处</p>
</li>
</ul>
</li>
<li><a href="https://github.com/loogg/agile_modbus_mcu_demos">mcu_demos</a> 提供在 MCU 上的例子。</li>
<li><a href="https://github.com/loogg/AT32F437_Boot">AT32F437_Boot</a> 在 AT32F437 上基于 RT-Thread 实现的支持 Modbus 固件升级的 Bootloader。</li>
<li><a href="https://github.com/loogg/HPM6750_Boot">HPM6750_Boot</a> 在 HPM6750 上基于 RT-Thread 实现的支持 Modbus 固件升级的 Bootloader。</li>
</ul>
<h2><a class="anchor" id="autotoc_md29"></a>
2.5、Doxygen 文档生成</h2>
<ul>
<li>使用 <code>Doxywizard</code> 打开 <a href="./doc/doxygen/Doxyfile">Doxyfile</a> 运行,生成的文件在 <a href="./doc/doxygen/output">doxygen/output</a> 下。</li>
<li>需要更改 <code>Graphviz</code> 路径。</li>
<li><code>HTML</code> 生成未使用 <code>chm</code> 格式的,如果使能需要更改 <code>hhc.exe</code> 路径。</li>
</ul>
<h1><a class="anchor" id="autotoc_md30"></a>
3、支持</h1>
<p ><img src="./figures/zanshang.jpg" alt="zanshang" class="inline"/></p>
<p >如果 Agile Modbus 解决了你的问题,不妨扫描上面二维码请我 <b>喝杯咖啡</b> ~</p>
<h1><a class="anchor" id="autotoc_md31"></a>
4、联系方式 &amp; 感谢</h1>
<ul>
<li>维护:马龙伟</li>
<li>主页:<a href="https://github.com/loogg/agile_modbus">https://github.com/loogg/agile_modbus</a></li>
<li>邮箱:<a href="#" onclick="location.href='mai'+'lto:'+'254'+'40'+'472'+'13'+'@qq'+'.c'+'om'; return false;">25440<span style="display: none;">.nosp@m.</span>4721<span style="display: none;">.nosp@m.</span>3@qq.<span style="display: none;">.nosp@m.</span>com</a> </li>
</ul>
</div></div><!-- PageDoc -->
</div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">制作者 <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.2 </li>
</ul>
</div>
</body>
</html>