207 lines
4.9 KiB
Markdown
207 lines
4.9 KiB
Markdown
# Modbus TCP 服务器模块
|
||
|
||
基于libmodbus库的Modbus TCP服务器实现,提供完整的Modbus TCP服务器功能和回调机制。
|
||
|
||
## 功能特性
|
||
|
||
- 基于libmodbus的稳定实现
|
||
- 支持多客户端并发连接
|
||
- 完整的Modbus功能码支持
|
||
- 写操作回调机制,支持应用层错误码反馈
|
||
- 线程安全的数据访问和更新接口
|
||
- 跨平台支持(Windows/Linux)
|
||
|
||
## 支持的Modbus功能
|
||
|
||
### 读操作(自动处理)
|
||
- 读取线圈(0x01)
|
||
- 读取离散输入(0x02)
|
||
- 读取保持寄存器(0x03)
|
||
- 读取输入寄存器(0x04)
|
||
|
||
### 写操作(支持回调)
|
||
- 写单个线圈(0x05)
|
||
- 写单个保持寄存器(0x06)
|
||
- 写多个线圈(0x0F)
|
||
- 写多个保持寄存器(0x10)
|
||
|
||
## API接口
|
||
|
||
### 基本操作
|
||
```cpp
|
||
#include "ModbusTCPServer.h"
|
||
|
||
ModbusTCPServer server;
|
||
|
||
// 启动服务器
|
||
if (server.start(502, 10)) {
|
||
// 服务器启动成功
|
||
}
|
||
|
||
// 停止服务器
|
||
server.stop();
|
||
```
|
||
|
||
### 设置写操作回调
|
||
```cpp
|
||
// 设置写线圈回调
|
||
server.setWriteCoilsCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint8_t* values) -> ModbusTCPServer::ErrorCode {
|
||
// 处理写线圈请求
|
||
// unitId: 单元ID
|
||
// address: 起始地址
|
||
// quantity: 数量
|
||
// values: 写入的值
|
||
|
||
// 返回错误码
|
||
return ModbusTCPServer::ErrorCode::SUCCESS;
|
||
});
|
||
|
||
// 设置写寄存器回调
|
||
server.setWriteRegistersCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint16_t* values) -> ModbusTCPServer::ErrorCode {
|
||
// 处理写寄存器请求
|
||
// 检查地址范围、权限等
|
||
|
||
if (address >= 1000 && address < 2000) {
|
||
// 允许写入
|
||
return ModbusTCPServer::ErrorCode::SUCCESS;
|
||
} else {
|
||
// 拒绝写入 - 非法地址
|
||
return ModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
});
|
||
```
|
||
|
||
### 数据更新接口
|
||
```cpp
|
||
// 更新单个数据
|
||
server.updateCoil(0, true);
|
||
server.updateHoldingRegister(100, 1234);
|
||
server.updateDiscreteInput(50, false);
|
||
server.updateInputRegister(200, 5678);
|
||
|
||
// 批量更新数据
|
||
std::vector<bool> coils = {true, false, true, false};
|
||
server.updateCoils(0, coils);
|
||
|
||
std::vector<uint16_t> registers = {1000, 2000, 3000};
|
||
server.updateHoldingRegisters(100, registers);
|
||
```
|
||
|
||
## 错误代码
|
||
|
||
服务器支持标准的Modbus异常代码:
|
||
|
||
```cpp
|
||
enum class ErrorCode {
|
||
SUCCESS = 0, // 成功
|
||
ILLEGAL_FUNCTION = 1, // 非法功能码
|
||
ILLEGAL_DATA_ADDRESS = 2, // 非法数据地址
|
||
ILLEGAL_DATA_VALUE = 3, // 非法数据值
|
||
SERVER_FAILURE = 4, // 服务器故障
|
||
ACKNOWLEDGE = 5, // 确认
|
||
SERVER_BUSY = 6, // 服务器忙
|
||
NEGATIVE_ACKNOWLEDGE = 7, // 否定确认
|
||
MEMORY_PARITY = 8, // 内存奇偶校验错误
|
||
GATEWAY_PATH_UNAVAILABLE = 10, // 网关路径不可用
|
||
GATEWAY_TARGET_FAILED = 11 // 网关目标设备响应失败
|
||
};
|
||
```
|
||
|
||
## 完整使用示例
|
||
|
||
```cpp
|
||
#include "ModbusTCPServer.h"
|
||
#include <iostream>
|
||
#include <thread>
|
||
#include <chrono>
|
||
|
||
int main() {
|
||
ModbusTCPServer server;
|
||
|
||
// 设置写操作回调
|
||
server.setWriteCoilsCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint8_t* values) {
|
||
std::cout << "写线圈请求 - 单元ID: " << (int)unitId
|
||
<< ", 地址: " << address
|
||
<< ", 数量: " << quantity << std::endl;
|
||
return ModbusTCPServer::ErrorCode::SUCCESS;
|
||
});
|
||
|
||
server.setWriteRegistersCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint16_t* values) {
|
||
std::cout << "写寄存器请求 - 单元ID: " << (int)unitId
|
||
<< ", 地址: " << address
|
||
<< ", 数量: " << quantity << std::endl;
|
||
|
||
// 检查地址范围
|
||
if (address < 1000) {
|
||
return ModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
|
||
return ModbusTCPServer::ErrorCode::SUCCESS;
|
||
});
|
||
|
||
// 启动服务器
|
||
if (!server.start(502, 10)) {
|
||
std::cerr << "启动服务器失败: " << server.getLastError() << std::endl;
|
||
return -1;
|
||
}
|
||
|
||
std::cout << "Modbus TCP服务器已启动,端口: 502" << std::endl;
|
||
|
||
// 定期更新数据
|
||
for (int i = 0; i < 100; ++i) {
|
||
server.updateHoldingRegister(1000, i);
|
||
server.updateCoil(0, i % 2 == 0);
|
||
|
||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||
}
|
||
|
||
// 停止服务器
|
||
server.stop();
|
||
std::cout << "服务器已停止" << std::endl;
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## 编译说明
|
||
|
||
### 依赖
|
||
- Qt 5.x 或更高版本
|
||
- C++17 编译器
|
||
- libmodbus源码(已包含在VrNets模块中)
|
||
|
||
### 构建
|
||
```bash
|
||
qmake ModbusTCPServer.pro
|
||
make
|
||
```
|
||
|
||
### 使用
|
||
该模块编译为静态库,在其他项目中包含:
|
||
```pro
|
||
LIBS += -L../Module/ModbusTCPServer -lModbusTCPServer
|
||
INCLUDEPATH += ../Module/ModbusTCPServer/Inc
|
||
```
|
||
|
||
## 特性说明
|
||
|
||
### 多客户端支持
|
||
- 支持同时处理多个客户端连接
|
||
- 使用select事件驱动模型,单线程处理所有客户端
|
||
- 高效的资源利用,避免线程过多的问题
|
||
- 线程安全的数据访问
|
||
|
||
### 数据存储
|
||
- 内部使用libmodbus的mapping结构存储数据
|
||
- 支持10000个线圈、离散输入、保持寄存器和输入寄存器
|
||
- 所有数据操作都是线程安全的
|
||
|
||
### 回调机制
|
||
- 写操作会触发用户定义的回调函数
|
||
- 回调函数可以返回错误码来拒绝写操作
|
||
- 支持异步处理和验证
|
||
|
||
### 错误处理
|
||
- 完整的错误处理和状态反馈
|
||
- 支持标准Modbus异常代码
|
||
- 详细的错误信息获取接口 |