Chao Dan 9 месяцев назад
Родитель
Сommit
463301a77d

+ 140 - 0
module/Air780EPM/demo/modbus/master_rtu/main.lua

@@ -0,0 +1,140 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "modbus_master_rtu"
+VERSION = "1.0.0"
+log.style(1)
+log.info("main", PROJECT, VERSION)
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+
+--初始化通讯串口
+local uartid = 1        -- 根据实际设备选取不同的uartid
+local uart485Pin = 24   -- 用于控制485接收和发送的使能引脚
+gpio.setup(1, 1)        --打开电源(开发板485供电脚是gpio1,用开发板测试需要开机初始化拉高gpio1)
+uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
+
+
+-- 创建主站设备,RTU模式
+mb_rtu = modbus.create_master(modbus.MODBUS_RTU, uartid,5000,3000,2)
+-- 创建主站设备,ASCII模式
+-- mb_rtu = modbus.create_master(modbus.MODBUS_ASCII, uartid)
+
+-- 为主站添加从站,从站ID为1
+
+mb_slave1 = modbus.add_slave(mb_rtu, 1)
+-- 为主站添加从站,从站ID为2
+-- mb_slave2 = modbus.add_slave(mb_rtu, 2)
+
+-- 为从站1创建数据存储区,并创建通讯消息
+slave1_msg1_buf = zbuff.create(1)
+mb_slave1_msg1 = modbus.create_msg(mb_rtu, mb_slave1, modbus.REGISTERS, modbus.READ, 0, 10, slave1_msg1_buf)
+-- mb_slave1_msg1 = modbus.create_msg(mb_rtu, mb_slave1, modbus.REGISTERS, modbus.READ, 0, 10, slave1_msg1_buf,1,modbus.EXEC)
+slave1_msg1_buf:clear()
+
+
+
+
+
+-- slave1_msg2_buf = zbuff.create(1)
+-- mb_slave1_msg2 = modbus.create_msg(mb_rtu, mb_slave1, modbus.CIOLS, modbus.WRITE, 0, 10, slave1_msg2_buf)
+-- slave1_msg2_buf:clear()
+
+-- 为从站2创建数据存储区,并创建通讯消息
+-- slave2_msg1_buf = zbuff.create(1)
+-- mb_slave2_msg1 = modbus.create_msg(mb_rtu, mb_slave2, modbus.REGISTERS, modbus.WRITE, 0, 10, slave2_msg1_buf)
+-- slave2_msg1_buf:clear()
+
+-- slave2_msg2_buf = zbuff.create(1)
+-- mb_slave2_msg2 = modbus.create_msg(mb_rtu, mb_slave2, modbus.CIOLS, modbus.WRITE, 0, 10, slave2_msg2_buf)
+-- slave2_msg2_buf:clear()
+
+-- 启动Modubs设备
+modbus.master_start(mb_rtu)
+
+-- modbus.set_comm_interval_time(mb_rtu, 5000)
+
+-- modbus.set_comm_timeout(mb_rtu, 3000)
+
+-- modbus.set_comm_resend_count(mb_rtu,2)
+
+sys.timerLoopStart(function()
+    local status = modbus.get_all_slave_state(mb_rtu)
+    log.info("modbus", status)
+end, 5000)
+
+sys.timerLoopStart(function()
+    local status = modbus.get_slave_state(mb_slave1)
+    log.info("modbus1", status)
+end, 5000)
+
+-- sys.timerLoopStart(function()
+--     local status = modbus.get_slave_state(mb_slave2)
+--     log.info("modbus2", status)
+-- end, 5000)
+
+
+-- sys.timerLoopStart(function()
+--     local status=modbus.exec(mb_rtu, mb_slave1_msg1)
+--     log.info("msg",status)
+-- end,5000)
+
+-- modbus.set_msg_comm_period(mb_slave1_msg1, 2)
+
+-- sys.timerStart(function()
+--     local status = modbus.remove_slave(mb_rtu, mb_slave1)
+--     log.info("modbus", "slave remove after 3 minutes")
+--     log.info("remove", status)
+    
+--     -- 移除从站后,5秒后重新启动Modbus主站
+--     sys.timerStart(function()
+--         modbus.master_start(mb_rtu)
+--         log.info("modbus", "Modbus master restarted after slave removal")
+--     end, 5000)
+-- end, 180000) 
+
+
+
+-- 修改和读取modbus值
+addvar = 0
+function modify_data()
+    -- 获取变量值
+    slave1_msg1_buf:seek(0)
+    log.info("slave1 reg: ", slave1_msg1_buf:readU16(), slave1_msg1_buf:readU16(),
+                             slave1_msg1_buf:readU16(), slave1_msg1_buf:readU16())
+
+    -- slave2_msg1_buf:seek(0)
+    -- log.info("slave2 reg: ", slave2_msg1_buf:readU16(), slave2_msg1_buf:readU16(),
+    --                          slave2_msg1_buf:readU16(), slave2_msg1_buf:readU16())
+
+    -- 写入变量值
+    -- slave2_msg1_buf:seek(0)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- addvar=addvar+1
+	
+	-- 每周期值取反
+    -- slave1_msg2_buf:seek(0)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+end
+sys.timerLoopStart(modify_data,1000)
+
+
+-- sys.timerStart(function()
+--     modbus.master_stop(mb_rtu)
+--     log.info("modbus", "Modbus stopped after 2 minutes")
+-- end, 120000) 
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 311 - 0
module/Air780EPM/demo/modbus/master_tcp/dhcpsrv.lua

