本文为实现modbus协议转换提供技术上的总体思路,具体实现需根据实际情况来确定。
需求说明
FSU对南向设备进行数据采集、控制,进行协议转换,对上层平台提供modbus协议来读写南向设备,屏蔽底层南向设备的交互细节,实现上层平台与底层南向设备协议间的解耦。
协议生成:
平台层使用的是一份由GatewayServer自动化生成的modbus协议文档协议配置:
GatewayServer支持web配置modbus协议协议实现:
modbus要同时支持tcp和rtu
需求拆分
协议生成
数据定义
uint32_t regAddr; //寄存器地址 uint16_t regNum; //单个meter包含的寄存器数量 int regSize; //寄存器总个数(这一轮里面,-1时表示无效) CData deviceID; //设备id bool meterBit = false; //meter是否是一个bit对应一个量(如果是的话,regNum和regSize都必须为1) int meterBitSize; //meterBit为true时才有效(有效时指定有效的bit位个数) CData type; //解析的数据类型 double factor; //当前的数值需要乘以多少 CData access; //读写权限 bool def = false; //是否有默认值(默认值为false) double defVal; //如果有,默认值为多少 bool range = false; //数据是否有数据范围(默认为false) double rangeMin; //如果有范围,此范围的最小值 double rangeMax; //如果有范围,此范围的最大值 //下面这两个只有主meter才会有此字段 bool distance = false; //是否有距离间隔 int distanceVal; //如果有,每组meterList之间间隔的寄存器值是多少 int step = 1000; //量id之间的变化基数(默认为1000) int highLowPos = -1; //解析方式是否按高16位和低16位解析(小于0表示不按照高低位解析,0表示低16位,1表示高16位)
协议格式
<?xml version="1.0" encoding="UTF-8" ?> <version>1.00</version> <devices> <!-- 系统状态r --> <device deviceId="5000001" name="系统状态"> <meter regAddr="0" regNum="1" regSize="1" meterID="312005001" meterBit="false" meterBitSize="0" type="u16" factor="1" access="r" default="true" defaultVal="1" range="false" rangeMin="0.1" rangeMax="10.0" distance="false" distanceVal="0"/> <meterList> <meter regAddr="1" regNum="1" regSize="1" meterID="312006001" meterBit="false" meterBitSize="0" type="u16" factor="1" access="r" default="false" defaultVal="0" range="false" rangeMin="0.1" rangeMax="10.0" step="1"/> </meterList> </device> </devices>
协议配置
页面原型(草稿)
在配置管理增加Modbus配置入口。
进入配置页面,根据实际需要增加对应的前端功能。
协议实现
GatewayServer解析xml配置文件,将xml配置文件包含的量存放到缓存中,采取定时获取meter值和订阅meter值变更时间的方式更新数据,并将值同步到Modbus的寄存器。
根据web页面是否开启tcp、rtu服务,来启动tcp、rtu子模块。
5 评论
XiongYong 发表:
看完协议实现的是使用Modbus RTU over TCP和 Modbus TCP来进行平台接入,需要平台与网关之间配置的同步(平台要解析,网关要生成Modbus 寄存器的点位,要保证平台与网关之间的一致性),如下图所示
Modbus RTU over TCP/Modbus TCP 的数据端一般是从机,即网关是从机,平台 是主机,在实现上可能需要 网关发起连接,再由平台来请求,除连接外其他 按照 标准的 Modbus 实现即可;
Modbus 的设备地址、寄存器与网关上设备和量的映射关系设置;
实现的协议是在 TCP 连接上,TCP 是明文传输,需要考虑是否 基于 TLS 的连接进行传输。
xie 发表:
项目计划说明
1、modbus tcp主机功能
2、modbus tcp从机功能
3、modbus rtu主机功能
4、modbus rtu从机功能
1、已完成,已自测
2、已完成,未自测
3、已完成,已自测
4、已完成,已自测
1、网关配置modbus协议及主从机
2、网关配置寄存器信息
3、数据存储
1、已完成,已自测
2、已完成,已自测
3、已完成,已自测
1、解析本地xml配置项
2、解析网关下发的配置,将其缓存到某个数据结构中
3、根据解析的配置,将网关上的数据同步更新到modbus寄存器中
1、已完成,已自测
2、已完成,已自测
3、已完成,未自测
1、定义与平台交互的接口及字段
2、将网关配置项与平台同步
1、已自测,无需额外开发
2、已自测,无需额外开发
1、模块功能整合
1、项目评审、优化、测试及bug验证
2、线上环境验证及bug修改
xie 发表:
web网关下发json,控制协议类型相关的字段如下:
{
"isOnModbusRtuSer":1, //是否开启rtuServer(0不开启,1开启)
"isOnModbusRtuCli":1, //是否开启rtuClient(0不开启,1开启)
"isOnModbusTcpSer":0, //是否开启tcpServer(0不开启,1开启)
"isOnModbusTcpCli":0, //是否开启tcpClient(0不开启,1开启)
"rtuServer": {
"device": "串口设备名称",
"baud": 9600,
"parity": "N", //"N":无奇偶校验, "O":奇校验,"E":偶校验
"dataBit": 8,
"stopBit": 1
},
"rtuClient": {
"device": "串口设备名称2",
"baud": 9600,
"parity": "N", //"N":无奇偶校验, "O":奇校验,"E":偶校验
"dataBit": 8,
"stopBit": 1
},
"tcpServer":{
"ip": "0.0.0.0", //ip和端口
"port": 502
},
"tcpClient":{
"ip": "192.168.1.100", //ip和端口
"port": 502
}
}
web网关下发json,获取、配置相关的字段如下:
[
{
"devName": "Device2",
"deviceId": "0",
"configs": [
{
"meterId": "0",
"regAddr": 1000,
"regNum": 10,
"regSize": -1,
"type": "uint16",
"factor": 1.0,
"access": "r", //这个字段只有"r"和"rw"两种可选值
"def": false,
"defVal": 0.0,
"range": false,
"rangeMin": 0.0,
"rangeMax": 0.0,
"step": 1000,
"highLowPos": -1
}
]
}
]
数据定义修改如下:
uint16_t regAddr; //寄存器地址
uint16_t regNum; //单个meter包含的寄存器数量
int regSize = -1; //寄存器总个数(这一轮里面,-1时表示无效)
CData deviceId = "0"; //设备id
CData meterId = "0"; //meterId(读的meterId)
std::string type; //解析的数据类型
double factor; //当前的数值需要乘以多少
std::string access; //读写权限
bool def = false; //是否有默认值(默认值为false)
double defVal; //如果有,默认值为多少
bool range = false; //数据是否有数据范围(默认为false)
double rangeMin; //如果有范围,此范围的最小值
double rangeMax; //如果有范围,此范围的最大值
int step = 1000; //量id之间的变化基数(默认为1000)
int highLowPos = -1; //解析方式是否按高16位和低16位解析(小于0表示不按照高低位解析,0表示低16位,1表示高16位)
数据类型:type的字段值有:str(字符串)、s16(int16_t)、u16(uint16_t)、hl(high 8 bit or low 8 bit)、bit(bit位)
xie 发表:
与web交互的四个接口验证如下:
1、Get请求协议选择的数据:
URL:http://192.168.1.113/jscmd/getModbusChoose
回复Body:
{
"jsonrpc": "2.0",
"method": "null",
"id": "null",
"result": {
"isOnModbusRtuSer": 0,
"isOnModbusRtuCli": 0,
"isOnModbusTcpSer": 1,
"isOnModbusTcpCli": 1,
"tcpServer": {
"ip": "192.168.1.100",
"port": 502
},
"tcpClient": {
"ip": "",
"port": 0
}
}
}
2、Post设置协议选择的数据:
URL:http://192.168.1.113/jscmd/setModbusChoose
请求Body:
{
"jsonrpc":"2.0",
"method":"webrpc",
"id":1,
"params": {
"isOnModbusRtuSer": 0,
"isOnModbusRtuCli": 0,
"isOnModbusTcpSer": 1,
"isOnModbusTcpCli": 1,
"tcpServer": {
"ip": "192.168.1.100",
"port": 502
},
"tcpClient": {
"ip": "",
"port": 0
}
}
}
回复Body:
{
"jsonrpc": "2.0",
"method": "null",
"id": "null",
"result": "true"
}
3、Get获取配置信息:
URL:http://192.168.1.113/jscmd/getDeviceList
回复Body:
{
"jsonrpc": "2.0",
"method": "null",
"id": "null",
"result": [
{
"devName": "系统状态",
"deviceId": "5000001",
"configs": [
{
"meterId": "312006001",
"regAddr": 1,
"regNum": 1,
"regSize": 1,
"type": "u16",
"factor": 1,
"access": "r",
"def": 0,
"defVal": 0,
"range": 0,
"rangeMin": 0.1,
"rangeMax": 10,
"step": 1000,
"highLowPos": 0
},
{
"meterId": "312002001",
"regAddr": 2,
"regNum": 1,
"regSize": 1,
"type": "u16",
"factor": 1,
"access": "r",
"def": 0,
"defVal": 0,
"range": 0,
"rangeMin": 0.1,
"rangeMax": 10,
"step": 1000,
"highLowPos": 0
}
]
}
]
}
4、Post修改配置信息:
URL:http://192.168.1.113/jscmd/updateDeviceList
请求Body:
{
"jsonrpc": "2.0",
"method": "null",
"id": "null",
"params": [
{
"devName": "系统状态",
"deviceId": "5000001",
"configs": [
{
"meterId": "312006002",
"regAddr": 1,
"regNum": 1,
"regSize": 1,
"type": "u16",
"factor": 1,
"access": "r",
"def": 0,
"defVal": 0,
"range": 0,
"rangeMin": 0.1,
"rangeMax": 10,
"step": 1000,
"highLowPos": 0
},
{
"meterId": "312002001",
"regAddr": 2,
"regNum": 1,
"regSize": 1,
"type": "u16",
"factor": 1,
"access": "r",
"def": 0,
"defVal": 0,
"range": 0,
"rangeMin": 0.1,
"rangeMax": 10,
"step": 1000,
"highLowPos": 0
}
]
}
]
}
回复Body:
{
"jsonrpc": "2.0",
"method": "null",
"id": "null",
"result": "true"
}
xie 发表:
{
"jsonrpc":"2.0",
"method":"webrpc",
"id":1,
"params": {
"isOnModbusRtuSer": 0,
"isOnModbusRtuCli": 0,
"isOnModbusTcpSer": 1,
"isOnModbusTcpCli": 1,
"tcpServer": {
"ip": "192.168.1.100",
"port": 502
},
"tcpClient": {
"ip": "",
"port": 0
}
}
}
将ip字段修改为“nic”,表示网卡(不使用ip了)
添加评论