3.14 ModbusClient 主站能力
概述
Arm::modbusClient 对应机器人作为 Modbus 主站时的串口参数管理、 从站会话创建、寄存器读写与串口透传能力。
当前 C++17 公开能力分成两层:
ModbusClient接口模块:负责GetSlave/GetParam/SetParammodbus_client::Slave会话:负责具体读写、串口收发和按会话取参
推荐调用路径
cpp
Arm arm; // 创建机器人会话对象
STATUS_CODE connectRet = arm.Connect("10.27.1.254", ""); // 连接控制器或路由地址
if (connectRet != STATUS_CODE::OK) { // 判断连接是否失败
return; // 连接失败时退出当前流程
} // 结束连接判断
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // 创建 Modbus 从站会话
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
1, // 指定从站 ID 为 1
0 // 指定 masterId 为 0
); // 结束从站会话创建调用
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // 判断会话是否创建成功且有效
return; // 会话不可用时退出当前流程
} // 结束会话判断
auto [values, readRet] = slave.ReadCoils(0, 2); // 从地址 0 开始读取 2 个线圈值
if (readRet != STATUS_CODE::OK) { // 判断读取是否失败
return; // 读取失败时退出当前流程
} // 结束读取判断接口总览
ModbusClient 接口模块
cpp
GetSlave(channel, slaveId, masterId) -> std::pair<modbus_client::Slave, STATUS_CODE>
GetParam(channel, masterId = 1) -> std::pair<modbus_client::SerialParams, STATUS_CODE>
SetParam(const modbus_client::SerialParams& params) -> std::pair<int32_t, STATUS_CODE>| 方法 | 输入 | 输出 | 关键行为 |
|---|---|---|---|
GetSlave | 通道、从站 ID、主站 ID | std::pair<modbus_client::Slave, STATUS_CODE> | 创建本地会话,后续读写时访问控制器 |
GetParam | 通道、主站 ID | std::pair<modbus_client::SerialParams, STATUS_CODE> | TCP_TO_485 通道按 masterId 查询 |
SetParam | 串口参数 | std::pair<int32_t, STATUS_CODE> | 返回控制器确认的参数记录 id |
modbus_client::Slave 会话
cpp
IsValid() const -> bool
ReadCoils(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteCoils(addr, values) -> STATUS_CODE
ReadHoldingRegs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteHoldingRegs(addr, values) -> STATUS_CODE
ReadDiscreteInputs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
ReadInputRegs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteInputRegs(addr, values) -> STATUS_CODE
GetParam() -> std::pair<modbus_client::SerialParams, STATUS_CODE>
SetParam(params) -> std::pair<int32_t, STATUS_CODE>
SerialSend(msg) -> STATUS_CODE
SerialReceive() -> std::pair<std::string, STATUS_CODE>| 方法 | 输入 | 输出 | 关键行为 |
|---|---|---|---|
IsValid | 无 | bool | 只检查会话是否仍绑定有效 Arm |
ReadCoils | 起始地址、数量 | std::pair<std::vector<int32_t>, STATUS_CODE> | 本地校验 1..120 和地址范围 |
WriteCoils | 起始地址、值列表 | STATUS_CODE | 本地校验写入数量 1..1024 |
ReadHoldingRegs | 起始地址、数量 | std::pair<std::vector<int32_t>, STATUS_CODE> | 行为同 ReadCoils |
WriteHoldingRegs | 起始地址、值列表 | STATUS_CODE | 行为同 WriteCoils |
ReadDiscreteInputs | 起始地址、数量 | std::pair<std::vector<int32_t>, STATUS_CODE> | 行为同 ReadCoils |
ReadInputRegs | 起始地址、数量 | std::pair<std::vector<int32_t>, STATUS_CODE> | 行为同 ReadCoils |
WriteInputRegs | 起始地址、值列表 | STATUS_CODE | 行为同 WriteCoils |
GetParam | 无 | std::pair<modbus_client::SerialParams, STATUS_CODE> | 沿用当前 Slave 保存的通道 / 主站上下文 |
SetParam | 串口参数 | std::pair<int32_t, STATUS_CODE> | 通过当前会话调用设置接口 |
SerialSend | 文本串口消息 | STATUS_CODE | 走按通道的串口透传协议 |
SerialReceive | 无 | std::pair<std::string, STATUS_CODE> | 返回透传收到的原始字符串 |
前置条件与生命周期
| 项 | 规则 |
|---|---|
| 连接前提 | 必须先 Arm::Connect() 成功,否则 ModbusClient 接口模块返回 NOT_CONNECTED |
GetSlave | 创建本地 Slave ;远端从站状态由后续读写结果体现 |
| 会话失效 | Arm::Disconnect() 后,已有 modbus_client::Slave 全部失效 |
IsValid | 只判断当前会话是否仍与有效 Arm 绑定;远端在线状态由读写结果体现 |
| 与总线配置冲突 | 调用方需要确认控制器上的总线配置是否冲突 |
参数校验与失败口径
| 场景 | 返回 |
|---|---|
modbus_client::Slave 会话失效 | INVALID_SESSION |
addr < 0 | INVALID_PARAMETER |
num < 1 或 num > 120 | INVALID_PARAMETER |
addr + num - 1 > 65535 | INVALID_PARAMETER |
values.size() < 1 或 values.size() > 1024 | INVALID_PARAMETER |
addr + values.size() - 1 > 65535 | INVALID_PARAMETER |
| 控制器返回非预期 JSON 结构 | OTHER_ERR |
额外说明:
- 读接口返回的
std::vector<int32_t>是控制器返回的原始整型数组,线圈值按控制器结果呈现。 - 写接口校验地址范围和数量;
values内容语义交由控制器处理。 SetParam()/GetParam()将波特率、端口等业务参数交由控制器判断是否合法。
详细语义
GetSlave
签名
cpp
std::pair<modbus_client::Slave, STATUS_CODE> GetSlave(
modbus_client::MODBUS_CHANNEL channel,
int32_t slaveId,
int32_t masterId
);| 输入 | 类型 | 说明 |
|---|---|---|
channel | modbus_client::MODBUS_CHANNEL | 通道枚举 |
slaveId | int32_t | 从站 ID;创建时直接记录到会话 |
masterId | int32_t | 主站 ID;后续读写请求会原样带上 |
| 输出 | 说明 |
|---|---|
modbus_client::Slave | 成功时返回可用会话;失败时返回默认构造的空会话 |
STATUS_CODE | OK / NOT_CONNECTED |
限制与行为
GetSlave()创建本地会话;远端从站状态由后续读写结果体现。slaveId/masterId按控制器语义传入。- 成功返回的
Slave依赖当前Arm生命周期,不能跨Disconnect()复用。
调用示例
cpp
auto [slave, ret] = arm.modbusClient.GetSlave( // 创建 Modbus 从站会话
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
7, // 指定从站 ID 为 7
0 // 指定 masterId 为 0
); // 结束从站会话创建调用
if (ret != STATUS_CODE::OK || !slave.IsValid()) { // 判断会话是否创建成功且仍然有效
return; // 会话不可用时退出当前流程
} // 结束会话判断GetParam
签名
cpp
std::pair<modbus_client::SerialParams, STATUS_CODE> GetParam(
modbus_client::MODBUS_CHANNEL channel,
int32_t masterId = 1
);| 输入 | 类型 | 说明 |
|---|---|---|
channel | modbus_client::MODBUS_CHANNEL | 要查询的通道 |
masterId | int32_t | 仅 CONTROLLER_TCP_TO_485 通道有实际意义;默认 1 |
| 输出 | 说明 |
|---|---|
modbus_client::SerialParams | 成功时返回参数;失败时返回默认构造值 |
STATUS_CODE | OK / NOT_CONNECTED / 其他控制器错误码 |
限制与行为
CONTROLLER_TCP_TO_485通道向控制器发送的是masterId。- 其他串口通道向控制器发送的是通道枚举值,
masterId被忽略。 - 这是对端协议既有口径,不是 SDK 自行定义的新规则。
调用示例
cpp
auto [params, ret] = arm.modbusClient.GetParam( // 查询 Modbus 串口参数
modbus_client::MODBUS_CHANNEL::CONTROLLER_TCP_TO_485, // 指定 TCP 转 485 通道
12 // 指定 masterId 为 12
); // 结束串口参数查询调用
if (ret == STATUS_CODE::OK) { // 判断参数查询是否成功
std::cout << "ip=" << params.ip << "\n"; // 打印查询到的目标 IP
} // 结束参数查询判断SetParam
签名
cpp
std::pair<int32_t, STATUS_CODE> SetParam(const modbus_client::SerialParams& params);| 输入 | 类型 | 说明 |
|---|---|---|
params | modbus_client::SerialParams | 串口参数对象 |
| 输出 | 说明 |
|---|---|
int32_t | 成功时返回控制器确认的参数记录 id ;失败时返回 0 |
STATUS_CODE | OK / NOT_CONNECTED / 其他控制器错误码 |
限制与行为
channel、ip、port、baud、dataBit、stopBit、parity、timeout都会被序列化后直接发给控制器。
调用示例
cpp
modbus_client::SerialParams params; // 创建串口参数对象
params.channel = modbus_client::MODBUS_CHANNEL::CONTROLLER_485; // 指定控制器 485 通道
params.ip = "10.27.1.99"; // 设置目标 IP
params.port = 1502; // 设置目标端口
auto [id, ret] = arm.modbusClient.SetParam(params); // 保存串口参数,会改变控制器配置
if (ret == STATUS_CODE::OK) { // 判断参数保存是否成功
std::cout << "saved_param_id=" << id << "\n"; // 打印控制器确认的参数记录 ID
} // 结束参数保存判断ReadCoils / ReadHoldingRegs / ReadDiscreteInputs / ReadInputRegs
这四个接口共用同一套本地校验规则和返回口径。
签名模式
cpp
std::pair<std::vector<int32_t>, STATUS_CODE> ReadXxx(
int32_t addr,
int32_t num
);| 输入 | 说明 |
|---|---|
addr | 起始地址,要求 addr >= 0 |
num | 读取数量,要求 1 <= num <= 120 |
| 输出 | 说明 |
|---|---|
std::vector<int32_t> | 成功时返回整型数组;失败时返回空数组 |
STATUS_CODE | OK / INVALID_SESSION / INVALID_PARAMETER / 其他控制器错误码 |
限制与行为
addr + num - 1不能超过65535。Slave无效时直接返回INVALID_SESSION。- 控制器返回的不是整型数组时,SDK 返回
OTHER_ERR。
调用示例
cpp
auto [coils, ret] = slave.ReadCoils(10, 3); // 从地址 10 开始读取 3 个线圈值
if (ret == STATUS_CODE::OK) { // 判断线圈读取是否成功
std::cout << "coils=" << coils.size() << "\n"; // 打印读取到的线圈数量
} // 结束线圈读取判断WriteCoils / WriteHoldingRegs / WriteInputRegs
这些写接口只在目标 Modbus 区域不同,其余规则一致。
签名模式
cpp
STATUS_CODE WriteXxx(int32_t addr, const std::vector<int32_t>& values);| 输入 | 说明 |
|---|---|
addr | 起始地址,要求 addr >= 0 |
values | 写入值列表,要求数量在 1..1024 |
| 输出 | 说明 |
|---|---|
STATUS_CODE | OK / INVALID_SESSION / INVALID_PARAMETER / 其他控制器错误码 |
限制与行为
addr + values.size() - 1不能超过65535。- SDK 校验地址和数量;每个元素的业务语义交由控制器处理。
调用示例
cpp
STATUS_CODE ret = slave.WriteHoldingRegs(20, {11, 12}); // 从地址 20 开始写入两个保持寄存器值
if (ret != STATUS_CODE::OK) { // 判断保持寄存器写入是否失败
return; // 写入失败时退出当前流程
} // 结束保持寄存器写入判断
// STATUS_CODE inputRet = slave.WriteInputRegs(20, {11, 12}); // 写输入寄存器会改变从站状态,确认后再执行Slave::GetParam / Slave::SetParam
这两个接口复用 ModbusClient::GetParam / SetParam 语义, 区别只是会话上下文来自当前 Slave :
Slave::GetParam()使用创建会话时记录的channel / masterIdSlave::SetParam(params)通过当前有效会话发请求
如果 Slave 已失效,两者都返回 INVALID_SESSION 。
SerialSend / SerialReceive
签名
cpp
STATUS_CODE SerialSend(const std::string& msg);
std::pair<std::string, STATUS_CODE> SerialReceive();| 接口 | 输入 | 输出 | 关键行为 |
|---|---|---|---|
SerialSend | 原始字符串 | STATUS_CODE | 请求按当前 channel 发送,不带 slaveId / masterId |
SerialReceive | 无 | std::pair<std::string, STATUS_CODE> | 成功返回原始字符串,失败返回空字符串 |
限制与行为
- 透传协议是按通道工作的,所以
Slave里保存的slaveId对串口透传没有作用。 SerialReceive()成功时要求控制器返回的data是字符串; 否则返回OTHER_ERR。
常用类型
modbus_client::MODBUS_CHANNEL
| 枚举值 | 值 | 说明 |
|---|---|---|
CONTROLLER_TCP_TO_485 | 2 | 控制器 TCP 转 485 通道 |
WRIST_485_0 | 3 | 手腕 485_0 通道 |
WRIST_485_1 | 4 | 手腕 485_1 通道 |
CONTROLLER_485 | 5 | 控制器 485 通道 |
modbus_client::MODBUS_PARITY
| 枚举值 | 值 | 说明 |
|---|---|---|
NONE | 78 | ASCII N |
ODD | 79 | ASCII O |
EVEN | 69 | ASCII E |
modbus_client::SerialParams
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | int32_t | 1 | 参数记录 ID |
channel | modbus_client::MODBUS_CHANNEL | CONTROLLER_TCP_TO_485 | 通道 |
ip | std::string | 空字符串 | 目标 IP |
port | int32_t | 502 | 端口 |
baud | int32_t | 9600 | 波特率 |
dataBit | int32_t | 8 | 数据位 |
stopBit | int32_t | 1 | 停止位 |
parity | modbus_client::MODBUS_PARITY | NONE | 校验位 |
timeout | int32_t | 1000 | 超时,毫秒 |
示例
C++17 最小示例
cpp
#include <iostream> // 引入标准输出流,用于打印 Modbus 查询结果
#include "arm_api.h" // 引入 Arm 主入口,连接后通过 arm.modbusClient 访问 Modbus 接口
int main() // 示例程序入口
{ // 进入示例主函数
Arm arm; // 创建机器人会话对象
STATUS_CODE connectRet = arm.Connect("10.27.1.254", ""); // 连接控制器或路由地址,示教器地址留空表示使用默认规则
if (connectRet != STATUS_CODE::OK) { // 判断连接是否失败
return 1; // 连接失败时直接退出
} // 结束连接结果判断
auto [params, getRet] = arm.modbusClient.GetParam( // 查询指定 Modbus 通道的串口参数
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
0 // 指定 masterId,非 TCP_TO_485 通道通常会被控制器忽略
); // 结束串口参数查询调用
if (getRet == STATUS_CODE::OK) { // 只有查询成功时才打印串口参数
std::cout << "modbus_ip=" << params.ip << "\n"; // 打印串口参数中的目标 IP
} // 结束串口参数查询判断
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // 创建一个 Modbus 从站会话
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
1, // 指定从站 ID 为 1
0 // 指定 masterId 为 0
); // 结束从站会话创建调用
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // 判断从站会话是否创建成功且有效
return 1; // 会话无效时返回错误码
} // 结束从站会话判断
auto [coils, readRet] = slave.ReadCoils(0, 2); // 从地址 0 开始读取 2 个线圈值
if (readRet != STATUS_CODE::OK) { // 判断线圈读取是否失败
return 1; // 读取失败时返回错误码
} // 结束线圈读取判断
std::cout << "coil_count=" << coils.size() << "\n"; // 打印读取到的线圈数量
return 0; // 示例正常结束
} // 结束示例主函数C++17 场景化示例
下面几组片段按 “Modbus 参数接口、从站会话、读写寄存器、串口透传” 交叉覆盖本页 API。片段默认承接最小示例里已经连接成功的 arm 对象;写寄存器、改串口参数和串口透传会访问现场设备,确认后再执行。
查询和设置串口参数
cpp
auto [facadeParams, facadeGetRet] = arm.modbusClient.GetParam( // 通过 ModbusClient 接口模块查询串口参数
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
0 // 指定 masterId 为 0
); // 结束参数查询调用
modbus_client::SerialParams params = facadeParams; // 复制当前参数,便于展示 SetParam 调用形态
params.channel = modbus_client::MODBUS_CHANNEL::CONTROLLER_485; // 指定要设置的通道
// auto [savedId, facadeSetRet] = arm.modbusClient.SetParam(params); // 设置串口参数会改变控制器配置,确认后再执行创建从站会话并按会话取参
cpp
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // 通过 ModbusClient 接口模块创建从站会话
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 指定控制器 485 通道
1, // 指定从站 ID 为 1
0 // 指定 masterId 为 0
); // 结束从站会话创建调用
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // 使用 Slave::IsValid 判断本地会话是否有效
return; // 会话无效时退出当前流程
} // 结束从站会话判断
auto [slaveParams, slaveGetRet] = slave.GetParam(); // 使用当前 Slave 会话查询串口参数
// auto [slaveSavedId, slaveSetRet] = slave.SetParam(slaveParams); // 通过 Slave 设置串口参数会改变控制器配置,确认后再执行读取和写入 Modbus 数据区
cpp
auto [coils, coilsRet] = slave.ReadCoils(0, 2); // 读取线圈区数据
auto [holdingRegs, holdingRet] = slave.ReadHoldingRegs(0, 2); // 读取保持寄存器数据
auto [discreteInputs, discreteRet] = slave.ReadDiscreteInputs(0, 2); // 读取离散输入数据
auto [inputRegs, inputRet] = slave.ReadInputRegs(0, 2); // 读取输入寄存器数据
if (coilsRet == STATUS_CODE::OK || holdingRet == STATUS_CODE::OK || discreteRet == STATUS_CODE::OK || inputRet == STATUS_CODE::OK) { // 判断至少一个读取是否成功
std::cout << "coil_count=" << coils.size() << " holding_count=" << holdingRegs.size() << "\n"; // 打印读取结果摘要
} // 结束 Modbus 读取判断
// STATUS_CODE writeCoilsRet = slave.WriteCoils(0, {1, 0}); // 写线圈会改变从站状态,确认后再执行
// STATUS_CODE writeHoldingRet = slave.WriteHoldingRegs(0, {100, 200}); // 写保持寄存器会改变从站状态,确认后再执行
// STATUS_CODE writeInputRet = slave.WriteInputRegs(0, {100, 200}); // 写输入寄存器会改变从站状态,确认后再执行串口透传
cpp
// STATUS_CODE serialSendRet = slave.SerialSend("010300000002"); // 串口透传发送会访问现场总线,确认后再执行
// auto [serialText, serialReceiveRet] = slave.SerialReceive(); // 串口透传接收会等待现场数据,确认后再执行示例代码
cpp
#include "query_master_params/run.h"
#include "operate_slave/run.h"
#include "set_master_params/run.h"
int main(void)
{
// [ZH] 默认只调用一个门面方法;如需体验其他接口,请把下一行替换成下面任意一行。
// [EN] The main function calls only one facade by default. Replace the next line with any line below to try other APIs.
return RunModbusBasicQueryMasterParams();
// return RunModbusBasicOperateSlave();
// return RunModbusBasicSetMasterParams();
}cpp
#include <stdio.h>
#include <string.h>
extern "C" {
#include "c_arm_api.h"
}
int main(void)
{
// [ZH] 本示例直接在源码中写死连接地址,不解析命令行参数。
// [EN] This example hard-codes the connection addresses in the source code and does not parse command-line arguments.
// [ZH] 创建并连接 SDK 句柄。
// [EN] Create the SDK handle and connect to the robot.
ArmHandle* handle = Arm_Create();
if (handle == NULL) {
printf("[c99_modbus] 创建句柄失败 / Failed to create the handle\n");
return 1;
}
int ret = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
if (ret != 0) {
printf("[c99_modbus] 连接失败 / Connect failed, 状态码 / Status code: %d\n", ret);
Arm_Destroy(handle);
return 1;
}
printf("[c99_modbus] 机器人连接成功 / Robot connected successfully\n");
// [ZH] 准备主站串口参数并读取当前值。
// [EN] Prepare master serial params and read the current values.
ArmSerialParams masterParams = {0};
int32_t paramId = 0;
snprintf(masterParams.ip, sizeof(masterParams.ip), "127.0.0.1");
masterParams.channel = ARM_MODBUS_CHANNEL_CONTROLLER_485;
masterParams.id = 1;
masterParams.port = 502;
masterParams.baud = 9600;
masterParams.dataBit = 8;
masterParams.stopBit = 1;
masterParams.parity = ARM_MODBUS_PARITY_NONE;
masterParams.timeout = 1000;
ret = Arm_Modbus_GetParam(handle, ARM_MODBUS_CHANNEL_CONTROLLER_485, 0, &masterParams);
printf("[c99_modbus] GetParam 状态码 / GetParam status code: %d, channel=%d, baud=%d\n", ret, masterParams.channel, masterParams.baud);
ret = Arm_Modbus_SetParam(handle, &masterParams, ¶mId);
printf("[c99_modbus] SetParam 状态码 / SetParam status code: %d, id=%d\n", ret, paramId);
// [ZH] 获取从站句柄并顺序执行全部从站接口。
// [EN] Acquire the slave handle and execute all slave APIs in sequence.
ArmModbusSlaveHandle* slave = NULL;
ret = Arm_Modbus_GetSlave(handle, ARM_MODBUS_CHANNEL_CONTROLLER_485, 1, 0, &slave);
printf("[c99_modbus] GetSlave 状态码 / GetSlave status code: %d\n", ret);
if (slave != NULL) {
int valid = Arm_ModbusSlave_IsValid(slave);
printf("[c99_modbus] Slave_IsValid / Slave_IsValid: %d\n", valid);
int32_t values[8] = {0};
size_t valueCount = 0U;
ret = Arm_ModbusSlave_ReadCoils(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadCoils 状态码 / ReadCoils status code: %d, count=%zu\n", ret, valueCount);
int32_t writeCoils[2] = {1, 0};
ret = Arm_ModbusSlave_WriteCoils(slave, 0, writeCoils, 2U);
printf("[c99_modbus] WriteCoils 状态码 / WriteCoils status code: %d\n", ret);
ret = Arm_ModbusSlave_ReadHoldingRegs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadHoldingRegs 状态码 / ReadHoldingRegs status code: %d, count=%zu\n", ret, valueCount);
int32_t holdingRegs[2] = {1, 2};
ret = Arm_ModbusSlave_WriteHoldingRegs(slave, 0, holdingRegs, 2U);
printf("[c99_modbus] WriteHoldingRegs 状态码 / WriteHoldingRegs status code: %d\n", ret);
ret = Arm_ModbusSlave_ReadDiscreteInputs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadDiscreteInputs 状态码 / ReadDiscreteInputs status code: %d, count=%zu\n", ret, valueCount);
ret = Arm_ModbusSlave_ReadInputRegs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadInputRegs 状态码 / ReadInputRegs status code: %d, count=%zu\n", ret, valueCount);
int32_t inputRegs[2] = {3, 4};
ret = Arm_ModbusSlave_WriteInputRegs(slave, 0, inputRegs, 2U);
printf("[c99_modbus] WriteInputRegs 状态码 / WriteInputRegs status code: %d\n", ret);
ret = Arm_ModbusSlave_SetParam(slave, &masterParams, ¶mId);
printf("[c99_modbus] Slave_SetParam 状态码 / Slave_SetParam status code: %d, id=%d\n", ret, paramId);
ret = Arm_ModbusSlave_GetParam(slave, &masterParams);
printf("[c99_modbus] Slave_GetParam 状态码 / Slave_GetParam status code: %d, baud=%d\n", ret, masterParams.baud);
ret = Arm_ModbusSlave_SerialSend(slave, "hello from c99 example");
printf("[c99_modbus] SerialSend 状态码 / SerialSend status code: %d\n", ret);
char recvBuf[256] = {0};
ret = Arm_ModbusSlave_SerialReceive(slave, recvBuf, sizeof(recvBuf));
printf("[c99_modbus] SerialReceive 状态码 / SerialReceive status code: %d, 内容 / Text: %s\n", ret, recvBuf);
Arm_ModbusSlave_Destroy(slave);
printf("[c99_modbus] 从站句柄已释放 / Slave handle destroyed\n");
}
// [ZH] 断开连接并销毁句柄。
// [EN] Disconnect and destroy the handle.
Arm_Disconnect(handle);
Arm_Destroy(handle);
printf("[c99_modbus] 示例结束 / Example finished\n");
return 0;
}