@@ -0,0 +1,311 @@
+
+local dhcpsrv = {}
+
+local udpsrv = require("udpsrv")
+
+local TAG = "dhcpsrv"
+
+----
+-- 参考地址
+-- https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
+
+local function dhcp_decode(buff)
+    -- buff:seek(0)
+    local dst = {}
+    -- 开始解析dhcp
+    dst.op = buff[0]
+    dst.htype = buff[1]
+    dst.hlen = buff[2]
+    dst.hops = buff[3]
+    buff:seek(4)
+    dst.xid = buff:read(4)
+
+    _, dst.secs = buff:unpack(">H")
+    _, dst.flags = buff:unpack(">H")
+    dst.ciaddr = buff:read(4)
+    dst.yiaddr = buff:read(4)
+    dst.siaddr = buff:read(4)
+    dst.giaddr = buff:read(4)
+    dst.chaddr = buff:read(16)
+
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+
+    -- 解析magic
+    _, dst.magic = buff:unpack(">I")
+
+    -- 解析option
+    local opt = {}
+    while buff:len() > buff:used() do
+        local tag = buff:read(1):byte()
+        if tag ~= 0 then
+            local len = buff:read(1):byte()
+            if tag == 0xFF or len == 0 then
+                break
+            end
+            local data = buff:read(len)
+            if tag == 53 then
+                -- 53: DHCP Message Type
+                dst.msgtype = data:byte()
+            end
+            table.insert(opt, {tag, data})
+            -- log.info(TAG, "tag", tag, "data", data:toHex())
+        end
+    end
+    if dst.msgtype == nil then
+        return -- 没有解析到msgtype,直接返回
+    end
+    dst.opts = opt
+    return dst
+end
+
+local function dhcp_buff2ip(buff)
+    return string.format("%d.%d.%d.%d", buff:byte(1), buff:byte(2), buff:byte(3), buff:byte(4))
+end
+
+local function dhcp_print_pkg(pkg)
+    log.info(TAG, "XID",  pkg.xid:toHex())
+    log.info(TAG, "secs", pkg.secs)
+    log.info(TAG, "flags", pkg.flags)
+    log.info(TAG, "chaddr", pkg.chaddr:sub(1, pkg.hlen):toHex())
+    log.info(TAG, "yiaddr", dhcp_buff2ip(pkg.yiaddr))
+    log.info(TAG, "siaddr", dhcp_buff2ip(pkg.siaddr))
+    log.info(TAG, "giaddr", dhcp_buff2ip(pkg.giaddr))
+    log.info(TAG, "ciaddr", dhcp_buff2ip(pkg.ciaddr))
+    log.info(TAG, "magic", string.format("%08X", pkg.magic))
+    for _, opt in pairs(pkg.opts) do
+        if opt[1] == 53 then
+            log.info(TAG, "msgtype", opt[2]:byte())
+        elseif opt[1] == 60 then
+            log.info(TAG, "auth", opt[2])
+        elseif opt[1] == 57 then
+            log.info(TAG, "Maximum DHCP message size", opt[2]:byte() * 256 + opt[2]:byte(2))
+        elseif opt[1] == 61 then
+            log.info(TAG, "Client-identifier", opt[2]:toHex())
+        elseif opt[1] == 55 then
+            log.info(TAG, "Parameter request list", opt[2]:toHex())
+        elseif opt[1] == 12 then
+            log.info(TAG, "Host name", opt[2])
+        -- elseif opt[1] == 58 then
+        --     log.info(TAG, "Renewal (T1) time value", opt[2]:unpack(">I"))
+        end
+    end
+end
+
+local function dhcp_encode(pkg, buff)
+    -- 合成DHCP包
+    buff:seek(0)
+    buff[0] = pkg.op
+    buff[1] = pkg.htype
+    buff[2] = pkg.hlen
+    buff[3] = pkg.hops
+    buff:seek(4)
+    -- 写入XID
+    buff:write(pkg.xid)
+    -- 几个重要的参数
+    buff:pack(">H", pkg.secs)
+    buff:pack(">H", pkg.flags)
+    buff:write(pkg.ciaddr)
+    buff:write(pkg.yiaddr)
+    buff:write(pkg.siaddr)
+    buff:write(pkg.giaddr)
+    -- 写入MAC地址
+    buff:write(pkg.chaddr)
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+    -- 写入magic
+    buff:pack(">I", pkg.magic)
+    -- 写入option
+    for _, opt in pairs(pkg.opts) do
+        buff:write(opt[1])
+        buff:write(#opt[2])
+        buff:write(opt[2])
+    end
+    buff:write(0xFF, 0x00)
+end
+
+----
+
+local function dhcp_send_x(srv, pkg, client, msgtype)
+    local buff = zbuff.create(300)
+    pkg.op = 2
+    pkg.ciaddr = "\0\0\0\0"
+    pkg.yiaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    pkg.siaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])
+    pkg.giaddr = "\0\0\0\0"
+    pkg.secs = 0
+
+    pkg.opts = {} -- 复位option
+    table.insert(pkg.opts, {53, string.char(msgtype)})
+    table.insert(pkg.opts, {1, string.char(srv.opts.mark[1], srv.opts.mark[2], srv.opts.mark[3], srv.opts.mark[4])})
+    table.insert(pkg.opts, {3, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {51, "\x00\x00\x1E\x00"}) -- 7200秒, 大概
+    table.insert(pkg.opts, {54, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {6, string.char(223, 5, 5, 5)})
+    table.insert(pkg.opts, {6, string.char(119, 29, 29, 29)})
+    table.insert(pkg.opts, {6, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+
+    dhcp_encode(pkg, buff)
+
+    local dst = "255.255.255.255"
+    if 4 == msgtype then
+        dst = string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    end
+    -- log.info(TAG, "发送", msgtype, dst, buff:query():toHex())
+    srv.udp:send(buff, dst, 68)
+end
+
+local function dhcp_send_offer(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 2)
+end
+
+local function dhcp_send_ack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 5)
+end
+
+local function dhcp_send_nack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 6)
+end
+
+local function dhcp_handle_discover(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "发现已经分配的mac地址, send offer")
+            dhcp_send_offer(srv, pkg, client)
+            return
+        end
+    end
+    -- TODO 清理已经过期的IP分配记录
+    -- 分配一个新的ip
+    if #srv.clients >= (srv.opts.ip_end - srv.opts.ip_start) then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    local ip = nil
+    for i = srv.opts.ip_start, srv.opts.ip_end, 1 do
+        if srv.clients[i] == nil then
+            ip = i
+            break
+        end
+    end
+    if ip == nil then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    log.info(TAG, "分配ip", mac:toHex(), string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], ip))
+    local client = {
+        mac = mac,
+        ip = ip,
+        tm = mcu.ticks() // mcu.hz(),
+        stat = 1
+    }
+    srv.clients[ip] = client
+    log.info(TAG, "send offer")
+    dhcp_send_offer(srv, pkg, client)
+end
+
+local function dhcp_handle_request(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "request,发现已经分配的mac地址, send ack")
+            client.tm = mcu.ticks() // mcu.hz()
+            stat = 3
+            dhcp_send_ack(srv, pkg, client)
+            return
+        end
+    end
+    -- 没有找到, 那应该返回NACK
+    log.info(TAG, "request,没有分配的mac地址, send nack")
+    dhcp_send_nack(srv, pkg, {ip=pkg.yiaddr:byte(1)})
+end
+
+local function dhcp_pkg_handle(srv, pkg)
+    -- 进行基本的检查
+    if pkg.magic ~= 0x63825363 then
+        log.warn(TAG, "dhcp数据包的magic不对劲,忽略该数据包", pkg.magic)
+        return
+    end
+    if pkg.op ~= 1 then
+        log.info(TAG, "op不对,忽略该数据包", pkg.op)
+        return
+    end
+    if pkg.htype ~= 1 or pkg.hlen ~= 6 then
+        log.warn(TAG, "htype/hlen 不认识, 忽略该数据包")
+        return
+    end
+    -- 看看是不是能处理的类型, 当前只处理discover/request
+    if pkg.msgtype == 1 or pkg.msgtype == 3 then
+    else
+        log.warn(TAG, "msgtype不是discover/request, 忽略该数据包", pkg.msgtype)
+        return
+    end
+    -- 检查一下mac地址是否合法
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    if mac == "\0\0\0\0\0\0" or mac == "\xFF\xFF\xFF\xFF\xFF\xFF" then
+        log.warn(TAG, "mac地址为空, 忽略该数据包")
+        return
+    end
+
+    -- 处理discover包
+    if pkg.msgtype == 1 then
+        log.info(TAG, "是discover包")
+        dhcp_handle_discover(srv, pkg)
+    elseif pkg.msgtype == 3 then
+        log.info(TAG, "是request包")
+        dhcp_handle_request(srv, pkg)
+    end
+    -- TODO 处理结束, 打印一下客户的列表?
+end
+
+local function dhcp_task(srv)
+    while 1 do
+        -- log.info("ulwip", "等待DHCP数据")
+        local result, data = sys.waitUntil(srv.udp_topic, 1000)
+        if result then
+            -- log.info("ulwip", "收到dhcp数据包", data:toHex())
+            -- 解析DHCP数据包
+            local pkg = dhcp_decode(zbuff.create(#data, data))
+            if pkg then
+                -- dhcp_print_pkg(pkg)
+                dhcp_pkg_handle(srv, pkg)
+            end
+        end
+    end
+end
+function dhcpsrv.create(opts)
+    local srv = {}
+    if not opts then
+        opts = {}
+    end
+    srv.udp_topic = "dhcpd_inc"
+    -- 补充参数
+    if not opts.mark then
+        opts.mark = {255, 255, 255, 0}
+    end
+    if not opts.gw then
+        opts.gw = {192, 168, 4, 1}
+    end
+    if not opts.dns then
+        opts.dns = opts.gw
+    end
+    if not opts.ip_start then
+        opts.ip_start = 100
+    end
+    if not opts.ip_end then
+        opts.ip_end = 200
+    end
+
+    srv.clients = {}
+    srv.opts = opts
+
+    srv.udp = udpsrv.create(67, srv.udp_topic, opts.adapter)
+    srv.task = sys.taskInit(dhcp_task, srv)
+    return srv
+end
+
+
+return dhcpsrv

+ 101 - 0
module/Air780EPM/demo/modbus/master_tcp/dnsproxy.lua

@@ -0,0 +1,101 @@
+local sys = require "sys"
+
+local dnsproxy = {}
+dnsproxy.map = {}
+dnsproxy.txid = 0x123
+dnsproxy.rxbuff = zbuff.create(1500)
+
+function dnsproxy.on_request(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len, remote_ip, remote_port = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                -- log.info("dnsproxy", "收到DNS查询数据", rxbuff:query():toHex())
+                if remote_ip and #remote_ip == 5 then
+                    local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_request = rxbuff[0] + rxbuff[1] * 256
+                    local txid_map = dnsproxy.txid
+                    dnsproxy.txid = dnsproxy.txid + 1
+                    if dnsproxy.txid > 65000 then
+                        dnsproxy.txid = 0x123
+                    end
+                    table.insert(dnsproxy.map, {txid_request, txid_map, remote_ip, remote_port})
+                    rxbuff[0] = txid_map % 256
+                    rxbuff[1] = txid_map // 256
+                    socket.tx(dnsproxy.main_sc, rxbuff, "223.5.5.5", 53)
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+function dnsproxy.on_response(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                if true then
+                    -- local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    -- remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_resp = rxbuff[0] + rxbuff[1] * 256
+                    local index = -1
+                    for i, mapit in pairs(dnsproxy.map) do
+                        if mapit[2] == txid_resp then
+                            local txid_request = mapit[1]
+                            local remote_ip = mapit[3]
+                            local remote_port = mapit[4]
+                            rxbuff[0] = txid_request % 256
+                            rxbuff[1] = txid_request // 256
+                            socket.tx(dnsproxy.sc, rxbuff, remote_ip, remote_port)
+                            index = i
+                            break
+                        end
+                    end
+                    if index > 0 then
+                        table.remove(dnsproxy.map, index)
+                    end
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+--[[
+创建UDP服务器
+@api dnsproxy.create(adapter, main_adapter)
+@int 监听的网络适配器id
+@int 网络适配编号, 默认为nil,可选
+@return table UDP服务的实体, 若创建失败会返回nil
+]]
+function dnsproxy.setup(adapter, main_adapter)
+    log.info("dnsproxy", adapter, main_adapter)
+    dnsproxy.adapter = adapter
+    dnsproxy.main_adapter = main_adapter
+    dnsproxy.sc = socket.create(dnsproxy.adapter, dnsproxy.on_request)
+    dnsproxy.main_sc = socket.create(dnsproxy.main_adapter, dnsproxy.on_response)
+    socket.config(dnsproxy.sc, 53, true)
+    socket.config(dnsproxy.main_sc, 1053, true)
+    dnsproxy.on_ip_ready()
+    return true
+end
+
+function dnsproxy.on_ip_ready()
+    socket.close(dnsproxy.sc)
+    socket.close(dnsproxy.main_sc)
+    log.info("dnsproxy", "开启DNS代理")
+    socket.connect(dnsproxy.sc, "255.255.255.255", 0)
+    socket.connect(dnsproxy.main_sc, "223.5.5.5", 53)
+end
+
+sys.subscribe("IP_READY", dnsproxy.on_ip_ready)
+
+return dnsproxy

+ 59 - 0
module/Air780EPM/demo/modbus/master_tcp/lan.lua

@@ -0,0 +1,59 @@
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+dhcps = require "dhcpsrv"
+dnsproxy = require "dnsproxy"
+
+sys.taskInit(function ()
+    -- sys.wait(3000)
+    local result = spi.setup(
+        0,--串口id
+        nil,
+        0,--CPHA
+        0,--CPOL
+        8,--数据宽度
+        25600000--,--频率
+        -- spi.MSB,--高低位顺序    可选,默认高位在前
+        -- spi.master,--主模式     可选,默认主
+        -- spi.full--全双工       可选,默认全双工
+    )
+    log.info("main", "open",result)
+    if result ~= 0 then--返回值为0,表示打开成功
+        log.info("main", "spi open error",result)
+        return
+    end
+
+    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spiid=0,cs=8})
+    sys.wait(3000)
+    local ipv4,mark, gw = netdrv.ipv4(socket.LWIP_ETH, "192.168.4.1", "255.255.255.0", "192.168.4.1")
+    log.info("ipv4", ipv4,mark, gw)
+    while netdrv.link(socket.LWIP_ETH) ~= true do
+        sys.wait(100)
+    end
+    dhcps.create({adapter=socket.LWIP_ETH})
+
+
+    dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_GP)
+    netdrv.napt(socket.LWIP_GP)
+
+
+    -- dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
+    -- netdrv.napt(socket.LWIP_ETH)
+
+    -- netdrv.dhcp(socket.LWIP_ETH, true)
+end)
+
+
+sys.taskInit(function()
+    -- sys.waitUntil("IP_READY")
+    while 1 do
+        sys.wait(300000)
+        -- log.info("http", http.request("GET", "http://httpbin.air32.cn/bytes/4096", nil, nil, {adapter=socket.LWIP_ETH}).wait())
+        log.info("lua", rtos.meminfo())
+        log.info("sys", rtos.meminfo("sys"))
+        -- log.info("psram", rtos.meminfo("psram"))
+    end
+end)
+
+

+ 127 - 0
module/Air780EPM/demo/modbus/master_tcp/main.lua

@@ -0,0 +1,127 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "modbus_master_tcp"
+VERSION = "1.0.0"
+log.style(1)
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+
+--初始化网络
+log.info("ch390", "打开LDO供电")
+gpio.setup(20, 1)  --打开lan供电
+
+mcu.hardfault(0) -- 死机后停机,一般用于调试状态
+require "lan"
+
+
+-- 创建主站设备,TCP模式
+mb_tcp = modbus.create_master(modbus.MODBUS_TCP, socket.LWIP_ETH)
+
+-- 为主站添加从站,从站ID为1,ip地址为 192.168.0.104,端口号为 6000
+mb_slave1 = modbus.add_slave(mb_tcp, 1, "192.168.4.100", 6001)
+-- 为主站添加从站,从站ID为2,ip地址为 192.168.0.104,端口号为 6001
+-- mb_slave2 = modbus.add_slave(mb_tcp, 2, "192.168.4.100", 6002)
+
+-- 为从站1创建数据存储区,并创建通讯消息
+slave1_msg1_buf = zbuff.create(1)
+-- mb_slave1_msg1 = modbus.create_msg(mb_tcp, mb_slave1, modbus.REGISTERS, modbus.READ, 0, 10, slave1_msg1_buf,1,modbus.EXEC)
+mb_slave1_msg1 = modbus.create_msg(mb_tcp, mb_slave1, modbus.REGISTERS, modbus.READ, 0, 10, slave1_msg1_buf)
+slave1_msg1_buf:clear()
+
+-- slave1_msg2_buf = zbuff.create(1)
+-- mb_slave1_msg2 = modbus.create_msg(mb_tcp, mb_slave1, modbus.CIOLS, modbus.WRITE, 0, 10, slave1_msg2_buf)
+-- slave1_msg2_buf:clear()
+
+-- 为从站2创建数据存储区,并创建通讯消息
+-- slave2_msg1_buf = zbuff.create(1)
+-- mb_slave2_msg1 = modbus.create_msg(mb_tcp, mb_slave2, modbus.REGISTERS, modbus.WRITE, 0, 10, slave2_msg1_buf)
+-- slave2_msg1_buf:clear()
+
+-- 启动Modubs设备
+modbus.master_start(mb_tcp)
+log.info("start modbus master")
+
+sys.timerLoopStart(function()
+    local status = modbus.get_all_slave_state(mb_tcp)
+    log.info("modbus", status)
+end, 5000)
+
+sys.timerLoopStart(function()
+    local status = modbus.get_slave_state(mb_slave1)
+    log.info("modbus1", status)
+end, 5000)
+
+-- sys.timerLoopStart(function()
+--     local status = modbus.get_slave_state(mb_slave2)
+--     log.info("modbus2", status)
+-- end, 5000)
+
+-- modbus.set_comm_interval_time(mb_tcp,2000)
+
+-- modbus.set_comm_timeout(mb_tcp, 3000)
+
+-- modbus.set_comm_resend_count(mb_tcp,3)
+
+-- modbus.set_msg_comm_period(mb_slave1_msg1, 2)
+
+-- modbus.set_comm_reconnection_time(mb_tcp, 6000)
+
+-- sys.timerLoopStart(function()
+--     local status=modbus.exec(mb_tcp, mb_slave1_msg1)
+--     log.info("msg",status)
+-- end,5000)
+
+-- sys.timerStart(function()
+--     local status = modbus.remove_slave(mb_tcp, mb_slave2)
+--     log.info("modbus", "slave remove after 3 minutes")
+--     log.info("remove", status)
+    
+--     -- 移除从站后,5秒后重新启动Modbus主站
+--     sys.timerStart(function()
+--         modbus.master_start(mb_tcp)
+--         log.info("modbus", "Modbus master restarted after slave removal")
+--     end, 5000)
+-- end, 180000) 
+
+-- 修改和读取modbus值
+addvar = 0
+function modify_data()
+    -- 获取变量值
+    slave1_msg1_buf:seek(0)
+    log.info("slave1 reg: ", slave1_msg1_buf:readU16(), slave1_msg1_buf:readU16(),
+                             slave1_msg1_buf:readU16(), slave1_msg1_buf:readU16())
+    
+    -- slave2_msg1_buf:seek(0)
+    -- log.info("slave2 reg: ", slave2_msg1_buf:readU16(), slave2_msg1_buf:readU16(),
+    --                          slave2_msg1_buf:readU16(), slave2_msg1_buf:readU16())
+    -- 写入变量值
+    -- slave2_msg1_buf:seek(0)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- slave2_msg1_buf:writeU16(addvar)
+    -- addvar=addvar+1
+
+	-- 每周期值取反
+    -- slave1_msg2_buf:seek(0)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+	-- slave1_msg2_buf:writeU8(addvar%2)
+end
+sys.timerLoopStart(modify_data,1000)
+
+-- sys.timerStart(function()
+--     modbus.master_stop(mb_tcp)
+--     log.info("modbus", "Modbus stopped after 2 minutes")
+-- end, 120000) 
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 70 - 0
module/Air780EPM/demo/modbus/slave_rtu/main.lua

@@ -0,0 +1,70 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "modbus_slave_rtu"
+VERSION = "1.0.0"
+log.style(1)
+log.info("main", PROJECT, VERSION)
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+--初始化通讯串口
+local uartid = 1        -- 根据实际设备选取不同的uartid
+local uart485Pin = 24   -- 用于控制485接收和发送的使能引脚
+gpio.setup(1, 1)        --打开电源(开发板485供电脚是gpio1,用开发板测试需要开机初始化拉高gpio1)
+uart.setup(uartid, 9600, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
+
+
+-- 创建从站设备
+local slave_id = 1
+mb_rtu_s = modbus.create_slave(modbus.MODBUS_RTU, slave_id, uartid)
+-- mb_rtu_s = modbus.create_slave(modbus.MODBUS_ASCII, slave_id, uartid)
+
+
+-- 创建寄存器数据区
+registers = zbuff.create(1)
+modbus.add_block(mb_rtu_s, modbus.REGISTERS, 0, 32, registers)
+registers:clear()
+
+-- 创建线圈数据区
+ciols = zbuff.create(1)
+modbus.add_block(mb_rtu_s, modbus.CIOLS, 0, 32, ciols)
+ciols:clear()
+
+-- 启动通讯
+modbus.slave_start(mb_rtu_s)
+
+local counter = 0
+
+-- 修改和读取modbus值
+function modify_data()
+    counter = counter + 1
+    
+    -- 写入寄存器数据 (16位无符号整数)
+    registers:seek(0)
+    for i=0,31 do
+        registers:writeU16((counter + i) % 65536)  -- 写入递增数字,限制在0-65535
+    end
+    
+    -- 写入线圈数据 (1位布尔值)
+    ciols:seek(0)
+    for i=0,31 do
+        ciols:writeU8((counter + i) % 2)  -- 交替写入0和1
+    end
+  
+    -- 读取并打印部分数据用于调试
+    registers:seek(0)
+    ciols:seek(0)
+    log.info("registers:", registers:readU16(), registers:readU16(), registers:readU16(), registers:readU16(), registers:readU16())
+    log.info("ciols    :", ciols:readU8(), ciols:readU8(), ciols:readU8(), ciols:readU8(), ciols:readU8())
+end
+sys.timerLoopStart(modify_data,1000)
+
+-- sys.timerStart(function()
+--     modbus.slave_stop(mb_rtu_s)
+--     log.info("Modbus", "2分钟时间到,停止Modbus从站")
+-- end, 2 * 60 * 1000)  -- 2分钟(单位:毫秒)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 311 - 0
module/Air780EPM/demo/modbus/slave_tcp/dhcpsrv.lua

@@ -0,0 +1,311 @@
+
+local dhcpsrv = {}
+
+local udpsrv = require("udpsrv")
+
+local TAG = "dhcpsrv"
+
+----
+-- 参考地址
+-- https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
+
+local function dhcp_decode(buff)
+    -- buff:seek(0)
+    local dst = {}
+    -- 开始解析dhcp
+    dst.op = buff[0]
+    dst.htype = buff[1]
+    dst.hlen = buff[2]
+    dst.hops = buff[3]
+    buff:seek(4)
+    dst.xid = buff:read(4)
+
+    _, dst.secs = buff:unpack(">H")
+    _, dst.flags = buff:unpack(">H")
+    dst.ciaddr = buff:read(4)
+    dst.yiaddr = buff:read(4)
+    dst.siaddr = buff:read(4)
+    dst.giaddr = buff:read(4)
+    dst.chaddr = buff:read(16)
+
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+
+    -- 解析magic
+    _, dst.magic = buff:unpack(">I")
+
+    -- 解析option
+    local opt = {}
+    while buff:len() > buff:used() do
+        local tag = buff:read(1):byte()
+        if tag ~= 0 then
+            local len = buff:read(1):byte()
+            if tag == 0xFF or len == 0 then
+                break
+            end
+            local data = buff:read(len)
+            if tag == 53 then
+                -- 53: DHCP Message Type
+                dst.msgtype = data:byte()
+            end
+            table.insert(opt, {tag, data})
+            -- log.info(TAG, "tag", tag, "data", data:toHex())
+        end
+    end
+    if dst.msgtype == nil then
+        return -- 没有解析到msgtype,直接返回
+    end
+    dst.opts = opt
+    return dst
+end
+
+local function dhcp_buff2ip(buff)
+    return string.format("%d.%d.%d.%d", buff:byte(1), buff:byte(2), buff:byte(3), buff:byte(4))
+end
+
+local function dhcp_print_pkg(pkg)
+    log.info(TAG, "XID",  pkg.xid:toHex())
+    log.info(TAG, "secs", pkg.secs)
+    log.info(TAG, "flags", pkg.flags)
+    log.info(TAG, "chaddr", pkg.chaddr:sub(1, pkg.hlen):toHex())
+    log.info(TAG, "yiaddr", dhcp_buff2ip(pkg.yiaddr))
+    log.info(TAG, "siaddr", dhcp_buff2ip(pkg.siaddr))
+    log.info(TAG, "giaddr", dhcp_buff2ip(pkg.giaddr))
+    log.info(TAG, "ciaddr", dhcp_buff2ip(pkg.ciaddr))
+    log.info(TAG, "magic", string.format("%08X", pkg.magic))
+    for _, opt in pairs(pkg.opts) do
+        if opt[1] == 53 then
+            log.info(TAG, "msgtype", opt[2]:byte())
+        elseif opt[1] == 60 then
+            log.info(TAG, "auth", opt[2])
+        elseif opt[1] == 57 then
+            log.info(TAG, "Maximum DHCP message size", opt[2]:byte() * 256 + opt[2]:byte(2))
+        elseif opt[1] == 61 then
+            log.info(TAG, "Client-identifier", opt[2]:toHex())
+        elseif opt[1] == 55 then
+            log.info(TAG, "Parameter request list", opt[2]:toHex())
+        elseif opt[1] == 12 then
+            log.info(TAG, "Host name", opt[2])
+        -- elseif opt[1] == 58 then
+        --     log.info(TAG, "Renewal (T1) time value", opt[2]:unpack(">I"))
+        end
+    end
+end
+
+local function dhcp_encode(pkg, buff)
+    -- 合成DHCP包
+    buff:seek(0)
+    buff[0] = pkg.op
+    buff[1] = pkg.htype
+    buff[2] = pkg.hlen
+    buff[3] = pkg.hops
+    buff:seek(4)
+    -- 写入XID
+    buff:write(pkg.xid)
+    -- 几个重要的参数
+    buff:pack(">H", pkg.secs)
+    buff:pack(">H", pkg.flags)
+    buff:write(pkg.ciaddr)
+    buff:write(pkg.yiaddr)
+    buff:write(pkg.siaddr)
+    buff:write(pkg.giaddr)
+    -- 写入MAC地址
+    buff:write(pkg.chaddr)
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+    -- 写入magic
+    buff:pack(">I", pkg.magic)
+    -- 写入option
+    for _, opt in pairs(pkg.opts) do
+        buff:write(opt[1])
+        buff:write(#opt[2])
+        buff:write(opt[2])
+    end
+    buff:write(0xFF, 0x00)
+end
+
+----
+
+local function dhcp_send_x(srv, pkg, client, msgtype)
+    local buff = zbuff.create(300)
+    pkg.op = 2
+    pkg.ciaddr = "\0\0\0\0"
+    pkg.yiaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    pkg.siaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])
+    pkg.giaddr = "\0\0\0\0"
+    pkg.secs = 0
+
+    pkg.opts = {} -- 复位option
+    table.insert(pkg.opts, {53, string.char(msgtype)})
+    table.insert(pkg.opts, {1, string.char(srv.opts.mark[1], srv.opts.mark[2], srv.opts.mark[3], srv.opts.mark[4])})
+    table.insert(pkg.opts, {3, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {51, "\x00\x00\x1E\x00"}) -- 7200秒, 大概
+    table.insert(pkg.opts, {54, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {6, string.char(223, 5, 5, 5)})
+    table.insert(pkg.opts, {6, string.char(119, 29, 29, 29)})
+    table.insert(pkg.opts, {6, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+
+    dhcp_encode(pkg, buff)
+
+    local dst = "255.255.255.255"
+    if 4 == msgtype then
+        dst = string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    end
+    -- log.info(TAG, "发送", msgtype, dst, buff:query():toHex())
+    srv.udp:send(buff, dst, 68)
+end
+
+local function dhcp_send_offer(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 2)
+end
+
+local function dhcp_send_ack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 5)
+end
+
+local function dhcp_send_nack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 6)
+end
+
+local function dhcp_handle_discover(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "发现已经分配的mac地址, send offer")
+            dhcp_send_offer(srv, pkg, client)
+            return
+        end
+    end
+    -- TODO 清理已经过期的IP分配记录
+    -- 分配一个新的ip
+    if #srv.clients >= (srv.opts.ip_end - srv.opts.ip_start) then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    local ip = nil
+    for i = srv.opts.ip_start, srv.opts.ip_end, 1 do
+        if srv.clients[i] == nil then
+            ip = i
+            break
+        end
+    end
+    if ip == nil then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    log.info(TAG, "分配ip", mac:toHex(), string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], ip))
+    local client = {
+        mac = mac,
+        ip = ip,
+        tm = mcu.ticks() // mcu.hz(),
+        stat = 1
+    }
+    srv.clients[ip] = client
+    log.info(TAG, "send offer")
+    dhcp_send_offer(srv, pkg, client)
+end
+
+local function dhcp_handle_request(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "request,发现已经分配的mac地址, send ack")
+            client.tm = mcu.ticks() // mcu.hz()
+            stat = 3
+            dhcp_send_ack(srv, pkg, client)
+            return
+        end
+    end
+    -- 没有找到, 那应该返回NACK
+    log.info(TAG, "request,没有分配的mac地址, send nack")
+    dhcp_send_nack(srv, pkg, {ip=pkg.yiaddr:byte(1)})
+end
+
+local function dhcp_pkg_handle(srv, pkg)
+    -- 进行基本的检查
+    if pkg.magic ~= 0x63825363 then
+        log.warn(TAG, "dhcp数据包的magic不对劲,忽略该数据包", pkg.magic)
+        return
+    end
+    if pkg.op ~= 1 then
+        log.info(TAG, "op不对,忽略该数据包", pkg.op)
+        return
+    end
+    if pkg.htype ~= 1 or pkg.hlen ~= 6 then
+        log.warn(TAG, "htype/hlen 不认识, 忽略该数据包")
+        return
+    end
+    -- 看看是不是能处理的类型, 当前只处理discover/request
+    if pkg.msgtype == 1 or pkg.msgtype == 3 then
+    else
+        log.warn(TAG, "msgtype不是discover/request, 忽略该数据包", pkg.msgtype)
+        return
+    end
+    -- 检查一下mac地址是否合法
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    if mac == "\0\0\0\0\0\0" or mac == "\xFF\xFF\xFF\xFF\xFF\xFF" then
+        log.warn(TAG, "mac地址为空, 忽略该数据包")
+        return
+    end
+
+    -- 处理discover包
+    if pkg.msgtype == 1 then
+        log.info(TAG, "是discover包")
+        dhcp_handle_discover(srv, pkg)
+    elseif pkg.msgtype == 3 then
+        log.info(TAG, "是request包")
+        dhcp_handle_request(srv, pkg)
+    end
+    -- TODO 处理结束, 打印一下客户的列表?
+end
+
+local function dhcp_task(srv)
+    while 1 do
+        -- log.info("ulwip", "等待DHCP数据")
+        local result, data = sys.waitUntil(srv.udp_topic, 1000)
+        if result then
+            -- log.info("ulwip", "收到dhcp数据包", data:toHex())
+            -- 解析DHCP数据包
+            local pkg = dhcp_decode(zbuff.create(#data, data))
+            if pkg then
+                -- dhcp_print_pkg(pkg)
+                dhcp_pkg_handle(srv, pkg)
+            end
+        end
+    end
+end
+function dhcpsrv.create(opts)
+    local srv = {}
+    if not opts then
+        opts = {}
+    end
+    srv.udp_topic = "dhcpd_inc"
+    -- 补充参数
+    if not opts.mark then
+        opts.mark = {255, 255, 255, 0}
+    end
+    if not opts.gw then
+        opts.gw = {192, 168, 4, 1}
+    end
+    if not opts.dns then
+        opts.dns = opts.gw
+    end
+    if not opts.ip_start then
+        opts.ip_start = 100
+    end
+    if not opts.ip_end then
+        opts.ip_end = 200
+    end
+
+    srv.clients = {}
+    srv.opts = opts
+
+    srv.udp = udpsrv.create(67, srv.udp_topic, opts.adapter)
+    srv.task = sys.taskInit(dhcp_task, srv)
+    return srv
+end
+
+
+return dhcpsrv

+ 101 - 0
module/Air780EPM/demo/modbus/slave_tcp/dnsproxy.lua

@@ -0,0 +1,101 @@
+local sys = require "sys"
+
+local dnsproxy = {}
+dnsproxy.map = {}
+dnsproxy.txid = 0x123
+dnsproxy.rxbuff = zbuff.create(1500)
+
+function dnsproxy.on_request(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len, remote_ip, remote_port = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                -- log.info("dnsproxy", "收到DNS查询数据", rxbuff:query():toHex())
+                if remote_ip and #remote_ip == 5 then
+                    local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_request = rxbuff[0] + rxbuff[1] * 256
+                    local txid_map = dnsproxy.txid
+                    dnsproxy.txid = dnsproxy.txid + 1
+                    if dnsproxy.txid > 65000 then
+                        dnsproxy.txid = 0x123
+                    end
+                    table.insert(dnsproxy.map, {txid_request, txid_map, remote_ip, remote_port})
+                    rxbuff[0] = txid_map % 256
+                    rxbuff[1] = txid_map // 256
+                    socket.tx(dnsproxy.main_sc, rxbuff, "223.5.5.5", 53)
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+function dnsproxy.on_response(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                if true then
+                    -- local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    -- remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_resp = rxbuff[0] + rxbuff[1] * 256
+                    local index = -1
+                    for i, mapit in pairs(dnsproxy.map) do
+                        if mapit[2] == txid_resp then
+                            local txid_request = mapit[1]
+                            local remote_ip = mapit[3]
+                            local remote_port = mapit[4]
+                            rxbuff[0] = txid_request % 256
+                            rxbuff[1] = txid_request // 256
+                            socket.tx(dnsproxy.sc, rxbuff, remote_ip, remote_port)
+                            index = i
+                            break
+                        end
+                    end
+                    if index > 0 then
+                        table.remove(dnsproxy.map, index)
+                    end
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+--[[
+创建UDP服务器
+@api dnsproxy.create(adapter, main_adapter)
+@int 监听的网络适配器id
+@int 网络适配编号, 默认为nil,可选
+@return table UDP服务的实体, 若创建失败会返回nil
+]]
+function dnsproxy.setup(adapter, main_adapter)
+    log.info("dnsproxy", adapter, main_adapter)
+    dnsproxy.adapter = adapter
+    dnsproxy.main_adapter = main_adapter
+    dnsproxy.sc = socket.create(dnsproxy.adapter, dnsproxy.on_request)
+    dnsproxy.main_sc = socket.create(dnsproxy.main_adapter, dnsproxy.on_response)
+    socket.config(dnsproxy.sc, 53, true)
+    socket.config(dnsproxy.main_sc, 1053, true)
+    dnsproxy.on_ip_ready()
+    return true
+end
+
+function dnsproxy.on_ip_ready()
+    socket.close(dnsproxy.sc)
+    socket.close(dnsproxy.main_sc)
+    log.info("dnsproxy", "开启DNS代理")
+    socket.connect(dnsproxy.sc, "255.255.255.255", 0)
+    socket.connect(dnsproxy.main_sc, "223.5.5.5", 53)
+end
+
+sys.subscribe("IP_READY", dnsproxy.on_ip_ready)
+
+return dnsproxy

+ 65 - 0
module/Air780EPM/demo/modbus/slave_tcp/lan.lua

@@ -0,0 +1,65 @@
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+dhcps = require "dhcpsrv"
+dnsproxy = require "dnsproxy"
+
+sys.taskInit(function ()
+    -- sys.wait(3000)
+    local result = spi.setup(
+        0,--串口id
+        nil,
+        0,--CPHA
+        0,--CPOL
+        8,--数据宽度
+        25600000--,--频率
+        -- spi.MSB,--高低位顺序    可选,默认高位在前
+        -- spi.master,--主模式     可选,默认主
+        -- spi.full--全双工       可选,默认全双工
+    )
+    log.info("main", "open",result)
+    if result ~= 0 then--返回值为0,表示打开成功
+        log.info("main", "spi open error",result)
+        return
+    end
+
+    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spiid=0,cs=8})
+    sys.wait(3000)
+    local ipv4,mark, gw = netdrv.ipv4(socket.LWIP_ETH, "192.168.4.1", "255.255.255.0", "192.168.4.1")
+    log.info("ipv4", ipv4,mark, gw)
+    while netdrv.link(socket.LWIP_ETH) ~= true do
+        sys.wait(100)
+    end
+    dhcps.create({adapter=socket.LWIP_ETH})
+
+
+    -- dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_GP)
+    -- netdrv.napt(socket.LWIP_GP)
+
+
+    dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
+    netdrv.napt(socket.LWIP_ETH)
+
+    -- netdrv.dhcp(socket.LWIP_ETH, true)
+
+    if iperf then
+        log.info("启动iperf服务器端")
+        iperf.server(socket.LWIP_ETH)
+    end
+end)
+
+
+sys.taskInit(function()
+    sys.waitUntil("IP_READY")
+    while 1 do
+        sys.wait(300000)
+        -- log.info("http", http.request("GET", "http://httpbin.air32.cn/bytes/4096", nil, nil, {adapter=socket.LWIP_ETH}).wait())
+        log.info("lua", rtos.meminfo())
+        log.info("sys", rtos.meminfo("sys"))
+        -- log.info("psram", rtos.meminfo("psram"))
+    end
+end)
+
+

+ 66 - 0
module/Air780EPM/demo/modbus/slave_tcp/main.lua

@@ -0,0 +1,66 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "modbus_slave_tcp"
+VERSION = "1.0.0"
+log.style(1)
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+
+log.info("ch390", "打开LDO供电")
+gpio.setup(20, 1)  --打开lan供电
+require "lan"
+
+-- 创建从站设备
+local slave_id = 1
+mb_tcp_s = modbus.create_slave(modbus.MODBUS_TCP, slave_id, 53, socket.LWIP_ETH)
+
+-- 创建寄存器数据区
+registers = zbuff.create(1)
+modbus.add_block(mb_tcp_s, modbus.REGISTERS, 0, 32, registers)
+registers:clear()
+-- 创建线圈数据区
+ciols = zbuff.create(1)
+modbus.add_block(mb_tcp_s, modbus.CIOLS, 0, 32, ciols)
+ciols:clear()
+
+-- 启动通讯
+modbus.slave_start(mb_tcp_s)
+log.info("start modbus slave")
+
+local counter = 0
+
+-- 修改和读取modbus值
+function modify_data()
+    counter = counter + 1
+    
+    -- 写入寄存器数据 (16位无符号整数)
+    registers:seek(0)
+    for i=0,31 do
+        registers:writeU16((counter + i) % 65536)  -- 写入递增数字,限制在0-65535
+    end
+    
+    -- 写入线圈数据 (1位布尔值)
+    ciols:seek(0)
+    for i=0,31 do
+        ciols:writeU8((counter + i) % 2)  -- 交替写入0和1
+    end
+    
+    -- 读取并打印部分数据用于调试
+    registers:seek(0)
+    ciols:seek(0)
+    log.info("registers:", registers:readU16(), registers:readU16(), registers:readU16(), registers:readU16(), registers:readU16())
+    log.info("ciols    :", ciols:readU8(), ciols:readU8(), ciols:readU8(), ciols:readU8(), ciols:readU8())
+end
+sys.timerLoopStart(modify_data,1000)
+
+-- sys.timerStart(function()
+--     modbus.slave_stop(mb_rtu_s)
+--     log.info("Modbus", "2分钟时间到,停止Modbus从站")
+-- end, 120000)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!