Просмотр исходного кода

Merge branch 'master' of https://gitee.com/openLuat/LuatOS

alienwalker 8 месяцев назад
Родитель
Сommit
da9a2b344c
25 измененных файлов с 1796 добавлено и 89 удалено
  1. 2 1
      components/tp/luat_lib_tp.c
  2. 2 1
      components/tp/luat_tp.h
  3. 61 70
      components/tp/luat_tp_cst820.c
  4. 2 2
      module/Air780EPM/demo/modbus/ascii/master_ascii/main.lua
  5. 2 2
      module/Air780EPM/demo/modbus/ascii/slave_ascii/main.lua
  6. 302 0
      module/Air780EPM/demo/modbus/tcp/master_tcp/dhcpsrv.lua
  7. 113 0
      module/Air780EPM/demo/modbus/tcp/master_tcp/dnsproxy.lua
  8. 0 2
      module/Air780EPM/demo/modbus/tcp/master_tcp/lan.lua
  9. 5 0
      module/Air780EPM/demo/modbus/tcp/master_tcp/main.lua
  10. 302 0
      module/Air780EPM/demo/modbus/tcp/slave_tcp/dhcpsrv.lua
  11. 113 0
      module/Air780EPM/demo/modbus/tcp/slave_tcp/dnsproxy.lua
  12. 0 2
      module/Air780EPM/demo/modbus/tcp/slave_tcp/lan.lua
  13. 6 0
      module/Air780EPM/demo/modbus/tcp/slave_tcp/main.lua
  14. 7 2
      module/Air8000/demo/modbus/ascii/master_ascii/main.lua
  15. 6 1
      module/Air8000/demo/modbus/ascii/slave_ascii/main.lua
  16. 8 3
      module/Air8000/demo/modbus/rtu/master_rtu/main.lua
  17. 6 1
      module/Air8000/demo/modbus/rtu/slave_rtu/main.lua
  18. 311 0
      module/Air8000/demo/modbus/tcp/master_tcp/dhcpsrv.lua
  19. 113 0
      module/Air8000/demo/modbus/tcp/master_tcp/dnsproxy.lua
  20. 0 1
      module/Air8000/demo/modbus/tcp/master_tcp/lan.lua
  21. 5 0
      module/Air8000/demo/modbus/tcp/master_tcp/main.lua
  22. 311 0
      module/Air8000/demo/modbus/tcp/slave_tcp/dhcpsrv.lua
  23. 113 0
      module/Air8000/demo/modbus/tcp/slave_tcp/dnsproxy.lua
  24. 0 1
      module/Air8000/demo/modbus/tcp/slave_tcp/lan.lua
  25. 6 0
      module/Air8000/demo/modbus/tcp/slave_tcp/main.lua

+ 2 - 1
components/tp/luat_lib_tp.c

@@ -32,7 +32,8 @@ static const tp_reg_t tp_regs[] = {
     {"jd9261t",  &tp_config_jd9261t},
 	{"jd9261t_inited",  &tp_config_jd9261t_inited},
 	{"ft3x68", &tp_config_ft3x68},
-    {"cts820", &tp_config_cts820},
+    {"cst820", &tp_config_cst820},
+    // {"cst9220", &tp_config_cst820},
     {"", NULL}
 };
 

+ 2 - 1
components/tp/luat_tp.h

@@ -68,7 +68,8 @@ extern luat_tp_opts_t tp_config_gt9157;
 extern luat_tp_opts_t tp_config_jd9261t;
 extern luat_tp_opts_t tp_config_jd9261t_inited;
 extern luat_tp_opts_t tp_config_ft3x68;
-extern luat_tp_opts_t tp_config_cts820;
+extern luat_tp_opts_t tp_config_cst820;
+// extern luat_tp_opts_t tp_config_cst9220;
 
 int luat_tp_init(luat_tp_config_t* luat_tp_config);
 

+ 61 - 70
components/tp/luat_tp_cst820.c

@@ -5,22 +5,21 @@
 #include "luat_rtos.h"
 #include "luat_tp_reg.h"
 
