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

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

alienwalker 1 год назад
Родитель
Сommit
3303ebf376

+ 7 - 6
components/ethernet/common/dhcp_client.c

@@ -261,7 +261,8 @@ int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out
 	uint16_t flag = 0x8000;
 	*remote_ip = 0xffffffff;
 	int result = 0;
-	LLOGD("dhcp state %d", dhcp->state);
+	uint64_t tnow = luat_mcu_tick64_ms();
+	LLOGD("dhcp state %d %lld %lld %lld", dhcp->state, tnow, dhcp->lease_p1_time, dhcp->lease_p2_time);
 	if (in)
 	{
 		result = analyze_ip4_dhcp(dhcp, in);
@@ -292,7 +293,7 @@ int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out
 	switch(dhcp->state)
 	{
 	case DHCP_STATE_WAIT_LEASE_P1:
-		if (luat_mcu_tick64_ms() >= dhcp->lease_p1_time)
+		if (tnow >= dhcp->lease_p1_time)
 		{
 			flag = 0;
 			*remote_ip = dhcp->server_ip;
@@ -314,7 +315,7 @@ int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out
 		}
 		break;
 	case DHCP_STATE_WAIT_LEASE_P2:
-		if (luat_mcu_tick64_ms() >= dhcp->lease_p2_time)
+		if (tnow >= dhcp->lease_p2_time)
 		{
 			dhcp->state = DHCP_STATE_WAIT_SELECT_ACK;
 			goto DHCP_NEED_REQUIRE;
@@ -327,14 +328,14 @@ int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out
 			dhcp->state = DHCP_STATE_WAIT_LEASE_P1;
 			break;
 		}
-		if (luat_mcu_tick64_ms() >= (dhcp->last_tx_time + 2500))
+		if (tnow >= (dhcp->last_tx_time + 2500))
 		{
 			LLOGD("lease p2 require ip long time no ack");
 			dhcp->state = DHCP_STATE_WAIT_LEASE_END;
 		}
 		break;
 	case DHCP_STATE_WAIT_LEASE_END:
-		if (luat_mcu_tick64_ms() >= dhcp->lease_end_time)
+		if (tnow >= dhcp->lease_end_time)
 		{
 			dhcp->state = DHCP_STATE_WAIT_SELECT_ACK;
 			goto DHCP_NEED_REQUIRE;
@@ -372,7 +373,7 @@ int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out
 			dhcp->wait_selec_ack_cnt = 0;
 			goto DHCP_NEED_REQUIRE;
 		}
-		if (luat_mcu_tick64_ms() >= (dhcp->last_tx_time + (dhcp->discover_cnt * 500) + 900))
+		if (tnow >= (dhcp->last_tx_time + (dhcp->discover_cnt * 500) + 900))
 		{
 			LLOGD("long time no offer, resend");
 			dhcp->discover_cnt++;

+ 5 - 1
components/lcd/luat_lcd.c

@@ -125,7 +125,7 @@ const char* luat_lcd_name(luat_lcd_conf_t* conf) {
     return conf->opts->name;
 }
 
-int luat_lcd_init(luat_lcd_conf_t* conf) {
+LUAT_WEAK int luat_lcd_init_default(luat_lcd_conf_t* conf) {
     uint8_t direction_date = 0;
 	conf->is_init_done = 0;
     if (conf->w == 0)
@@ -176,6 +176,10 @@ int luat_lcd_init(luat_lcd_conf_t* conf) {
     return -1;
 }
 
+LUAT_WEAK int luat_lcd_init(luat_lcd_conf_t* conf) {
+    return luat_lcd_init_default(conf);
+}
+
 int luat_lcd_close(luat_lcd_conf_t* conf) {
     if (conf->pin_pwr != 255)
         luat_gpio_set(conf->pin_pwr, Luat_GPIO_LOW);

+ 12 - 3
components/lcd/luat_lcd.h

@@ -24,11 +24,19 @@
 #elif (LUAT_LCD_COLOR_DEPTH == 8)
 #define luat_color_t uint8_t
 #else
-#error "no supprt color depth"
+#error "no support color depth"
 #endif
 
-#define LUAT_LCD_SPI_DEVICE 255
-#define LUAT_LCD_HW_ID_0 0x20	//专用LCD接口的SPI ID
+enum{
+	LUAT_LCD_HW_ID_0    = 0x20,	//专用LCD接口 ID
+
+    LUAT_LCD_SPI_DEVICE,
+    LUAT_LCD_PORT_RGB,
+    LUAT_LCD_PORT_8080,
+    LUAT_LCD_PORT_ARM2D,
+    LUAT_LCD_PORT_DMA2D,
+    LUAT_LCD_PORT_MAX,
+};
 
 struct luat_lcd_opts;
 
@@ -119,6 +127,7 @@ int lcd_read_cmd_data(luat_lcd_conf_t* conf,const uint8_t cmd, const uint8_t *da
 
 luat_lcd_conf_t* luat_lcd_get_default(void);
 const char* luat_lcd_name(luat_lcd_conf_t* conf);
+int luat_lcd_init_default(luat_lcd_conf_t* conf);//通用spi设备使用
 int luat_lcd_init(luat_lcd_conf_t* conf);
 int luat_lcd_close(luat_lcd_conf_t* conf);
 int luat_lcd_display_on(luat_lcd_conf_t* conf);

+ 32 - 7
components/lcd/luat_lib_lcd.c

@@ -49,6 +49,7 @@ static const lcd_reg_t lcd_regs[] = {
   {"ili9341", &lcd_opts_ili9341},
   {"ili9486", &lcd_opts_ili9486},
   {"nv3037", &lcd_opts_nv3037},
+  {"h050iwv",LUAT_NULL},
   {"", NULL} // 最后一个必须是空字符串
 };
 
@@ -97,6 +98,7 @@ lcd.init("st7796s",{port = "DMA2D",direction = 2,w = 160,h = 80,xoffset = 1,yoff
 
 static int l_lcd_init(lua_State* L) {
     size_t len = 0;
+    uint8_t spi_device = 0;
     luat_lcd_conf_t *conf = luat_heap_malloc(sizeof(luat_lcd_conf_t));
     if (conf == NULL) {
       LLOGE("out of system memory!!!");
@@ -126,7 +128,7 @@ static int l_lcd_init(lua_State* L) {
         // 所以, 直接引用之外, 再加上强制引用, 避免被GC
         // 鉴于LCD不太可能重复初始化, 引用也没什么问题
         conf->lcd_spi_ref = luaL_ref(L, LUA_REGISTRYINDEX);
-        conf->port = LUAT_LCD_SPI_DEVICE;
+        spi_device = 1;
     }
     const char* tp = luaL_checklstring(L, 1, &len);
     int16_t s_index = -1;//第几个屏幕,-1表示没匹配到
@@ -146,17 +148,29 @@ static int l_lcd_init(lua_State* L) {
 
             lua_pushstring(L, "port");
             int port = lua_gettable(L, 2);
-            if (conf->port == LUAT_LCD_SPI_DEVICE && port ==LUA_TNUMBER) {
+            if (LUA_TNUMBER == port) {
+                conf->port = luaL_checkinteger(L, -1);
+            }else if(LUA_TSTRING == port){
+                size_t len;
+                const char *lcd_port = luaL_checklstring(L, -1,&len);
+                if(memcmp("device", lcd_port, len) == 0){
+                    conf->port = LUAT_LCD_SPI_DEVICE;
+                }else if(memcmp("rgb", lcd_port, len) == 0){
+                    conf->port = LUAT_LCD_PORT_RGB;
+                }else{
+                    LLOGE("port %s is not support ",lcd_port);
+                    goto end; 
+                }
+            }
+
+            if (spi_device == 1 && conf->port != LUAT_LCD_SPI_DEVICE) {
               LLOGE("port is not device but find luat_spi_device_t");
               goto end;
-            }else if (conf->port != LUAT_LCD_SPI_DEVICE && LUA_TSTRING == port){
+            }else if (spi_device == 0 && conf->port == LUAT_LCD_SPI_DEVICE){
               LLOGE("port is device but not find luat_spi_device_t");
               goto end;
-            }else if (LUA_TNUMBER == port) {
-                conf->port = luaL_checkinteger(L, -1);
-            }else if (LUA_TSTRING == port){
-                conf->port = LUAT_LCD_SPI_DEVICE;
             }
+
             lua_pop(L, 1);
 
             lua_pushstring(L, "pin_dc");
@@ -1882,8 +1896,19 @@ static const rotable_Reg_t reg_lcd[] =
     { "direction_180",  ROREG_INT(2)},
     //@const direction_270 int 270°方向命令
     { "direction_270",  ROREG_INT(3)},
+    //@const SPI 硬件spi device lcd驱动
+    { "SPI",            ROREG_INT(LUAT_LCD_SPI_DEVICE)},
     //@const HWID_0 硬件lcd驱动id0 (根据芯片支持选择)
     { "HWID_0",         ROREG_INT(LUAT_LCD_HW_ID_0)},
+    //@const RGB 硬件RGB lcd驱动 (根据芯片支持选择)
+    { "RGB",            ROREG_INT(LUAT_LCD_PORT_RGB)},
+
+    // //@const ARM2D 硬件ARM2D lcd驱动 (根据芯片支持选择)
+    // { "ARM2D",         ROREG_INT(LUAT_LCD_PORT_ARM2D)},
+    // //@const DMA2D 硬件DMA2D lcd驱动 (根据芯片支持选择)
+    // { "DMA2D",         ROREG_INT(LUAT_LCD_PORT_DMA2D)},
+
+
     //@const WIRE_3_BIT_9_INTERFACE_I 三线spi 9bit 模式I
     { "WIRE_3_BIT_9_INTERFACE_I",   ROREG_INT(LUAT_LCD_IM_3_WIRE_9_BIT_INTERFACE_I)},
     //@const WIRE_4_BIT_8_INTERFACE_I 四线spi 8bit 模式I

+ 25 - 0
components/network/adapter/luat_lib_socket.c

@@ -1249,6 +1249,31 @@ NO_REMOTE_IP:
 	return 4;
 }
 
+/*
+设置默认网络适配器编号
+@api socket.dft(id)
+@int 默认适配器编号,若不传,则打包获取
+@return int 默认适配器编号
+@usage
+-- 本函数于 2025.1.6 新增
+-- 获取当前默认适配器编号
+local id = socket.dft()
+
+-- 设置默认适配器编号
+socket.dft(socket.LWIP_ETH)
+*/
+static int l_socket_default(lua_State *L) {
+	uint8_t id = 0;
+	if (lua_type(L, 1) == LUA_TNUMBER) {
+		id = (uint8_t)luaL_checkinteger(L, 1);
+		if (id < NW_ADAPTER_QTY) {
+			network_register_set_default(id);
+		}
+	}
+	lua_pushinteger(L, network_get_last_register_adapter());
+	return 1;
+}
+
 #include "rotable2.h"
 static const rotable_Reg_t reg_socket_adapter[] =
 {

+ 15 - 1
components/network/adapter_lwip2/net_lwip2.c

@@ -968,6 +968,12 @@ static uint8_t net_lwip2_check_ready(void *user_data)
 		LLOGD("lwip netif is null %d", adapter_index);
 		return 0;
 	}
+	if (!netif_is_up(prvlwip.lwip_netif[adapter_index])) {
+		return 0;
+	}
+	if (!netif_is_link_up(prvlwip.lwip_netif[adapter_index])) {
+		return 0;
+	}
 	return !ip_addr_isany(&prvlwip.lwip_netif[adapter_index]->ip_addr);
 }
 
@@ -1016,7 +1022,15 @@ static void net_lwip2_create_socket_now(uint8_t adapter_index, uint8_t socket_id
 			prvlwip.socket[socket_id].pcb.tcp->errf = net_lwip2_tcp_err_cb;
 			prvlwip.socket[socket_id].pcb.tcp->so_options |= SOF_KEEPALIVE|SOF_REUSEADDR;
 //					tcp_set_flags(prvlwip.socket[socket_id].pcb.tcp, TCP_NODELAY);
-
+			#if LWIP_TCP_KEEPALIVE
+			if (adapter_index == NW_ADAPTER_INDEX_LWIP_WIFI_STA ||
+				adapter_index == NW_ADAPTER_INDEX_LWIP_WIFI_AP ||
+				adapter_index == NW_ADAPTER_INDEX_LWIP_ETH) {
+				prvlwip.socket[socket_id].pcb.tcp->keep_intvl = 5*1000;
+				prvlwip.socket[socket_id].pcb.tcp->keep_idle = 5*60*1000;
+				prvlwip.socket[socket_id].pcb.tcp->keep_cnt = 2;
+			}
+			#endif
 		}
 		else
 		{

+ 4 - 0
components/network/libhttp/luat_lib_http.c

@@ -449,6 +449,10 @@ int32_t l_http_callback(lua_State *L, void* ptr){
 		luat_cbcwait(L, idp, 3); // code, headers, body
 	}
 #endif
+	else if (http_ctrl->zbuff_body) {
+		lua_pushinteger(L, http_ctrl->body_len);
+		luat_cbcwait(L, idp, 3); // code, headers, body
+	}
 	else {
 		// 非下载模式
 		lua_pushlstring(L, http_ctrl->body, http_ctrl->body_len);

+ 46 - 0
components/network/netdrv/binding/luat_lib_netdrv.c

@@ -0,0 +1,46 @@
+
+/*
+@module  netdrv
+@summary 网络设备管理
+@catalog 外设API
+@version 1.0
+@date    2025.01.07
+@demo netdrv
+@tag LUAT_USE_NETDRV
+*/
+#include "luat_base.h"
+#include "luat_gpio.h"
+#include "luat_mem.h"
+#include "luat_mcu.h"
+#include "luat_msgbus.h"
+#include "luat_timer.h"
+#include "luat_rtos.h"
+#include "luat_netdrv.h"
+
+#define LUAT_LOG_TAG "netdrv"
+#include "luat_log.h"
+
+/*
+初始化指定netdrv设备
+*/
+static int l_netdrv_setup(lua_State *L) {
+    luat_netdrv_conf_t conf = {0};
+    conf.id = luaL_checkinteger(L, 1);
+    conf.impl = luaL_optinteger(L, 2, 0);
+    conf.tp = luaL_optinteger(L, 3, 0);
+    int ret = luat_netdrv_setup(&conf);
+    lua_pushboolean(L, ret == 0 ? 1 : 0);
+    return 1;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_netdrv[] =
+{
+    { "setup" ,         ROREG_FUNC(l_netdrv_setup )},
+	{ NULL,             ROREG_INT(0) }
+};
+
+LUAMOD_API int luaopen_netdrv( lua_State *L ) {
+    luat_newlib2(L, reg_netdrv);
+    return 1;
+}

+ 46 - 0
components/network/netdrv/include/luat_netdrv.h

@@ -0,0 +1,46 @@
+#ifndef LUAT_NETDRV_H
+#define LUAT_NETDRV_H
+
+#include "lwip/pbuf.h"
+
+typedef void (*luat_netdrv_dataout_cb)(void* userdata, struct pbuf* pb, int flags);
+typedef int (*luat_netdrv_bootup_cb)(void* userdata);
+typedef int (*luat_netdrv_ready_cb)(void* userdata);
+
+typedef struct luat_netdrv {
+    int32_t id;
+    struct netif* netif;
+    luat_netdrv_dataout_cb dataout;
+    luat_netdrv_bootup_cb boot;
+    luat_netdrv_ready_cb ready;
+    void* userdata;
+}luat_netdrv_t;
+
+enum {
+    LUAT_NETDRV_TP_NATIVE,
+    LUAT_NETDRV_TP_CH390H,
+    LUAT_NETDRV_TP_W5100,
+    LUAT_NETDRV_TP_W5500,
+    LUAT_NETDRV_TP_SPINET,
+    LUAT_NETDRV_TP_UARTNET,
+    LUAT_NETDRV_TP_USB
+};
+
+typedef struct luat_netdrv_conf
+{
+    int32_t id;
+    int32_t impl;
+    int32_t tp;
+    int32_t flags;
+}luat_netdrv_conf_t;
+
+
+luat_netdrv_t* luat_netdrv_setup(luat_netdrv_conf_t *conf);
+
+int luat_netdrv_dhcp(int32_t id, int32_t enable);
+
+int luat_netdrv_ready(int32_t id);
+
+int luat_netdrv_register(int32_t id, luat_netdrv_t* drv);
+
+#endif

+ 37 - 0
components/network/netdrv/src/luat_netdrv.c

@@ -0,0 +1,37 @@
+#include "luat_base.h"
+#include "luat_netdrv.h"
+#include "luat_network_adapter.h"
+
+static luat_netdrv_t* drvs[NW_ADAPTER_QTY];
+
+luat_netdrv_t* luat_netdrv_setup(luat_netdrv_conf_t *conf) {
+    if (conf->id < 0 || conf->id >= NW_ADAPTER_QTY) {
+        return NULL;
+    }
+    if (drvs[conf->id] == NULL) {
+        // 注册新的设备?
+    }
+    else {
+        drvs[conf->id]->boot(NULL);
+    }
+    return NULL;
+}
+
+int luat_netdrv_dhcp(int32_t id, int32_t enable) {
+    return -1;
+}
+
+int luat_netdrv_ready(int32_t id) {
+    if (drvs[id] == NULL) {
+        return -1;
+    }
+    return drvs[id]->ready(drvs[id]->userdata);
+}
+
+int luat_netdrv_register(int32_t id, luat_netdrv_t* drv) {
+    if (drvs[id] != NULL) {
+        return -1;
+    }
+    drvs[id] = drv;
+    return 0;
+}

+ 13 - 5
components/network/ulwip/binding/luat_lib_ulwip.c

@@ -394,12 +394,20 @@ static int l_ulwip_link(lua_State *L) {
     }
     if (lua_isboolean(L, 2))
     {
-        if (lua_toboolean(L, 2))
+        int new_status = lua_toboolean(L, 2);
+        int old_status = netif_is_link_up(nets[idx].netif);
+        if (new_status != old_status)
         {
-            netif_set_link_up(nets[idx].netif);
-        }
-        else {
-            netif_set_link_down(nets[idx].netif);
+            if (new_status) {
+                netif_set_link_up(nets[idx].netif);
+                if (!nets[idx].ip_static) {
+                    ulwip_dhcp_client_start(&nets[idx]);
+                }
+            }
+            else {
+                netif_set_link_down(nets[idx].netif);
+                ulwip_dhcp_client_stop(&nets[idx]);
+            }
         }
         ulwip_netif_ip_event(&nets[idx]);
     }

+ 33 - 7
components/network/ulwip/src/ulwip_dhcp_client.c

@@ -15,6 +15,8 @@
 //           DHCP 客户端逻辑
 // -------------------------------------
 
+static void dhcp_client_timer_cb(void *arg);
+
 static int ulwip_dhcp_client_run(ulwip_ctx_t* ctx, char* rxbuff, size_t len) {
     PV_Union uIP;
     // 检查dhcp的状态
@@ -26,6 +28,11 @@ static int ulwip_dhcp_client_run(ulwip_ctx_t* ctx, char* rxbuff, size_t len) {
 	uint32_t remote_ip = 0;
     int result = 0;
 
+    if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
+        LLOGD("网卡未就绪,不发送dhcp请求 %d", ctx->adapter_index);
+        return 0;
+    }
+
     if (rxbuff) {
         rx_msg_buf.Data = (uint8_t*)rxbuff;
         rx_msg_buf.Pos = len;
@@ -34,6 +41,7 @@ static int ulwip_dhcp_client_run(ulwip_ctx_t* ctx, char* rxbuff, size_t len) {
 
     // 看看是不是获取成功了
     if (DHCP_STATE_CHECK == dhcp->state) {
+on_check:
         uIP.u32 = dhcp->ip;
 		LLOGD("动态IP:%d.%d.%d.%d", uIP.u8[0], uIP.u8[1], uIP.u8[2], uIP.u8[3]);
 		uIP.u32 = dhcp->submask;
@@ -49,19 +57,26 @@ static int ulwip_dhcp_client_run(ulwip_ctx_t* ctx, char* rxbuff, size_t len) {
         dhcp->state = DHCP_STATE_WAIT_LEASE_P1;
         if (rxbuff) {
             luat_heap_free(rxbuff);
+            rxbuff = NULL;
         }
         ulwip_netif_ip_event(ctx);
+        luat_rtos_timer_stop(ctx->dhcp_timer);
+        luat_rtos_timer_start(ctx->dhcp_timer, 60000, 1, dhcp_client_timer_cb, ctx);
         return 0;
     }
     result = ip4_dhcp_run(dhcp, rxbuff == NULL ? NULL : &rx_msg_buf, &tx_msg_buf, &remote_ip);
     if (rxbuff) {
         luat_heap_free(rxbuff);
+        rxbuff = NULL;
     }
     if (result) {
         LLOGE("ip4_dhcp_run error %d", result);
         return 0;
     }
     if (!tx_msg_buf.Pos) {
+        if (DHCP_STATE_CHECK == dhcp->state) {
+            goto on_check;
+        }
         return 0; // 没有数据需要发送
     }
     // 通过UDP发出来
@@ -76,13 +91,16 @@ static int ulwip_dhcp_client_run(ulwip_ctx_t* ctx, char* rxbuff, size_t len) {
         data += q->len;
     }
     data = p->payload;
-    // LLOGI("dhcp payload len %d %02X%02X%02X%02X", p->tot_len, data[0], data[1], data[2], data[3]);
+    LLOGI("dhcp payload len %d %02X%02X%02X%02X", p->tot_len, data[0], data[1], data[2], data[3]);
     udp_sendto_if(ctx->dhcp_pcb, p, IP_ADDR_BROADCAST, 67, netif);
     pbuf_free(p);
     return 0;
 }
 
 static int ulwip_dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
+    if (addr == NULL || port != 67 || pcb == NULL) {
+        return 0;
+    }
     LLOGD("收到DHCP数据包(len=%d)", p->tot_len);
     ulwip_ctx_t *ctx = (ulwip_ctx_t *)arg;
     char* ptr = luat_heap_malloc(p->tot_len);
@@ -118,19 +136,26 @@ static void dhcp_client_timer_cb(void *arg) {
     #endif
 }
 
+static void reset_dhcp_client(ulwip_ctx_t *ctx) {
+    memset(ctx->dhcp_client, 0, sizeof(dhcp_client_info_t));
+    memcpy(ctx->dhcp_client->mac, ctx->netif->hwaddr, 6);
+    luat_crypto_trng((char*)&ctx->dhcp_client->xid, sizeof(ctx->dhcp_client->xid));
+    sprintf_(ctx->dhcp_client->name, "airm2m-%02x%02x%02x%02x%02x%02x",
+			ctx->dhcp_client->mac[0],ctx->dhcp_client->mac[1], ctx->dhcp_client->mac[2],
+			ctx->dhcp_client->mac[3],ctx->dhcp_client->mac[4], ctx->dhcp_client->mac[5]);
+}
+
 void ulwip_dhcp_client_start(ulwip_ctx_t *ctx) {
     if (!ctx->dhcp_client) {
         ctx->dhcp_client = luat_heap_malloc(sizeof(dhcp_client_info_t));
-        memset(ctx->dhcp_client, 0, sizeof(dhcp_client_info_t));
-        memcpy(ctx->dhcp_client->mac, ctx->netif->hwaddr, 6);
-        luat_crypto_trng((char*)&ctx->dhcp_client->xid, sizeof(ctx->dhcp_client->xid));
-        sprintf_(ctx->dhcp_client->name, "airm2m-%02x%02x%02x%02x%02x%02x",
-			ctx->dhcp_client->mac[0],ctx->dhcp_client->mac[1], ctx->dhcp_client->mac[2],
-			ctx->dhcp_client->mac[3],ctx->dhcp_client->mac[4], ctx->dhcp_client->mac[5]);
+        reset_dhcp_client(ctx);
         luat_rtos_timer_create(&ctx->dhcp_timer);
         ctx->dhcp_pcb = udp_new();
         ip_set_option(ctx->dhcp_pcb, SOF_BROADCAST);
         udp_bind(ctx->dhcp_pcb, IP4_ADDR_ANY, 68);
+        #ifdef udp_bind_netif
+        udp_bind_netif(ctx->dhcp_pcb, ctx->netif);
+        #endif
         udp_connect(ctx->dhcp_pcb, IP4_ADDR_ANY, 67);
         udp_recv(ctx->dhcp_pcb, ulwip_dhcp_recv, ctx);
     }
@@ -147,5 +172,6 @@ void ulwip_dhcp_client_start(ulwip_ctx_t *ctx) {
 void ulwip_dhcp_client_stop(ulwip_ctx_t *ctx) {
     if (luat_rtos_timer_is_active(ctx->dhcp_timer)) {
         luat_rtos_timer_stop(ctx->dhcp_timer);
+        reset_dhcp_client(ctx);
     }
 }

+ 166 - 0
demo/ch390h/ch390h.lua

@@ -0,0 +1,166 @@
+local ch390h = {
+    buff = zbuff.create(2048)
+}
+
+local sys = require "sys"
+
+local spiId = 0
+local cs = 8
+local CS = gpio.setup(cs, 1, gpio.PULLUP)
+
+function ch390h.read(addr, len)
+    if not len then
+        len = 1
+    end
+    CS(0)
+    local data = ""
+    if addr == 0x72 then
+        spi.send(spiId, string.char(addr))
+        while len > 0 do
+            if len > 64 then
+                data = data .. spi.recv(spiId, 64)
+                len = len - 64
+            else
+                data = data .. spi.recv(spiId, len)
+                len = 0
+                break
+            end
+        end
+    else
+        for i = 1, len, 1 do
+            spi.send(spiId, string.char(addr + i - 1))
+            data = data .. spi.recv(spiId, 1)
+        end
+    end
+    CS(1)
+    return data
+end
+
+function ch390h.write(addr, data)
+    -- log.info("ch390h", "写入寄存器", addr, data, (string.char(addr | 0x80, data):toHex()))
+    if type(data) == "number" then
+        data = string.char(data)
+    end
+    CS(0)
+    local tmp = string.char(addr | 0x80) .. data
+    spi.send(spiId, tmp)
+    -- local len = #tmp
+    -- local offset = 1
+    -- while len > 0 do
+    --     if len > 64 then
+    --         spi.send(spiId, data:sub(offset, offset + 64))
+    --         len = len - 64
+    --         offset = offset + 64
+    --     else
+    --         spi.send(spiId, data:sub(offset))
+    --         break
+    --     end
+    -- end
+    CS(1)
+    -- log.info("读到的数据", addr, data:toHex())
+    return data
+end
+
+function ch390h.mac()
+    return ch390h.read(0x10, 6)
+end
+
+function ch390h.vid()
+    return ch390h.read(0x28, 2)
+end
+
+function ch390h.pid()
+    return ch390h.read(0x2A, 2)
+end
+
+function ch390h.revision()
+    return ch390h.read(0x2C, 1)
+end
+
+function ch390h.default_config()
+    ch390h.write(0, 0x01)
+    sys.wait(20)
+    ch390h.write(0x01, (1 << 5) | (1 << 3) | (1 << 2))
+    ch390h.write(0x7E, 0xFF)
+    ch390h.write(0x2D, 0x80)
+    -- write_reg(0x31, 0x1F)
+    ch390h.write(0x7F, 0xFF)
+
+    ch390h.write(0x55, 0x01)
+    ch390h.write(0x75, 0x0c)
+    sys.wait(20)
+    -- ch390h.enable_rx()
+end
+
+function ch390h.software_reset()
+    ch390h.write(0, 0x01)
+    sys.wait(20)
+    ch390h.write(0, 0x00)
+    ch390h.write(0, 0x01)
+    sys.wait(20)
+end
+
+function ch390h.enable_rx()
+    -- ch390h.write(0x05, (1 <<4) | (1 <<0) | (1 << 1) | (1 << 3))
+    ch390h.write(0x05, (1 <<4) | (1 <<0) | (1 << 3))
+    -- ch390h.write(0x05, (1 <<4) | (1 <<0))
+    ch390h.write(0x1F, 0)
+end
+
+function ch390h.disable_rx()
+    ch390h.write(0x05, 0)
+end
+
+function ch390h.enable_phy()
+    ch390h.write(0x1F, 0)
+end
+
+function ch390h.link()
+    local link = (ch390h.read(0x01, 1):byte() & (1 << 6))
+    return link ~= 0
+end
+
+function ch390h.receive_packet()
+    -- 先假读一次
+    ch390h.read(0x70, 1)
+    local rx_ready = ch390h.read(0x70, 1):byte()
+    if (rx_ready & 0xFE) ~= 0x0 then
+        log.info("ch390h", "出错了,复位!!!", (string.char(rx_ready):toHex()))
+        ch390h.write(0x05, 0)
+        ch390h.write(0x55, 1)
+        ch390h.write(0x75, 0)
+        sys.wait(1)
+        -- ch390h.enable_rx()
+        -- ch390h.software_reset()
+        ch390h.default_config()
+        -- ch390h.write(0x05, (1 <<4) | (1 <<3) | (1 <<1) | (1 <<0))
+        return
+    end
+    if (rx_ready & 0x01) == 0 then
+        -- log.info("ch390h", "没有数据", (string.char(rx_ready):toHex()))
+        return -- 没有数据
+    end
+    -- 读4个字节
+    local tmp = ch390h.read(0x72, 4)
+    local rx_status = tmp:byte(2)
+    local rx_len = tmp:byte(3) + (tmp:byte(4) << 8)
+    log.info("ch390h", rx_status, rx_len, (tmp:toHex()))
+    return ch390h.read(0x72, rx_len)
+end
+
+function ch390h.send_packet(buff)
+    ch390h.write(0x78, buff:query())
+    local tmp = ch390h.read(0x02, 1):byte()
+    if (tmp & 0x01) == 0 then
+        local len = buff:used()
+        ch390h.write(0x7C, len & 0xFF)
+        ch390h.write(0x7D, (len >> 8) & 0xFF)
+        tmp = ch390h.read(0x02, 1):byte()
+        ch390h.write(0x02, tmp | (1<<0))
+        log.info("ch390h", "底层发送", buff:used())
+    else
+        log.info("ch390h", "底层忙")
+    end
+end
+
+return ch390h

+ 109 - 0
demo/ch390h/main.lua

@@ -0,0 +1,109 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ch390h"
+VERSION = "1.0.0"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "xxx" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+
+ch390h = require "ch390h"
+
+function netif_write_out(id, buff)
+    -- log.info("ch390h", "out", buff:query():toHex())
+    ch390h.send_packet(buff)
+end
+
+sys.taskInit(function ()
+    sys.wait(100)
+    local result = spi.setup(
+        0,--串口id
+        nil,
+        0,--CPHA
+        0,--CPOL
+        8,--数据宽度
+        25600000--,--频率
+        -- spi.MSB,--高低位顺序    可选,默认高位在前
+        -- spi.master,--主模式     可选,默认主
+        -- spi.full--全双工       可选,默认全双工
+    )
+    print("open",result)
+    if result ~= 0 then--返回值为0,表示打开成功
+        print("spi open error",result)
+        return
+    end
+
+
+    ch390h.software_reset()
+    ch390h.default_config()
+
+    local mac = ch390h.mac()
+    log.info("MAC地址", (mac:toHex()))
+    log.info("vid", (ch390h.vid():toHex()), "pid", (ch390h.pid():toHex()))
+
+    
+    -- log.info("通用寄存器", (ch390h.read(0x1F):toHex()))
+
+    log.info("ulwip可用", ulwip)
+    local neti = socket.LWIP_ETH
+    ulwip.setup(neti, mac, netif_write_out, {zbuff_out=true})
+    ulwip.reg(neti)
+    -- ulwip.ip(neti, "192.168.1.219", "255.255.255.0", "192.168.1.1")
+
+    local prev_stat = false
+    ulwip.link(neti, prev_stat)
+    ch390h.disable_rx()
+    ch390h.enable_phy()
+    ulwip.dhcp(neti, true)
+    ulwip.updown(neti, true)
+    while 1 do
+        local link = ch390h.link()
+        -- log.info("网线状态", link, "通用寄存器", (ch390h.read(0x01):toHex()))
+        ch390h.write(0x05, (1 <<4) | (1 <<0) | (1 << 3))
+        if link ~= prev_stat then
+            log.info("ch390h", "网线状态变化", prev_stat, link)
+            if link then
+                ch390h.enable_rx()
+            end
+            ulwip.link(neti, link)
+            prev_stat = link
+        end
+        if link then
+            -- 读取rx寄存器长度
+            local tmp = ch390h.receive_packet()
+            if not tmp then
+                sys.wait(5)
+            else
+                -- https://packetor.com/
+                -- https://hpd.gasmi.net/
+                -- log.info("ch390h", (tmp:toHex()))
+                log.info("ch390h", "收到数据长度", #tmp)
+                ulwip.input(neti, tmp)
+            end
+        else
+            ch390h.enable_phy()
+            sys.wait(100)
+        end
+        
+    end
+end)
+
+
+sys.taskInit(function()
+    sys.waitUntil("IP_READY")
+    while 1 do
+        sys.wait(1000)
+        log.info("http", http.request("GET", "https://httpbin.air32.cn/get", nil, nil, {adapter=socket.LWIP_ETH}).wait())
+        log.info("lua", rtos.meminfo())
+        log.info("sys", rtos.meminfo("sys"))
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 8 - 2
lua/src/lstrlib_exts.c

@@ -153,7 +153,7 @@ int l_str_split (lua_State *L) {
   }
 
   size_t dlen = 0;
-  const char *delimiters = luaL_checklstring(L, 2, &dlen);
+  const char *delimiters = luaL_optlstring(L, 2, ",", &dlen);
   if (dlen < 1) {
     delimiters = ",";
     dlen = 1;
@@ -695,7 +695,13 @@ int l_str_fromBase32(lua_State *L) {
   luaL_Buffer buff = {0};
   luaL_buffinitsize(L, &buff, len + 1);
   int rl = luat_str_base32_decode((const uint8_t * )str,(uint8_t *)buff.b,buff.size);
-  luaL_pushresultsize(&buff, rl);
+  if (rl > 0 && rl <= len + 1) {
+    luaL_pushresultsize(&buff, rl);
+  }
+  else {
+    lua_pushstring(L, "");
+  }
+
   return 1;
 }
 

+ 3 - 0
luat/include/luat_libs.h

@@ -193,4 +193,7 @@ LUAMOD_API int luaopen_ht1621(lua_State *L);
 // NAPT
 LUAMOD_API int luaopen_napt(lua_State *L);
 
+// NETDRV
+LUAMOD_API int luaopen_netdrv( lua_State *L );
+
 #endif

+ 4 - 0
luat/vfs/luat_fs_lfs2.c

@@ -116,6 +116,10 @@ size_t luat_vfs_lfs2_fread(void* userdata, void *ptr, size_t size, size_t nmemb,
 size_t luat_vfs_lfs2_fwrite(void* userdata, const void *ptr, size_t size, size_t nmemb, FILE *stream) {
     lfs_t* fs = (lfs_t*)userdata;
     lfs_file_t* file = (lfs_file_t*)stream;
+    if ((file->flags & LFS_O_WRONLY) != LFS_O_WRONLY && (file->flags & LFS_O_APPEND) != LFS_O_APPEND) {
+        LLOGE("open file at readonly mode, reject for write flags=%08X", file->flags);
+        return 0;
+    }
     int ret = lfs_file_write(fs, file, ptr, size*nmemb);
     return ret < 0 ? 0 : ret;
 }

+ 1 - 1
luat/vfs/luat_fs_luadb.c

@@ -356,8 +356,8 @@ FILE* luat_vfs_luadb_fopen(void* userdata, const char *filename, const char *mod
     if (!strcmp("r", mode) || !strcmp("rb", mode) || !strcmp("r+", mode) || !strcmp("rb+", mode)) {
     }
     else {
-        // 暂时只警告
         LLOGW("/luadb is readonly %s %s", filename, mode);
+        return (FILE*)NULL;
     }
     return (FILE*)luat_luadb_open((luadb_fs_t*)userdata, filename, 0, 0);
 }

+ 99 - 0
script/libs/dnsproxy.lua

@@ -0,0 +1,99 @@
+--[[
+@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 = 0x1234
+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
+                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
+                    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, "114.114.114.114", 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(port, topic, adapter)
+@int 端口号, 必填, 必须大于0小于65525
+@string 收取UDP数据的topic,必填
+@int 网络适配编号, 默认为nil,可选
+@return table UDP服务的实体, 若创建失败会返回nil
+]]
+function dnsproxy.setup(adapter, main_adapter)
+    log.info("dnsproxy", adapter, main_adapter)
+    dnsproxy.sc = socket.create(adapter, dnsproxy.on_request)
+    dnsproxy.main_sc = socket.create(main_adapter, dnsproxy.on_response)
+    socket.config(dnsproxy.sc, 53, true)
+    socket.config(dnsproxy.main_sc, nil, true)
+    socket.connect(dnsproxy.sc, "255.255.255.255", 0)
+    socket.connect(dnsproxy.main_sc, "114.114.114.114", 53)
+    return true
+end
+
+return dnsproxy

+ 10 - 8
script/libs/libfota.lua

@@ -68,18 +68,20 @@ local function fota_task(cbFnc,storge_location, len, param1,ota_url,ota_port,lib
         else
             local x,y,z = string.match(_G.VERSION,"(%d+).(%d+).(%d+)")
             if x and y and z then
-                version = x.."."..z
-                local imei = ""
-                local model = ""
+                local query = ""
+                local firmware_name = _G.PROJECT.. "_" .. rtos.firmware()
+                local version = _G.VERSION
                 if mobile then
-                    imei = mobile.imei()
+                    query = "imei=" .. mobile.imei()
+                    version = rtos.version():sub(2) .. "." ..  x .. "." .. z
+                    firmware_name = _G.PROJECT.. "_LuatOS-SoC_" .. rtos.bsp()
                 elseif wlan and wlan.getMac then
-                    imei = wlan.getMac()
+                    query = "mac=" .. wlan.getMac()
                 else
-                    imei = mcu.unique_id():toHex()
+                    query = "uid=" .. mcu.unique_id():toHex()
                 end
-                model = hmeta and ("&model=" .. hmeta.model() .. "_" .. (hmeta.hwver and hmeta.hwver() or "A00")) or ""
-                ota_url = "http://iot.openluat.com/api/site/firmware_upgrade?project_key=" .. _G.PRODUCT_KEY .. "&imei=".. imei .. "&device_key=&firmware_name=" .. _G.PROJECT.. "_LuatOS-SoC_" .. rtos.bsp() .. "&version=" .. rtos.version():sub(2) .. "." .. version .. model
+                local tmp = "http://iot.openluat.com/api/site/firmware_upgrade?project_key=%s&firmware_name=%s&version=%s&%s"
+                ota_url = string.format(tmp, _G.PRODUCT_KEY, firmware_name, version, query)
             else
                 log.error("fota", "_G.VERSION must be xxx.yyy.zzz!!!")
                 cbFnc(5)

+ 1 - 1
script/turnkey/web_audio/main.lua

@@ -92,7 +92,7 @@ sys.taskInit(function()
     if not result then
         log.info("网络连接失败")
     end
-    mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl, ca_file)
+    mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
     mqttc:auth(client_id, user_name, password) -- client_id必填,其余选填
     mqttc:keepalive(30) -- 默认值240s
     mqttc:autoreconn(true, 3000) -- 自动重连机制

+ 1 - 4
tools/make_doc_file.py

@@ -4,13 +4,10 @@ import requests
 
 #bsp.h文件列表
 bsp_header_list = [
+{"name":"Air780EPM","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air780epm.h"},
 {"name":"Air780E","url":"https://github.com/openLuat/luatos-soc-2022/raw/master/project/luatos/inc/luat_conf_bsp.h"},
 {"name":"Air780EP","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_dft.h"},
 {"name":"Air780EPS","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air780eps.h"},
-{"name":"Air780EQ","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air780eq.h"},
-{"name":"Air700EAQ","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air700exq.h"},
-{"name":"Air700EMQ","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air700exq.h"},
-{"name":"Air700ECQ","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air700exq.h"},
 {"name":"Air201","url":"https://github.com/openLuat/luatos-soc-2024/raw/master/project/luatos/inc/luat_conf_bsp_air201.h"},
 ]
 print("getting bsp.h files...")