- Modbus 应用示例
Modbus 应用示例
- 此应用使用了一个Lua实现的modbus模块(modbus_lua)
- 此应用使用SocketChannel和SerialChannel作为链路层
- 更为详细的modbus数据采集可以参考: modbus_example
代码:
local class = require 'middleclass'--- 导入需要的模块local modbus = require 'modbus.init'local sm_client = require 'modbus.skynet_client'local socketchannel = require 'socketchannel'local serialchannel = require 'serialchannel'--- 注册对象(请尽量使用唯一的标识字符串)local app = class("XXXX_App")--- 设定应用最小运行接口版本(目前版本为1,为了以后的接口兼容性)app.API_VER = 1----- 应用对象初始化函数-- @param name: 应用本地安装名称。 如modbus_com_1-- @param sys: 系统sys接口对象。参考API文档中的sys接口说明-- @param conf: 应用配置参数。由安装配置中的json数据转换出来的数据对象function app:initialize(name, sys, conf)self._name = nameself._sys = sysself._conf = conf--- 获取数据接口self._api = sys:data_api()--- 获取日志接口self._log = sys:logger()self._log:debug(name.." Application initlized")end--- 应用启动函数function app:start()--- 设定回调处理函数(目前此应用只做数据采集)self._api:set_handler({on_ctrl = function(...)print(...)end,})---获取设备序列号和应用配置local sys_id = self._sys:id()local config = self._conf or {channel_type = 'socket'}--- 添加10个采集项local inputs = {}for i = 1, 10 doinputs[#inputs + 1] = {name='tag'..i,desc='tag'..i..' description',}end--- 生成设备的序列号local dev_sn = sys_id..".modbus_"..self._namelocal meta = self._api:default_meta()meta.name = "Modbus"meta.description = "Modbus Device"meta.series = "XXX"--- 生成设备对象local dev = self._api:add_device(dev_sn, meta, inputs)--- 生成设备通讯口统计对象local stat = dev:stat('port')local client = nil--- 获取配置if config.channel_type == 'socket' thenopt = {host = "127.0.0.1",port = 1503,nodelay = true,}print('socket')client = sm_client(socketchannel, opt, modbus.apdu_tcp, 1)elseopt = {port = "/dev/ttymxc1",baudrate = 115200}print('serial')client = sm_client(serialchannel, opt, modbus.apdu_rtu, 1)end--- 设定通讯口数据回调client:set_io_cb(function(io, msg)--- 输出通讯报文dev:dump_comm(io, msg)--- 计算统计信息if io == 'IN' thenstat:inc('bytes_in', string.len(msg))elsestat:inc('bytes_out', string.len(msg))endend)self._client1 = clientself._dev1 = devself._stat1 = statreturn trueend--- 应用退出函数function app:close(reason)print(self._name, reason)end--- modbus寄存器数据解析function decode_registers(raw, count)local d = modbus.decodelocal len = d.uint8(raw, 2)assert(len >= count * 2)local regs = {}--- 按照无符号短整数进行解析for i = 0, count - 1 doregs[#regs + 1] = d.uint16(raw, i * 2 + 3)endreturn regsend--- 应用运行入口function app:run(tms)local client = self._client1if not client thenreturnend--- 设定读取的起始地址和读取的长度local base_address = 0x00local req = {func = 0x03, -- 03指令addr = base_address, -- 起始地址len = 10, -- 长度}--- 读取数据local r, pdu, err = pcall(function(req, timeout)--- 统计数据self._stat1:inc('packets_out', 1)--- 接口调用return client:request(req, timeout)end, req, 1000)if not r thenpdu = tostring(pdu)if string.find(pdu, 'timeout') thenself._log:debug(pdu, err)elseself._log:warning(pdu, err)endreturnendif not pdu thenself._log:warning("read failed: " .. err)returnend--- 统计数据self._log:trace("read input registers done!")self._stat1:inc('packets_in', 1)--- 解析数据local regs = decode_registers(pdu, 10)local now = self._sys:time()--- 将解析好的数据设定到输入项for r,v in ipairs(regs) doself._dev1:set_input_prop('tag'..r, "value", math.tointeger(v), now, 0)end--- 返回下一次调用run之前的时间间隔return tmsend--- 返回应用对象return app