-#define LUAT_LOG_TAG "cts820"
+#define LUAT_LOG_TAG "cst820"
 #include "luat_log.h"
 
-#define CTS820_ADDRESS               (0x15)
-#define CTS820_CHIP_ID_CODE          (0xB7)
-#define CTS820_CHIP_ID               (0xA7)
-#define CTS820_STATUS                (0x02)
-#define CTS820_POINT1_REG            (0x03)
+#define CST820_ADDRESS               (0x15)
+#define CST820_CHIP_ID_CODE          (0xB7)
+#define CST820_CHIP_ID               (0xA7)
+#define CST820_STATUS                (0x02)
+#define CST820_POINT1_REG            (0x03)
 
-#define CTS820_CONFIG_SIZE           (CTS820_CONFIG_FRESH - CTS820_CONFIG_REG + 1)
-#define CTS820_POINT_INFO_NUM        (4)
-#define CTS820_TOUCH_NUMBER_MIN      (1)
-#define CTS820_TOUCH_NUMBER_MAX      (2)
+#define CST820_POINT_INFO_NUM        (4)
+#define CST820_TOUCH_NUMBER_MIN      (1)
+#define CST820_TOUCH_NUMBER_MAX      (2)
 
-#define CTS820_REFRESH_RATE_MIN      (5)
-#define CTS820_REFRESH_RATE_MAX      (20)
+#define CST820_REFRESH_RATE_MIN      (5)
+#define CST820_REFRESH_RATE_MAX      (20)
 
 typedef struct luat_touch_info{
     union{
@@ -41,22 +40,23 @@ typedef struct luat_touch_info{
     };
 }luat_tp_info_t;
 
-static uint8_t cts820_init_state = 0;
+static uint8_t cst820_init_state = 0;
 
-int tp_cts820_clear_status(luat_tp_config_t* luat_tp_config){
-	if (tp_i2c_write_reg16(luat_tp_config, CTS820_STATUS, (uint8_t[]){0x00}, 1)){
+int tp_cst820_clear_status(luat_tp_config_t* luat_tp_config){
+	if (tp_i2c_write_reg16(luat_tp_config, CST820_STATUS, (uint8_t[]){0x00}, 1)){
 		LLOGE("write status reg fail!");
 		return -1;
 	}
 	return 0;
 }
 
-static int tp_cts820_detect(luat_tp_config_t* luat_tp_config){
+static int tp_cst820_detect(luat_tp_config_t* luat_tp_config){
     uint8_t chip_id = 0;
-    luat_tp_config->address = CTS820_ADDRESS;
-    tp_i2c_read_reg8(luat_tp_config, CTS820_CHIP_ID, &chip_id, 1, 0);
-    if (chip_id == CTS820_CHIP_ID_CODE){
-        LLOGI("TP find device CTS820 ,address:0x%02X",luat_tp_config->address);
+    luat_tp_config->address = CST820_ADDRESS;
+    tp_i2c_read_reg8(luat_tp_config, CST820_CHIP_ID, &chip_id, 1, 0);
+    LLOGD("chip_id:0x%02X", chip_id);
+    if (chip_id == CST820_CHIP_ID_CODE){
+        LLOGI("TP find device CST820 ,address:0x%02X",luat_tp_config->address);
         return 0;
     }else{
         return -1;
@@ -65,7 +65,7 @@ static int tp_cts820_detect(luat_tp_config_t* luat_tp_config){
 
 
 static int luat_tp_irq_cb(int pin, void *args){
-    if (cts820_init_state == 0){
+    if (cst820_init_state == 0){
         return -1;
     }
     luat_tp_config_t* luat_tp_config = (luat_tp_config_t*)args;
@@ -74,7 +74,7 @@ static int luat_tp_irq_cb(int pin, void *args){
     return 0;
 }
 
-static int tp_cts820_hw_reset(luat_tp_config_t* luat_tp_config){
+static int tp_cst820_hw_reset(luat_tp_config_t* luat_tp_config){
     if (luat_tp_config->pin_rst != LUAT_GPIO_NONE){
         luat_gpio_set(luat_tp_config->pin_rst, Luat_GPIO_LOW);
         luat_rtos_task_sleep(10);
@@ -84,21 +84,21 @@ static int tp_cts820_hw_reset(luat_tp_config_t* luat_tp_config){
     return 0;
 }
 
-static int tp_cts820_gpio_init(luat_tp_config_t* luat_tp_config){
+static int tp_cst820_gpio_init(luat_tp_config_t* luat_tp_config){
     luat_gpio_mode(luat_tp_config->pin_rst, Luat_GPIO_OUTPUT, Luat_GPIO_DEFAULT, Luat_GPIO_HIGH);
     luat_gpio_mode(luat_tp_config->pin_int, Luat_GPIO_OUTPUT, Luat_GPIO_DEFAULT, Luat_GPIO_HIGH);
     luat_gpio_set(luat_tp_config->pin_rst, Luat_GPIO_HIGH);
     luat_gpio_set(luat_tp_config->pin_int, Luat_GPIO_HIGH);
-    tp_cts820_hw_reset(luat_tp_config);
+    tp_cst820_hw_reset(luat_tp_config);
     return 0;
 }
 
-static int tp_cts820_init(luat_tp_config_t* luat_tp_config){
+static int tp_cst820_init(luat_tp_config_t* luat_tp_config){
     int ret = 0;
     luat_rtos_task_sleep(100);
-    tp_cts820_gpio_init(luat_tp_config);
+    tp_cst820_gpio_init(luat_tp_config);
     luat_rtos_task_sleep(10);
-    ret = tp_cts820_detect(luat_tp_config);
+    ret = tp_cst820_detect(luat_tp_config);
     if (ret){
         LLOGE("tp detect fail!");
         return ret;
@@ -116,13 +116,13 @@ static int tp_cts820_init(luat_tp_config_t* luat_tp_config){
     gpio.irq_args = luat_tp_config;
     luat_gpio_setup(&gpio);
 
-    cts820_init_state = 1;
+    cst820_init_state = 1;
     return ret;
 
 }
 
-static int tp_cts820_deinit(luat_tp_config_t* luat_tp_config){
-    cts820_init_state = 0;
+static int tp_cst820_deinit(luat_tp_config_t* luat_tp_config){
+    cst820_init_state = 0;
     if (luat_tp_config->pin_int != LUAT_GPIO_NONE){
         luat_gpio_close(luat_tp_config->pin_int);
     }
@@ -132,11 +132,11 @@ static int tp_cts820_deinit(luat_tp_config_t* luat_tp_config){
     return 0;
 }
 
-static void tp_cts820_read_done(luat_tp_config_t * luat_tp_config){
+static void tp_cst820_read_done(luat_tp_config_t * luat_tp_config){
 	luat_tp_irq_enable(luat_tp_config, 1);
 }
 
-// cts820 get tp info.
+// cst820 get tp info.
 typedef struct {
     uint8_t x_h : 4;
     uint8_t : 4;
@@ -146,14 +146,14 @@ typedef struct {
     uint8_t y_l;
 } point_data_t;
 
-static int16_t pre_x[CTS820_TOUCH_NUMBER_MAX] = {-1, -1};
-static int16_t pre_y[CTS820_TOUCH_NUMBER_MAX] = {-1, -1};
-static int16_t pre_w[CTS820_TOUCH_NUMBER_MAX] = {-1, -1};
-static uint8_t s_tp_down[CTS820_TOUCH_NUMBER_MAX];
+static int16_t pre_x[CST820_TOUCH_NUMBER_MAX] = {-1, -1};
+static int16_t pre_y[CST820_TOUCH_NUMBER_MAX] = {-1, -1};
+static int16_t pre_w[CST820_TOUCH_NUMBER_MAX] = {-1, -1};
+static uint8_t s_tp_down[CST820_TOUCH_NUMBER_MAX];
 
-static uint8_t read_buff[CTS820_POINT_INFO_NUM * CTS820_TOUCH_NUMBER_MAX];
+static uint8_t read_buff[CST820_POINT_INFO_NUM * CST820_TOUCH_NUMBER_MAX];
 
-void cts820_touch_up(void *buf, int8_t id){
+void cst820_touch_up(void *buf, int8_t id){
 	luat_tp_data_t *read_data = (luat_tp_data_t *)buf;
 
 	if(s_tp_down[id] == 1){
@@ -174,7 +174,7 @@ void cts820_touch_up(void *buf, int8_t id){
 	pre_w[id] = -1;
 }
 
-void cts820_touch_down(void *buf, int8_t id, int16_t x, int16_t y, int16_t w){
+void cst820_touch_down(void *buf, int8_t id, int16_t x, int16_t y, int16_t w){
 	luat_tp_data_t *read_data = (luat_tp_data_t *)buf;
 
 	if (s_tp_down[id] == 1){
@@ -195,7 +195,7 @@ void cts820_touch_down(void *buf, int8_t id, int16_t x, int16_t y, int16_t w){
 	pre_w[id] = w;
 }
 
-void cts820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
+void cst820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
 	uint8_t *read_buf = input_buff;
 	uint8_t read_index;
 	int8_t read_id = 0;
@@ -204,14 +204,14 @@ void cts820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
 	int16_t input_w = 0;
 
 	static uint8_t pre_touch = 0;
-	static int8_t pre_id[CTS820_TOUCH_NUMBER_MAX] = {0};
+	static int8_t pre_id[CST820_TOUCH_NUMBER_MAX] = {0};
 
 	if (pre_touch > touch_num){                                       /* point up */
 		for (read_index = 0; read_index < pre_touch; read_index++){
 			uint8_t j;
 			for (j = 0; j < touch_num; j++){                          /* this time touch num */
 				read_id = j;
-				if (read_id >= CTS820_POINT_INFO_NUM){
+				if (read_id >= CST820_POINT_INFO_NUM){
 					LLOGE("%s, touch ID %d is out range!\r\n", __func__, read_id);
 					return;
 				}
@@ -221,7 +221,7 @@ void cts820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
 				if (j >= touch_num - 1){
 					uint8_t up_id;
 					up_id = pre_id[read_index];
-					cts820_touch_up(buf, up_id);
+					cst820_touch_up(buf, up_id);
 				}
 			}
 		}
@@ -229,9 +229,9 @@ void cts820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
 	if (touch_num){                                                 /* point down */
 		uint8_t off_set;
 		for (read_index = 0; read_index < touch_num; read_index++){
-			off_set = read_index * CTS820_POINT_INFO_NUM;
+			off_set = read_index * CST820_POINT_INFO_NUM;
 			read_id = read_index;
-			if (read_id >= CTS820_POINT_INFO_NUM){
+			if (read_id >= CST820_POINT_INFO_NUM){
 				LLOGE("%s, touch ID %d is out range!\r\n", __func__, read_id);
 				return;
 			}
@@ -239,30 +239,21 @@ void cts820_read_point(uint8_t *input_buff, void *buf, uint8_t touch_num){
             point_data_t* point_buff = &read_buf[off_set];
 			input_x = point_buff->x_h << 8 | point_buff->x_l;	/* x */
 			input_y = point_buff->y_h << 8 | point_buff->y_l;	/* y */
-			cts820_touch_down(buf, read_id, input_x, input_y, input_w);
+			cst820_touch_down(buf, read_id, input_x, input_y, input_w);
 		}
 	}else if (pre_touch){
 		for(read_index = 0; read_index < pre_touch; read_index++){
-			cts820_touch_up(buf, pre_id[read_index]);
+			cst820_touch_up(buf, pre_id[read_index]);
 		}
 	}
 	pre_touch = touch_num;
 }
 
-int tp_cts820_read_status(luat_tp_config_t* luat_tp_config, uint8_t *status){
-	if (tp_i2c_read_reg16(luat_tp_config, CTS820_STATUS, status, 1, 1)){
-		LLOGE("read status reg fail!\r\n");
-		return -1;
-	}
-	// LLOGD("status=0x%02X\r\n", *status); // 调试需要看!!!
-	return 0;
-}
-
-static int tp_cts820_read(luat_tp_config_t* luat_tp_config, luat_tp_data_t *luat_tp_data){
+static int tp_cst820_read(luat_tp_config_t* luat_tp_config, luat_tp_data_t *luat_tp_data){
     uint8_t touch_num=0, point_status=0;
-    tp_i2c_read_reg8(luat_tp_config, CTS820_STATUS, &touch_num, 1, 0);
+    tp_i2c_read_reg8(luat_tp_config, CST820_STATUS, &touch_num, 1, 0);
     
-    // tp_cts820_read_status(luat_tp_config, &point_status);
+    // tp_cst820_read_status(luat_tp_config, &point_status);
     // if (point_status == 0){           /* no data */
     //     goto exit_;
     // }
@@ -271,30 +262,30 @@ static int tp_cts820_read(luat_tp_config_t* luat_tp_config, luat_tp_data_t *luat
     // }
     // touch_num = point_status & 0x0F;  /* get point num */
     // LLOGD("touch_num = %d",touch_num);
-    if (touch_num > CTS820_TOUCH_NUMBER_MAX) {/* point num is not correct */
+    if (touch_num > CST820_TOUCH_NUMBER_MAX) {/* point num is not correct */
         touch_num = 0;
         goto exit_;
     }
     
-    // LLOGD("tp_cts820_read touch_num:%d",touch_num);
+    // LLOGD("tp_cst820_read touch_num:%d",touch_num);
 
     memset(read_buff, 0x00, sizeof(read_buff));
     
     if (touch_num){
-        tp_i2c_read_reg8(luat_tp_config, CTS820_POINT1_REG, read_buff, touch_num * CTS820_POINT_INFO_NUM, 0);
+        tp_i2c_read_reg8(luat_tp_config, CST820_POINT1_REG, read_buff, touch_num * CST820_POINT_INFO_NUM, 0);
     }
 
-    cts820_read_point(read_buff, luat_tp_data, touch_num);
+    cst820_read_point(read_buff, luat_tp_data, touch_num);
     
 exit_:
-    // tp_cts820_clear_status(luat_tp_config);
+    // tp_cst820_clear_status(luat_tp_config);
     return touch_num;
 }
 
-luat_tp_opts_t tp_config_cts820 = {
-    .name = "cts820",
-    .init = tp_cts820_init,
-    .deinit = tp_cts820_deinit,
-    .read = tp_cts820_read,
-	.read_done = tp_cts820_read_done,
+luat_tp_opts_t tp_config_cst820 = {
+    .name = "cst820",
+    .init = tp_cst820_init,
+    .deinit = tp_cst820_deinit,
+    .read = tp_cst820_read,
+	.read_done = tp_cst820_read_done,
 };

+ 2 - 2
module/Air780EPM/demo/modbus/ascii/master_ascii/main.lua

@@ -19,7 +19,7 @@ uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 -- 设置通讯间隔时间,主站将按每隔 设置时间 的频率向从站问询数据(默认100ms),当添加了多个从站后,主站向每个从站问询的时间间隔将叠加
 -- 设置通讯超时时间和消息发送超时重发次数,当主站未在 设置的时间 内接收到从站数据,将向从站再次发送问询(问询次数按设置的 消息超时重发次数 发送,默认1)
 -- 设置断线重连时间间隔,当从站与主站断连后,主站将在设置时间内重新连接从站(默认5000ms)
-mb_ascii = modbus.create_master(modbus.MODBUS_ASCII, uartid,3000,2000,1,5000)
+mb_ascii = modbus.create_master(modbus.MODBUS_ASCII, uartid,115200,3000,2000,1,5000)
 
 
 -- 为主站添加从站,从站ID为1,可使用modbus.add_slave(master_handler, slave_id)接口添加多个从站,最多可以添加247个
@@ -84,7 +84,7 @@ end, 5000)
 -- end, 5000)
 
 
--- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在modbus.set_msg_comm_period(msg_handler, comm_period)接口中设置为手动模式;成功返回true,其他情况返回false
+-- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在modbus.create_msg接口中设置为手动模式;成功返回true,其他情况返回false
 -- sys.timerLoopStart(function()
 --     local status=modbus.exec(mb_ascii, mb_slave1_msg1)
 --     log.info("msg",status)

+ 2 - 2
module/Air780EPM/demo/modbus/ascii/slave_ascii/main.lua

@@ -11,12 +11,12 @@ 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)
+uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 
 
 -- 创建从站设备,此demo用作测试ASCII。
 local slave_id = 1
-mb_ascii_s = modbus.create_slave(modbus.MODBUS_ASCII, slave_id, uartid)
+mb_ascii_s = modbus.create_slave(modbus.MODBUS_ASCII, slave_id, uartid, 115200)
 
 
 -- 添加一块寄存器内存区

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

@@ -0,0 +1,302 @@
+
+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(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_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
+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

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

@@ -0,0 +1,113 @@
+--[[
+@module dnsproxy
+@summary DNS代理转发
+@version 1.0
+@date    2024.4.20
+@author  wendal
+@demo    socket
+@tag LUAT_USE_NETWORK
+@usage
+-- 具体用法请查阅demo
+]]
+
+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

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

@@ -40,8 +40,6 @@ sys.taskInit(function ()
 
     dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
     netdrv.napt(socket.LWIP_ETH)
-
-    -- netdrv.dhcp(socket.LWIP_ETH, true)
 end)
 
 

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

@@ -15,6 +15,11 @@ gpio.setup(20, 1)  --打开lan供电
 mcu.hardfault(0) -- 死机后停机,一般用于调试状态
 require "lan"
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 
 -- 创建主站设备,TCP模式
 -- 设置连接方式为socket.LWIP_ETH

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

@@ -0,0 +1,302 @@
+
+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(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_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
+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

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

@@ -0,0 +1,113 @@
+--[[
+@module dnsproxy
+@summary DNS代理转发
+@version 1.0
+@date    2024.4.20
+@author  wendal
+@demo    socket
+@tag LUAT_USE_NETWORK
+@usage
+-- 具体用法请查阅demo
+]]
+
+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

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

@@ -41,8 +41,6 @@ sys.taskInit(function ()
 
     dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
     netdrv.napt(socket.LWIP_ETH)
-
-    -- netdrv.dhcp(socket.LWIP_ETH, true)
 end)
 
 

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

@@ -12,6 +12,12 @@ log.info("ch390", "打开LDO供电")
 gpio.setup(20, 1)  --打开lan供电
 require "lan"
 
+
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 -- 创建从站设备,可选择RTU、ASCII、TCP,此demo仅用作测试TCP。设置该从站端口号为6000,网卡适配器序列号为socket.LWIP_ETH。
 local slave_id = 1
 mb_tcp_s = modbus.create_slave(modbus.MODBUS_TCP, slave_id, 6000, socket.LWIP_ETH)

+ 7 - 2
module/Air8000/demo/modbus/ascii/master_ascii/main.lua

@@ -7,6 +7,11 @@ log.info("main", PROJECT, VERSION)
 -- 引入必要的库文件(lua编写), 内部库不需要require
 sys = require("sys")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 
 --初始化通讯串口
 local uartid = 1        -- 根据实际设备选取不同的uartid
@@ -19,7 +24,7 @@ uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 -- 设置通讯间隔时间,主站将按每隔 设置时间 的频率向从站问询数据(默认100ms),当添加了多个从站后,主站向每个从站问询的时间间隔将叠加
 -- 设置通讯超时时间和消息发送超时重发次数,当主站未在 设置的时间 内接收到从站数据,将向从站再次发送问询(问询次数按设置的 消息超时重发次数 发送,默认1)
 -- 设置断线重连时间间隔,当从站与主站断连后,主站将在设置时间内重新连接从站(默认5000ms)
-mb_ascii = modbus.create_master(modbus.MODBUS_ASCII, uartid,3000,2000,1,5000)
+mb_ascii = modbus.create_master(modbus.MODBUS_ASCII, uartid,115200,3000,2000,1,5000)
 
 
 -- 为主站添加从站,从站ID为1,可使用modbus.add_slave(master_handler, slave_id)接口添加多个从站,最多可以添加247个
@@ -84,7 +89,7 @@ end, 5000)
 -- end, 5000)
 
 
--- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在modbus.set_msg_comm_period(msg_handler, comm_period)接口中设置为手动模式;成功返回true,其他情况返回false
+-- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在mmodbus.create_msg接口中设置为手动模式;成功返回true,其他情况返回false
 -- sys.timerLoopStart(function()
 --     local status=modbus.exec(mb_ascii, mb_slave1_msg1)
 --     log.info("msg",status)

+ 6 - 1
module/Air8000/demo/modbus/ascii/slave_ascii/main.lua

@@ -7,6 +7,11 @@ log.info("main", PROJECT, VERSION)
 -- 引入必要的库文件(lua编写), 内部库不需要require
 sys = require("sys")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 --初始化通讯串口
 local uartid = 1        -- 根据实际设备选取不同的uartid
 local uart485Pin = 17   -- 用于控制485接收和发送的使能引脚
@@ -16,7 +21,7 @@ uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 
 -- 创建从站设备,可选择RTU、ASCII、TCP,此demo用作测试ASCII。
 local slave_id = 1
-mb_ascii_s = modbus.create_slave(modbus.MODBUS_ASCII, slave_id, uartid)
+mb_ascii_s = modbus.create_slave(modbus.MODBUS_ASCII, slave_id, uartid,115200)
 
 
 -- 添加一块寄存器内存区

+ 8 - 3
module/Air8000/demo/modbus/rtu/master_rtu/main.lua

@@ -7,6 +7,11 @@ log.info("main", PROJECT, VERSION)
 -- 引入必要的库文件(lua编写), 内部库不需要require
 sys = require("sys")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 
 --初始化通讯串口
 local uartid = 1        -- 根据实际设备选取不同的uartid
@@ -19,7 +24,7 @@ uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 -- 设置通讯间隔时间,主站将按每隔 设置时间 的频率向从站问询数据(默认100ms),当添加了多个从站后,主站向每个从站问询的时间间隔将叠加
 -- 设置通讯超时时间和消息发送超时重发次数,当主站未在 设置的时间 内接收到从站数据,将向从站再次发送问询(问询次数按设置的 消息超时重发次数 发送,默认1)
 -- 设置断线重连时间间隔,当从站与主站断连后,主站将在设置时间内重新连接从站(默认5000ms)
-mb_rtu = modbus.create_master(modbus.MODBUS_RTU, uartid,3000,2000,1,5000)
+mb_rtu = modbus.create_master(modbus.MODBUS_RTU, uartid,115200,3000,2000,1,5000)
 
 
 -- 为主站添加从站,从站ID为1,可使用modbus.add_slave(master_handler, slave_id)接口添加多个从站,最多可以添加247个
@@ -61,7 +66,7 @@ modbus.master_start(mb_rtu)
 
 
 -- -- 设置消息通讯周期,搭配modbus.create_master/modbus.set_comm_interval_time(mb_rtu, 3000)设置通讯时间使用,若设置通讯周期为2次,将在2倍的通讯时间后向从站问询数据
-modbus.set_msg_comm_period(mb_slave1_msg1, 2)
+-- modbus.set_msg_comm_period(mb_slave1_msg1, 2)
 
 
 -- 获取所有从站状态,如果所有从站状态为正常,返回true,其他情况返回false,将在每隔5秒的时间获取所有从站状态,并在日志中打印状态(仅方便调试使用,量产时可删除)
@@ -84,7 +89,7 @@ end, 5000)
 -- end, 5000)
 
 
--- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在modbus.set_msg_comm_period(msg_handler, comm_period)接口中设置为手动模式;成功返回true,其他情况返回false
+-- -- 每隔5秒执行一次mb_slave1_msg1消息,使用modbus.exec(master_handler, msg_handler)接口须先在modbus.create_msg接口中设置为手动模式;成功返回true,其他情况返回false
 -- sys.timerLoopStart(function()
 --     local status=modbus.exec(mb_rtu, mb_slave1_msg1)
 --     log.info("msg",status)

+ 6 - 1
module/Air8000/demo/modbus/rtu/slave_rtu/main.lua

@@ -7,6 +7,11 @@ log.info("main", PROJECT, VERSION)
 -- 引入必要的库文件(lua编写), 内部库不需要require
 sys = require("sys")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 --初始化通讯串口
 local uartid = 1        -- 根据实际设备选取不同的uartid
 local uart485Pin = 17   -- 用于控制485接收和发送的使能引脚
@@ -16,7 +21,7 @@ uart.setup(uartid, 115200, 8, 1, uart.NONE, uart.LSB, 1024, uart485Pin, 0, 2000)
 
 -- 创建从站设备,可选择RTU、ASCII、TCP,此demo用作测试RTU
 local slave_id = 1
-mb_rtu_s = modbus.create_slave(modbus.MODBUS_RTU, slave_id, uartid)
+mb_rtu_s = modbus.create_slave(modbus.MODBUS_RTU, slave_id, uartid,115200)
 
 
 -- 添加一块寄存器内存区

+ 311 - 0
module/Air8000/demo/modbus/tcp/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

+ 113 - 0
module/Air8000/demo/modbus/tcp/master_tcp/dnsproxy.lua

@@ -0,0 +1,113 @@
+--[[
+@module dnsproxy
+@summary DNS代理转发
+@version 1.0
+@date    2024.4.20
+@author  wendal
+@demo    socket
+@tag LUAT_USE_NETWORK
+@usage
+-- 具体用法请查阅demo
+]]
+
+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

+ 0 - 1
module/Air8000/demo/modbus/tcp/master_tcp/lan.lua

@@ -45,7 +45,6 @@ sys.taskInit(function ()
     dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
     netdrv.napt(socket.LWIP_ETH)
 
-    -- netdrv.dhcp(socket.LWIP_ETH, true)
 end)
 
 

+ 5 - 0
module/Air8000/demo/modbus/tcp/master_tcp/main.lua

@@ -8,6 +8,11 @@ log.info("main", PROJECT, VERSION)
 _G.sys = require("sys")
 _G.sysplus = require("sysplus")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
 --初始化网络
 log.info("ch390", "打开LDO供电")
 gpio.setup(140, 1)  --打开开发板lan供电

+ 311 - 0
module/Air8000/demo/modbus/tcp/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

+ 113 - 0
module/Air8000/demo/modbus/tcp/slave_tcp/dnsproxy.lua

@@ -0,0 +1,113 @@
+--[[
+@module dnsproxy
+@summary DNS代理转发
+@version 1.0
+@date    2024.4.20
+@author  wendal
+@demo    socket
+@tag LUAT_USE_NETWORK
+@usage
+-- 具体用法请查阅demo
+]]
+
+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

+ 0 - 1
module/Air8000/demo/modbus/tcp/slave_tcp/lan.lua

@@ -45,7 +45,6 @@ sys.taskInit(function ()
     dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_ETH)
     netdrv.napt(socket.LWIP_ETH)
 
-    -- netdrv.dhcp(socket.LWIP_ETH, true)
 end)
 
 

+ 6 - 0
module/Air8000/demo/modbus/tcp/slave_tcp/main.lua

@@ -8,6 +8,12 @@ log.info("main", PROJECT, VERSION)
 _G.sys = require("sys")
 _G.sysplus = require("sysplus")
 
+-- 开启调试模式
+modbus.debug(1)
+-- -- 关闭调试模式
+-- modbus.debug(0)
+
+
 log.info("ch390", "打开LDO供电")
 gpio.setup(140, 1)  --打开开发板lan供电
 require "lan"