Browse Source

add:lua脚本层的modbus_rtu增加一些防呆

黄何 2 tháng trước cách đây
mục cha
commit
c83c4eb3c1
1 tập tin đã thay đổi với 71 bổ sung52 xóa
  1. 71 52
      olddemo/modbus_rtu/modbus_rtu.lua

+ 71 - 52
olddemo/modbus_rtu/modbus_rtu.lua

@@ -1,21 +1,20 @@
 --[[
 @module modbus_rtu
-@summary modbus_rtu MODBUS_RTU协议 
-@version 1.0
+@summary modbus_rtu MODBUS_RTU协议
+@version 1.1
 @date    2025.01.10
 @author  HH
 @usage
---注意:
---注意:
 -- 用法实例
 local modbus_rtu = require "modbus_rtu"
 
 -- 初始化modbus_rtu
 modbus_rtu.init({
-    uartid = 1, -- 接收/发送数据的串口id
+    uartid = 1,      -- 接收/发送数据的串口id
     baudrate = 4800, -- 波特率
-    gpio_485 = 25, -- 转向GPIO编号
+    gpio_485 = 25,   -- 转向GPIO编号
     tx_delay = 50000 -- 转向延迟时间,单位us
+})
 
 -- 定义modbus_rtu数据接收回调
 local function on_modbus_rtu_receive(frame)
@@ -23,7 +22,6 @@ local function on_modbus_rtu_receive(frame)
     if frame.fun == 0x03 then -- 功能码0x03表示读取保持寄存器
         local byte = frame.byte
         local payload = frame.payload
-        -- log.info("modbus_rtu payload (hex):", payload:toHex())
 
         -- 解析数据(假设数据为16位寄存器值)
         local values_big = {} -- 大端序解析结果
@@ -54,7 +52,6 @@ local function on_modbus_rtu_receive(frame)
             for index, value in ipairs(values_big) do
                 log.info(string.format("寄存器 %d: %d (大端序)", index, value))
             end
-
         end
     else
         log.info("功能码不是03")
@@ -67,38 +64,31 @@ modbus_rtu.set_receive_callback(1, on_modbus_rtu_receive)
 local function send_modbus_rtu_command()
     local addr = 0x01 -- 设备地址,此处填客户自己的
     local fun = 0x03 -- 功能码(03为读取保持寄存器),此处填客户自己的
-    local data = string.char(0x00, 0x00, 0x00, 0x02) -- 起始地址和寄存器数量(此处填客户自己的起始地址进而寄存器数量)
+    local data = string.char(0x00, 0x00, 0x00, 0x02) -- 起始地址和寄存器数量
 
-    -- modbus_rtu.send_command(1, addr, fun, data) -- 只发送一次命令并等待响应处理
     modbus_rtu.send_command(1, addr, fun, data, 5000) -- 循环5S发送一次
-
 end
 
 sys.taskInit(function()
     sys.wait(5000)
     send_modbus_rtu_command()
-
 end)
-
-]]
-
-
-
+]] 
 
 local modbus_rtu = {}
 
 -- 默认配置
 local DEFAULT_CONFIG = {
-    uartid = 1,          -- 串口ID
-    baudrate = 4800,     -- 波特率
-    databits = 8,        -- 数据位
-    stopbits = 1,        -- 停止位
-    parity = uart.None,  -- 校验位
+    uartid = 1, -- 串口ID
+    baudrate = 4800, -- 波特率
+    databits = 8, -- 数据位
+    stopbits = 1, -- 停止位
+    parity = uart.None, -- 校验位
     endianness = uart.LSB, -- 字节序
-    buffer_size = 1024,  -- 缓冲区大小
-    gpio_485 = 25,       -- 485转向GPIO
-    rx_level = 0,        -- 485模式下RX的GPIO电平
-    tx_delay = 10000,    -- 485模式下TX向RX转换的延迟时间(us)
+    buffer_size = 1024, -- 缓冲区大小
+    gpio_485 = 25, -- 485转向GPIO
+    rx_level = 0, -- 485模式下RX的GPIO电平
+    tx_delay = 10000 -- 485模式下TX向RX转换的延迟时间(us)
 }
 
 --[[
@@ -128,19 +118,31 @@ modbus_rtu.init(config)
 -- 初始化modbus_rtu
 function modbus_rtu.init(config)
     config = config or {}
-     -- 遍历 DEFAULT_CONFIG,为缺省的参数赋值
-     for key, default_value in pairs(DEFAULT_CONFIG) do
+    
+    -- 参数验证
+    if not config.uartid then
+        log.error("modbus_rtu", "缺少必要的uartid参数")
+        return false
+    end
+    
+    -- 遍历 DEFAULT_CONFIG,为缺省的参数赋值
+    for key, default_value in pairs(DEFAULT_CONFIG) do
         if config[key] == nil then
             config[key] = default_value
         end
     end
+    
     -- 初始化UART
-    uart.setup(
-        config.uartid, config.baudrate, config.databits, config.stopbits,
-        config.parity, config.endianness, config.buffer_size,
-        config.gpio_485, config.rx_level, config.tx_delay
-    )
-    log.info("modbus_rtu 当前串口初始化配置为:", json.encode(config))
+    local result = uart.setup(config.uartid, config.baudrate, config.databits, config.stopbits, config.parity, config.endianness,
+        config.buffer_size, config.gpio_485, config.rx_level, config.tx_delay)
+    
+    if result then
+        log.info("modbus_rtu", "串口初始化成功,配置为:", json.encode(config))
+        return true
+    else
+        log.error("modbus_rtu", "串口初始化失败")
+        return false
+    end
 end
 
 --[[
@@ -159,7 +161,6 @@ function modbus_rtu.crc16(data)
     return crc16_data
 end
 
-
 --[[
 对下位机返回过来的数据进行modbus_rtu解析
 @api  modbus_rtu.parse_frame()
@@ -172,25 +173,40 @@ log.info("crc16_data", crc16_data.addr,crc16_data.fun,crc16_data.byte,crc16_data
 
 function modbus_rtu.parse_frame(data)
     local str = data or ""
-    local addr = str:byte(1) or"" -- 地址位
-    local fun = str:byte(2) or ""  -- 功能码
-    local byte = str:byte(3)or "" -- 有效字节数
-    local payload = str:sub(4, 4 + byte - 1)or"" -- 数据部分(根据有效字节数动态截取)
-    local crc_data = str:sub(-2, -1) or ""
-    local idx,crc = pack.unpack(crc_data, "H")  -- CRC校验值
+    
+    -- 数据长度验证
+    if #str < 4 then
+        log.error("modbus_rtu", "数据帧长度不足")
+        return nil, "Frame too short"
+    end
+    
+    local addr = str:byte(1) -- 地址位
+    local fun = str:byte(2) -- 功能码
+    local byte = str:byte(3) -- 有效字节数
+    
+    -- 验证数据长度
+    if #str < byte + 5 then -- 地址(1) + 功能码(1) + 字节数(1) + 数据(byte) + CRC(2)
+        log.error("modbus_rtu", "数据帧长度与字节数不匹配")
+        return nil, "Frame length mismatch"
+    end
+    
+    local payload = str:sub(4, 4 + byte - 1) -- 数据部分
+    local crc_data = str:sub(-2, -1)
+    local idx, crc = pack.unpack(crc_data, "H") -- CRC校验值
 
     -- 校验CRC
-    if crc == modbus_rtu.crc16(str:sub(1, -3)) then
-        log.info("modbus_rtu CRC校验成功")
+    local calculated_crc = modbus_rtu.crc16(str:sub(1, -3))
+    if crc == calculated_crc then
+        log.info("modbus_rtu", "CRC校验成功")
         return {
             addr = addr,
             fun = fun,
             byte = byte,
             payload = payload,
-            crc = crc,
+            crc = crc
         }
     else
-        log.info("modbus_rtu CRC校验失败",crc)
+        log.error("modbus_rtu", "CRC校验失败,期望:", calculated_crc, "实际:", crc)
         return nil, "CRC error"
     end
 end
@@ -224,10 +240,10 @@ function modbus_rtu.send_command(uartid, addr, fun, data, interval)
     local cmd = modbus_rtu.build_frame(addr, fun, data)
     if interval then
         -- 如果传入了interval,则启用循环发送
-        sys.timerLoopStart(function ()
-            -- log.info("每隔"..interval.."秒发一次指令",cmd:toHex())
-            uart.write(uartid,cmd)
-        end,interval)
+        sys.timerLoopStart(function()
+            log.info("每隔" .. interval .. "秒发一次指令", cmd:toHex())
+            uart.write(uartid, cmd)
+        end, interval)
         -- sys.timerLoopStart(uart.write, interval, uartid, cmd)
         -- log.info("modbus_rtu 循环发送的间隔时间为", interval, "ms",cmd:toHex())
     else
@@ -242,7 +258,7 @@ function modbus_rtu.set_receive_callback(uartid, callback)
     uart.on(uartid, "receive", function(id, len)
         local s = ""
         repeat
-            s = uart.read(id, 128)
+            s = uart.read(id, len)
             if #s > 0 then
                 log.info("modbus_rtu 收到的下位机回复:", s:toHex())
                 local frame, err = modbus_rtu.parse_frame(s)
@@ -260,8 +276,11 @@ end
 function modbus_rtu.set_sent_callback(uartid, callback)
     uart.on(uartid, "sent", function(id)
         log.info("modbus_rtu 数据发送:", id)
-        if callback then callback(id) end
+        if callback then
+            callback(id)
+        end
     end)
 end
 
-return modbus_rtu
+return modbus_rtu
+