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

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

alienwalker 6 месяцев назад
Родитель
Сommit
01841278a5
100 измененных файлов с 1976 добавлено и 4962 удалено
  1. 42 1
      components/gmssl/bind/luat_lib_gmssl.c
  2. 115 68
      components/mreport/src/luat_mreport.c
  3. 1 0
      components/multimedia/luat_multimedia_audio.c
  4. 3 3
      components/network/netdrv/src/luat_netdrv_napt.c
  5. 2 0
      components/yhm27xx/binding/luat_lib_yhm27xx.c
  6. 10 123
      luat/demo/gmssl/main.lua
  7. 28 0
      luat/demo/gmssl/sm2sign.lua
  8. 55 0
      luat/demo/gmssl/sm2test.lua
  9. 11 0
      luat/demo/gmssl/sm3test.lua
  10. 43 0
      luat/demo/gmssl/sm4test.lua
  11. 17 9
      luat/modules/luat_lib_gpio.c
  12. 1 0
      module/Air6101/core/readme.md
  13. 64 0
      module/Air6101/demo/zbuff/main.lua
  14. 172 0
      module/Air6101/demo/zbuff/readme.md
  15. 100 0
      module/Air6101/demo/zbuff/zbuff_advanced.lua
  16. 89 0
      module/Air6101/demo/zbuff/zbuff_core.lua
  17. 62 0
      module/Air6101/demo/zbuff/zbuff_memory.lua
  18. 1 0
      module/Air6101/demolib/readme.md
  19. 0 0
      module/Air6101/project/readme.md
  20. 71 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/main.lua
  21. 41 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/open_ecm.lua
  22. 39 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/open_rndis.lua
  23. 112 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/readme.md
  24. 2 2
      module/Air780EHM_Air780EHV_Air780EGH/demo/socket/client/long_connection/netdrv_device.lua
  25. 0 142
      module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP-UART/main.lua
  26. 0 145
      module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP单向认证/main.lua
  27. 0 141
      module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP断链续连/main.lua
  28. 0 130
      module/Air780EHM_Air780EHV_Air780EGH/demo/udp/main.lua
  29. 4 3
      module/Air780EPM/demo/lowpower/lowpower_dissipation.lua
  30. 2 2
      module/Air780EPM/demo/lowpower/main.lua
  31. 15 11
      module/Air780EPM/demo/pwm/示例1 PWM输出/main.lua
  32. 71 0
      module/Air780EPM/demo/rndis_ecm/main.lua
  33. 41 0
      module/Air780EPM/demo/rndis_ecm/open_ecm.lua
  34. 39 0
      module/Air780EPM/demo/rndis_ecm/open_rndis.lua
  35. 112 0
      module/Air780EPM/demo/rndis_ecm/readme.md
  36. 2 2
      module/Air780EPM/demo/socket/client/long_connection/netdrv_device.lua
  37. 0 142
      module/Air780EPM/demo/tcp/TCP-UART/main.lua
  38. 0 145
      module/Air780EPM/demo/tcp/TCP单向认证/main.lua
  39. 0 141
      module/Air780EPM/demo/tcp/TCP断链续连/main.lua
  40. 0 130
      module/Air780EPM/demo/udp/main.lua
  41. 0 46
      module/Air8000/demo/luatos_framework/luatos_task/create.lua
  42. 15 1
      module/Air8000/demo/luatos_framework/luatos_task/global_msg_receiver1.lua
  43. 21 2
      module/Air8000/demo/luatos_framework/luatos_task/global_msg_receiver2.lua
  44. 14 0
      module/Air8000/demo/luatos_framework/luatos_task/global_msg_sender.lua
  45. 6 8
      module/Air8000/demo/luatos_framework/luatos_task/main.lua
  46. 9 7
      module/Air8000/demo/luatos_framework/luatos_task/memory_task.lua
  47. 12 7
      module/Air8000/demo/luatos_framework/luatos_task/memory_valid.lua
  48. 15 31
      module/Air8000/demo/luatos_framework/luatos_task/non_targeted_msg.lua
  49. 98 10
      module/Air8000/demo/luatos_framework/luatos_task/readme.md
  50. 3 2
      module/Air8000/demo/luatos_framework/luatos_task/scheduling.lua
  51. 1 1
      module/Air8000/demo/luatos_framework/luatos_task/shared_resource.lua
  52. 13 2
      module/Air8000/demo/luatos_framework/luatos_task/targeted_msg_sender.lua
  53. 9 10
      module/Air8000/demo/luatos_framework/luatos_task/task_count.lua
  54. 9 9
      module/Air8000/demo/luatos_framework/luatos_task/task_func.lua
  55. 27 2
      module/Air8000/demo/luatos_framework/luatos_task/task_inout_env_err.lua
  56. 38 121
      module/Air8000/demo/luatos_framework/luatos_task/tgted_msg_receiver.lua
  57. 34 1
      module/Air8000/demo/luatos_framework/luatos_task/timer.lua
  58. 10 7
      module/Air8000/demo/luatos_framework/luatos_task/variable_args.lua
  59. 0 103
      module/Air8000/demo/mqttv2/main.lua
  60. 0 266
      module/Air8000/demo/mqttv2/mqtt/mqtt_main.lua
  61. 0 64
      module/Air8000/demo/mqttv2/mqtt/mqtt_receiver.lua
  62. 0 154
      module/Air8000/demo/mqttv2/mqtt/mqtt_sender.lua
  63. 0 266
      module/Air8000/demo/mqttv2/mqtts/mqtts_main.lua
  64. 0 64
      module/Air8000/demo/mqttv2/mqtts/mqtts_receiver.lua
  65. 0 154
      module/Air8000/demo/mqttv2/mqtts/mqtts_sender.lua
  66. 0 20
      module/Air8000/demo/mqttv2/mqtts_ca/airlbs_parent_ca.crt
  67. 0 293
      module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_main.lua
  68. 0 64
      module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_receiver.lua
  69. 0 154
      module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_sender.lua
  70. 0 66
      module/Air8000/demo/mqttv2/mqtts_ca/sntp_app.lua
  71. 0 33
      module/Air8000/demo/mqttv2/netdrv/netdrv_4g.lua
  72. 0 85
      module/Air8000/demo/mqttv2/netdrv/netdrv_eth_spi.lua
  73. 0 95
      module/Air8000/demo/mqttv2/netdrv/netdrv_multiple.lua
  74. 0 50
      module/Air8000/demo/mqttv2/netdrv/netdrv_wifi.lua
  75. 0 33
      module/Air8000/demo/mqttv2/netdrv_device.lua
  76. 0 64
      module/Air8000/demo/mqttv2/network_watchdog.lua
  77. 0 144
      module/Air8000/demo/mqttv2/readme.md
  78. 0 44
      module/Air8000/demo/mqttv2/timer_app.lua
  79. 0 80
      module/Air8000/demo/mqttv2/uart_app.lua
  80. 71 0
      module/Air8000/demo/rndis_ecm/main.lua
  81. 41 0
      module/Air8000/demo/rndis_ecm/open_ecm.lua
  82. 39 0
      module/Air8000/demo/rndis_ecm/open_rndis.lua
  83. 112 0
      module/Air8000/demo/rndis_ecm/readme.md
  84. 1 1
      module/Air8000/demo/socket/client/long_connection/netdrv/netdrv_wifi.lua
  85. 2 2
      module/Air8000/demo/socket/client/long_connection/netdrv_device.lua
  86. 1 1
      module/Air8000/demo/socket/client/long_connection/tcp/tcp_client_main.lua
  87. 1 1
      module/Air8000/demo/socket/client/long_connection/tcp_ssl/tcp_ssl_main.lua
  88. 1 1
      module/Air8000/demo/socket/client/long_connection/udp/udp_client_main.lua
  89. 0 142
      module/Air8000/demo/tcp/TCP-UART/main.lua
  90. 0 145
      module/Air8000/demo/tcp/TCP单向认证/main.lua
  91. 0 141
      module/Air8000/demo/tcp/TCP断链续连/main.lua
  92. 0 130
      module/Air8000/demo/udp/main.lua
  93. 1 1
      module/Air8000/project/整机开发板出厂工程/user/aircamera.lua
  94. 2 2
      module/Air8101/demo/socket/client/long_connection/netdrv_device.lua
  95. 1 1
      module/Air8101/demo/socket/client/long_connection/tcp/tcp_client_main.lua
  96. 1 1
      module/Air8101/demo/socket/client/long_connection/tcp_ssl/tcp_ssl_main.lua
  97. 1 1
      module/Air8101/demo/socket/client/long_connection/udp/udp_client_main.lua
  98. 0 161
      module/Air8101/demo/tcp/TCP_Uart/main.lua
  99. 0 164
      module/Air8101/demo/tcp/TCP单向认证/main.lua
  100. 0 164
      module/Air8101/demo/tcp/TCP断链续连/main.lua

+ 42 - 1
components/gmssl/bind/luat_lib_gmssl.c

@@ -82,7 +82,7 @@ sm2算法加密
 @string 公钥y,必选. HEX字符串
 @string 待计算的数据,必选,最长32字节, 非HEX字符串
 @boolean 输出模式,默认false. false-GMSSL默认格式DER, true-网站兼容模式
-@boolean 标准版本,默认false. false-C1C3C2新国际, true-C1C2C3老国际
+@boolean 标准版本,默认false. false-C1C3C2新国际, true-C1C2C3老国际. 仅"网站兼容模式"时有效
 @return string 加密后的字符串, 原样输出,未经HEX转换. 若加密失败会返回nil或空字符串
 @usage
 -- 提示 mode/mode2 参数是 2023.10.17 新增
@@ -674,6 +674,46 @@ static int l_sm2_verify(lua_State *L)
     return 1;
 }
 
+/*
+SM2密钥生成
+@api sm.sm2keygen()
+@return string 公钥X, HEX字符串
+@return string 公钥Y, HEX字符串
+@return string 私钥, HEX字符串
+@usage
+-- 本函数于2025.8.27新增
+-- 注意返回值是HEX字符串, 传递给sm2系列函数可以直接使用
+-- 如果传递给服务器, 按格式需要, 可能需要 fromHex 操作
+local pkx, pky, private = gmssl.sm2keygen()
+local originStr = "32wrniosadnfvnadsio;fasiow"
+local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr)
+log.info("sm2默认模式", "加密后", encodeStr and  string.toHex(encodeStr))
+if encodeStr then
+    log.info("sm2默认模式", "解密后", gmssl.sm2decrypt(private,encodeStr))
+end
+
+-- 提醒, 生成的密钥对请妥善保管
+-- 一定要看 gmssl.sm2encrypt 的文档和demo
+*/
+static int l_sm2_keygen(lua_State *L)
+{
+    int ret = 0;
+    SM2_SIGN_CTX ctx = {0};
+    ret = sm2_key_generate(&ctx.key);
+    if (ret != 1) {
+        LLOGW("sm2_keygen %d", ret);
+        return 0;
+    }
+    char tmp[128] = {0};
+    luat_str_tohex((const char*)ctx.key.public_key.x, 32, tmp);
+    lua_pushlstring(L, tmp, 64);
+    luat_str_tohex((const char*)ctx.key.public_key.y, 32, tmp);
+    lua_pushlstring(L, tmp, 64);
+    luat_str_tohex((const char*)ctx.key.private_key, 32, tmp);
+    lua_pushlstring(L, tmp, 64);
+    return 3;
+}
+
 #include "rotable2.h"
 static const rotable_Reg_t reg_gmssl[] =
 {
@@ -686,6 +726,7 @@ static const rotable_Reg_t reg_gmssl[] =
     { "sm4decrypt",      ROREG_FUNC(l_sm4_decrypt)},
     { "sm2sign",         ROREG_FUNC(l_sm2_sign)},
     { "sm2verify",       ROREG_FUNC(l_sm2_verify)},
+    { "sm2keygen",       ROREG_FUNC(l_sm2_keygen)},
 
 	{ NULL,             ROREG_INT(0) }
 };

+ 115 - 68
components/mreport/src/luat_mreport.c

@@ -38,8 +38,40 @@ static inline uint16_t u162bcd(uint16_t src) {
     return dst;
 }
 
-// 模块的基础信息
-void luat_mreport_mobile(cJSON* mreport_data) {
+// 基础信息
+static void luat_mreport_sys_basic(cJSON* mreport_data) {
+    // 时间戳
+	time_t t;
+	time(&t);
+    cJSON_AddNumberToObject(mreport_data, "localtime", t);
+
+    // luatos项目信息
+    cJSON_AddStringToObject(mreport_data, "proj", project_name);
+    cJSON_AddStringToObject(mreport_data, "pver", project_version);
+    
+    // rndis
+    cJSON_AddNumberToObject(mreport_data, "rndis", 0);
+    // usb
+    cJSON_AddNumberToObject(mreport_data, "usb", 1);
+    // vbus
+    cJSON_AddNumberToObject(mreport_data, "vbus", 1);
+
+    // 开机原因
+    cJSON_AddNumberToObject(mreport_data, "powerreson", luat_pm_get_poweron_reason());
+
+    // 开机次数
+    cJSON_AddNumberToObject(mreport_data, "bootc", 1);
+
+    // 开机时长
+    uint64_t tick64 = luat_mcu_tick64();
+    uint64_t tmms = tick64 / 1000000;
+    uint64_t tms = tick64 % 1000000;
+    cJSON_AddNumberToObject(mreport_data, "tmms", tmms);
+    cJSON_AddNumberToObject(mreport_data, "tms", tms);
+}
+
+// 模块的信息
+static void luat_mreport_mobile(cJSON* mreport_data) {
     // IMEI
     char imei[16] = {0};
     luat_mobile_get_imei(0, imei, 16);                  
@@ -77,7 +109,7 @@ void luat_mreport_mobile(cJSON* mreport_data) {
 }
 
 // 网络信息
-void luat_mreport_sim_network(cJSON* mreport_data, struct netif* netif) {
+static void luat_mreport_sim_network(cJSON* mreport_data, struct netif* netif) {
     cJSON* cells = cJSON_CreateArray();
     // ICCID
     char iccid[24] = {0};
@@ -142,6 +174,9 @@ void luat_mreport_sim_network(cJSON* mreport_data, struct netif* netif) {
             }
         }
     }
+    if (cell_info != NULL) {
+        luat_heap_free(cell_info);
+    }
 
     // ip地址
     cJSON_AddStringToObject(mreport_data, "ipv4", ip4addr_ntoa(&netif->ip_addr));
@@ -161,7 +196,7 @@ void luat_mreport_sim_network(cJSON* mreport_data, struct netif* netif) {
 }
 
 // adc信息
-void luat_mreport_adc(cJSON* mreport_data) {
+static void luat_mreport_adc(cJSON* mreport_data) {
     // adc-vbat
     if (luat_adc_open(LUAT_ADC_CH_VBAT, NULL) == 0) {
         int val = 0xFF;
@@ -183,13 +218,63 @@ void luat_mreport_adc(cJSON* mreport_data) {
 }
 
 // wifi信息
-void luat_mreport_wifi(cJSON* mreport_data) {
+static void luat_mreport_wifi(cJSON* mreport_data) {
     // wifi版本
     uint32_t wifi_version = 0;
     if (g_airlink_ext_dev_info.tp == 0x01) {
         memcpy(&wifi_version, g_airlink_ext_dev_info.wifi.version, 4);
     }
-    cJSON_AddNumberToObject(mreport_data, "wifiver", wifi_version);
+    cJSON_AddNumberToObject(mreport_data, "wifi_ver", wifi_version);
+
+    // wifi mac
+    char mac[18] = {0};
+    sprintf_(mac, "%02x:%02x:%02x:%02x:%02x:%02x", g_airlink_ext_dev_info.wifi.sta_mac[0], g_airlink_ext_dev_info.wifi.sta_mac[1], g_airlink_ext_dev_info.wifi.sta_mac[2], g_airlink_ext_dev_info.wifi.sta_mac[3], g_airlink_ext_dev_info.wifi.sta_mac[4], g_airlink_ext_dev_info.wifi.sta_mac[5]);
+    cJSON_AddStringToObject(mreport_data, "wifi_sta_mac", mac);
+    sprintf_(mac, "%02x:%02x:%02x:%02x:%02x:%02x", g_airlink_ext_dev_info.wifi.ap_mac[0], g_airlink_ext_dev_info.wifi.ap_mac[1], g_airlink_ext_dev_info.wifi.ap_mac[2], g_airlink_ext_dev_info.wifi.ap_mac[3], g_airlink_ext_dev_info.wifi.ap_mac[4], g_airlink_ext_dev_info.wifi.ap_mac[5]);
+    cJSON_AddStringToObject(mreport_data, "wifi_ap_mac", mac);
+    sprintf_(mac, "%02x:%02x:%02x:%02x:%02x:%02x", g_airlink_ext_dev_info.wifi.bt_mac[0], g_airlink_ext_dev_info.wifi.bt_mac[1], g_airlink_ext_dev_info.wifi.bt_mac[2], g_airlink_ext_dev_info.wifi.bt_mac[3], g_airlink_ext_dev_info.wifi.bt_mac[4], g_airlink_ext_dev_info.wifi.bt_mac[5]);
+    cJSON_AddStringToObject(mreport_data, "wifi_bt_mac", mac);
+
+    // wifi状态
+    cJSON_AddNumberToObject(mreport_data, "wifi_sta_state", g_airlink_ext_dev_info.wifi.sta_state);
+    cJSON_AddNumberToObject(mreport_data, "wifi_ap_state", g_airlink_ext_dev_info.wifi.ap_state);
+
+    // wifi connect ap bssid/rssi/channel
+    if (g_airlink_ext_dev_info.wifi.sta_state == 1) {
+        sprintf_(mac, "%02x:%02x:%02x:%02x:%02x:%02x", g_airlink_ext_dev_info.wifi.sta_ap_bssid[0], g_airlink_ext_dev_info.wifi.sta_ap_bssid[1], g_airlink_ext_dev_info.wifi.sta_ap_bssid[2], g_airlink_ext_dev_info.wifi.sta_ap_bssid[3], g_airlink_ext_dev_info.wifi.sta_ap_bssid[4], g_airlink_ext_dev_info.wifi.sta_ap_bssid[5]);
+        cJSON_AddStringToObject(mreport_data, "wifi_bssid", mac);
+        cJSON_AddNumberToObject(mreport_data, "wifi_rssi", g_airlink_ext_dev_info.wifi.sta_ap_rssi);
+        cJSON_AddNumberToObject(mreport_data, "wifi_channel", g_airlink_ext_dev_info.wifi.sta_ap_channel);
+    }
+}
+
+// 内存信息
+static void luat_mreport_meminfo(cJSON* mreport_data) {
+    // 当前内存状态
+    size_t total = 0;
+    size_t used = 0;
+    size_t max_used = 0;
+    cJSON* meminfo_sram = cJSON_CreateArray();
+    luat_meminfo_opt_sys(LUAT_HEAP_SRAM, &total, &used, &max_used);
+    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(total));
+    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(used));
+    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(max_used));
+    cJSON_AddItemToObject(mreport_data, "mem_sram", meminfo_sram);
+    
+    cJSON* meminfo_psram = cJSON_CreateArray();
+    luat_meminfo_opt_sys(LUAT_HEAP_PSRAM, &total, &used, &max_used);
+    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(total));
+    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(used));
+    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(max_used));
+    cJSON_AddItemToObject(mreport_data, "mem_psram", meminfo_psram);
+
+    cJSON* meminfo_luavm = cJSON_CreateArray();
+    luat_meminfo_luavm(&total, &used, &max_used);
+    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(total));
+    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(used));
+    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(max_used));
+    cJSON_AddItemToObject(mreport_data, "mem_lua", meminfo_luavm);
+    cJSON_AddNumberToObject(mreport_data, "memfree", total - used);
 }
 
 void luat_mreport_send(void) {
@@ -198,21 +283,26 @@ void luat_mreport_send(void) {
     size_t olen = 0;
     cJSON* mreport_data = cJSON_CreateObject();
 
-    luat_netdrv_t* netdrv = luat_netdrv_get(NW_ADAPTER_INDEX_LWIP_GPRS);
+    int adapter_index = network_register_get_default();
+	if (adapter_index < 0 || adapter_index >= NW_ADAPTER_QTY){
+		LLOGE("尚无已注册的网络适配器");
+		return;
+	}
+    luat_netdrv_t* netdrv = luat_netdrv_get(adapter_index);
     if (netdrv == NULL || netdrv->netif == NULL) {
         return;
     }
 
     struct netif *netif = netdrv->netif;
-    if (netif == NULL || ip_addr_isany(&netif->ip_addr)) {
-        // LLOGD("还没联网");
+    if (ip_addr_isany(&netif->ip_addr)) {
+        LLOGD("还没联网");
         return;
     }
 
     if (mreport_pcb == NULL) {
         mreport_pcb = udp_new();
         if (mreport_pcb == NULL) {
-            LLOGE("创建udp pcb 失败, 内存不足?");
+            LLOGE("创建,mreport udp pcb 失败, 内存不足?");
             cJSON_Delete(mreport_data);
             return;
         }
@@ -226,83 +316,40 @@ void luat_mreport_send(void) {
         return;
     }
 
-    // 时间戳
-	time_t t;
-	time(&t);
-    cJSON_AddNumberToObject(mreport_data, "localtime", t);
-
-    // luatos项目信息
-    cJSON_AddStringToObject(mreport_data, "proj", project_name);
-    cJSON_AddStringToObject(mreport_data, "pver", project_version);
-
+    // 基础信息
+    luat_mreport_sys_basic(mreport_data);
     // 模组信息
     luat_mreport_mobile(mreport_data);
-
     // sim卡和网络相关
     luat_mreport_sim_network(mreport_data, netif);
-
     // adc信息
     luat_mreport_adc(mreport_data);
-
     // wifi信息
+#ifdef LUAT_USE_DRV_WLAN
     luat_mreport_wifi(mreport_data);
-
-    // rndis
-    cJSON_AddNumberToObject(mreport_data, "rndis", 0);
-    // usb
-    cJSON_AddNumberToObject(mreport_data, "usb", 1);
-    // vbus
-    cJSON_AddNumberToObject(mreport_data, "vbus", 1);
-
-    // 开机原因
-    cJSON_AddNumberToObject(mreport_data, "powerreson", luat_pm_get_poweron_reason());
-    // 当前内存状态
-    size_t total = 0;
-    size_t used = 0;
-    size_t max_used = 0;
-    cJSON* meminfo_sram = cJSON_CreateArray();
-    luat_meminfo_opt_sys(LUAT_HEAP_SRAM, &total, &used, &max_used);
-    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(total));
-    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(used));
-    cJSON_AddItemToArray(meminfo_sram, cJSON_CreateNumber(max_used));
-    cJSON_AddItemToObject(mreport_data, "mem_sram", meminfo_sram);
-    
-    cJSON* meminfo_psram = cJSON_CreateArray();
-    luat_meminfo_opt_sys(LUAT_HEAP_PSRAM, &total, &used, &max_used);
-    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(total));
-    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(used));
-    cJSON_AddItemToArray(meminfo_psram, cJSON_CreateNumber(max_used));
-    cJSON_AddItemToObject(mreport_data, "mem_sys", meminfo_psram);
-    cJSON_AddItemToObject(mreport_data, "mem_psram", meminfo_psram);
-
-    cJSON* meminfo_luavm = cJSON_CreateArray();
-    luat_meminfo_luavm(&total, &used, &max_used);
-    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(total));
-    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(used));
-    cJSON_AddItemToArray(meminfo_luavm, cJSON_CreateNumber(max_used));
-    cJSON_AddItemToObject(mreport_data, "mem_lua", meminfo_luavm);
-    cJSON_AddNumberToObject(mreport_data, "memfree", total - used);
-
-    // 开机次数
-    cJSON_AddNumberToObject(mreport_data, "bootc", 1);
-
-    // 开机时长
-    uint64_t tick64 = luat_mcu_tick64();
-    uint64_t tmms = tick64 / 1000000;
-    uint64_t tms = tick64 % 1000000;
-    cJSON_AddNumberToObject(mreport_data, "tmms", tmms);
-    cJSON_AddNumberToObject(mreport_data, "tms", tms);
+#endif
+    // 内存信息
+    luat_mreport_meminfo(mreport_data);
 
     // 结束 转换成json字符串
     char* json = cJSON_PrintUnformatted(mreport_data);
+    if (json == NULL) {
+        LLOGE("拼接转换为json数据格式, 失败");
+        cJSON_Delete(mreport_data);
+        return;
+    }
     LLOGE("mreport json --- len: %d\r\n%s", strlen(json), json);
 
     struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, strlen(json), PBUF_RAM);
     if (p == NULL) {
         LLOGE("获取pbuf失败 %d", strlen(json));
+        free(json);
+        cJSON_Delete(mreport_data);
         return;
     }
+
     pbuf_take(p, json, strlen(json));
+    memcpy(&mreport_pcb->local_ip, &netif->ip_addr, sizeof(ip_addr_t));
     ret = udp_sendto_if(mreport_pcb, p, &host, MREPORT_PORT, netif);
     pbuf_free(p);
     free(json);

+ 1 - 0
components/multimedia/luat_multimedia_audio.c

@@ -136,6 +136,7 @@ LUAT_WEAK void luat_audio_config_dac(uint8_t multimedia_id, int pin, int level,
     luat_audio_conf_t* audio_conf = luat_audio_get_config(multimedia_id);
     if (audio_conf){
         if (pin != LUAT_GPIO_NONE){
+            luat_gpio_mode(pin, Luat_GPIO_OUTPUT, Luat_GPIO_DEFAULT, level);
             audio_conf->power_pin = pin;
             audio_conf->power_on_level = level;
             audio_conf->power_off_delay_time = dac_off_delay_time;

+ 3 - 3
components/network/netdrv/src/luat_netdrv_napt.c

@@ -25,7 +25,7 @@
 
 #define ICMP_MAP_SIZE (32)
 #define UDP_MAP_TIMEOUT (60 * 1000)
-
+#define NAPT_MAX_PACKET_SIZE (1520)
 /* napt icmp id range: 3000-65535 */
 #define NAPT_ICMP_ID_RANGE_START     0xBB8
 #define NAPT_ICMP_ID_RANGE_END       0xFFFF
@@ -180,7 +180,7 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_pkg_input(int id, uint8_t* buff, siz
 static uint8_t* napt_buff;
 err_t netdrv_ip_input_cb(int id, struct pbuf *p, struct netif *inp) {
     size_t len = p->tot_len;
-    if (len > 1500 || len < 24) {
+    if (len > NAPT_MAX_PACKET_SIZE || len < 24) {
         return 1;
     }
     if (napt_buff == NULL) {
@@ -198,7 +198,7 @@ err_t netdrv_ip_input_cb(int id, struct pbuf *p, struct netif *inp) {
 
 // 辅助函数
 int luat_netdrv_napt_pkg_input_pbuf(int id, struct pbuf* p) {
-    if (p == NULL || p->tot_len > 1500) {
+    if (p == NULL || p->tot_len > NAPT_MAX_PACKET_SIZE) {
         return 0;
     }
     // LLOGD("pbuf情况 total %d len %d", p->tot_len, p->len);

+ 2 - 0
components/yhm27xx/binding/luat_lib_yhm27xx.c

@@ -125,6 +125,7 @@ static int l_yhm27xx_reqinfo(lua_State *L)
   return 0;
 }
 
+#ifdef LUAT_USE_YHM27XX
 #include "rotable2.h"
 static const rotable_Reg_t reg_yhm27xx[] = {
         {"cmd",     ROREG_FUNC(l_pm_chgcmd)},
@@ -137,3 +138,4 @@ LUAMOD_API int luaopen_yhm27xx(lua_State *L)
   luat_newlib2(L, reg_yhm27xx);
   return 1;
 }
+#endif

+ 10 - 123
luat/demo/gmssl/main.lua

@@ -5,131 +5,18 @@ VERSION = "1.0.0"
 
 log.info("main", PROJECT, VERSION)
 
--- sys库是标配
-_G.sys = require("sys")
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
--- Air101/Air103默认80M主频, 跑国密算法会很慢的,调整到240M
-if mcu and (rtos.bsp() == "AIR101" or rtos.bsp() == "AIR103" or rtos.bsp() == "AIR601" ) then
-    mcu.setClk(240)
-end
 
 sys.taskInit(function()
-
-    sys.wait(1000)
-    log.info("gmssl", "start")
-    -- 未加密字符串
-    local originStr = "!!from LuatOS!!"
-
-    -- SM2 , 非对称加密, 类似于RSA,但属于椭圆算法
-    -- 就当前实现还是比较慢的
-    if gmssl.sm2encrypt then -- 部分BSP不支持
-        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
-        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
-        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
-
-        -- GMSSL默认格式
-        log.info("==== SM2 默认GMSSL模式")
-        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr)
-        log.info("sm2默认模式", "加密后", encodeStr and  string.toHex(encodeStr))
-        if encodeStr then
-            log.info("sm2默认模式", "解密后", gmssl.sm2decrypt(private,encodeStr))
-        end
-        
-
-        -- 网站兼容模式 https://i.goto327.top/CryptTools/SM2.aspx
-        -- 密文格式 C1C3C2, 新国标, 一般是这种
-        log.info("==== SM2 网站兼容模式")
-        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true)
-        log.info("sm2网站兼容模式 C1C3C2", "加密后", encodeStr and  string.toHex(encodeStr))
-        if encodeStr then
-            log.info("sm2网站兼容模式 C1C3C2", "解密后", gmssl.sm2decrypt(private,encodeStr, true))
-        else
-            log.info("解密失败")
-        end
-        -- 密文格式 C1C2C3, 老国标, 老的Java库通常支持这种
-        log.info("==== SM2 网站兼容模式, 但C1C2C3")
-        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true, true)
-        log.info("sm2网站兼容模式 C1C2C3", "加密后", encodeStr and  string.toHex(encodeStr))
-        if encodeStr then
-            log.info("sm2网站兼容模式 C1C2C3", "解密后", gmssl.sm2decrypt(private,encodeStr, true, true))
-        else
-            log.info("解密失败")
-        end
-    end
-
-    -- SM3 算法, hash类
-    if gmssl.sm3update then
-        log.info("=== SM3测试")
-        encodeStr = gmssl.sm3update("lqlq666lqlq946")
-        log.info("gmssl.sm3update",string.toHex(encodeStr))
-    end
-
-    if gmssl.sm4encrypt then
-        log.info("=== SM4测试")
-        local passwd = "1234567890123456"
-        local iv = "1234567890666666"
-        -- SM4 算法, 对称加密
-        originStr = ">>SM4 ECB ZeroPadding test<<"
-        --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;密钥长度:128 bit
-        encodeStr = gmssl.sm4encrypt("ECB", "ZERO", originStr, passwd)
-        log.info("sm4.ecb.zero", "加密后", string.toHex(encodeStr))
-        log.info("sm4.ecb.zero", "解密后", gmssl.sm4decrypt("ECB","ZERO",encodeStr,passwd))
-
-        originStr = ">>SM4 ECB Pkcs5Padding test<<"
-        --加密模式:ECB;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit
-        encodeStr = gmssl.sm4encrypt("ECB", "PKCS5", originStr, passwd)
-        log.info("sm4.ecb.pks5", "加密后", string.toHex(encodeStr))
-        log.info("sm4.ecb.pks5", "解密后", gmssl.sm4decrypt("ECB","PKCS5",encodeStr,passwd))
-
-        originStr = ">>SM4 CBC Pkcs5Padding test<<"
-        --加密模式:CBC;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit;偏移量:1234567890666666
-        encodeStr = gmssl.sm4encrypt("CBC","PKCS5", originStr, passwd, iv)
-        log.info("sm4.cbc.pks5", "加密后", string.toHex(encodeStr))
-        log.info("sm4.cbc.pks5", "解密后", gmssl.sm4decrypt("CBC","PKCS5",encodeStr,passwd, iv))
-
-        -- 完全对齐16字节的对比测试
-        originStr = "1234567890123456"
-        encodeStr = gmssl.sm4encrypt("ECB","PKCS7",originStr,passwd)
-        log.info("sm4.ecb.pkcs7", encodeStr:toHex())
-        encodeStr = gmssl.sm4encrypt("ECB","PKCS5",originStr,passwd)
-        log.info("sm4.ecb.pkcs5", encodeStr:toHex())
-        encodeStr = gmssl.sm4encrypt("ECB","ZERO",originStr,passwd)
-        log.info("sm4.ecb.zero", encodeStr:toHex())
-        encodeStr = gmssl.sm4encrypt("ECB","NONE",originStr,passwd)
-        log.info("sm4.ecb.none", encodeStr:toHex())
-    end
-
-    -- SM2签名和验签
-    if gmssl.sm2sign then
-        local originStr = string.fromHex("434477813974bf58f94bcf760833c2b40f77a5fc360485b0b9ed1bd9682edb45")
-        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
-        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
-        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
-
-        -- 不带id的情况,即默认id="1234567812345678"
-        local sig = gmssl.sm2sign(private, originStr, nil)
-        log.info("sm2sign", sig and sig:toHex())
-        if sig then
-            local ret = gmssl.sm2verify(pkx, pky, originStr, nil, sig)
-            log.info("sm2verify", ret or "false")
-        end
-
-        -- 带id的情况
-        local id = "1234"
-        local sig = gmssl.sm2sign(private, originStr, id)
-        log.info("sm2sign", sig and sig:toHex())
-        if sig then
-            local ret = gmssl.sm2verify(pkx, pky, originStr, id, sig)
-            log.info("sm2verify", ret or "false")
-        end
-    end
-
+    -- 测试sm2算法, 含密钥生成
+    require "sm2test"
+    -- 测试sm3算法
+    require "sm3test"
+    -- 测试sm4算法
+    require "sm4test"
+    -- 测试sm2签名和验签
+    require "sm2sign"
+
+    log.info("=====================================")
     log.info("gmssl", "ALL Done")
 end)
 

+ 28 - 0
luat/demo/gmssl/sm2sign.lua

@@ -0,0 +1,28 @@
+
+sys.taskInit(function()
+
+    -- SM2签名和验签
+    if gmssl.sm2sign then
+        local originStr = string.fromHex("434477813974bf58f94bcf760833c2b40f77a5fc360485b0b9ed1bd9682edb45")
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+
+        -- 不带id的情况,即默认id="1234567812345678"
+        local sig = gmssl.sm2sign(private, originStr, nil)
+        log.info("sm2sign", sig and sig:toHex())
+        if sig then
+            local ret = gmssl.sm2verify(pkx, pky, originStr, nil, sig)
+            log.info("sm2verify", ret or "false")
+        end
+
+        -- 带id的情况
+        local id = "1234"
+        local sig = gmssl.sm2sign(private, originStr, id)
+        log.info("sm2sign", sig and sig:toHex())
+        if sig then
+            local ret = gmssl.sm2verify(pkx, pky, originStr, id, sig)
+            log.info("sm2verify", ret or "false")
+        end
+    end
+end)

+ 55 - 0
luat/demo/gmssl/sm2test.lua

@@ -0,0 +1,55 @@
+
+function sm2test(originStr, pkx, pky, private)
+    -- GMSSL默认格式
+    log.info("==== SM2 默认GMSSL模式")
+    local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr)
+    log.info("sm2默认模式", "加密后", encodeStr and  string.toHex(encodeStr))
+    if encodeStr then
+        log.info("sm2默认模式", "解密后", gmssl.sm2decrypt(private,encodeStr))
+    end
+    
+
+    -- 网站兼容模式 https://i.goto327.top/CryptTools/SM2.aspx
+    -- 密文格式 C1C3C2, 新国标, 一般是这种
+    log.info("==== SM2 网站兼容模式")
+    local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true)
+    log.info("sm2网站兼容模式 C1C3C2", "加密后", encodeStr and  string.toHex(encodeStr))
+    if encodeStr then
+        log.info("sm2网站兼容模式 C1C3C2", "解密后", gmssl.sm2decrypt(private,encodeStr, true))
+    else
+        log.info("解密失败")
+    end
+    -- 密文格式 C1C2C3, 老国标, 老的Java库通常支持这种
+    log.info("==== SM2 网站兼容模式, 但C1C2C3")
+    local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true, true)
+    log.info("sm2网站兼容模式 C1C2C3", "加密后", encodeStr and  string.toHex(encodeStr))
+    if encodeStr then
+        log.info("sm2网站兼容模式 C1C2C3", "解密后", gmssl.sm2decrypt(private,encodeStr, true, true))
+    else
+        log.info("解密失败")
+    end
+end
+
+sys.taskInit(function()
+    -- 未加密字符串
+    local originStr = "!!from LuatOS!!"
+
+    -- SM2 , 非对称加密, 类似于RSA,但属于椭圆算法
+    -- 就当前实现还是比较慢的
+    if gmssl.sm2encrypt then -- 部分BSP不支持
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+        sm2test(originStr, pkx, pky, private)
+    end
+
+    -- SM密钥生成
+    if gmssl.sm2keygen then
+        log.info("SM2密钥生成测试")
+        originStr = "32wrniosadnfvnadsio;fasiow"
+        local pkx, pky, private = gmssl.sm2keygen()
+        sm2test(originStr, pkx, pky, private)
+    end
+
+end)
+

+ 11 - 0
luat/demo/gmssl/sm3test.lua

@@ -0,0 +1,11 @@
+
+sys.taskInit(function()
+
+    -- SM3 算法, hash类
+    if gmssl.sm3update then
+        log.info("=== SM3测试")
+        encodeStr = gmssl.sm3update("lqlq666lqlq946")
+        log.info("gmssl.sm3update",string.toHex(encodeStr))
+    end
+end)
+

+ 43 - 0
luat/demo/gmssl/sm4test.lua

@@ -0,0 +1,43 @@
+
+sys.taskInit(function()
+
+    if gmssl.sm4encrypt then
+        log.info("=== SM4测试")
+        local passwd = "1234567890123456"
+        local iv = "1234567890666666"
+        -- SM4 算法, 对称加密
+        originStr = ">>SM4 ECB ZeroPadding test<<"
+        --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;密钥长度:128 bit
+        encodeStr = gmssl.sm4encrypt("ECB", "ZERO", originStr, passwd)
+        log.info("sm4.ecb.zero", "加密后", string.toHex(encodeStr))
+        log.info("sm4.ecb.zero", "解密后", gmssl.sm4decrypt("ECB","ZERO",encodeStr,passwd))
+
+        originStr = ">>SM4 ECB Pkcs5Padding test<<"
+        --加密模式:ECB;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit
+        encodeStr = gmssl.sm4encrypt("ECB", "PKCS5", originStr, passwd)
+        log.info("sm4.ecb.pks5", "加密后", string.toHex(encodeStr))
+        log.info("sm4.ecb.pks5", "解密后", gmssl.sm4decrypt("ECB","PKCS5",encodeStr,passwd))
+
+        originStr = ">>SM4 CBC Pkcs5Padding test<<"
+        --加密模式:CBC;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit;偏移量:1234567890666666
+        encodeStr = gmssl.sm4encrypt("CBC","PKCS5", originStr, passwd, iv)
+        log.info("sm4.cbc.pks5", "加密后", string.toHex(encodeStr))
+        log.info("sm4.cbc.pks5", "解密后", gmssl.sm4decrypt("CBC","PKCS5",encodeStr,passwd, iv))
+
+        -- 完全对齐16字节的对比测试
+        originStr = "1234567890123456"
+        encodeStr = gmssl.sm4encrypt("ECB","PKCS7",originStr,passwd)
+        log.info("sm4.ecb.pkcs7", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","PKCS5",originStr,passwd)
+        log.info("sm4.ecb.pkcs5", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","ZERO",originStr,passwd)
+        log.info("sm4.ecb.zero", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","NONE",originStr,passwd)
+        log.info("sm4.ecb.none", encodeStr:toHex())
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 17 - 9
luat/modules/luat_lib_gpio.c

@@ -396,8 +396,8 @@ int luat_caplevel_irq_cb(int pin, void* args) {
 @function func 完成捕获后的回调函数,仅一个参数,参数为捕获到的时间长度number型数值,单位us
 @return any 返回获取电平的闭包
 @usage
--- 捕获pin.PA07为高电平的持续时间
-gpio.caplevel(pin.PA07,1,function(us_int) print(us_float) end)
+-- 捕获GPIO7为高电平的持续时间
+gpio.caplevel(7,1,function(us_int) print(us_float) end)
 */
 static int l_gpio_caplevel(lua_State *L){
     luat_gpio_t conf = {0};
@@ -439,6 +439,8 @@ static int l_gpio_caplevel(lua_State *L){
 @int value 电平, 可以是 高电平gpio.HIGH, 低电平gpio.LOW, 或者直接写数值1或0
 @return nil 无返回值
 @usage
+-- 注意!!! 仅输出状态下,这个函数才有效
+-- 一定要先gpio.setup, 起码执行过一次gpio.setup, 才能使用本函数. 但不需要每次都gpio.setup
 -- 设置gpio17为低电平
 gpio.set(17, 0)
 */
@@ -468,8 +470,11 @@ static int l_gpio_set(lua_State *L) {
 @int pin GPIO编号,必须是数值
 @return value 电平, 高电平gpio.HIGH, 低电平gpio.LOW, 对应数值1和0
 @usage
+-- 注意!!! 仅输入模式或者中断模式状态下,这个函数才有效
+-- 一定要先gpio.setup, 起码执行过一次gpio.setup, 才能使用本函数. 但不需要每次都gpio.setup
 -- 获取gpio17的当前电平
-gpio.get(17)
+local value = gpio.get(17)
+log.info("gpio", "GPIO17:", value)
 */
 static int l_gpio_get(lua_State *L) {
     int upindex = lua_upvalueindex(1);
@@ -496,7 +501,7 @@ static int l_gpio_get(lua_State *L) {
 }
 
 /*
-关闭管脚功能(高阻输入态),关掉中断
+关闭管脚功能(恢复高阻输入态),关掉中断
 @api gpio.close(pin)
 @int pin GPIO编号,必须是数值
 @return nil 无返回值,总是执行成功
@@ -553,6 +558,7 @@ static int l_gpio_set_default_pull(lua_State *L) {
 @usage
 -- 本API于 2022.05.17 添加
 -- 假设GPIO16上有LED, 每500ms切换一次开关
+-- 注意!!! 仅输出状态下,这个函数才有效
 gpio.setup(16, 0)
 sys.timerLoopStart(function()
     gpio.toggle(16)
@@ -579,7 +585,7 @@ static int l_gpio_toggle(lua_State *L) {
 }
 
 /*
-在同一个GPIO输出一组脉冲, 注意, len的单位是bit, 高位在前,高低电平时间均是由delay决定。本API是阻塞操作,不可以一次性输出太多的脉冲!!!
+在同一个GPIO输出一组脉冲
 @api gpio.pulse(pin,level,len,delay)
 @int gpio号
 @int/string 数值或者字符串.
@@ -587,8 +593,10 @@ static int l_gpio_toggle(lua_State *L) {
 @int delay 高低电平延迟时间, 用的软件while来delay, 这里的delay值是while循环次数, 具体delay时间必须实际调试才知道
 @return nil 无返回值
 @usage
--- 通过PB06脚输出输出8个电平变化,while循环次数是0
-gpio.pulse(pin.PB06,0xA9, 8, 0)
+-- 注意, len的单位是bit, 高位在前,高低电平时间均是由delay决定。
+-- 本API是阻塞操作,不可以一次性输出太多的脉冲!!! 否则会死机!!!
+-- 通过GPIO1脚输出输出8个电平变化,while循环次数是0
+gpio.pulse(1,0xA9, 8, 0)
 */
 static int l_gpio_pulse(lua_State *L) {
     int pin,delay = 0;
@@ -637,7 +645,7 @@ static int l_gpio_pulse(lua_State *L) {
 -- 1 触发中断后,延迟N个毫秒,期间没有新中断且电平没有变化,上报一次
 
 -- 开启防抖, 模式0-冷却, 中断后马上上报, 但100ms内只上报一次
-gpio.debounce(7, 100) -- 若芯片支持pin库, 可用pin.PA7代替数字7
+gpio.debounce(7, 100) -- 对应GPIO7
 -- 开启防抖, 模式1-延时, 中断后等待100ms,期间若保持该电平了,时间到之后上报一次
 -- 对应的,如果输入的是一个 50hz的方波,那么不会触发任何上报
 gpio.debounce(7, 100, 1)
@@ -677,7 +685,7 @@ static int l_gpio_debounce(lua_State *L) {
 }
 
 /*
-获取gpio中断数量,并清空累计值,类似air724的脉冲计数
+获取gpio中断数量,并清空累计值
 @api gpio.count(pin)
 @int gpio号, 0~127, 与硬件相关
 @return int 返回从上次获取中断数量后到当前的中断计数

+ 1 - 0
module/Air6101/core/readme.md

@@ -0,0 +1 @@
+Air6101内核固件,待完善

+ 64 - 0
module/Air6101/demo/zbuff/main.lua

@@ -0,0 +1,64 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 003.000.000
+@date    2025.08.08
+@author  王棚嶙
+@usage
+本 Demo 完整覆盖了 zbuff 的核心到高级操作,包括:
+​基础​:创建、读写、指针控制、元信息查询
+​进阶​:结构化数据打包/解包、类型化操作、浮点处理
+​内存管理​:动态调整、块操作、数据比对、Base64 编码
+适用于嵌入式开发中高效处理二进制数据流、协议解析、内存优化等场景。
+
+]]
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "zbuff"
+VERSION = "003.000.000"
+log.info("main", "项目启动", PROJECT, VERSION)
+
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+--示例:
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+--示例:
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+
+-- 加载zbuff应用功能模块
+require "zbuff_core"
+require "zbuff_advanced"
+require "zbuff_memory"
+
+-- 启动系统调度
+sys.run()

+ 172 - 0
module/Air6101/demo/zbuff/readme.md

@@ -0,0 +1,172 @@
+## **功能模块介绍:**
+
+本demo进行了一个完整的 zbuff 二进制数据处理库 的演示,示了在嵌入式环境中高效处理二进制数据的全流程。项目分为三个核心模块,覆盖了从基础到高级的二进制数据处理场景:
+
+1、main.lua:主程序入口
+
+2、zbuff_core.lua:为zbuff的基础操作模块,包含zbuff最常用的创建,读写高效查询等基础功能。
+
+3、zbuff_advanced.lua:为zbuff高级操作模块,包含zbuff较为复杂的结构化打包,类型化操作等数据处理功能。
+
+4、zbuff_memory.lua:为内存管理模块,核心业务逻辑为内存管理操作。
+
+## 演示功能概述
+
+### 1、核心功能模块 (zbuff_core.lua)
+
+#### 缓冲区管理:
+
+(1)创建固定大小(1024字节)的缓冲区 zbuff.create
+
+(2)索引直接访问(如 buff[0] = 0xAE)
+
+#### 基础IO操作:
+
+(1)写入字符串和数值数据(write("123"))
+
+(2)指针控制(seek()定位操作)
+
+(3)数据读取(read(3))
+
+#### 元信息查询
+
+(1)获取缓冲区总长度(len())
+
+(2)查询已使用空间(used())
+
+#### 高效数据查询
+
+(1)query()接口快速提取数据
+
+(2)自动格式转换(大端序处理)
+
+### 2、高级功能模块 (zbuff_advanced.lua)
+
+#### 结构化数据处理
+
+(1)数据打包(pack(">IIHA", ...)):支持大端序/多种数据类型
+
+(2)数据解包(unpack(">IIHA10")):自动解析复合数据结构
+
+#### 类型化操作
+
+(1)精确类型读写:writeI8()/readU32()等
+
+#### 浮点处理
+
+(1)单精度浮点写入(writeF32(1.2))
+
+(2)浮点数据读取(readF32())
+
+### 3、内存管理模块 (zbuff_memory.lua)
+
+#### 动态内存管理
+
+(1)缓冲区动态扩容resize(2048)
+
+#### 块操作
+
+(1)内存块设置(set(10,0xaa,5))类似 memset
+
+(2)数据删除(del(2,3))及前移
+
+#### 数据工具
+
+(1)内存比较(isEqual())
+
+(2)Base64编码转换(toBase64())
+
+## **演示硬件环境**
+
+1、Air8101_B11开发板一块/Air8101系列核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air8101开发板和数据线的硬件接线方式为
+
+- Air8101开发板通过串口小板上的TYPE-C USB口供电。(USB旁边的开关拨到ON)
+- TYPE-C USB数据线直接插到Air8101开发板配套的外接串口小板的的TYPE-C USB座子,另外一端连接电脑USB口;
+
+4、如果是Air8101系列核心板,需要将正面拨到3.3V,背面拨码拨到off, 通过TYPE-C USB口供电,另外一端连接电脑USB口;
+
+## **演示软件环境**
+
+1、Luatools下载调试工具: https://docs.openluat.com/air780epm/common/Luatools/
+
+2、内核固件版本:https://docs.openluat.com/air8101/luatos/firmware/
+
+## **演示核心步骤**
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与内核固件烧录到核心板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印:
+
+```Lua
+(1)开始打印项目信息正式开始展示。
+[2025-08-11 16:38:35.922][000000000.369] I/user.main 项目启动 zbuff 003.000.000
+[2025-08-11 16:38:35.932][000000000.379] I/user.zbuff_core 启动核心功能演示
+[2025-08-11 16:38:35.938][000000000.380] I/user.zbuff_core 缓冲区创建 长度: 1024
+
+
+(2)进行BUFF创建,初始化以及索引,读写,清除等基础功能演示操作
+[2025-08-11 16:38:35.950][000000000.380] I/user.zbuff_core === 缓冲区创建与初始化演示 ===
+[2025-08-11 16:38:35.955][000000000.380] I/user.zbuff_core 索引访问示例 buff[0] = 174
+
+[2025-08-11 16:38:35.965][000000000.381] I/user.zbuff_core === 基础IO操作演示 ===
+[2025-08-11 16:38:35.971][000000000.381] I/user.zbuff_core 写入字符串 123
+[2025-08-11 16:38:35.979][000000000.381] I/user.zbuff_core 写入数值 0x12, 0x13, 0x13, 0x33
+[2025-08-11 16:38:35.985][000000000.381] I/user.zbuff_core 指针当前位置 向后移动5字节 当前位置: 12
+[2025-08-11 16:38:35.991][000000000.382] I/user.zbuff_core 指针移动 重置到开头
+[2025-08-11 16:38:36.000][000000000.382] I/user.zbuff_core 读取数据 长度3: 123
+
+[2025-08-11 16:38:36.005][000000000.382] I/user.zbuff_core === 缓冲区清除操作 ===
+[2025-08-11 16:38:36.013][000000000.382] I/user.zbuff_core 清除操作 全部清零
+[2025-08-11 16:38:36.019][000000000.382] I/user.zbuff_core 清除操作 填充0xA5
+
+[2025-08-11 16:38:36.027][000000000.383] I/user.zbuff_core === 元信息查询 ===
+[2025-08-11 16:38:36.033][000000000.383] I/user.zbuff_core 元信息 总长度: 1024
+[2025-08-11 16:38:36.043][000000000.383] I/user.zbuff_core 元信息 已使用: 3
+
+[2025-08-11 16:38:36.048][000000000.383] I/user.zbuff_core === 高效数据查询 ===
+[2025-08-11 16:38:36.056][000000000.384] I/user.zbuff_core query查询 全部数据: 123456789ABC 12
+[2025-08-11 16:38:36.060][000000000.384] I/user.zbuff_core query查询 大端序格式: 305419896
+[2025-08-11 16:38:36.067][000000000.384] I/user.zbuff_core 核心功能演示完成
+
+
+(3)进行高级功能演示,包括数据打包与解包、类型化读写、浮点操作演示等。
+[2025-08-11 16:38:36.072][000000000.398] I/user.zbuff_advanced 启动高级功能演示
+
+[2025-08-11 16:38:36.078][000000000.398] I/user.zbuff_advanced === 数据打包与解包演示 ===
+[2025-08-11 16:38:36.088][000000000.399] I/user.zbuff_advanced 数据打包 格式: >IIHA 值: 0x1234, 0x4567, 0x12, 'abcdefg'
+[2025-08-11 16:38:36.092][000000000.399] I/user.zbuff_advanced 打包后数据 0000123400004567001261626364656667 34
+[2025-08-11 16:38:36.101][000000000.400] I/user.zbuff_advanced 数据解包 数量: 20 值: 4660 17767 18 abcdefg
+[2025-08-11 16:38:36.105][000000000.401] I/user.zbuff_advanced 解包输出内容 cnt: 20 a(32位): 0x1234 b(32位): 0x4567 c(16位): 0x12 s(字符串): abcdefg
+
+[2025-08-11 16:38:36.109][000000000.401] I/user.zbuff_advanced === 类型化读写演示 ===
+[2025-08-11 16:38:36.119][000000000.401] I/user.zbuff_advanced 类型化写入 I8: 10
+[2025-08-11 16:38:36.126][000000000.402] I/user.zbuff_advanced 类型化写入 U32: 1024
+[2025-08-11 16:38:36.135][000000000.402] I/user.zbuff_advanced 类型化读取 I8: 10
+[2025-08-11 16:38:36.140][000000000.402] I/user.zbuff_advanced 类型化读取 U32: 1024
+
+[2025-08-11 16:38:36.151][000000000.402] I/user.zbuff_advanced === 浮点数操作演示 ===
+[2025-08-11 16:38:36.156][000000000.403] I/user.zbuff_advanced 浮点数操作 写入F32: 1.200000
+[2025-08-11 16:38:36.165][000000000.403] I/user.zbuff_advanced 浮点数操作 读取F32: 1.200000
+[2025-08-11 16:38:36.171][000000000.403] I/user.zbuff_advanced 高级功能演示完成
+
+
+(4)内存管理演示:内存块设置(set(10,0xaa,5)),数据删除(del(2,3))及前移,内存比较,Base64编码转换等
+[2025-08-11 16:38:36.182][000000000.415] I/user.zbuff_memory 启动内存管理功能演示
+[2025-08-11 16:38:36.188][000000000.416] I/user.zbuff_memory 大小调整 原始大小: 1024 新大小: 2048
+[2025-08-11 16:38:36.198][000000000.417] I/user.zbuff_memory 内存设置 位置10-14设置为0xaa
+[2025-08-11 16:38:36.204][000000000.417] I/user.zbuff_memory 验证结果 位置10: 170 应为0xaa
+[2025-08-11 16:38:36.215][000000000.417] I/user.zbuff_memory 删除前数据 
+[2025-08-11 16:38:36.222][000000000.418] ABCDEFGH
+[2025-08-11 16:38:36.233][000000000.418] I/user.zbuff_memory 删除操作 删除位置2-4 结果: 
+[2025-08-11 16:38:36.244][000000000.418] ABFGH
+[2025-08-11 16:38:36.251][000000000.418] I/user.zbuff_memory 内存比较 结果: false 差异位置: 0
+[2025-08-11 16:38:36.258][000000000.419] I/user.zbuff_memory Base64编码 长度: 8 结果: QUJGR0g=
+[2025-08-11 16:38:36.264][000000000.419] I/user.zbuff_memory 内存管理功能演示完成
+```
+

+ 100 - 0
module/Air6101/demo/zbuff/zbuff_advanced.lua

@@ -0,0 +1,100 @@
+--[[
+    @module  zbuff_advanced
+    @summary zbuff的高级操作模块
+    @version 1.0.0
+    @date    2025.08.08
+    @author  王棚嶙
+    @usage
+    本文件为本部分为zbuff高级操作模块,包含zbuff的复杂数据处理功能,包括:
+    1. 数据打包/解包
+    2. 类型化读写
+    3. 浮点数操作
+    本文件没有对外接口,直接在main.lua中require "zbuff_advanced"就可以加载运行
+    ]] --
+local function zbuff_advanced_task_func()
+    log.info("zbuff_advanced", "启动高级功能演示")
+
+    -- 创建1024字节的缓冲区
+    local buff = zbuff.create(1024)
+
+    -- === 数据打包与解包演示 ===
+    log.info("zbuff_advanced", "=== 数据打包与解包演示 ===")
+
+    -- 清空缓冲区
+    buff:clear()
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 打包数据:大端序,2个32位整数,1个16位整数,1个字符串
+    buff:pack(">IIHA", 0x1234, 0x4567, 0x12, "abcdefg")
+    log.info("zbuff_advanced", "数据打包", "格式: >IIHA", "值: 0x1234, 0x4567, 0x12, 'abcdefg'")
+    -- 显示打包后的二进制内容
+    local packed = buff:toStr(0, buff:used()) -- 按照起始位置和长度,取出数据,并转换为字符串
+    log.info("zbuff_advanced", "打包后数据", packed:toHex())
+
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 解包数据:大端序,2个32位整数,1个16位整数,1个10字节字符串
+    local cnt, a, b, c, s = buff:unpack(">IIHA10")
+    log.info("zbuff_advanced", "数据解包", "数量:", cnt, "值:", a, b, c, s)
+    -- 显示解包后的输出内容
+    -- string.forma是Lua的格式化字符串函数,按照格式化参数formatstring,返回后面...内容的格式化版本。string.format("0x%X", a)表示将整数a转换为十六进制字符串。
+    log.info("zbuff_advanced", "解包输出内容", "cnt:", cnt, "a(32位):", string.format("0x%X", a), "b(32位):",
+        string.format("0x%X", b), "c(16位):", string.format("0x%X", c), "s(字符串):", s)
+    -- === 类型化读写演示 ===
+    --[[
+    类型化读写演示
+    展示I8和U32两种类型操作
+    @param buff zbuff对象
+    --]]
+    log.info("zbuff_advanced", "=== 类型化读写演示 ===")
+
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 写入8位有符号整数
+    buff:writeI8(10)
+    log.info("zbuff_advanced", "类型化写入", "I8:", 10)
+
+    -- 写入32位无符号整数
+    buff:writeU32(1024)
+    log.info("zbuff_advanced", "类型化写入", "U32:", 1024)
+
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 读取8位有符号整数
+    local i8data = buff:readI8()
+    log.info("zbuff_advanced", "类型化读取", "I8:", i8data)
+
+    -- 读取32位无符号整数
+    local u32data = buff:readU32()
+    log.info("zbuff_advanced", "类型化读取", "U32:", u32data)
+
+    --[[
+    浮点数操作演示
+    @param buff zbuff对象
+    --]]
+    log.info("zbuff_advanced", "=== 浮点数操作演示 ===")
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 写入32位浮点数
+    buff:writeF32(1.2)
+    log.info("zbuff_advanced", "浮点数操作", "写入F32:", 1.2)
+
+    -- 重置指针到开头
+    buff:seek(0)
+
+    -- 读取32位浮点数
+    local f32data = buff:readF32()
+    log.info("zbuff_advanced", "浮点数操作", "读取F32:", f32data)
+
+    -- 清空缓冲区
+    buff:clear()
+    -- 重置指针到开头
+    buff:seek(0)
+    log.info("zbuff_advanced", "高级功能演示完成")
+end
+sys.taskInit(zbuff_advanced_task_func)

+ 89 - 0
module/Air6101/demo/zbuff/zbuff_core.lua

@@ -0,0 +1,89 @@
+ --[[
+    @module  zbuff_core
+    @summary zbuff的基础操作模块
+    @version 1.0.0
+    @date    2025.08.08
+    @author  王棚嶙
+    @usage
+    本文件为zbuff的基础操作模块,包含zbuff最常用的基础功能:
+
+    1. 缓冲区创建与初始化
+    2. 基础功能操作(读写)
+    3. 指针控制
+    4. 元信息查询
+    5. 高效数据查询(query接口)
+    本文件没有对外接口,直接在main.lua中require "zbuff_core"就可以加载运行
+    ]]
+    
+       
+local function zbuff_core_task_func()
+    log.info("zbuff_core", "启动核心功能演示")
+    
+    -- 创建1024字节的缓冲区
+    local buff = zbuff.create(1024)
+    log.info("zbuff_core", "缓冲区创建", "长度:", buff:len()) -- 打印缓冲区长度
+    -- === 缓冲区创建与初始化演示 ===
+    log.info("zbuff_core", "=== 缓冲区创建与初始化演示 ===")
+    buff[0] = 0xAE -- 通过索引直接访问和修改数据(索引从0开始)
+    log.info("zbuff_core", "索引访问示例", "buff[0] =", buff[0])
+
+
+    
+    -- === 基础读写操作演示 ===
+    log.info("zbuff_core", "=== 基础IO操作演示 ===")
+    --此处的读写操作只作为演示,具体的读取数据看后续的buff:query接口
+    --buff:write()中的参数可以是任意类型,zbuff会自动进行类型转换,写入buff的数据,string时为一个参数,number时可为多个参数
+
+    buff:write("123")
+    log.info("zbuff_core", "写入字符串", "123")
+    buff:write(0x12, 0x13, 0x13, 0x33)
+    log.info("zbuff_core", "写入数值", "0x12, 0x13, 0x13, 0x33")
+    
+    buff:seek(5, zbuff.SEEK_CUR)
+    log.info("zbuff_core", "指针当前位置", "向后移动5字节","当前位置:", buff:used())
+    
+    buff:seek(0)
+    log.info("zbuff_core", "指针移动", "重置到开头")
+    
+    local data = buff:read(3)
+    log.info("zbuff_core", "读取数据", "长度3:",data)
+   
+    
+
+    -- === 缓冲区清除操作 ===
+    log.info("zbuff_core", "=== 缓冲区清除操作 ===")
+    buff:clear()
+    log.info("zbuff_core", "清除操作", "全部清零")
+    
+    buff:clear(0xA5)
+    log.info("zbuff_core", "清除操作", "填充0xA5")
+    
+
+
+    -- === 元信息查询 ===
+    log.info("zbuff_core", "=== 元信息查询 ===")
+    local len = buff:len()
+    log.info("zbuff_core", "元信息", "总长度:", len)
+    
+    local used = buff:used()
+    log.info("zbuff_core", "元信息", "已使用:", used)
+    
+
+
+    -- === 高效数据查询 ===
+    log.info("zbuff_core", "=== 高效数据查询 ===")
+    buff:clear()
+    buff:seek(0)
+    buff:write(0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC)
+    
+    local all_data = buff:query(0, 6)
+    log.info("zbuff_core", "query查询", "全部数据:" ,all_data:toHex())
+     -- 查询部分数据并转换格式,查询1,2,4,8字节的时候会自动根据后续参数进行转换(大端序、无符号)
+    -- 参数:起始位置0,长度4,大端序,无符号,非浮点
+    local part_data = buff:query(0, 4, true, false, false)
+    log.info("zbuff_core", "query查询", "大端序格式:", part_data)
+    
+    log.info("zbuff_core", "核心功能演示完成")
+end
+
+sys.taskInit(zbuff_core_task_func)

+ 62 - 0
module/Air6101/demo/zbuff/zbuff_memory.lua

@@ -0,0 +1,62 @@
+    --[[
+    @module  zbuff_memory
+    @summary zbuff的内存管理模块
+    @version 1.0.0
+    @date    2025.08.08
+    @author  王棚嶙
+    @usage
+    本文件为zbuff的内存管理模块,核心业务逻辑为内存管理操作,包括:
+    1.缓冲区大小调整 
+    2.内存块设置 
+    3.数据删除
+    4.内存比较 
+    5.Base64编码转换功能
+    本文件没有对外接口,直接在main.lua中require "zbuff_memory"就可以加载运行
+    ]]
+local function zbuff_memory_task_func()
+    --[[内存管理操作演示@param buff zbuff对象]]
+    log.info("zbuff_memory", "启动内存管理功能演示")
+
+
+    -- 1. 调整缓冲区大小
+    local buff = zbuff.create(1024)
+    local original_size = buff:len()
+    buff:resize(2048)  -- 扩容到2048字节
+    log.info("zbuff_memory", "大小调整", "原始大小:", original_size, "新大小:", buff:len())
+    
+    -- 2. 内存块设置(类似memset)
+    -- 从位置10开始设置5个字节为0xaa
+    buff:set(10,0xaa,5)
+    log.info("zbuff_memory", "内存设置", "位置10-14设置为0xaa")
+    -- 验证设置结果
+    log.info("zbuff_memory", "验证结果", "位置10:", buff[10], "应为0xaa")
+    
+    -- 3. 数据删除操作
+    -- 写入测试数据
+    buff:clear()
+    buff:seek(0)
+    buff:write("ABCDEFGH")
+    log.info("zbuff_memory", "删除前数据", buff:toStr())
+    
+    -- 删除位置2开始的3个字节
+    buff:del(2, 3)
+    log.info("zbuff_memory", "删除操作", "删除位置2-4", "结果:", buff:toStr())
+    
+    -- 4. 内存比较
+    local buff2 = zbuff.create(10)
+    buff2:write("12345")
+    
+    -- 比较两个缓冲区前5字节内容
+    local equal, offset = buff:isEqual(0, buff2, 0, 5)
+    log.info("zbuff_memory", "内存比较", "结果:", equal, "差异位置:", offset)
+    
+    -- 5. Base64编码转换
+    local dst = zbuff.create(buff:used() * 2)  -- 创建足够大的目标缓冲区
+    
+    -- 进行Base64编码
+    local len = buff:toBase64(dst)
+    log.info("zbuff_memory", "Base64编码", "长度:", len, "结果:", dst:toStr(0, len))
+
+    log.info("zbuff_memory", "内存管理功能演示完成")
+end
+sys.taskInit(zbuff_memory_task_func)

+ 1 - 0
module/Air6101/demolib/readme.md

@@ -0,0 +1 @@
+待完善

+ 0 - 0
module/Air6101/project/readme.md


+ 71 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/main.lua

@@ -0,0 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+演示功能概述
+RNDIS是指Remote NDIS,基于USB实现RNDIS实际上就是TCP/IP over USB,就是在USB设备上跑TCP/IP,让USB设备看上去像一块网卡。从而使Windows /Linux可以通过 USB 设备连接网络。
+ECM(Ethernet Control Model)是一种基于 USB 的通信设备类(CDC)子类协议,它将 “TCP/IP over USB” 抽象成一条虚拟以太网链路:USB 设备端实现 ECM 功能后,会在主机侧呈现为一块标准的以太网卡(如 usb0)。主机操作系统(Linux、macOS 等)无需额外专用驱动,即可通过该虚拟网卡发送/接收以太网帧,从而经 USB 设备连接到网络。
+1、功能使用说明
+由于 Air780Exx 系列模组 只支持 LUATOS 模式,且 RNDIS 网卡应用默认关闭,所以在使用 RNIDS 之前,需要使用接口打开,本demo将为大家讲解如何使用 RNIDS 功能。
+本demo仅演示在 Windows系统上运行 RNDIS 功能,如果需要在 Linux系统上使用功能,请查看文档:xxxxxxxxx
+2、ECM 功能说明
+由于Windows系统没有测试环境无法测试 ECM 功能,所以 open_ecm.lua 没有完整测试。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+更多说明参考本目录下的readme.md文件
+]]
+PROJECT = "RNDIS_ECM"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- 加载 open_rndis 主应用功能模块
+require "open_rndis"
+
+-- 加载 open_ecm 主应用功能模块
+-- require "open_ecm"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 41 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/open_ecm.lua

@@ -0,0 +1,41 @@
+--[[
+@module  open_ecm
+@summary ecm 服务启动功能模块
+@version 1.0
+@date    2025.08.26
+@author  拓毅恒
+@usage
+用法实例
+
+启动 ECM 服务
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+注:由于Windows系统没有测试环境无法测试 ECM 功能,所以本demo没有完整测试。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_ecm" 即可加载运行。
+]]
+
+-- 运行 ECM 模式任务
+local function ecm_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开ECM模式")
+        -- 调用 mobile.config 函数启用 ECM 功能
+        -- 传入的第二个参数 7 ,实际为二进制的 0111
+        -- 蜂窝网络模块的usb以太网卡控制,bit0开关,1开0关,bit1模式,1NAT0独立IP(在usb以太网卡开启前可以修改,开启过就不行),bit2协议1 ECM,0 RNDIS,飞行模式里设置。
+        log.info("我看看 ECM 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 7))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 ecm_task 函数
+sys.taskInit(ecm_task)

+ 39 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/open_rndis.lua

@@ -0,0 +1,39 @@
+--[[
+@module  open_rndis
+@summary rndis 服务启动功能模块
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+用法实例
+
+启动 RNDIS 服务
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_rndis" 即可加载运行。
+]]
+
+-- 运行 RNDIS 模式任务
+local function rndis_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开RNDIS模式")
+        -- 调用 mobile.config 函数启用 RNDIS 功能
+        log.info("我看看 RNDIS 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 3))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 rndis_task 函数
+sys.taskInit(rndis_task)

+ 112 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/rndis_ecm/readme.md

@@ -0,0 +1,112 @@
+## 演示功能概述
+
+本demo支持两种基于USB的网络连接模式:RNDIS和ECM。
+
+- **RNDIS**(Remote NDIS):基于USB实现的TCP/IP over USB,让USB设备在Windows系统上呈现为一块网卡,从而使Windows/Linux可以通过USB设备连接网络。
+
+- **ECM**(Ethernet Control Model):一种基于USB的通信设备类(CDC)子类协议,将"TCP/IP over USB"抽象成一条虚拟以太网链路,在主机侧呈现为一块标准的以太网卡。Linux、macOS等操作系统无需额外专用驱动即可使用。
+
+#### 1、功能使用说明
+
+本demo已将功能拆分为三个文件:
+- `main.lua`:主入口文件,负责加载和调度各个功能模块
+- `open_rndis.lua`:RNDIS功能实现模块
+- `open_ecm.lua`:ECM功能实现模块
+
+由于 Air780Exx 系列模组 只支持 LUATOS 模式,且RNDIS/ECM网卡应用默认关闭,需要使用接口打开。
+
+**注意:**
+- 本demo在Windows系统上主要测试RNDIS功能
+- ECM功能由于Windows系统缺少测试环境,无法在Windows上完整测试
+
+#### 2、启动 RNDIS 服务
+
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 3)
+传入的第二个参数 3 ,实际为二进制的 0011
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为0,则开启RNDIS模式。
+
+#### 3、启动 ECM 服务
+
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 7)
+传入的第二个参数 7 ,实际为二进制的 0111
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为1,则开启ECM模式。
+
+> 特别说明:由于Windows系统缺少测试环境,ECM功能无法在Windows系统上完整测试。在Linux、macOS等系统上可能需要不同的配置和测试方法。
+>
+>注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+#### 4、运行效果
+
+- **飞行模式进入成功**:日志打印 “进入飞行模式成功”
+
+- **RNDIS 创建成功**:日志中会打印“我看看 RNDIS 是否启动成功: true”,并且在电脑网络上显示出RNDIS联网图标。
+
+- **ECM 创建**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。在日志中会打印“我看看 ECM 是否启动成功: [结果]”,但无法在Windows系统上验证网络连接状态。
+
+> **注意**:在main.lua中,RNDIS和ECM功能默认只启用了RNDIS。如需测试ECM功能,请修改main.lua文件,注释掉`require "open_rndis"`并取消注释`require "open_ecm"`
+
+## 演示硬件环境
+
+1、Air780Exx 系列模组核心板/开发板一块
+
+2、配套天线一套
+
+3、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air780Exx 系列模组 版本固件](https://docs.openluat.com/air780Exx 系列模组/luatos/firmware/)(V2013以下固件使用mobile.config()的返回值有bug,需要烧录V2013及以上固件才能完整验证此demo)
+
+3、确保插入的sim卡可以正常上网。
+
+## 演示核心步骤
+
+### RNDIS功能测试步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中(默认启用RNDIS功能)
+
+3、烧录好后,板子开机同时在luatools上查看日志,确认是否进入飞行模式、RNDIS是否启用成功。
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开RNDIS模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 RNDIS 是否启动成功: true
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、日志提示成功后,可以在**Windows** → **设备管理器** → **网络适配器** 中查看是否有 **“Remote NDIS based Internet Sharing Device”** 来确认 RNDIS是否开启成功,如果被禁用请手动开启。
+
+### ECM功能测试说明
+
+1、**修改配置**:在测试ECM功能前,需要修改main.lua文件,注释掉`require = "open_rndis"`并取消注释`require = "open_ecm"`
+
+2、**烧录程序**:通过Luatools将修改后的demo与固件烧录到核心板中
+
+3、**查看日志**:板子开机后在luatools上查看日志,确认是否进入飞行模式、ECM是否尝试启动
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开ECM模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 ECM 是否启动成功: [结果]
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、**特别说明**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。即使日志显示ECM启动成功,也无法在Windows系统上验证网络连接状态。ECM功能主要适用于Linux、macOS等操作系统。

+ 2 - 2
module/Air780EHM_Air780EHV_Air780EGH/demo/socket/client/long_connection/netdrv_device.lua

@@ -20,11 +20,11 @@
 -- 根据自己的项目需求,只需要require以下四种中的一种即可;
 
 -- 加载“4G网卡”驱动模块
-require "netdrv_4g"
+-- require "netdrv_4g"
 
 
 -- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
 -- require "netdrv_eth_spi"
 
 -- 加载“可以配置优先级的多种网卡”驱动模块
--- require "netdrv_multiple"
+require "netdrv_multiple"

+ 0 - 142
module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP-UART/main.lua

@@ -1,142 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 43919                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-              local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-               if len <= 0 then    -- 接收到的字节长度为0 则退出
-                   break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                   sys_send(taskName, socket.EVENT, 0)
-                end
-                break
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 145
module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP单向认证/main.lua

@@ -1,145 +0,0 @@
--- main.lua文件
-
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46428            -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = true                     -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 141
module/Air780EHM_Air780EHV_Air780EGH/demo/tcp/TCP断链续连/main.lua

@@ -1,141 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46244                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 130
module/Air780EHM_Air780EHV_Air780EGH/demo/udp/main.lua

@@ -1,130 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "scdemo"
-VERSION = "1.0.0"
-log.info("main", PROJECT, VERSION)
--- 一定要添加sys.lua !!!!
-sys = require("sys")
-_G.sysplus = require("sysplus")
-local taskName = "UDP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-----------------------------网络配置---------------------------
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接UDP服务器的ip地址
-local port = 46139                      -- 连接UDP服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = true                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)     -- 发送至UDP服务器的数据
-local rx_buff = zbuff.create(1024)     -- 从UDP服务器接收到的数据
---==============================================================
---Uart初始化  
-local uartid = 1 -- 根据实际设备选取不同的uartid
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-function UDP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    -- 串口和UDP服务器的交互逻辑
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl) -- 此配置为UDP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        local result = libnet.connect(taskName, 15000, socket_client, ip, port)
-        -----查询网络状态
-        local status = mobile.status()    
-        log.info("status", status) 
-        
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        log.info("connect ip: 等待连接 ",result)
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            log.info("connect ip: 连接成功")
-            connect_state = true
-           libnet.tx(taskName, 0, socket_client, "UDP CONNECT")
-        end
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-               uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给UDP待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(taskName, 5000, socket_client)
-        socket.release(netc)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-end
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(UDP_TASK, taskName, tcp_client_main_cbfunc)
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 4 - 3
module/Air780EPM/demo/lowpower/lowpower_dissipation.lua

@@ -1,14 +1,14 @@
 
 -- netlab.luatos.com上打开TCP 有测试服务器
 local server_ip = "112.125.89.8"
-local server_port = 47523
+local server_port = 43667
 local is_udp = false --用户根据自己实际情况选择
 
 --是UDP服务器就赋值为true,是TCP服务器就赋值为flase
 --UDP服务器比TCP服务器功耗低
 --如果用户对数据的丢包率有极为苛刻的要求,最好选择TCP
 
-local Heartbeat_interval = 5 -- 发送数据的间隔时间,单位分钟
+local Heartbeat_interval = 1 -- 发送数据的间隔时间,单位分钟
 
 -- 数据内容  
 local heart_data = string.rep("1234567890", 10)
@@ -79,8 +79,9 @@ function socketDemo()
      --进入低功耗长连接模式
     pm.power(pm.WORK_MODE, 1)
 
+    -- pm.dtimerStart(0, 120 * 1000)
     sys.taskInit(socketTask)
-
+    pm.dtimerStart(0, 120 * 1000)
 end
 
 sys.taskInit(socketDemo)

+ 2 - 2
module/Air780EPM/demo/lowpower/main.lua

@@ -8,8 +8,8 @@ _G.sysplus = require("sysplus")
 log.style(1)
 
 -- require "normal" --正常模式
--- require "lowpower_dissipation" --低功耗模式
-require "ultra_low_power" --超低功耗模式(PSM+模式)
+require "lowpower_dissipation" --低功耗模式
+-- require "ultra_low_power" --超低功耗模式(PSM+模式)
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句

+ 15 - 11
module/Air780EPM/demo/pwm/示例1 PWM输出/main.lua

@@ -15,19 +15,23 @@ if wdt then
 end
 
 sys.taskInit(function()
-    while true do
-        -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为10/1000=1% 持续输出
-        pwm.open(4, 1000, 10, 0, 1000) -- 小灯微微发光
-        sys.wait(1000)
-        -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为500/1000=50% 持续输出
-        pwm.open(4, 1000, 500, 0, 1000) -- 小灯中等亮度
-        sys.wait(1000)
-        -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为1000/1000=100% 持续输出
-        pwm.open(4, 1000, 1000, 0, 1000) -- 小灯很高亮度
-        sys.wait(1000)
-    end
+    gpio.setup(27,1)
 end)
 
+-- sys.taskInit(function()
+--     while true do
+--         -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为10/1000=1% 持续输出
+--         pwm.open(4, 1000, 10, 0, 1000) -- 小灯微微发光
+--         sys.wait(1000)
+--         -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为500/1000=50% 持续输出
+--         pwm.open(4, 1000, 500, 0, 1000) -- 小灯中等亮度
+--         sys.wait(1000)
+--         -- 开启pwm通道4,设置脉冲频率为1kHz,分频精度为1000,占空比为1000/1000=100% 持续输出
+--         pwm.open(4, 1000, 1000, 0, 1000) -- 小灯很高亮度
+--         sys.wait(1000)
+--     end
+-- end)
+
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()

+ 71 - 0
module/Air780EPM/demo/rndis_ecm/main.lua

@@ -0,0 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+演示功能概述
+RNDIS是指Remote NDIS,基于USB实现RNDIS实际上就是TCP/IP over USB,就是在USB设备上跑TCP/IP,让USB设备看上去像一块网卡。从而使Windows /Linux可以通过 USB 设备连接网络。
+ECM(Ethernet Control Model)是一种基于 USB 的通信设备类(CDC)子类协议,它将 “TCP/IP over USB” 抽象成一条虚拟以太网链路:USB 设备端实现 ECM 功能后,会在主机侧呈现为一块标准的以太网卡(如 usb0)。主机操作系统(Linux、macOS 等)无需额外专用驱动,即可通过该虚拟网卡发送/接收以太网帧,从而经 USB 设备连接到网络。
+1、功能使用说明
+由于 Air780EPM 只支持 LUATOS 模式,且 RNDIS 网卡应用默认关闭,所以在使用 RNIDS 之前,需要使用接口打开,本demo将为大家讲解如何使用 RNIDS 功能。
+本demo仅演示在 Windows系统上运行 RNDIS 功能,如果需要在 Linux系统上使用功能,请查看文档:xxxxxxxxx
+2、ECM 功能说明
+由于Windows系统没有测试环境无法测试 ECM 功能,所以 open_ecm.lua 没有完整测试。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+更多说明参考本目录下的readme.md文件
+]]
+PROJECT = "RNDIS_ECM"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- 加载 open_rndis 主应用功能模块
+require "open_rndis"
+
+-- 加载 open_ecm 主应用功能模块
+-- require "open_ecm"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 41 - 0
module/Air780EPM/demo/rndis_ecm/open_ecm.lua

@@ -0,0 +1,41 @@
+--[[
+@module  open_ecm
+@summary ecm 服务启动功能模块
+@version 1.0
+@date    2025.08.26
+@author  拓毅恒
+@usage
+用法实例
+
+启动 ECM 服务
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+注:由于Windows系统没有测试环境无法测试 ECM 功能,所以本demo没有完整测试。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_ecm" 即可加载运行。
+]]
+
+-- 运行 ECM 模式任务
+local function ecm_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开ECM模式")
+        -- 调用 mobile.config 函数启用 ECM 功能
+        -- 传入的第二个参数 7 ,实际为二进制的 0111
+        -- 蜂窝网络模块的usb以太网卡控制,bit0开关,1开0关,bit1模式,1NAT0独立IP(在usb以太网卡开启前可以修改,开启过就不行),bit2协议1 ECM,0 RNDIS,飞行模式里设置。
+        log.info("我看看 ECM 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 7))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 ecm_task 函数
+sys.taskInit(ecm_task)

+ 39 - 0
module/Air780EPM/demo/rndis_ecm/open_rndis.lua

@@ -0,0 +1,39 @@
+--[[
+@module  open_rndis
+@summary rndis 服务启动功能模块
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+用法实例
+
+启动 RNDIS 服务
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_rndis" 即可加载运行。
+]]
+
+-- 运行 RNDIS 模式任务
+local function rndis_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开RNDIS模式")
+        -- 调用 mobile.config 函数启用 RNDIS 功能
+        log.info("我看看 RNDIS 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 3))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 rndis_task 函数
+sys.taskInit(rndis_task)

+ 112 - 0
module/Air780EPM/demo/rndis_ecm/readme.md

@@ -0,0 +1,112 @@
+## 演示功能概述
+
+本demo支持两种基于USB的网络连接模式:RNDIS和ECM。
+
+- **RNDIS**(Remote NDIS):基于USB实现的TCP/IP over USB,让USB设备在Windows系统上呈现为一块网卡,从而使Windows/Linux可以通过USB设备连接网络。
+
+- **ECM**(Ethernet Control Model):一种基于USB的通信设备类(CDC)子类协议,将"TCP/IP over USB"抽象成一条虚拟以太网链路,在主机侧呈现为一块标准的以太网卡。Linux、macOS等操作系统无需额外专用驱动即可使用。
+
+#### 1、功能使用说明
+
+本demo已将功能拆分为三个文件:
+- `main.lua`:主入口文件,负责加载和调度各个功能模块
+- `open_rndis.lua`:RNDIS功能实现模块
+- `open_ecm.lua`:ECM功能实现模块
+
+由于 Air780EPM 只支持 LUATOS 模式,且RNDIS/ECM网卡应用默认关闭,需要使用接口打开。
+
+**注意:**
+- 本demo在Windows系统上主要测试RNDIS功能
+- ECM功能由于Windows系统缺少测试环境,无法在Windows上完整测试
+
+#### 2、启动 RNDIS 服务
+
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 3)
+传入的第二个参数 3 ,实际为二进制的 0011
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为0,则开启RNDIS模式。
+
+#### 3、启动 ECM 服务
+
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 7)
+传入的第二个参数 7 ,实际为二进制的 0111
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为1,则开启ECM模式。
+
+> 特别说明:由于Windows系统缺少测试环境,ECM功能无法在Windows系统上完整测试。在Linux、macOS等系统上可能需要不同的配置和测试方法。
+>
+>注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+#### 4、运行效果
+
+- **飞行模式进入成功**:日志打印 “进入飞行模式成功”
+
+- **RNDIS 创建成功**:日志中会打印“我看看 RNDIS 是否启动成功: true”,并且在电脑网络上显示出RNDIS联网图标。
+
+- **ECM 创建**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。在日志中会打印“我看看 ECM 是否启动成功: [结果]”,但无法在Windows系统上验证网络连接状态。
+
+> **注意**:在main.lua中,RNDIS和ECM功能默认只启用了RNDIS。如需测试ECM功能,请修改main.lua文件,注释掉`require "open_rndis"`并取消注释`require "open_ecm"`
+
+## 演示硬件环境
+
+1、Air780EPM核心板/开发板一块
+
+2、配套天线一套
+
+3、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air780EPM 版本固件](https://docs.openluat.com/air780EPM/luatos/firmware/)(V2013以下固件使用mobile.config()的返回值有bug,需要烧录V2013及以上固件才能完整验证此demo)
+
+3、确保插入的sim卡可以正常上网。
+
+## 演示核心步骤
+
+### RNDIS功能测试步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中(默认启用RNDIS功能)
+
+3、烧录好后,板子开机同时在luatools上查看日志,确认是否进入飞行模式、RNDIS是否启用成功。
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开RNDIS模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 RNDIS 是否启动成功: true
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、日志提示成功后,可以在**Windows** → **设备管理器** → **网络适配器** 中查看是否有 **“Remote NDIS based Internet Sharing Device”** 来确认 RNDIS是否开启成功,如果被禁用请手动开启。
+
+### ECM功能测试说明
+
+1、**修改配置**:在测试ECM功能前,需要修改main.lua文件,注释掉`require = "open_rndis"`并取消注释`require = "open_ecm"`
+
+2、**烧录程序**:通过Luatools将修改后的demo与固件烧录到核心板中
+
+3、**查看日志**:板子开机后在luatools上查看日志,确认是否进入飞行模式、ECM是否尝试启动
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开ECM模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 ECM 是否启动成功: [结果]
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、**特别说明**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。即使日志显示ECM启动成功,也无法在Windows系统上验证网络连接状态。ECM功能主要适用于Linux、macOS等操作系统。

+ 2 - 2
module/Air780EPM/demo/socket/client/long_connection/netdrv_device.lua

@@ -20,11 +20,11 @@
 -- 根据自己的项目需求,只需要require以下四种中的一种即可;
 
 -- 加载“4G网卡”驱动模块
-require "netdrv_4g"
+-- require "netdrv_4g"
 
 
 -- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
 -- require "netdrv_eth_spi"
 
 -- 加载“可以配置优先级的多种网卡”驱动模块
--- require "netdrv_multiple"
+require "netdrv_multiple"

+ 0 - 142
module/Air780EPM/demo/tcp/TCP-UART/main.lua

@@ -1,142 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 44451                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-              local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-               if len <= 0 then    -- 接收到的字节长度为0 则退出
-                   break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                   sys_send(taskName, socket.EVENT, 0)
-                end
-                break
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 145
module/Air780EPM/demo/tcp/TCP单向认证/main.lua

@@ -1,145 +0,0 @@
--- main.lua文件
-
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46428            -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = true                     -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 141
module/Air780EPM/demo/tcp/TCP断链续连/main.lua

@@ -1,141 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46244                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 130
module/Air780EPM/demo/udp/main.lua

@@ -1,130 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "scdemo"
-VERSION = "1.0.0"
-log.info("main", PROJECT, VERSION)
--- 一定要添加sys.lua !!!!
-sys = require("sys")
-_G.sysplus = require("sysplus")
-local taskName = "UDP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-----------------------------网络配置---------------------------
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接UDP服务器的ip地址
-local port = 42335                      -- 连接UDP服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = true                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)     -- 发送至UDP服务器的数据
-local rx_buff = zbuff.create(1024)     -- 从UDP服务器接收到的数据
---==============================================================
---Uart初始化  
-local uartid = 1 -- 根据实际设备选取不同的uartid
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-function UDP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    -- 串口和UDP服务器的交互逻辑
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl) -- 此配置为UDP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        local result = libnet.connect(taskName, 15000, socket_client, ip, port)
-        -----查询网络状态
-        local status = mobile.status()    
-        log.info("status", status) 
-        
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        log.info("connect ip: 等待连接 ",result)
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            log.info("connect ip: 连接成功")
-            connect_state = true
-           libnet.tx(taskName, 0, socket_client, "UDP CONNECT")
-        end
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-               uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给UDP待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(taskName, 5000, socket_client)
-        socket.release(netc)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-end
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(UDP_TASK, taskName, tcp_client_main_cbfunc)
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 46
module/Air8000/demo/luatos_framework/luatos_task/create.lua

@@ -1,46 +0,0 @@
---[[
-@module  create
-@summary task调度演示 
-@version 1.0
-@date    2025.08.12
-@author  朱天华
-@usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2;
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
-
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
-]]
-
-local count = 0
-
--- led task的任务处理函数
-local function led_task_func()
-    while true do
-        log.info("led_task_func")
-
-        -- 等待500ms
-        -- sys.wait(500)
-
-        sys.waitUntil("INVALID_MESSAGE")
-
-        -- log.info("during led task, mem.lua", rtos.meminfo())
-        -- log.info("before led task, mem.sys", rtos.meminfo("sys"))
-    end
-end
-
-log.info("before led task, mem.lua", rtos.meminfo())
-log.info("before led task, mem.sys", rtos.meminfo("sys"))
-
--- 创建并启动第一个led task
--- 运行这个task的任务处理函数led_task_func
-while true do
-    sys.taskInit(led_task_func)
-    count = count+1
-    log.info("create task count", count)
-end
-
-log.info("after led task, mem.lua", rtos.meminfo())
-log.info("before led task, mem.sys", rtos.meminfo("sys"))
-

+ 15 - 1
module/Air8000/demo/luatos_framework/luatos_task/global_msg_receiver1.lua

@@ -1,4 +1,18 @@
-
+--[[
+@module  global_msg_receiver1
+@summary “使用sys.subscribe和sys.unsubscribe接口实现用户全局消息订阅和取消订阅”功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为global_msg_receiver1应用功能模块;
+用来演示“使用sys.subscribe和sys.unsubscribe接口实现用户全局消息订阅和取消订阅”的功能,核心业务逻辑为:
+1、开机初始化时,订阅"SEND_DATA_REQ"全局消息的回调函数init_subscribe_cbfunc;
+2、开机后延时5秒,订阅"SEND_DATA_REQ"全局消息的回调函数delay_subscribe_cbfunc;
+3、开机10秒后,取消订阅"SEND_DATA_REQ"全局消息的以上两个回调函数;
+
+本文件没有对外接口,直接在main.lua中require "global_msg_receiver1"就可以加载运行;
+]]
 
 
 local function init_subscribe_cbfunc(tag, count)

+ 21 - 2
module/Air8000/demo/luatos_framework/luatos_task/global_msg_receiver2.lua

@@ -1,4 +1,17 @@
-
+--[[
+@module  global_msg_receiver2
+@summary “使用sys.waitUntil接口实现task内用户全局消息接收”功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为global_msg_receiver2应用功能模块;
+用来演示“使用sys.waitUntil接口实现task内用户全局消息接收”的功能,核心业务逻辑为:
+1、创建一个基础task,演示“使用sys.waitUntil接口实现task内用户全局消息接收”的正确方法;
+2、创建另一个基础task,演示“使用sys.waitUntil接口实现task内用户全局消息接收”的错误方法;
+
+本文件没有对外接口,直接在main.lua中require "global_msg_receiver2"就可以加载运行;
+]]
 
 
 local function success_wait_until_base_task_func()
@@ -15,6 +28,8 @@ end
 local function lost_wait_until_base_task_func()
     local result, tag, count
     while true do
+        -- 阻塞等待3秒钟
+        -- 在这段时间内,本task无法及时处理全局消息发送模块发布的"SEND_DATA_REQ"消息,会造成消息丢失
         sys.wait(3000)
         
         result, tag, count = sys.waitUntil("SEND_DATA_REQ")
@@ -24,7 +39,11 @@ local function lost_wait_until_base_task_func()
     end
 end
 
-
+-- 创建并且启动一个基础task
+-- 运行这个task的任务处理函数success_wait_until_base_task_func
 sys.taskInit(success_wait_until_base_task_func)
+
+-- 创建并且启动一个基础task
+-- 运行这个task的任务处理函数lost_wait_until_base_task_func
 sys.taskInit(lost_wait_until_base_task_func)
 

+ 14 - 0
module/Air8000/demo/luatos_framework/luatos_task/global_msg_sender.lua

@@ -1,4 +1,16 @@
+--[[
+@module  global_msg_sender
+@summary “用户全局消息发送”演示功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为global_msg_sender应用功能模块,用来演示“用户全局消息发送”功能,核心业务逻辑为:
+1、创建并且启动一个基础task,每隔一秒钟发布一条全局消息;
+2、创建并且启动一个循环定时器,每隔一秒钟发布一条全局消息;
 
+本文件没有对外接口,直接在main.lua中require "global_msg_sender"就可以加载运行;
+]]
 
 
 local function global_sender_msg_task_func()
@@ -38,6 +50,8 @@ end
 -- 运行这个task的任务处理函数global_sender_msg_task_func
 sys.taskInit(global_sender_msg_task_func)
 
+-- 首先执行定时器的处理函数发布一条全局消息
 global_sender_msg_timer_cbfunc()
+-- 创建并且启动一个超时时长为1秒钟的循环定时器
 sys.timerLoopStart(global_sender_msg_timer_cbfunc, 1000)
 

+ 6 - 8
module/Air8000/demo/luatos_framework/luatos_task/main.lua

@@ -6,7 +6,8 @@
 @author  朱天华
 @usage
 本demo演示的核心功能为:
-每隔一秒钟通过日志输出一次Hello, LuatOS
+基于sys核心库提供的api,演示LuatOS框架(task,msg,timer,调度器)如何使用
+
 更多说明参考本目录下的readme.md文件
 ]]
 
@@ -63,15 +64,12 @@ end
 -- end, 3000)
 
 -- 加载“task调度”演示功能模块
--- require "scheduling"
+require "scheduling"
 
 -- 加载“task访问共享资源”演示功能模块
 -- require "shared_resource"
 
--- 加载“task创建”演示功能模块
--- require "create"
-
--- 加载“用户可用ram信息”演示功能模块
+-- 加载“查看用户可用ram信息”演示功能模块
 -- require "memory_valid"
 
 -- 加载“单个task占用的ram资源”演示功能模块
@@ -80,7 +78,7 @@ end
 -- 加载“创建task的数量”演示功能模块
 -- require "task_count"
 
--- 加载“task_func参数”演示功能模块
+-- 加载“task任务处理函数”演示功能模块
 -- require "task_func"
 
 -- 加载“task创建时的可变参数”演示功能模块
@@ -102,7 +100,7 @@ end
 -- require "timer"
 
 -- 加载“task内外部运行环境典型错误”演示功能模块
-require "task_inout_env_err"
+-- require "task_inout_env_err"
 
 
 -- 用户代码已结束---------------------------------------------

+ 9 - 7
module/Air8000/demo/luatos_framework/luatos_task/memory_task.lua

@@ -1,16 +1,16 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  memory_task
+@summary “单个task占用的ram资源”演示功能模块 
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值
+本文件为memory_task应用功能模块,用来演示“单个task占用的ram资源”,核心业务逻辑为:
+1、在创建一个task前,打印下当前的ram信息
+2、创建并且启动一个task
+3、在创建并且启动这个task后,打印下当前的ram信息
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "memory_task"就可以加载运行;
 ]]
 
 local function print_mem_info()
@@ -41,6 +41,7 @@ local function led_task_func()
 end
 
 log.info("before led task")
+-- 在创建一个task之前,打印下当前的ram信息
 print_mem_info()
 
 -- 创建并启动一个led task
@@ -48,5 +49,6 @@ print_mem_info()
 sys.taskInit(led_task_func)
 
 log.info("after led task")
+-- 在创建一个task之后,打印下当前的ram信息
 print_mem_info()
 

+ 12 - 7
module/Air8000/demo/luatos_framework/luatos_task/memory_valid.lua

@@ -1,16 +1,15 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  memory_valid
+@summary “查看用户可用ram信息”演示功能模块
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2;
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
+本文件为memory_valid应用功能模块,用来演示:如何查看用户可用ram信息,核心业务逻辑为:
+1、创建一个task;
+2、在task的任务处理函数中,每隔1秒查询一次当前的ram信息;
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "memory_valid"就可以加载运行;
 ]]
 
 
@@ -31,12 +30,18 @@ local function print_mem_info()
     log.info("mem.sys", rtos.meminfo("sys"))
 end
 
+
 local function mem_task_func()
     while true do
+        -- 打印当前的ram信息
         print_mem_info()
+
+        -- 延时1秒
         sys.wait(1000)
     end
 end
 
+-- 创建并启动一个task
+-- 运行这个task的任务处理函数mem_task_func
 sys.taskInit(mem_task_func)
 

+ 15 - 31
module/Air8000/demo/luatos_framework/luatos_task/non_targeted_msg.lua

@@ -1,21 +1,21 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  non_targeted_msg
+@summary “非目标消息回调函数”演示功能模块 
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值
+本文件为non_targeted_msg应用功能模块,用来演示“非目标消息回调函数”如何使用,核心业务逻辑为:
+1、创建一个高级task,task名称为"MQTT_CLINET_MAIN",task的非目标消息回调函数为mqtt_client_main_cbfunc
+2、创建一个基础task,每隔一秒向名称为"MQTT_CLINET_MAIN"的高级task发送一条非目标消息
+3、创建一个高级task,task名称为"SEND_MSG_TASK",每隔一秒向名称为"MQTT_CLINET_MAIN"的高级task发送一条目标消息
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "non_targeted_msg"就可以加载运行;
 ]]
 
 
--- tcp_client_main的任务名
-local TASK_NAME = "TCP_CLINET_MAIN"
+-- mqtt_client_main的任务名
+local TASK_NAME = "MQTT_CLINET_MAIN"
 
 
 -- 非目标消息回调函数
@@ -28,7 +28,7 @@ local function mqtt_client_main_task_func()
     -- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
     while true do
         -- 等待"MQTT_EVENT"消息
-        msg = sysplus.waitMsg(TASK_NAME, "MQTT_EVENT")
+        msg = sys.waitMsg(TASK_NAME, "MQTT_EVENT")
         log.info("mqtt_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
 
         -- connect连接结果
@@ -77,22 +77,6 @@ local function send_non_targeted_msg_task_func()
     end
 end
 
-local function send_non_targeted_msg_task_func()
-    local count = 0
-
-    while true do
-        count = count+1
-
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"UNKNOWN_EVENT"
-        -- 消息携带一个number类型的参数count
-        sysplus.sendMsg(TASK_NAME, "UNKNOWN_EVENT", count)
-
-        -- 延时等待1秒
-        sys.wait(1000)
-    end
-end
-
 
 local function send_targeted_msg_task_func()
     while true do
@@ -102,7 +86,7 @@ local function send_targeted_msg_task_func()
         -- 第一个参数为"CONNECT"
         -- 第二个参数为true
         -- 这条消息的意思是MQTT连接成功
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
+        sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
 
         -- 延时等待1秒
         sys.wait(1000)
@@ -114,7 +98,7 @@ local function send_targeted_msg_task_func()
         -- 第二个参数为true
         -- 第三个参数为0
         -- 这条消息的意思是MQTT订阅成功,qos为0
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", true, 0)
+        sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", true, 0)
 
         -- 延时等待1秒
         sys.wait(1000)
@@ -123,7 +107,7 @@ local function send_targeted_msg_task_func()
         -- 消息名称为"MQTT_EVENT"
         -- 消息携带一个参数"DISCONNECTED"
         -- 这条消息的意思是MQTT连接被动断开
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
+        sys.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
 
         -- 延时等待1秒
         sys.wait(1000)
@@ -135,7 +119,7 @@ end
 -- task的名称为TASK_NAME变量的值"MQTT_CLINET_MAIN"
 -- task的非目标消息回调函数为mqtt_client_main_cbfunc
 -- 运行这个task的任务处理函数mqtt_client_main_task_func
-sysplus.taskInitEx(mqtt_client_main_task_func, TASK_NAME, mqtt_client_main_cbfunc)
+sys.taskInitEx(mqtt_client_main_task_func, TASK_NAME, mqtt_client_main_cbfunc)
 
 
 -- 创建并且启动一个基础task
@@ -146,4 +130,4 @@ sys.taskInit(send_non_targeted_msg_task_func)
 -- task的任务处理函数为send_targeted_msg_task_func
 -- task的名称为SEND_TASK_NAME
 -- 运行这个task的任务处理函数send_targeted_msg_task_func
-sysplus.taskInitEx(send_targeted_msg_task_func, "SEND_MSG_TASK")
+sys.taskInitEx(send_targeted_msg_task_func, "SEND_MSG_TASK")

+ 98 - 10
module/Air8000/demo/luatos_framework/luatos_task/readme.md

@@ -1,9 +1,17 @@
 
 ## 演示功能概述
 
-1、创建一个task;
+演示LuatOS运行框架如何使用,包括:
 
-2、在task中的任务处理函数中,每隔一秒钟通过日志输出一次Hello, LuatOS;
+1、LuatOS task如何使用;
+
+2、LuatOS msg如何使用;
+
+3、LuatOS timer如何使用;
+
+4、LuatOS 调度器如何使用;
+
+5、以上四项功能全部基于sys核心库提供的api才能正常运行,所以本demo本质是在演示sys核心库提供的所有api如何使用;
 
 
 ## 演示硬件环境
@@ -30,18 +38,98 @@
 
 1、搭建好硬件环境
 
-2、Luatools烧录内核固件和demo脚本代码
+2、在main.lua中按需启动如下某一段代码,单独演示某一项功能,这样分析起来比较清晰
+
+``` lua
+-- 加载“task调度”演示功能模块
+-- require "scheduling"
+
+-- 加载“task访问共享资源”演示功能模块
+-- require "shared_resource"
+
+-- 加载“查看用户可用ram信息”演示功能模块
+-- require "memory_valid"
+
+-- 加载“单个task占用的ram资源”演示功能模块
+-- require "memory_task"
+
+-- 加载“创建task的数量”演示功能模块
+-- require "task_count"
+
+-- 加载“task任务处理函数”演示功能模块
+-- require "task_func"
+
+-- 加载“task创建时的可变参数”演示功能模块
+-- require "variable_args"
+
+-- 加载“非目标消息回调函数”演示功能模块
+-- require "non_targeted_msg"
+
+-- 加载“用户全局消息处理”演示功能模块
+-- require "global_msg_receiver1"
+-- require "global_msg_receiver2"
+-- require "global_msg_sender"
+
+-- 加载“用户定向消息处理”演示功能模块
+-- require "tgted_msg_receiver"
+-- require "targeted_msg_sender"
+
+-- 加载“定时器”演示功能模块
+-- require "timer"
+
+-- 加载“task内外部运行环境典型错误”演示功能模块
+-- require "task_inout_env_err"
+```
+
+2、Luatools烧录内核固件和修改main.lua后的demo脚本代码
 
 3、烧录成功后,自动开机运行
 
-4、出现类似于下面的日志,每隔1秒输出1次Hello, LuatOS,就表示运行成功:
+4、在main.lua中打开不同的演示功能模块,对应在Luatools的日志窗口会出现不同的日志信息,例如
 
 ``` lua
-[2025-07-19 23:19:04.944][000000015.256] I/user.Hello, LuatOS
-[2025-07-19 23:19:05.954][000000016.256] I/user.Hello, LuatOS
-[2025-07-19 23:19:06.956][000000017.256] I/user.Hello, LuatOS
-[2025-07-19 23:19:07.947][000000018.256] I/user.Hello, LuatOS
-[2025-07-19 23:19:08.955][000000019.256] I/user.Hello, LuatOS
-[2025-07-19 23:19:09.944][000000020.256] I/user.Hello, LuatOS
+如果在main.lua中开启以下代码
+-- 加载“task调度”演示功能模块
+require "scheduling"
+
+则日志信息如下:
+[2025-08-28 12:04:33.469][00000000.228] I/user.task1_func 运行中,计数: 1
+[2025-08-28 12:04:33.469][00000000.228] I/user.task_scheduling after task1 and before task2
+[2025-08-28 12:04:33.469][00000000.228] I/user.task2_func 运行中,计数: 1
+[2025-08-28 12:04:33.554][00000000.313] I/user.task2_func 运行中,计数: 2
+[2025-08-28 12:04:33.748][00000000.507] I/user.task1_func 运行中,计数: 2
+[2025-08-28 12:04:33.865][00000000.624] I/user.task2_func 运行中,计数: 3
+[2025-08-28 12:04:34.179][00000000.938] I/user.task2_func 运行中,计数: 4
+[2025-08-28 12:04:34.254][00000001.013] I/user.task1_func 运行中,计数: 3
+[2025-08-28 12:04:34.494][00000001.253] I/user.task2_func 运行中,计数: 5
+[2025-08-28 12:04:34.763][00000001.522] I/user.task1_func 运行中,计数: 4
+[2025-08-28 12:04:34.808][00000001.567] I/user.task2_func 运行中,计数: 6
+[2025-08-28 12:04:35.121][00000001.880] I/user.task2_func 运行中,计数: 7
+[2025-08-28 12:04:35.274][00000002.033] I/user.task1_func 运行中,计数: 5
+[2025-08-28 12:04:35.436][00000002.196] I/user.task2_func 运行中,计数: 8
+[2025-08-28 12:04:35.739][00000002.499] I/user.task2_func 运行中,计数: 9
+[2025-08-28 12:04:35.783][00000002.542] I/user.task1_func 运行中,计数: 6
+[2025-08-28 12:04:36.046][00000002.806] I/user.task2_func 运行中,计数: 10
+[2025-08-28 12:04:36.285][00000003.045] I/user.task1_func 运行中,计数: 7
+[2025-08-28 12:04:36.357][00000003.116] I/user.task2_func 运行中,计数: 11
+[2025-08-28 12:04:36.661][00000003.420] I/user.task2_func 运行中,计数: 12
+[2025-08-28 12:04:36.797][00000003.556] I/user.task1_func 运行中,计数: 8
+[2025-08-28 12:04:36.960][00000003.719] I/user.task2_func 运行中,计数: 13
+[2025-08-28 12:04:37.275][00000004.034] I/user.task2_func 运行中,计数: 14
+[2025-08-28 12:04:37.305][00000004.064] I/user.task1_func 运行中,计数: 9
+[2025-08-28 12:04:37.579][00000004.338] I/user.task2_func 运行中,计数: 15
+[2025-08-28 12:04:37.818][00000004.577] I/user.task1_func 运行中,计数: 10
+[2025-08-28 12:04:37.889][00000004.648] I/user.task2_func 运行中,计数: 16
+[2025-08-28 12:04:38.199][00000004.958] I/user.task2_func 运行中,计数: 17
+[2025-08-28 12:04:38.325][00000005.084] I/user.task1_func 运行中,计数: 11
+[2025-08-28 12:04:38.500][00000005.259] I/user.task2_func 运行中,计数: 18
+[2025-08-28 12:04:38.812][00000005.571] I/user.task2_func 运行中,计数: 19
+[2025-08-28 12:04:38.825][00000005.584] I/user.task1_func 运行中,计数: 12
+[2025-08-28 12:04:39.113][00000005.872] I/user.task2_func 运行中,计数: 20
+[2025-08-28 12:04:39.333][00000006.092] I/user.task1_func 运行中,计数: 13
+[2025-08-28 12:04:39.414][00000006.173] I/user.task2_func 运行中,计数: 21
+[2025-08-28 12:04:39.717][00000006.476] I/user.task2_func 运行中,计数: 22
+[2025-08-28 12:04:39.835][00000006.594] I/user.task1_func 运行中,计数: 14
+[2025-08-28 12:04:40.020][00000006.779] I/user.task2_func 运行中,计数: 23
 
 ```

+ 3 - 2
module/Air8000/demo/luatos_framework/luatos_task/scheduling.lua

@@ -5,12 +5,13 @@
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
+本文件为scheduling应用功能模块,用来演示task协作式的调度方式,核心业务逻辑为:
 1、创建两个task,task1和task2;
 2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
 3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
 
-本文件没有对外接口,直接在main.lua中require "task_scheduling"就可以加载运行;
+
+本文件没有对外接口,直接在main.lua中require "scheduling"就可以加载运行;
 ]]
 
 

+ 1 - 1
module/Air8000/demo/luatos_framework/luatos_task/shared_resource.lua

@@ -5,7 +5,7 @@
 @date    2025.08.15
 @author  朱天华
 @usage
-本文件为shared_resource应用功能模块,用来演示多个task访问共享资源,核心业务逻辑为:
+本文件为shared_resource应用功能模块,用来演示多个task访问共享资源的功能,核心业务逻辑为:
 1、创建一个全局共享变量global_shared_variable,变量值初始化为0;
 2、创建两个task,task1和task2;
 2、在task1的任务处理函数中:

+ 13 - 2
module/Air8000/demo/luatos_framework/luatos_task/targeted_msg_sender.lua

@@ -1,4 +1,15 @@
+--[[
+@module  targeted_msg_sender
+@summary “用户定向消息发送”演示功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为targeted_msg_sender应用功能模块,用来演示“用户定向消息发送”功能,核心业务逻辑为:
+1、创建并且启动一个基础task,每隔一秒钟向两个高级task发布各发送一条定向消息;
 
+本文件没有对外接口,直接在main.lua中require "targeted_msg_sender"就可以加载运行;
+]]
 
 
 local function targeted_msg_sender_task_func()
@@ -12,14 +23,14 @@ local function targeted_msg_sender_task_func()
         -- 消息携带两个参数:
         -- 第一个参数是"from task"
         -- 第二个参数是number类型的count
-        sysplus.sendMsg("nromal_wait_msg_task", "SEND_DATA_REQ", "from task", count)
+        sys.sendMsg("nromal_wait_msg_task", "SEND_DATA_REQ", "from task", count)
 
         -- 发布一条定向消息到名称为"delay_wait_msg_task"的高级task
         -- 消息名称为"SEND_DATA_REQ"
         -- 消息携带两个参数:
         -- 第一个参数是"from task"
         -- 第二个参数是number类型的count
-        sysplus.sendMsg("delay_wait_msg_task", "SEND_DATA_REQ", "from task", count)
+        sys.sendMsg("delay_wait_msg_task", "SEND_DATA_REQ", "from task", count)
 
         -- 延时等待1秒
         sys.wait(1000)

+ 9 - 10
module/Air8000/demo/luatos_framework/luatos_task/task_count.lua

@@ -1,21 +1,21 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  task_count
+@summary “创建task的数量”演示功能模块 
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2;
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
+本文件为task_count应用功能模块,用来演示“可以创建多少个task”,核心业务逻辑为:
+执行一个while true循环,每次执行到循环体内,执行以下两项动作:
+1、创建并且启动一个task,启动后,task处于阻塞状态,永远不会死亡
+2、task数量的计数器加一,并且打印当前已经创建的task总数量
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "task_count"就可以加载运行;
 ]]
 
 local count = 0
 
--- led task的任务处理函数
+-- task的任务处理函数
 local function led_task_func()
     while true do
         log.info("led_task_func")
@@ -23,8 +23,7 @@ local function led_task_func()
     end
 end
 
--- 创建并启动第一个led task
--- 运行这个task的任务处理函数led_task_func
+-- 不断地创建task,直到ram资源耗尽
 while true do
     sys.taskInit(led_task_func)
     count = count+1

+ 9 - 9
module/Air8000/demo/luatos_framework/luatos_task/task_func.lua

@@ -1,18 +1,20 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  task_func
+@summary “task任务处理函数”演示功能模块 
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2;
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
+本文件为task_func应用功能模块,用来演示“如何设置task任务处理函数”,核心业务逻辑为:
+1、创建一个task时,需要设置task任务处理函数;
+2、演示一种常见的错误设置方式;
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "task_func"就可以加载运行;
 ]]
 
+-- 创建并启动一个led task
+-- 运行这个task的任务处理函数led_task_func
+-- 此处运行会报错,因为执行到这行代码时,找不到led_task_func函数的定义,犯了“先使用,后定义”的错误
 sys.taskInit(led_task_func)
 
 
@@ -23,5 +25,3 @@ local function led_task_func()
     end
 end
 
-
-

+ 27 - 2
module/Air8000/demo/luatos_framework/luatos_task/task_inout_env_err.lua

@@ -1,7 +1,24 @@
+--[[
+@module  targeted_msg_sender
+@summary “task内和task外运行环境典型错误”演示功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为task_inout_env_err应用功能模块,用来演示“task内和task外运行环境典型错误”,核心业务逻辑为:
+演示“task内外运行环境使用不当”而出现的典型错误
+1、在用户全局消息订阅的回调函数中执行sys.wait接口;
+2、在单次定时器的回调函数中执行sys.waitUntil接口;
+3、在循环定时器的回调函数中执行sys.waitMsg接口;
+4、以上三种都是在task外的运行环境中执行“必须在task内运行”的接口,还有其他类似的使用错误,不再一一列举;
+
+本文件没有对外接口,直接在main.lua中require "task_inout_env_err"就可以加载运行;
+]]
 
 
 local function mqtt_event_cbfunc()
     log.info("mqtt_event_cbfunc")
+    -- 在用户全局消息订阅的回调函数中执行sys.wait接口,会报错
     sys.wait(1000)
 end
 
@@ -9,17 +26,25 @@ end
 -- sys.timerStart(sys.publish, 1000, "MQTT_EVENT")
 
 
+
+
+
 local function timer_cbfunc()
     log.info("timer_cbfunc")
+    -- 在单次定时器的回调函数中执行sys.waitUntil接口,会报错
     sys.waitUntil("UNKNOWN_MSG", 1000)
 end
 
 -- sys.timerStart(timer_cbfunc, 1000)
 
 
+
+
+
 local function loop_timer_cbfunc()
     log.info("loop_timer_cbfunc")
-    sysplus.waitMsg("SEND_MSG_TASK", "UNKNOWN_MSG", 1000)
+    -- 在循环定时器的回调函数中执行sys.waitMsg接口,会报错
+    sys.waitMsg("SEND_MSG_TASK", "UNKNOWN_MSG", 1000)
 end
 
 local function send_targeted_msg_task_func()
@@ -33,5 +58,5 @@ end
 -- task的任务处理函数为send_targeted_msg_task_func
 -- task的名称为SEND_TASK_NAME
 -- 运行这个task的任务处理函数send_targeted_msg_task_func
-sysplus.taskInitEx(send_targeted_msg_task_func, "SEND_MSG_TASK")
+sys.taskInitEx(send_targeted_msg_task_func, "SEND_MSG_TASK")
 sys.timerLoopStart(loop_timer_cbfunc, 1000)

+ 38 - 121
module/Air8000/demo/luatos_framework/luatos_task/tgted_msg_receiver.lua

@@ -1,131 +1,48 @@
-local TASK_NAME = "MQTT_CLINET_MAIN"
-
--- 非目标消息回调函数
-local function mqtt_client_main_cbfunc(msg)
-	log.info("mqtt_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
--- mqtt main task 的任务处理函数
-local function mqtt_client_main_task_func()
-    -- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
+--[[
+@module  tgted_msg_receiver
+@summary “使用sys.waitMsg接口实现task内用户定向消息接收”功能演示模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为tgted_msg_receiver应用功能模块;
+用来演示“使用sys.waitMsg接口实现task内用户定向消息接收”的功能,核心业务逻辑为:
+1、创建并且启动一个高级task,task名称为"nromal_wait_msg_task",在task的任务处理函数内及时接收发送给自己的定向消息;
+2、创建并且启动另一个高级task,task名称为"delay_wait_msg_task",在task的任务处理函数内延时接收发送给自己的定向消息;
+
+本文件没有对外接口,直接在main.lua中require "tgted_msg_receiver"就可以加载运行;
+]]
+
+local function normal_wait_msg_task_func()
+    local msg
     while true do
-        -- 等待"MQTT_EVENT"消息
-        msg = sysplus.waitMsg(TASK_NAME, "MQTT_EVENT")
-        log.info("mqtt_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
-
-        -- connect连接结果
-        -- msg[3]表示连接结果,true为连接成功,false为连接失败
-        if msg[2] == "CONNECT" then
-            -- mqtt连接成功
-            if msg[3] then
-                log.info("mqtt_client_main_task_func", "connect success")
-            -- mqtt连接失败
-            else
-                log.info("mqtt_client_main_task_func", "connect error")
-            end
-
-        -- subscribe订阅结果
-        -- msg[3]表示订阅结果,true为订阅成功,false为订阅失败
-        elseif msg[2] == "SUBSCRIBE" then
-            -- 订阅成功
-            if msg[3] then
-                log.info("mqtt_client_main_task_func", "subscribe success", "qos: "..(msg[4] or "nil"))
-            -- 订阅失败
-            else
-                log.error("mqtt_client_main_task_func", "subscribe error", "code", msg[4])
-            end
-
-        -- 被动关闭了mqtt连接
-        -- 被网络或者服务器断开了连接
-        elseif msg[2] == "DISCONNECTED" then
-            log.info("mqtt_client_main_task_func", "disconnected")
+        msg = sys.waitMsg("nromal_wait_msg_task", "SEND_DATA_REQ")
+        if msg then
+            log.info("normal_wait_msg_task_func", msg[1], msg[2], msg[3], msg[4])
         end
     end
 end
 
-local function send_non_targeted_msg_task_func()
-    local count = 0
-
+local function delay_wait_msg_task_func()
+    local msg
     while true do
-        count = count+1
-
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"UNKNOWN_EVENT"
-        -- 消息携带一个number类型的参数count
-        sys.sendMsg(TASK_NAME, "UNKNOWN_EVENT", count)
-
-        -- 延时等待1秒
-        sys.wait(1000)
-    end
-end
-
-local function send_non_targeted_msg_task_func()
-    local count = 0
-
-    while true do
-        count = count+1
-
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"UNKNOWN_EVENT"
-        -- 消息携带一个number类型的参数count
-        sysplus.sendMsg(TASK_NAME, "UNKNOWN_EVENT", count)
-
-        -- 延时等待1秒
-        sys.wait(1000)
-    end
-end
-
-
-local function send_targeted_msg_task_func()
-    while true do
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"MQTT_EVENT"
-        -- 消息携带两个参数
-        -- 第一个参数为"CONNECT"
-        -- 第二个参数为true
-        -- 这条消息的意思是MQTT连接成功
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-
-        -- 延时等待1秒
-        sys.wait(1000)
-
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"MQTT_EVENT"
-        -- 消息携带三个参数
-        -- 第一个参数为"SUBSCRIBE"
-        -- 第二个参数为true
-        -- 第三个参数为0
-        -- 这条消息的意思是MQTT订阅成功,qos为0
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", true, 0)
-
-        -- 延时等待1秒
-        sys.wait(1000)
-
-        -- 向TASK_NAME这个任务发送一条消息
-        -- 消息名称为"MQTT_EVENT"
-        -- 消息携带一个参数"DISCONNECTED"
-        -- 这条消息的意思是MQTT连接被动断开
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
-
-        -- 延时等待1秒
-        sys.wait(1000)
+        -- 阻塞等待3秒钟
+        -- 在这段时间内,本task无法及时处理定向消息发送模块发布的"SEND_DATA_REQ"消息
+        -- 但是不会造成消息丢失,消息会存储到本task绑定的定向消息队列中
+        -- 虽然不会造成消息丢失,但是业务逻辑中这样写明显也存在问题,因为消息处理的及时性很差
+        sys.wait(3000)
+        
+        msg = sys.waitMsg("delay_wait_msg_task", "SEND_DATA_REQ")
+        if msg then
+            log.info("delay_wait_msg_task_func", msg[1], msg[2], msg[3], msg[4])
+        end
     end
 end
 
--- 创建并且启动一个高级task
--- task的任务处理函数为mqtt_client_main_task_func
--- task的名称为TASK_NAME变量的值"MQTT_CLINET_MAIN"
--- task的非目标消息回调函数为mqtt_client_main_cbfunc
--- 运行这个task的任务处理函数mqtt_client_main_task_func
-sysplus.taskInitEx(mqtt_client_main_task_func, TASK_NAME, mqtt_client_main_cbfunc)
-
-
--- 创建并且启动一个基础task
--- 运行这个task的任务处理函数send_targeted_msg_task_func
-sys.taskInit(send_non_targeted_msg_task_func)
+-- 创建并且启动一个高级task,task名称为"nromal_wait_msg_task"
+-- 运行这个task的任务处理函数normal_wait_msg_task_func
+sys.taskInitEx(normal_wait_msg_task_func, "nromal_wait_msg_task")
 
--- 创建并且启动一个高级task
--- task的任务处理函数为send_targeted_msg_task_func
--- task的名称为SEND_TASK_NAME
--- 运行这个task的任务处理函数send_targeted_msg_task_func
-sysplus.taskInitEx(send_targeted_msg_task_func, "SEND_MSG_TASK")
+-- 创建并且启动一个高级task,task名称为"delay_wait_msg_task"
+-- 运行这个task的任务处理函数delay_wait_msg_task_func
+sys.taskInitEx(delay_wait_msg_task_func, "delay_wait_msg_task")

+ 34 - 1
module/Air8000/demo/luatos_framework/luatos_task/timer.lua

@@ -1,18 +1,41 @@
+--[[
+@module  timer
+@summary “定时器”演示功能模块
+@version 1.0
+@date    2025.08.12
+@author  朱天华
+@usage
+本文件为timer应用功能模块,用来演示“定时器”如何使用,核心业务逻辑为:
+1、演示单次定时器,循环定时器,task内的延时定时器的创建,启动,停止和删除功能;
 
+本文件没有对外接口,直接在main.lua中require "timer"就可以加载运行;
+]]
 
 
 local function timer_test_task_func()
+    -- 以下三行代码执行后,只有最后一个定时器存在
     sys.timerStart(log.info, 1000, "red")
     sys.timerStart(log.info, 2000, "red")
     sys.timerStart(log.info, 3000, "red")
 
+    -- 阻塞等待3秒钟,实际上创建了一个3秒钟超时时长的单次定时器
+    -- 超时时长到达后,会控制本task退出阻塞状态,继续运行
     sys.wait(3000)
 
+    -- 创建并且启动一个循环定时器,每隔1秒钟执行一次sys.publish("loop_timer_cbfunc_msg")
+    -- 相当于每隔1秒钟发布一条用户全局消息"loop_timer_cbfunc_msg"
     sys.timerLoopStart(sys.publish, 1000, "loop_timer_cbfunc_msg")
+
+    -- 创建并且启动一个单次定时器,5.5秒后执行sys.timerStop(sys.publish, "loop_timer_cbfunc_msg")
+    -- 相当于5.5秒后主动停止并且删除了上一行代码创建的循环定时器
     sys.timerStart(sys.timerStop, 5500, sys.publish, "loop_timer_cbfunc_msg")
 
     while true do
+        -- 阻塞等待用户全局消息"loop_timer_cbfunc_msg",超时时长为2秒钟
+        -- 5秒内,每秒都会收到一次消息;
+        -- 5秒后,不再收到消息,超时2秒退出阻塞状态;
         local result = sys.waitUntil("loop_timer_cbfunc_msg", 2000)
+        
         if result then
             log.info("receive loop_timer_cbfunc_msg")
         else
@@ -21,19 +44,29 @@ local function timer_test_task_func()
         end
     end
 
+    -- 以下五行代码执行后,创建并且启动了5个不同的定时器
     local timer_id = sys.timerStart(log.info, 1000, "1")
     sys.timerStart(log.info, 2000, "2")
     sys.timerStart(log.info, 3000, "3")
     sys.timerStart(log.info, 4000, "4")
     sys.timerStart(log.info, 5000, "5")
 
+    -- 根据定时器id停止并且删除刚才创建的5个定时器中的第一个定时器
     sys.timerStop(timer_id)
     
+    -- 阻塞等待2秒钟
     sys.wait(2000)
 
+    -- 运行到这里
+    -- 刚才创建的5个定时器中的后4个定时器:
+    -- sys.timerStart(log.info, 2000, "2"),这个定时器已经超时,并且自动停止和删除
+    -- 还剩下另外3个定时器处于运行状态,超时时长未到达
+    -- 执行下面这行代码后,可以将这3个定时器全部停止并且删除
     sys.timerStopAll(log.info)
 end
 
-
+-- 创建并且启动一个单次定时器,超时时长为3秒
+-- 3秒后执行sys.taskInit(timer_test_task_func)
+-- 相当于3秒后,创建并且启动一个基础task,然后执行这个task的任务处理函数timer_test_task_func
 sys.timerStart(sys.taskInit, 3000, timer_test_task_func)
 

+ 10 - 7
module/Air8000/demo/luatos_framework/luatos_task/variable_args.lua

@@ -1,16 +1,15 @@
 --[[
-@module  create
-@summary task调度演示 
+@module  variable_args
+@summary “task创建时的可变参数”演示功能模块 
 @version 1.0
 @date    2025.08.12
 @author  朱天华
 @usage
-本文件为task_scheduling应用功能模块,用来演示task调度,核心业务逻辑为:
-1、创建两个task,task1和task2;
-2、在task1的任务处理函数中,每隔500毫秒,task1的计数器加1,并且通过日志打印task1计数器的值;
-3、在task2的任务处理函数中,每隔300毫秒,task2的计数器加1,并且通过日志打印task2计数器的值;
+本文件为variable_args应用功能模块,用来演示“task创建时的可变参数”如何使用,核心业务逻辑为:
+1、创建一个task,可变参数部分携带5个参数;
+2、在task的任务处理函数中打印传入的5个参数的值;
 
-本文件没有对外接口,直接在main.lua中require "create"就可以加载运行;
+本文件没有对外接口,直接在main.lua中require "variable_args"就可以加载运行;
 ]]
 
 
@@ -21,4 +20,8 @@ local function led_task_func(arg1, arg2, arg3, arg4, arg5)
     end
 end
 
+-- 创建并启动一个task
+-- 这个task的任务处理函数为led_task_func
+-- 携带5个参数,分别为"arg1", 3, nil, true, led_task_func
+-- 运行这个task的任务处理函数led_task_func时,会将这5个参数传递给任务处理函数使用
 sys.taskInit(led_task_func, "arg1", 3, nil, true, led_task_func)

+ 0 - 103
module/Air8000/demo/mqttv2/main.lua

@@ -1,103 +0,0 @@
---[[
-@module  main
-@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
-@version 1.0
-@date    2025.07.28
-@author  朱天华
-@usage
-本demo演示的核心功能为:
-1、创建三路mqtt连接,详情如下
-- 创建一个mqtt client,连接mqtt server;
-- 创建一个mqtt ssl client,连接mqtt ssl server,不做证书校验;
-- 创建一个mqtt ssl client,连接mqtt ssl server,client仅单向校验server的证书,server不校验client的证书和密钥文件;
-2、每一路mqtt连接出现异常后,自动重连;
-3、每一路mqtt连接,client按照以下几种逻辑发送数据给server
-- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后,使用mobile.imei().."/uart/up"主题,发送给server;
-- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer:前缀后,使用mobile.imei().."/timer/up"主题,发送给server;
-4、每一路mqtt连接,client收到server数据后,将数据增加recv from mqtt/mqtt ssl/mqtt ssl ca(三选一)server: 前缀后,通过uart1发送出去;
-5、启动一个网络业务逻辑看门狗task,用来监控网络环境,如果连续长时间工作不正常,重启整个软件系统;
-6、netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
-   (1) netdrv_4g:4G网卡
-   (2) netdrv_wifi:WIFI STA网卡
-   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
-   (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
-
-更多说明参考本目录下的readme.md文件
-]]
-
-
---[[
-必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
-PROJECT:项目名,ascii string类型
-        可以随便定义,只要不使用,就行
-VERSION:项目版本号,ascii string类型
-        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
-            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
-            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
-        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
-]]
-PROJECT = "MQTT"
-VERSION = "001.000.000"
-
-
--- 在日志中打印项目名和项目版本号
-log.info("main", PROJECT, VERSION)
-
-
--- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
--- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
-if wdt then
-    --配置喂狗超时时间为9秒钟
-    wdt.init(9000)
-    --启动一个循环定时器,每隔3秒钟喂一次狗
-    sys.timerLoopStart(wdt.feed, 3000)
-end
-
-
--- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
--- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
--- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
--- 启动errDump日志存储并且上传功能,600秒上传一次
--- if errDump then
---     errDump.config(true, 600)
--- end
-
-
--- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
--- 可以使用合宙的iot.openluat.com平台进行远程升级
--- 也可以使用客户自己搭建的平台进行远程升级
--- 远程升级的详细用法,可以参考fota的demo进行使用
-
-
--- 启动一个循环定时器
--- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
--- 方便分析内存使用是否有异常
--- sys.timerLoopStart(function()
---     log.info("mem.lua", rtos.meminfo())
---     log.info("mem.sys", rtos.meminfo("sys"))
--- end, 3000)
-
--- 加载网络环境检测看门狗功能模块
-require "network_watchdog"
-
--- 加载网络驱动设备功能模块
-require "netdrv_device"
-
--- 加载串口应用功能模块
-require "uart_app"
--- 加载定时器应用功能模块
-require "timer_app"
-
--- 加载mqtt client 主应用功能模块
-require "mqtt_main"
-
--- 加载mqtt ssl client 主应用功能模块(目前还没有合适的服务器,等服务器搭建好之后再调试)
--- require "mqtts_main"
-
--- 加载mqtt ssl ca client 主应用功能模块(目前还没有合适的服务器,等服务器搭建好之后再调试)
--- require "mqtts_ca_main"
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 0 - 266
module/Air8000/demo/mqttv2/mqtt/mqtt_main.lua

@@ -1,266 +0,0 @@
---[[
-@module  mqtt_main
-@summary mqtt client 主应用功能模块 
-@version 1.0
-@date    2025.07.28
-@author  朱天华
-@usage
-本文件为mqtt client 主应用功能模块,核心业务逻辑为:
-1、创建一个mqtt client,连接server;
-2、处理连接/订阅/取消订阅/异常逻辑,出现异常后执行重连动作;
-3、调用mqtt_receiver的外部接口mqtt_receiver.proc,对接收到的publish数据进行处理;
-4、调用sysplus.sendMsg接口,发送"CONNECT OK"、"PUBLISH OK"和"DISCONNECTED"三种类型的"MQTT_EVENT"消息到mqtt_sender的task,控制publish数据发送逻辑;
-5、收到MQTT心跳应答后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗;
-
-本文件没有对外接口,直接在main.lua中require "mqtt_main"就可以加载运行;
-]]
-
-
--- 加载mqtt client数据接收功能模块
-local mqtt_receiver = require "mqtt_receiver"
--- 加载mqtt client数据发送功能模块
-local mqtt_sender = require "mqtt_sender"
-
--- mqtt服务器地址和端口
--- 这里使用的地址和端口,仅能用作测试用途,不可商用,说不定哪一天就关闭了
--- 用户开发项目时,替换为自己的商用服务器地址和端口
-local SERVER_ADDR = "lbsmqtt.airm2m.com"
-local SERVER_PORT = 1884
-
--- mqtt_main的任务名
-local TASK_NAME = mqtt_sender.TASK_NAME_PREFIX.."main"
-
--- mqtt主题的前缀:IMEI号
-local TOPIC_PREFIX = mobile.imei()
-
--- mqtt client的事件回调函数
-local function mqtt_client_event_cbfunc(mqtt_client, event, data, payload, metas)
-    log.info("mqtt_client_event_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-
-    -- mqtt连接成功
-    if event == "conack" then
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-        -- 订阅单主题
-        -- 第二个参数表示qos,取值范围为0,1,2,如果不设置,默认为0
-        if not mqtt_client:subscribe(TOPIC_PREFIX .. "/down") then
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        end
-        -- 订阅多主题,如果有需要,打开注释
-        -- 表中的每一个订阅主题的格式为[topic]=qos
-        -- if not mqtt_client:subscribe(
-        --         {
-        --             [(TOPIC_PREFIX .. "/data"]=0,
-        --             [(TOPIC_PREFIX .. "/cmd"]=1
-        --         }
-        -- ) then
-        --     sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        -- end
-
-    -- 订阅结果
-    -- data:订阅应答结果,true为成功,false为失败
-    -- payload:number类型;成功时表示qos,取值范围为0,1,2;失败时表示失败码,一般是0x80
-    elseif event == "suback" then
-        -- 发送消息通知 mqtt main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", data, payload)
-        
-    -- 取消订阅成功
-    elseif event == "unsuback" then
-        -- 发送消息通知 mqtt main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "UNSUBSCRIBE", true)
-
-    -- 接收到服务器下发的publish数据
-    -- data:string类型,表示topic
-    -- payload:string类型,表示payload
-    -- metas:table类型,数据内容如下
-    -- {
-    --     qos: number类型,取值范围0,1,2
-    --     retain:number类型,取值范围0,1
-    --     dup:number类型,取值范围0,1
-    --     message_id: number类型
-    -- }
-    elseif event == "recv" then
-        -- 对接收到的publish数据处理
-        mqtt_receiver.proc(data, payload, metas)
-
-    -- 发送成功publish数据
-    -- data:number类型,表示message id
-    elseif event == "sent" then
-        -- 发送消息通知 mqtt sender task
-        sysplus.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_OK", data)
-
-    -- 服务器断开mqtt连接
-    elseif event == "disconnect" then
-        -- 发送消息通知 mqtt main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED", false)
-
-    -- 收到服务器的心跳应答
-    elseif event == "pong" then
-        -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-        sys.publish("FEED_NETWORK_WATCHDOG") 
-	
-    -- 严重异常,本地会主动断开连接
-    -- data:string类型,表示具体的异常,有以下几种:
-    --       "connect":tcp连接失败
-    --       "tx":数据发送失败
-    --       "conack":mqtt connect后,服务器应答CONNACK鉴权失败,失败码为payload(number类型)
-    --       "other":其他异常
-    elseif event == "error" then
-        if data == "connect" or data == "conack" then
-            -- 发送消息通知 mqtt main task,连接失败
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", false)
-        elseif data == "other" or data == "tx" then
-            -- 发送消息通知 mqtt main task,出现异常
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "ERROR")
-        end
-    end
-end
-
--- mqtt main task 的任务处理函数
-local function mqtt_client_main_task_func() 
-
-    local mqtt_client
-    local result, msg, para
-
-    while true do
-        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
-        while not socket.adapter(socket.dft()) do
-            log.warn("mqtt_client_main_task_func", "wait IP_READY", socket.dft())
-            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-            -- 或者等待1秒超时退出阻塞等待状态;
-            -- 注意:此处的1000毫秒超时不要修改的更长;
-            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
-            sys.waitUntil("IP_READY", 1000)
-        end
-
-        -- 检测到了IP_READY消息
-        log.info("mqtt_client_main_task_func", "recv IP_READY", socket.dft())
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 创建mqtt client对象
-        mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT)
-        -- 如果创建mqtt client对象失败
-        if not mqtt_client then
-            log.error("mqtt_client_main_task_func", "mqtt.create error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 配置mqtt client对象的client id,username,password和clean session标志
-        result = mqtt_client:auth(mobile.imei(), "", "", true)
-        -- 如果配置失败
-        if not result then
-            log.error("mqtt_client_main_task_func", "mqtt_client:auth error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 注册mqtt client对象的事件回调函数
-        mqtt_client:on(mqtt_client_event_cbfunc)
-
-        -- 设置mqtt keepalive时间为120秒
-        -- 如果没有设置,内核固件中默认为180秒
-        -- 有需要的话,可以打开注释
-        -- mqtt_client:keepalive(120)
-
-        -- 设置遗嘱消息,有需要的话,可以打开注释
-        -- mqtt_client:will(TOPIC_PREFIX .. "/status", "offline")
-
-        -- 连接server
-        result = mqtt_client:connect()
-        -- 如果连接server失败
-        if not result then
-            log.error("mqtt_client_main_task_func", "mqtt_client:connect error")
-            goto EXCEPTION_PROC
-        end
-
-
-        -- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
-        while true do
-            -- 等待"MQTT_EVENT"消息
-            msg = sysplus.waitMsg(TASK_NAME, "MQTT_EVENT")
-            log.info("mqtt_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
-
-            -- connect连接结果
-            -- msg[3]表示连接结果,true为连接成功,false为连接失败
-            if msg[2] == "CONNECT" then                
-                -- mqtt连接成功
-                if msg[3] then
-                    log.info("mqtt_client_main_task_func", "connect success")
-                    -- 通知mqtt sender数据发送应用模块的task,MQTT连接成功
-                    sysplus.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "CONNECT_OK", mqtt_client)
-                -- mqtt连接失败
-                else
-                    log.info("mqtt_client_main_task_func", "connect error")
-                    -- 退出循环,发起重连
-                    break
-                end
-
-            -- subscribe订阅结果
-            -- msg[3]表示订阅结果,true为订阅成功,false为订阅失败
-            elseif msg[2] == "SUBSCRIBE" then
-                -- 订阅成功
-                if msg[3] then
-                    log.info("mqtt_client_main_task_func", "subscribe success", "qos: "..(msg[4] or "nil"))
-                -- 订阅失败
-                else
-                    log.error("mqtt_client_main_task_func", "subscribe error", "code", msg[4])
-                    -- 主动断开mqtt client连接
-                    mqtt_client:disconnect()
-                    -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                    -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                    sys.wait(1000)
-                    break
-                end
-
-            -- unsubscribe取消订阅成功
-            elseif msg[2] == "UNSUBSCRIBE" then
-                log.info("mqtt_client_main_task_func", "unsubscribe success")
-            
-            -- 需要主动关闭mqtt连接
-            -- 用户需要主动关闭mqtt连接时,可以调用sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CLOSE")
-            elseif msg[2] == "CLOSE" then
-                -- 主动断开mqtt client连接
-                mqtt_client:disconnect()
-                -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                sys.wait(1000)
-                break
-            
-            -- 被动关闭了mqtt连接
-            -- 被网络或者服务器断开了连接
-            elseif msg[2] == "DISCONNECTED" then
-                break
-            
-            -- 出现了其他异常
-            elseif msg[2] == "ERROR" then
-                break
-            end     
-        end
-
-        -- 出现异常    
-        ::EXCEPTION_PROC::
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 通知mqtt sender数据发送应用模块的task,MQTT连接已经断开
-        sysplus.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
-
-        -- 如果存在mqtt client对象
-        if mqtt_client then
-            -- 关闭mqtt client,并且释放mqtt client对象
-            mqtt_client:close()
-            mqtt_client = nil
-        end
-        
-        -- 5秒后跳转到循环体开始位置,自动发起重连
-        sys.wait(5000)
-    end
-end
-
---创建并且启动一个task
---运行这个task的处理函数mqtt_client_main_task_func
-sysplus.taskInitEx(mqtt_client_main_task_func, TASK_NAME)
-

+ 0 - 64
module/Air8000/demo/mqttv2/mqtt/mqtt_receiver.lua

@@ -1,64 +0,0 @@
---[[
-@module  mqtt_receiver
-@summary mqtt client数据接收处理应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtt client 数据接收应用功能模块,核心业务逻辑为:
-处理接收到的publish数据,同时将数据发送给其他应用功能模块做进一步处理;
-
-本文件的对外接口有2个:
-1、mqtt_receiver.proc(topic, payload, metas):publish数据处理入口,在mqtt_main.lua中调用;
-2、sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt server: ", topic, payload):
-   将接收到的publish中的topic和payload数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
-   需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
-]]
-
-local mqtt_receiver = {}
-
-
-
---[[
-处理接收到的publish数据
-
-@api mqtt_receiver.proc(topic, payload, metas)
-
-@param1 topic string
-表示publish主题
-
-@param2 payload string
-表示publish数据负载
-
-@param2 payload string
-表示publish数据负载
-
-@param3 metas table
-表示publish报文的一些参数;格式如下:
-{
-    qos: number类型,取值范围0,1,2
-    retain:number类型,取值范围0,1
-    dup:number类型,取值范围0,1
-    message_id: number类型
-}
-
-@return1 result nil
-
-@usage
-
-mqtt_receiver.proc(topic, payload, metas)
-]]
-function mqtt_receiver.proc(topic, payload, metas)
-
-    log.info("mqtt_receiver.proc", topic, payload:len(), json.encode(metas))
-
-    -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-    sys.publish("FEED_NETWORK_WATCHDOG") 
-
-    -- 将topic和payload通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
-    sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt server: ", topic, payload)
-
-    -- 也可以直接在此处编写代码,处理topic和payload   
-end
-
-return mqtt_receiver

+ 0 - 154
module/Air8000/demo/mqttv2/mqtt/mqtt_sender.lua

@@ -1,154 +0,0 @@
---[[
-@module  mqtt_sender
-@summary mqtt client数据发送应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtt client 数据发送应用功能模块,核心业务逻辑为:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
-2、mqtt sender task接收"CONNECT OK"、"PUBLISH_REQ"、"PUBLISH OK"三种类型的"MQTT_EVENT"消息,遍历队列send_queue,逐条发送数据到server;
-3、mqtt sender task接收"DISCONNECTED"类型的"MQTT_EVENT"消息,丢弃掉队列send_queue中未发送的数据;
-4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
-
-本文件的对外接口有1个:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
-   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的topic,payload和qos以及回调函数和回调参数一起publish出去;
-   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-]]
-
-local mqtt_sender = {}
-
---[[
-数据发送队列,数据结构为:
-{
-    [1] = {topic="topic1", payload="payload1", qos=0, cb={func=callback_function1, para=callback_para1}},
-    [2] = {topic="topic2", payload="payload2", qos=1, cb={func=callback_function2, para=callback_para2}},
-    [3] = {topic="topic3", payload="payload3", qos=2, cb={func=callback_function3, para=callback_para3}},
-}
-topic的内容为publish的主题,string类型,必须存在;
-payload的内容为publish的负载数据,string类型,必须存在;
-qos的内容为publish的质量等级,number类型,取值范围0,1,2,可选,如果用户没有指定,默认为0;
-cb.func的内容为数据发送结果的用户回调函数,可以不存在;
-cb.para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
-]]
-local send_queue = {}
-
--- mqtt client的任务名前缀
-mqtt_sender.TASK_NAME_PREFIX = "mqtt_"
-
--- mqtt_client_sender的任务名
-mqtt_sender.TASK_NAME = mqtt_sender.TASK_NAME_PREFIX.."sender"
-
--- "SEND_DATA_REQ"消息的处理函数
-local function send_data_req_proc_func(tag, topic, payload, qos, cb)
-    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
-    table.insert(send_queue, {topic=topic, payload="send from "..tag..": "..payload, qos=qos or 0, cb=cb})
-    -- 发送消息通知 mqtt sender task,有新数据等待发送
-    sysplus.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_REQ")
-end
-
--- 按照顺序发送send_queue中的数据
--- 如果调用publish接口成功,则返回当前正在发送的数据项
--- 如果调用publish接口失败,通知回调函数发送失败后,继续发送下一条数据
-local function publish_item(mqtt_client)
-    local item
-    -- 如果发送队列中有数据等待发送
-    while #send_queue>0 do
-        -- 取出来第一条数据赋值给item
-        -- 同时从队列send_queue中删除这一条数据
-        item = table.remove(send_queue, 1)
-
-        -- publish数据
-        -- result表示调用publish接口的同步结果,返回值有以下几种:
-        -- 如果失败,返回nil
-        -- 如果成功,number类型,qos为0时直接返回0;qos为1或者2时返回publish报文的message id
-        result = mqtt_client:publish(item.topic, item.payload, item.qos)
-
-        -- publish接口调用成功
-        if result then
-            return item
-        -- publish接口调用失败
-        else
-            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-            if item.cb and item.cb.func then
-                item.cb.func(false, item.cb.para)
-            end
-        end
-    end
-end
-
-
-local function publish_item_cbfunc(item, result)
-    if item then
-        -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-        if item.cb and item.cb.func then
-            item.cb.func(result, item.cb.para)
-        end
-    end
-end
-
--- mqtt client sender的任务处理函数
-local function mqtt_client_sender_task_func() 
-
-    local mqtt_client
-    local send_item
-    local result, msg
-
-    while true do
-        -- 等待"MQTT_EVENT"消息
-        msg = sysplus.waitMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT")
-
-        -- mqtt连接成功
-        -- msg[3]表示mqtt client对象
-        if msg[2] == "CONNECT_OK" then
-            mqtt_client = msg[3]
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt publish数据请求
-        elseif msg[2] == "PUBLISH_REQ" then
-            -- 如果mqtt client对象存在,并且没有正在等待发送结果的发送数据项
-            if mqtt_client and not send_item then
-                -- 发送send_queue中的数据
-                send_item = publish_item(mqtt_client)
-            end
-        -- mqtt publish数据成功
-        elseif msg[2] == "PUBLISH_OK" then
-            -- publish成功,执行回调函数通知发送方
-            publish_item_cbfunc(send_item, true)
-            -- publish成功,通知网络环境检测看门狗功能模块进行喂狗
-            sys.publish("FEED_NETWORK_WATCHDOG")
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt断开连接
-        elseif msg[2] == "DISCONNECTED" then
-            -- 清空mqtt client对象
-            mqtt_client = nil
-            -- 如果存在正在等待发送结果的发送项,执行回调函数通知发送方失败
-            publish_item_cbfunc(send_item, false)
-            -- 如果发送队列中有数据等待发送
-            while #send_queue>0 do
-                -- 取出来第一条数据赋值给send_item
-                -- 同时从队列send_queue中删除这一条数据
-                send_item = table.remove(send_queue,1)
-                -- 执行回调函数通知发送方失败
-                publish_item_cbfunc(send_item, false)
-            end
-            -- 当前没有正在等待发送结果的发送项
-            send_item = nil
-        end
-    end
-end
-
-
--- 订阅"SEND_DATA_REQ"消息;
--- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
--- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
-
-
---创建并且启动一个task
---运行这个task的处理函数mqtt_client_sender_task_func
-sysplus.taskInitEx(mqtt_client_sender_task_func, mqtt_sender.TASK_NAME)
-
-return mqtt_sender

+ 0 - 266
module/Air8000/demo/mqttv2/mqtts/mqtts_main.lua

@@ -1,266 +0,0 @@
---[[
-@module  mqtts_main
-@summary mqtts client 主应用功能模块 
-@version 1.0
-@date    2025.07.28
-@author  朱天华
-@usage
-本文件为mqtts client 主应用功能模块,核心业务逻辑为:
-1、创建一个mqtts client,连接server;
-2、处理连接/订阅/取消订阅/异常逻辑,出现异常后执行重连动作;
-3、调用mqtts_receiver的外部接口mqtts_receiver.proc,对接收到的publish数据进行处理;
-4、调用sysplus.sendMsg接口,发送"CONNECT OK"、"PUBLISH OK"和"DISCONNECTED"三种类型的"MQTT_EVENT"消息到mqtts_sender的task,控制publish数据发送逻辑;
-5、收到MQTT心跳应答后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗;
-
-本文件没有对外接口,直接在main.lua中require "mqtts_main"就可以加载运行;
-]]
-
-
--- 加载mqtts client数据接收功能模块
-local mqtts_receiver = require "mqtts_receiver"
--- 加载mqtts client数据发送功能模块
-local mqtts_sender = require "mqtts_sender"
-
--- mqtts服务器地址和端口
--- 这里使用的地址和端口,仅能用作测试用途,不可商用,说不定哪一天就关闭了
--- 用户开发项目时,替换为自己的商用服务器地址和端口
-local SERVER_ADDR = "airlbs.openluat.com"
-local SERVER_PORT = 8883
-
--- mqtts_main的任务名
-local TASK_NAME = mqtts_sender.TASK_NAME_PREFIX.."main"
-
--- mqtt主题的前缀:IMEI号
-local TOPIC_PREFIX = mobile.imei()
-
--- mqtts client的事件回调函数
-local function mqtts_client_event_cbfunc(mqtt_client, event, data, payload, metas)
-    log.info("mqtts_client_event_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-
-    -- mqtt连接成功
-    if event == "conack" then
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-        -- 订阅单主题
-        -- 第二个参数表示qos,取值范围为0,1,2,如果不设置,默认为0
-        if not mqtt_client:subscribe(TOPIC_PREFIX .. "/down") then
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        end
-        -- 订阅多主题,如果有需要,打开注释
-        -- 表中的每一个订阅主题的格式为[topic]=qos
-        -- if not mqtt_client:subscribe(
-        --         {
-        --             [(TOPIC_PREFIX .. "/data"]=0,
-        --             [(TOPIC_PREFIX .. "/cmd"]=1
-        --         }
-        -- ) then
-        --     sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        -- end
-
-    -- 订阅结果
-    -- data:订阅应答结果,true为成功,false为失败
-    -- payload:number类型;成功时表示qos,取值范围为0,1,2;失败时表示失败码,一般是0x80
-    elseif event == "suback" then
-        -- 发送消息通知 mqtts main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", data, payload)
-        
-    -- 取消订阅成功
-    elseif event == "unsuback" then
-        -- 发送消息通知 mqtts main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "UNSUBSCRIBE", true)
-
-    -- 接收到服务器下发的publish数据
-    -- data:string类型,表示topic
-    -- payload:string类型,表示payload
-    -- metas:table类型,数据内容如下
-    -- {
-    --     qos: number类型,取值范围0,1,2
-    --     retain:number类型,取值范围0,1
-    --     dup:number类型,取值范围0,1
-    --     message_id: number类型
-    -- }
-    elseif event == "recv" then
-        -- 对接收到的publish数据处理
-        mqtts_receiver.proc(data, payload, metas)
-
-    -- 发送成功publish数据
-    -- data:number类型,表示message id
-    elseif event == "sent" then
-        -- 发送消息通知 mqtts sender task
-        sysplus.sendMsg(mqtts_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_OK", data)
-
-    -- 服务器断开mqtt连接
-    elseif event == "disconnect" then
-        -- 发送消息通知 mqtts main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED", false)
-
-    -- 收到服务器的心跳应答
-    elseif event == "pong" then
-        -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-        sys.publish("FEED_NETWORK_WATCHDOG") 
-	
-    -- 严重异常,本地会主动断开连接
-    -- data:string类型,表示具体的异常,有以下几种:
-    --       "connect":tcp连接失败
-    --       "tx":数据发送失败
-    --       "conack":mqtt connect后,服务器应答CONNACK鉴权失败,失败码为payload(number类型)
-    --       "other":其他异常
-    elseif event == "error" then
-        if data == "connect" or data == "conack" then
-            -- 发送消息通知 mqtts main task,连接失败
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", false)
-        elseif data == "other" or data == "tx" then
-            -- 发送消息通知 mqtts main task,出现异常
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "ERROR")
-        end
-    end
-end
-
--- mqtts main task 的任务处理函数
-local function mqtts_client_main_task_func() 
-
-    local mqtt_client
-    local result, msg, para
-
-    while true do
-        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
-        while not socket.adapter(socket.dft()) do
-            log.warn("mqtts_client_main_task_func", "wait IP_READY", socket.dft())
-            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-            -- 或者等待1秒超时退出阻塞等待状态;
-            -- 注意:此处的1000毫秒超时不要修改的更长;
-            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
-            sys.waitUntil("IP_READY", 1000)
-        end
-
-        -- 检测到了IP_READY消息
-        log.info("mqtts_client_main_task_func", "recv IP_READY", socket.dft())
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 创建mqtt client对象,ssl连接,不需要证书校验
-        mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT, true)
-        -- 如果创建mqtt client对象失败
-        if not mqtt_client then
-            log.error("mqtts_client_main_task_func", "mqtt.create error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 配置mqtt client对象的client id,username,password和clean session标志
-        result = mqtt_client:auth(mobile.imei(), "", "", true)
-        -- 如果配置失败
-        if not result then
-            log.error("mqtts_client_main_task_func", "mqtt_client:auth error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 注册mqtt client对象的事件回调函数
-        mqtt_client:on(mqtts_client_event_cbfunc)
-
-        -- 设置mqtt keepalive时间为120秒
-        -- 如果没有设置,内核固件中默认为180秒
-        -- 有需要的话,可以打开注释
-        -- mqtt_client:keepalive(120)
-
-        -- 设置遗嘱消息,有需要的话,可以打开注释
-        -- mqtt_client:will(TOPIC_PREFIX .. "/status", "offline")
-
-        -- 连接server
-        result = mqtt_client:connect()
-        -- 如果连接server失败
-        if not result then
-            log.error("mqtts_client_main_task_func", "mqtt_client:connect error")
-            goto EXCEPTION_PROC
-        end
-
-
-        -- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
-        while true do
-            -- 等待"MQTT_EVENT"消息
-            msg = sysplus.waitMsg(TASK_NAME, "MQTT_EVENT")
-            log.info("mqtts_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
-
-            -- connect连接结果
-            -- msg[3]表示连接结果,true为连接成功,false为连接失败
-            if msg[2] == "CONNECT" then                
-                -- mqtt连接成功
-                if msg[3] then
-                    log.info("mqtts_client_main_task_func", "connect success")
-                    -- 通知数据发送应用模块,MQTT连接成功
-                    sysplus.sendMsg(mqtts_sender.TASK_NAME, "MQTT_EVENT", "CONNECT_OK", mqtt_client)
-                -- mqtt连接失败
-                else
-                    log.info("mqtts_client_main_task_func", "connect error")
-                    -- 退出循环,发起重连
-                    break
-                end
-
-            -- subscribe订阅结果
-            -- msg[3]表示订阅结果,true为订阅成功,false为订阅失败
-            elseif msg[2] == "SUBSCRIBE" then
-                -- 订阅成功
-                if msg[3] then
-                    log.info("mqtts_client_main_task_func", "subscribe success", "qos: "..(msg[4] or "nil"))
-                -- 订阅失败
-                else
-                    log.error("mqtts_client_main_task_func", "subscribe error", "code", msg[4])
-                    -- 主动断开mqtt client连接
-                    mqtt_client:disconnect()
-                    -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                    -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                    sys.wait(1000)
-                    break
-                end
-
-            -- unsubscribe取消订阅成功
-            elseif msg[2] == "UNSUBSCRIBE" then
-                log.info("mqtts_client_main_task_func", "unsubscribe success")
-            
-            -- 需要主动关闭mqtt连接
-            -- 用户需要主动关闭mqtt连接时,可以调用sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CLOSE")
-            elseif msg[2] == "CLOSE" then
-                -- 主动断开mqtt client连接
-                mqtt_client:disconnect()
-                -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                sys.wait(1000)
-                break
-            
-            -- 被动关闭了mqtt连接
-            -- 被网络或者服务器断开了连接
-            elseif msg[2] == "DISCONNECTED" then
-                break
-            
-            -- 出现了其他异常
-            elseif msg[2] == "ERROR" then
-                break
-            end     
-        end
-
-        -- 出现异常    
-        ::EXCEPTION_PROC::
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 通知mqtts sender数据发送应用模块的task,MQTT连接已经断开
-        sysplus.sendMsg(mqtts_sender.TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
-
-        -- 如果存在mqtt client对象
-        if mqtt_client then
-            -- 关闭mqtt client,并且释放mqtt client对象
-            mqtt_client:close()
-            mqtt_client = nil
-        end
-        
-        -- 5秒后跳转到循环体开始位置,自动发起重连
-        sys.wait(5000)
-    end
-end
-
---创建并且启动一个task
---运行这个task的处理函数mqtts_client_main_task_func
-sysplus.taskInitEx(mqtts_client_main_task_func, TASK_NAME)
-

+ 0 - 64
module/Air8000/demo/mqttv2/mqtts/mqtts_receiver.lua

@@ -1,64 +0,0 @@
---[[
-@module  mqtts_receiver
-@summary mqtts cient数据接收处理应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtts client 数据接收应用功能模块,核心业务逻辑为:
-处理接收到的publish数据,同时将数据发送给其他应用功能模块做进一步处理;
-
-本文件的对外接口有2个:
-1、mqtts_receiver.proc(topic, payload, metas):publish数据处理入口,在mqtts_main.lua中调用;
-2、sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt ssl server: ", topic, payload):
-   将接收到的publish中的topic和payload数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
-   需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
-]]
-
-local mqtts_receiver = {}
-
-
-
---[[
-处理接收到的publish数据
-
-@api mqtts_receiver.proc(topic, payload, metas)
-
-@param1 topic string
-表示publish主题
-
-@param2 payload string
-表示publish数据负载
-
-@param2 payload string
-表示publish数据负载
-
-@param3 metas table
-表示publish报文的一些参数;格式如下:
-{
-    qos: number类型,取值范围0,1,2
-    retain:number类型,取值范围0,1
-    dup:number类型,取值范围0,1
-    message_id: number类型
-}
-
-@return1 result nil
-
-@usage
-
-mqtts_receiver.proc(topic, payload, metas)
-]]
-function mqtts_receiver.proc(topic, payload, metas)
-
-    log.info("mqtts_receiver.proc", topic, payload:len(), json.encode(metas))
-
-    -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-    sys.publish("FEED_NETWORK_WATCHDOG") 
-
-    -- 将topic和payload通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
-    sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt ssl server: ", topic, payload)
-
-    -- 也可以直接在此处编写代码,处理topic和payload   
-end
-
-return mqtts_receiver

+ 0 - 154
module/Air8000/demo/mqttv2/mqtts/mqtts_sender.lua

@@ -1,154 +0,0 @@
---[[
-@module  mqtts_sender
-@summary mqtts client数据发送应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtts client 数据发送应用功能模块,核心业务逻辑为:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
-2、mqtts sender task接收"CONNECT OK"、"PUBLISH_REQ"、"PUBLISH OK"三种类型的"MQTT_EVENT"消息,遍历队列send_queue,逐条发送数据到server;
-3、mqtts sender task接收"DISCONNECTED"类型的"MQTT_EVENT"消息,丢弃掉队列send_queue中未发送的数据;
-4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
-
-本文件的对外接口有1个:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
-   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的topic,payload和qos以及回调函数和回调参数一起publish出去;
-   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-]]
-
-local mqtts_sender = {}
-
---[[
-数据发送队列,数据结构为:
-{
-    [1] = {topic="topic1", payload="payload1", qos=0, cb={func=callback_function1, para=callback_para1}},
-    [2] = {topic="topic2", payload="payload2", qos=1, cb={func=callback_function2, para=callback_para2}},
-    [3] = {topic="topic3", payload="payload3", qos=2, cb={func=callback_function3, para=callback_para3}},
-}
-topic的内容为publish的主题,string类型,必须存在;
-payload的内容为publish的负载数据,string类型,必须存在;
-qos的内容为publish的质量等级,number类型,取值范围0,1,2,可选,如果用户没有指定,默认为0;
-cb.func的内容为数据发送结果的用户回调函数,可以不存在;
-cb.para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
-]]
-local send_queue = {}
-
--- mqtts client的任务名前缀
-mqtts_sender.TASK_NAME_PREFIX = "mqtts_"
-
--- mqtts_client_sender的任务名
-mqtts_sender.TASK_NAME = mqtts_sender.TASK_NAME_PREFIX.."sender"
-
--- "SEND_DATA_REQ"消息的处理函数
-local function send_data_req_proc_func(tag, topic, payload, qos, cb)
-    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
-    table.insert(send_queue, {topic=topic, payload="send from "..tag..": "..payload, qos=qos or 0, cb=cb})
-    -- 发送消息通知 mqtts sender task,有新数据等待发送
-    sysplus.sendMsg(mqtts_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_REQ")
-end
-
--- 按照顺序发送send_queue中的数据
--- 如果调用publish接口成功,则返回当前正在发送的数据项
--- 如果调用publish接口失败,通知回调函数发送失败后,继续发送下一条数据
-local function publish_item(mqtt_client)
-    local item
-    -- 如果发送队列中有数据等待发送
-    while #send_queue>0 do
-        -- 取出来第一条数据赋值给item
-        -- 同时从队列send_queue中删除这一条数据
-        item = table.remove(send_queue, 1)
-
-        -- publish数据
-        -- result表示调用publish接口的同步结果,返回值有以下几种:
-        -- 如果失败,返回nil
-        -- 如果成功,number类型,qos为0时直接返回0;qos为1或者2时返回publish报文的message id
-        result = mqtt_client:publish(item.topic, item.payload, item.qos)
-
-        -- publish接口调用成功
-        if result then
-            return item
-        -- publish接口调用失败
-        else
-            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-            if item.cb and item.cb.func then
-                item.cb.func(false, item.cb.para)
-            end
-        end
-    end
-end
-
-
-local function publish_item_cbfunc(item, result)
-    if item then
-        -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-        if item.cb and item.cb.func then
-            item.cb.func(result, item.cb.para)
-        end
-    end
-end
-
--- mqtts client sender的任务处理函数
-local function mqtts_client_sender_task_func() 
-
-    local mqtt_client
-    local send_item
-    local result, msg
-
-    while true do
-        -- 等待"MQTT_EVENT"消息
-        msg = sysplus.waitMsg(mqtts_sender.TASK_NAME, "MQTT_EVENT")
-
-        -- mqtt连接成功
-        -- msg[3]表示mqtt client对象
-        if msg[2] == "CONNECT_OK" then
-            mqtt_client = msg[3]
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt publish数据请求
-        elseif msg[2] == "PUBLISH_REQ" then
-            -- 如果mqtt client对象存在,并且没有正在等待发送结果的发送数据项
-            if mqtt_client and not send_item then
-                -- 发送send_queue中的数据
-                send_item = publish_item(mqtt_client)
-            end
-        -- mqtt publish数据成功
-        elseif msg[2] == "PUBLISH_OK" then
-            -- publish成功,执行回调函数通知发送方
-            publish_item_cbfunc(send_item, true)
-            -- publish成功,通知网络环境检测看门狗功能模块进行喂狗
-            sys.publish("FEED_NETWORK_WATCHDOG")
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt断开连接
-        elseif msg[2] == "DISCONNECTED" then
-            -- 清空mqtt client对象
-            mqtt_client = nil
-            -- 如果存在正在等待发送结果的发送项,执行回调函数通知发送方失败
-            publish_item_cbfunc(send_item, false)
-            -- 如果发送队列中有数据等待发送
-            while #send_queue>0 do
-                -- 取出来第一条数据赋值给send_item
-                -- 同时从队列send_queue中删除这一条数据
-                send_item = table.remove(send_queue,1)
-                -- 执行回调函数通知发送方失败
-                publish_item_cbfunc(send_item, false)
-            end
-            -- 当前没有正在等待发送结果的发送项
-            send_item = nil
-        end
-    end
-end
-
-
--- 订阅"SEND_DATA_REQ"消息;
--- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
--- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
-
-
---创建并且启动一个task
---运行这个task的处理函数mqtts_client_sender_task_func
-sysplus.taskInitEx(mqtts_client_sender_task_func, mqtts_sender.TASK_NAME)
-
-return mqtts_sender

+ 0 - 20
module/Air8000/demo/mqttv2/mqtts_ca/airlbs_parent_ca.crt

@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDUTCCAjmgAwIBAgIJAPPYCjTmxdt/MA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV
-BAYTAkNOMREwDwYDVQQIDAhoYW5nemhvdTEMMAoGA1UECgwDRU1RMQ8wDQYDVQQD
-DAZSb290Q0EwHhcNMjAwNTA4MDgwNjUyWhcNMzAwNTA2MDgwNjUyWjA/MQswCQYD
-VQQGEwJDTjERMA8GA1UECAwIaGFuZ3pob3UxDDAKBgNVBAoMA0VNUTEPMA0GA1UE
-AwwGUm9vdENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzcgVLex1
-EZ9ON64EX8v+wcSjzOZpiEOsAOuSXOEN3wb8FKUxCdsGrsJYB7a5VM/Jot25Mod2
-juS3OBMg6r85k2TWjdxUoUs+HiUB/pP/ARaaW6VntpAEokpij/przWMPgJnBF3Ur
-MjtbLayH9hGmpQrI5c2vmHQ2reRZnSFbY+2b8SXZ+3lZZgz9+BaQYWdQWfaUWEHZ
-uDaNiViVO0OT8DRjCuiDp3yYDj3iLWbTA/gDL6Tf5XuHuEwcOQUrd+h0hyIphO8D
-tsrsHZ14j4AWYLk1CPA6pq1HIUvEl2rANx2lVUNv+nt64K/Mr3RnVQd9s8bK+TXQ
-KGHd2Lv/PALYuwIDAQABo1AwTjAdBgNVHQ4EFgQUGBmW+iDzxctWAWxmhgdlE8Pj
-EbQwHwYDVR0jBBgwFoAUGBmW+iDzxctWAWxmhgdlE8PjEbQwDAYDVR0TBAUwAwEB
-/zANBgkqhkiG9w0BAQsFAAOCAQEAGbhRUjpIred4cFAFJ7bbYD9hKu/yzWPWkMRa
-ErlCKHmuYsYk+5d16JQhJaFy6MGXfLgo3KV2itl0d+OWNH0U9ULXcglTxy6+njo5
-CFqdUBPwN1jxhzo9yteDMKF4+AHIxbvCAJa17qcwUKR5MKNvv09C6pvQDJLzid7y
-E2dkgSuggik3oa0427KvctFf8uhOV94RvEDyqvT5+pgNYZ2Yfga9pD/jjpoHEUlo
-88IGU8/wJCx3Ds2yc8+oBg/ynxG8f/HmCC1ET6EHHoe2jlo8FpU/SgGtghS1YL30
-IWxNsPrUP+XsZpBJy/mvOhE5QXo6Y35zDqqj8tI7AGmAWu22jg==
------END CERTIFICATE-----

+ 0 - 293
module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_main.lua

@@ -1,293 +0,0 @@
---[[
-@module  mqtts_ca_main
-@summary mqtts ca client 主应用功能模块 
-@version 1.0
-@date    2025.07.28
-@author  朱天华
-@usage
-本文件为mqtts ca client 主应用功能模块,核心业务逻辑为:
-1、创建一个mqtts ca client,连接server;
-2、处理连接/订阅/取消订阅/异常逻辑,出现异常后执行重连动作;
-3、调用mqtts_ca_receiver的外部接口mqtts_ca_receiver.proc,对接收到的publish数据进行处理;
-4、调用sysplus.sendMsg接口,发送"CONNECT OK"、"PUBLISH OK"和"DISCONNECTED"三种类型的"MQTT_EVENT"消息到mqtts_ca_sender的task,控制publish数据发送逻辑;
-5、收到MQTT心跳应答后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗;
-
-本文件没有对外接口,直接在main.lua中require "mqtts_ca_main"就可以加载运行;
-]]
-
--- 加载sntp时间同步应用功能模块(ca证书校验的mqtt ssl需要时间同步功能)
-require "sntp_app"
-
--- 加载mqtts ca client数据接收功能模块
-local mqtts_ca_receiver = require "mqtts_ca_receiver"
--- 加载mqtts ca client数据发送功能模块
-local mqtts_ca_sender = require "mqtts_ca_sender"
-
--- mqtts ca服务器地址和端口
--- 这里使用的地址和端口,仅能用作测试用途,不可商用,说不定哪一天就关闭了
--- 用户开发项目时,替换为自己的商用服务器地址和端口
-local SERVER_ADDR = "airlbs.openluat.com"
-local SERVER_PORT = 8883
-
--- mqtts_ca_main的任务名
-local TASK_NAME = mqtts_ca_sender.TASK_NAME_PREFIX.."main"
-
--- mqtt主题的前缀:IMEI号
-local TOPIC_PREFIX = mobile.imei()
-
--- mqtts ca client的事件回调函数
-local function mqtts_ca_client_event_cbfunc(mqtt_client, event, data, payload, metas)
-    log.info("mqtts_ca_client_event_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-
-    -- mqtt连接成功
-    if event == "conack" then
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-        -- 订阅单主题
-        -- 第二个参数表示qos,取值范围为0,1,2,如果不设置,默认为0
-        if not mqtt_client:subscribe(TOPIC_PREFIX .. "/down") then
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        end
-        -- 订阅多主题,如果有需要,打开注释
-        -- 表中的每一个订阅主题的格式为[topic]=qos
-        -- if not mqtt_client:subscribe(
-        --         {
-        --             [(TOPIC_PREFIX .. "/data"]=0,
-        --             [(TOPIC_PREFIX .. "/cmd"]=1
-        --         }
-        -- ) then
-        --     sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-        -- end
-
-    -- 订阅结果
-    -- data:订阅应答结果,true为成功,false为失败
-    -- payload:number类型;成功时表示qos,取值范围为0,1,2;失败时表示失败码,一般是0x80
-    elseif event == "suback" then
-        -- 发送消息通知 mqtts ca main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", data, payload)
-        
-    -- 取消订阅成功
-    elseif event == "unsuback" then
-        -- 发送消息通知 mqtts ca main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "UNSUBSCRIBE", true)
-
-    -- 接收到服务器下发的publish数据
-    -- data:string类型,表示topic
-    -- payload:string类型,表示payload
-    -- metas:table类型,数据内容如下
-    -- {
-    --     qos: number类型,取值范围0,1,2
-    --     retain:number类型,取值范围0,1
-    --     dup:number类型,取值范围0,1
-    --     message_id: number类型
-    -- }
-    elseif event == "recv" then
-        -- 对接收到的publish数据处理
-        mqtts_ca_receiver.proc(data, payload, metas)
-
-    -- 发送成功publish数据
-    -- data:number类型,表示message id
-    elseif event == "sent" then
-        -- 发送消息通知 mqtts ca sender task
-        sysplus.sendMsg(mqtts_ca_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_OK", data)
-
-    -- 服务器断开mqtt连接
-    elseif event == "disconnect" then
-        -- 发送消息通知 mqtts ca main task
-        sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED", false)
-
-    -- 收到服务器的心跳应答
-    elseif event == "pong" then
-        -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-        sys.publish("FEED_NETWORK_WATCHDOG") 
-	
-    -- 严重异常,本地会主动断开连接
-    -- data:string类型,表示具体的异常,有以下几种:
-    --       "connect":tcp连接失败
-    --       "tx":数据发送失败
-    --       "conack":mqtt connect后,服务器应答CONNACK鉴权失败,失败码为payload(number类型)
-    --       "other":其他异常
-    elseif event == "error" then
-        if data == "connect" or data == "conack" then
-            -- 发送消息通知 mqtts ca main task,连接失败
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", false)
-        elseif data == "other" or data == "tx" then
-            -- 发送消息通知 mqtts ca main task,出现异常
-            sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "ERROR")
-        end
-    end
-end
-
--- mqtts ca main task 的任务处理函数
-local function mqtts_ca_client_main_task_func() 
-
-    local mqtt_client
-    local result, msg, para
-
-    -- 用来验证server证书是否合法的ca证书文件为airlbs_parent_ca.crt
-    -- 此ca证书的有效期截止到2030年5月6日
-    -- 将这个ca证书文件的内容读取出来,赋值给server_ca_cert
-    -- 注意:此处的ca证书文件仅用来验证airlbs.openluat.com:8883端口的server证书
-    -- baidu网站的server证书有效期截止到2026年8月10日
-    -- 在有效期之前,baidu会更换server证书,如果server证书更换后,此处验证使用的baidu_parent_ca.crt也可能需要更换
-    -- 使用电脑上的网页浏览器访问https://www.baidu.com,可以实时看到baidu的server证书以及baidu_parent_ca.crt
-    -- 如果你使用的是自己的server,要替换为自己server证书对应的ca证书文件
-    local server_ca_cert = io.readFile("/luadb/airlbs_parent_ca.crt")
-
-    while true do
-        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
-        while not socket.adapter(socket.dft()) do
-            log.warn("mqtts_ca_client_main_task_func", "wait IP_READY", socket.dft())
-            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-            -- 或者等待1秒超时退出阻塞等待状态;
-            -- 注意:此处的1000毫秒超时不要修改的更长;
-            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
-            sys.waitUntil("IP_READY", 1000)
-        end
-
-        -- 检测到了IP_READY消息
-        log.info("mqtts_ca_client_main_task_func", "recv IP_READY", socket.dft())
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 创建mqtt client对象,ssl连接,单向证书校验
-        -- client仅单向校验server的证书,server不校验client的证书和密钥文件
-        -- 如果做证书校验,需要特别注意以下几点:
-        -- 1、证书校验前,设备端必须同步为正确的时间,因为校验过程中会检查ca证书以及server证书中的有效期是否合法;本demo中的sntp_app.lua会同步时间;
-        -- 2、任何证书都有有效期,无论是ca证书还是server证书,必须在有效期截止之前,及时更换证书,延长有效期,否则证书校验会失败;
-        -- 3、如果要更换ca证书,需要在设备端远程升级,必须保证ca证书失效之前升级成功,否则校验失败,就无法连接server;
-        -- 综上所述,证书校验虽然安全,可以验证身份,但是后续维护成本比较高;除非有需要,否则可以不配置证书校验功能;
-        -- 另外,如果使用https://netlab.luatos.com/创建的TCP SSL Server,使用的server证书有可能过了有效期;
-        -- 如果过了有效期,使用本文件无法连接成功tcp ssl ca server,遇到这种问题,可以在main.lua中打开socket.sslLog(3),观察Luatools的日志,如果出现类似于下面的日志
-        -- expires on        : 2020-12-27 15:46:55
-        -- 表示证书有效期截止到2020-12-27 15:46:55,明显就是证书已经过了有效期
-        -- 遇到这种情况,可以反馈给合宙的技术人员;或者不再使用netlab server测试,使用你自己的tcp ssl server来测试,只要保证你的server证书合法就行
-        mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT, {server_cert = server_ca_cert})
-        -- 如果创建mqtt client对象失败
-        if not mqtt_client then
-            log.error("mqtts_ca_client_main_task_func", "mqtt.create error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 配置mqtt client对象的client id,username,password和clean session标志
-        result = mqtt_client:auth(mobile.imei(), "", "", true)
-        -- 如果配置失败
-        if not result then
-            log.error("mqtts_ca_client_main_task_func", "mqtt_client:auth error")
-            goto EXCEPTION_PROC
-        end
-
-        -- 注册mqtt client对象的事件回调函数
-        mqtt_client:on(mqtts_ca_client_event_cbfunc)
-
-        -- 设置mqtt keepalive时间为120秒
-        -- 如果没有设置,内核固件中默认为180秒
-        -- 有需要的话,可以打开注释
-        -- mqtt_client:keepalive(120)
-
-        -- 设置遗嘱消息,有需要的话,可以打开注释
-        -- mqtt_client:will(TOPIC_PREFIX .. "/status", "offline")
-
-        -- 配置开启debug信息,有需要的话,可以打开注释
-        -- mqtt_client:debug(true)
-        -- socket.sslLog(3)
-
-        -- 连接server
-        result = mqtt_client:connect()
-        -- 如果连接server失败
-        if not result then
-            log.error("mqtts_ca_client_main_task_func", "mqtt_client:connect error")
-            goto EXCEPTION_PROC
-        end
-
-
-        -- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
-        while true do
-            -- 等待"MQTT_EVENT"消息
-            msg = sysplus.waitMsg(TASK_NAME, "MQTT_EVENT")
-            log.info("mqtts_ca_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
-
-            -- connect连接结果
-            -- msg[3]表示连接结果,true为连接成功,false为连接失败
-            if msg[2] == "CONNECT" then                
-                -- mqtt连接成功
-                if msg[3] then
-                    log.info("mqtts_ca_client_main_task_func", "connect success")
-                    -- 通知数据发送应用模块,MQTT连接成功
-                    sysplus.sendMsg(mqtts_ca_sender.TASK_NAME, "MQTT_EVENT", "CONNECT_OK", mqtt_client)
-                -- mqtt连接失败
-                else
-                    log.info("mqtts_ca_client_main_task_func", "connect error")
-                    -- 退出循环,发起重连
-                    break
-                end
-
-            -- subscribe订阅结果
-            -- msg[3]表示订阅结果,true为订阅成功,false为订阅失败
-            elseif msg[2] == "SUBSCRIBE" then
-                -- 订阅成功
-                if msg[3] then
-                    log.info("mqtts_ca_client_main_task_func", "subscribe success", "qos: "..(msg[4] or "nil"))
-                -- 订阅失败
-                else
-                    log.error("mqtts_ca_client_main_task_func", "subscribe error", "code", msg[4])
-                    -- 主动断开mqtt client连接
-                    mqtt_client:disconnect()
-                    -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                    -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                    sys.wait(1000)
-                    break
-                end
-
-            -- unsubscribe取消订阅成功
-            elseif msg[2] == "UNSUBSCRIBE" then
-                log.info("mqtts_ca_client_main_task_func", "unsubscribe success")
-            
-            -- 需要主动关闭mqtt连接
-            -- 用户需要主动关闭mqtt连接时,可以调用sysplus.sendMsg(TASK_NAME, "MQTT_EVENT", "CLOSE")
-            elseif msg[2] == "CLOSE" then
-                -- 主动断开mqtt client连接
-                mqtt_client:disconnect()
-                -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-                -- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-                sys.wait(1000)
-                break
-            
-            -- 被动关闭了mqtt连接
-            -- 被网络或者服务器断开了连接
-            elseif msg[2] == "DISCONNECTED" then
-                break
-            
-            -- 出现了其他异常
-            elseif msg[2] == "ERROR" then
-                break
-            end     
-        end
-
-        -- 出现异常    
-        ::EXCEPTION_PROC::
-
-        -- 清空此task绑定的消息队列中的未处理的消息
-        sysplus.cleanMsg(TASK_NAME)
-
-        -- 通知mqtts ca sender数据发送应用模块的task,MQTT连接已经断开
-        sysplus.sendMsg(mqtts_ca_sender.TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
-
-        -- 如果存在mqtt client对象
-        if mqtt_client then
-            -- 关闭mqtt client,并且释放mqtt client对象
-            mqtt_client:close()
-            mqtt_client = nil
-        end
-        
-        -- 5秒后跳转到循环体开始位置,自动发起重连
-        sys.wait(5000)
-    end
-end
-
---创建并且启动一个task
---运行这个task的处理函数mqtts_ca_client_main_task_func
-sysplus.taskInitEx(mqtts_ca_client_main_task_func, TASK_NAME)
-

+ 0 - 64
module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_receiver.lua

@@ -1,64 +0,0 @@
---[[
-@module  mqtts_ca_receiver
-@summary mqtts ca cient数据接收处理应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtts ca client 数据接收应用功能模块,核心业务逻辑为:
-处理接收到的publish数据,同时将数据发送给其他应用功能模块做进一步处理;
-
-本文件的对外接口有2个:
-1、mqtts_ca_receiver.proc(topic, payload, metas):publish数据处理入口,在mqtts_ca_main.lua中调用;
-2、sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt ssl ca server: ", topic, payload):
-   将接收到的publish中的topic和payload数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
-   需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
-]]
-
-local mqtts_ca_receiver = {}
-
-
-
---[[
-处理接收到的publish数据
-
-@api mqtts_ca_receiver.proc(topic, payload, metas)
-
-@param1 topic string
-表示publish主题
-
-@param2 payload string
-表示publish数据负载
-
-@param2 payload string
-表示publish数据负载
-
-@param3 metas table
-表示publish报文的一些参数;格式如下:
-{
-    qos: number类型,取值范围0,1,2
-    retain:number类型,取值范围0,1
-    dup:number类型,取值范围0,1
-    message_id: number类型
-}
-
-@return1 result nil
-
-@usage
-
-mqtts_ca_receiver.proc(topic, payload, metas)
-]]
-function mqtts_ca_receiver.proc(topic, payload, metas)
-
-    log.info("mqtts_ca_receiver.proc", topic, payload:len(), json.encode(metas))
-
-    -- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
-    sys.publish("FEED_NETWORK_WATCHDOG") 
-
-    -- 将topic和payload通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
-    sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt ssl ca server: ", topic, payload)
-
-    -- 也可以直接在此处编写代码,处理topic和payload   
-end
-
-return mqtts_ca_receiver

+ 0 - 154
module/Air8000/demo/mqttv2/mqtts_ca/mqtts_ca_sender.lua

@@ -1,154 +0,0 @@
---[[
-@module  mqttt_ca_sender
-@summary mqtts ca client数据发送应用功能模块 
-@version 1.0
-@date    2025.07.29
-@author  朱天华
-@usage
-本文件为mqtts ca client 数据发送应用功能模块,核心业务逻辑为:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
-2、mqtts ca sender task接收"CONNECT OK"、"PUBLISH_REQ"、"PUBLISH OK"三种类型的"MQTT_EVENT"消息,遍历队列send_queue,逐条发送数据到server;
-3、mqtts ca sender task接收"DISCONNECTED"类型的"MQTT_EVENT"消息,丢弃掉队列send_queue中未发送的数据;
-4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
-
-本文件的对外接口有1个:
-1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
-   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的topic,payload和qos以及回调函数和回调参数一起publish出去;
-   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-]]
-
-local mqtts_ca_sender = {}
-
---[[
-数据发送队列,数据结构为:
-{
-    [1] = {topic="topic1", payload="payload1", qos=0, cb={func=callback_function1, para=callback_para1}},
-    [2] = {topic="topic2", payload="payload2", qos=1, cb={func=callback_function2, para=callback_para2}},
-    [3] = {topic="topic3", payload="payload3", qos=2, cb={func=callback_function3, para=callback_para3}},
-}
-topic的内容为publish的主题,string类型,必须存在;
-payload的内容为publish的负载数据,string类型,必须存在;
-qos的内容为publish的质量等级,number类型,取值范围0,1,2,可选,如果用户没有指定,默认为0;
-cb.func的内容为数据发送结果的用户回调函数,可以不存在;
-cb.para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
-]]
-local send_queue = {}
-
--- mqtts ca client的任务名前缀
-mqtts_ca_sender.TASK_NAME_PREFIX = "mqtts_ca_"
-
--- mqtts_ca_client_sender的任务名
-mqtts_ca_sender.TASK_NAME = mqtts_ca_sender.TASK_NAME_PREFIX.."sender"
-
--- "SEND_DATA_REQ"消息的处理函数
-local function send_data_req_proc_func(tag, topic, payload, qos, cb)
-    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
-    table.insert(send_queue, {topic=topic, payload="send from "..tag..": "..payload, qos=qos or 0, cb=cb})
-    -- 发送消息通知 mqtts ca sender task,有新数据等待发送
-    sysplus.sendMsg(mqtts_ca_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_REQ")
-end
-
--- 按照顺序发送send_queue中的数据
--- 如果调用publish接口成功,则返回当前正在发送的数据项
--- 如果调用publish接口失败,通知回调函数发送失败后,继续发送下一条数据
-local function publish_item(mqtt_client)
-    local item
-    -- 如果发送队列中有数据等待发送
-    while #send_queue>0 do
-        -- 取出来第一条数据赋值给item
-        -- 同时从队列send_queue中删除这一条数据
-        item = table.remove(send_queue, 1)
-
-        -- publish数据
-        -- result表示调用publish接口的同步结果,返回值有以下几种:
-        -- 如果失败,返回nil
-        -- 如果成功,number类型,qos为0时直接返回0;qos为1或者2时返回publish报文的message id
-        result = mqtt_client:publish(item.topic, item.payload, item.qos)
-
-        -- publish接口调用成功
-        if result then
-            return item
-        -- publish接口调用失败
-        else
-            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-            if item.cb and item.cb.func then
-                item.cb.func(false, item.cb.para)
-            end
-        end
-    end
-end
-
-
-local function publish_item_cbfunc(item, result)
-    if item then
-        -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
-        if item.cb and item.cb.func then
-            item.cb.func(result, item.cb.para)
-        end
-    end
-end
-
--- mqtts_ca client sender的任务处理函数
-local function mqtts_ca_client_sender_task_func() 
-
-    local mqtt_client
-    local send_item
-    local result, msg
-
-    while true do
-        -- 等待"MQTT_EVENT"消息
-        msg = sysplus.waitMsg(mqtts_ca_sender.TASK_NAME, "MQTT_EVENT")
-
-        -- mqtt连接成功
-        -- msg[3]表示mqtt client对象
-        if msg[2] == "CONNECT_OK" then
-            mqtt_client = msg[3]
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt publish数据请求
-        elseif msg[2] == "PUBLISH_REQ" then
-            -- 如果mqtt client对象存在,并且没有正在等待发送结果的发送数据项
-            if mqtt_client and not send_item then
-                -- 发送send_queue中的数据
-                send_item = publish_item(mqtt_client)
-            end
-        -- mqtt publish数据成功
-        elseif msg[2] == "PUBLISH_OK" then
-            -- publish成功,执行回调函数通知发送方
-            publish_item_cbfunc(send_item, true)
-            -- publish成功,通知网络环境检测看门狗功能模块进行喂狗
-            sys.publish("FEED_NETWORK_WATCHDOG")
-            -- 发送send_queue中的数据
-            send_item = publish_item(mqtt_client)
-        -- mqtt断开连接
-        elseif msg[2] == "DISCONNECTED" then
-            -- 清空mqtt client对象
-            mqtt_client = nil
-            -- 如果存在正在等待发送结果的发送项,执行回调函数通知发送方失败
-            publish_item_cbfunc(send_item, false)
-            -- 如果发送队列中有数据等待发送
-            while #send_queue>0 do
-                -- 取出来第一条数据赋值给send_item
-                -- 同时从队列send_queue中删除这一条数据
-                send_item = table.remove(send_queue,1)
-                -- 执行回调函数通知发送方失败
-                publish_item_cbfunc(send_item, false)
-            end
-            -- 当前没有正在等待发送结果的发送项
-            send_item = nil
-        end
-    end
-end
-
-
--- 订阅"SEND_DATA_REQ"消息;
--- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
--- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
-sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
-
-
---创建并且启动一个task
---运行这个task的处理函数mqtts_ca_client_sender_task_func
-sysplus.taskInitEx(mqtts_ca_client_sender_task_func, mqtts_ca_sender.TASK_NAME)
-
-return mqtts_ca_sender

+ 0 - 66
module/Air8000/demo/mqttv2/mqtts_ca/sntp_app.lua

@@ -1,66 +0,0 @@
---[[
-@module  sntp_app
-@summary sntp时间同步应用功能模块 
-@version 1.0
-@date    2025.07.01
-@author  朱天华
-@usage
-本文件为sntp时间同步应用功能模块,核心业务逻辑为:
-1、连接ntp服务器进行时间同步;
-2、如果同步成功,1小时之后重新发起同步动作;
-3、如果同步失败,10秒钟之后重新发起同步动作;
-
-本文件没有对外接口,直接在其他应用功能模块中require "sntp_app"就可以加载运行;
-]]
-
--- sntp时间同步的任务处理函数
-local function sntp_task_func() 
-
-    while true do
-        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
-        while not socket.adapter(socket.dft()) do
-            log.warn("sntp_task_func", "wait IP_READY", socket.dft())
-            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-            -- 或者等待1秒超时退出阻塞等待状态;
-            -- 注意:此处的1000毫秒超时不要修改的更长;
-            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
-            sys.waitUntil("IP_READY", 1000)
-        end
-
-        -- 检测到了IP_READY消息
-        log.warn("sntp_task_func", "recv IP_READY")
-
-        -- 发起ntp时间同步动作
-        socket.sntp()
-
-        -- 等待ntp时间同步结果,30秒超时失败,通常只需要几百毫秒就能成功
-        local ret = sys.waitUntil("NTP_UPDATE", 30000)
-
-        --同步成功
-        if ret then
-            -- 以下是获取/打印时间的演示,注意时区问题
-            log.info("sntp_task_func", "时间同步成功", "本地时间", os.date())
-            log.info("sntp_task_func", "时间同步成功", "UTC时间", os.date("!%c"))
-            log.info("sntp_task_func", "时间同步成功", "RTC时钟(UTC时间)", json.encode(rtc.get()))
-            log.info("sntp_task_func", "时间同步成功", "本地时间戳", os.time())
-            local t = os.date("*t")
-            log.info("sntp_task_func", "时间同步成功", "本地时间os.date() json格式", json.encode(t))
-            log.info("sntp_task_func", "时间同步成功", "本地时间os.date(os.time())", os.time(t))
-
-            -- 正常使用, 一小时一次, 已经足够了, 甚至1天一次也可以
-            sys.wait(3600000) 
-        --同步失败
-        else
-            log.info("sntp_task_func", "时间同步失败")
-            -- 10秒后重新发起同步动作
-            sys.wait(10000) 
-        end
-    end
-end
-
---创建并且启动一个task
---运行这个task的主函数sntp_task_func
-sys.taskInit(sntp_task_func)
-

+ 0 - 33
module/Air8000/demo/mqttv2/netdrv/netdrv_4g.lua

@@ -1,33 +0,0 @@
---[[
-@module  netdrv_4g
-@summary “4G网卡”驱动模块 
-@version 1.0
-@date    2025.07.01
-@author  朱天华
-@usage
-本文件为4G网卡驱动模块,核心业务逻辑为:
-1、监听"IP_READY"和"IP_LOSE",在日志中进行打印;
-
-本文件没有对外接口,直接在其他功能模块中require "netdrv_4g"就可以加载运行;
-]]
-
-local function ip_ready_func()
-    log.info("netdrv_4g.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_GP))
-end
-
-local function ip_lose_func()
-    log.warn("netdrv_4g.ip_lose_func", "IP_LOSE")
-end
-
-
-
---此处订阅"IP_READY"和"IP_LOSE"两种消息
---在消息的处理函数中,仅仅打印了一些信息,便于实时观察4G网络的连接状态
---也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
-sys.subscribe("IP_READY", ip_ready_func)
-sys.subscribe("IP_LOSE", ip_lose_func)
-
--- 设置默认网卡为socket.LWIP_GP
--- 在Air8000上,内核固件运行起来之后,默认网卡就是socket.LWIP_GP
--- 在单4G网卡使用场景下,下面这一行代码加不加都没有影响,为了和其他网卡驱动模块的代码风格保持一致,所以加上了
-socket.dft(socket.LWIP_GP)

+ 0 - 85
module/Air8000/demo/mqttv2/netdrv/netdrv_eth_spi.lua

@@ -1,85 +0,0 @@
---[[
-@module  netdrv_eth_spi
-@summary “通过SPI外挂CH390H芯片的以太网卡”驱动模块 
-@version 1.0
-@date    2025.07.24
-@author  朱天华
-@usage
-本文件为“通过SPI外挂CH390H芯片的以太网卡”驱动模块 ,核心业务逻辑为:
-1、打开CH390H芯片供电开关;
-2、初始化spi1,初始化以太网卡,并且在以太网卡上开启DHCP(动态主机配置协议);
-3、以太网卡的连接状态发生变化时,在日志中进行打印;
-
-直接使用Air8000开发板硬件测试即可;
-
-本文件没有对外接口,直接在其他功能模块中require "netdrv_eth_spi"就可以加载运行;
-]]
-
-local function ip_ready_func()
-    log.info("netdrv_eth_spi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_ETH))
-end
-
-local function ip_lose_func()
-    log.warn("netdrv_eth_spi.ip_lose_func", "IP_LOSE")
-end
-
-
-
---此处订阅"IP_READY"和"IP_LOSE"两种消息
---在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
---也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
-sys.subscribe("IP_READY", ip_ready_func)
-sys.subscribe("IP_LOSE", ip_lose_func)
-
-
--- 设置默认网卡为socket.LWIP_ETH
-socket.dft(socket.LWIP_ETH)
-
-
---本demo测试使用的是Air8000开发板
---GPIO140为CH390H以太网芯片的供电使能控制引脚
-gpio.setup(140, 1, gpio.PULLUP)
-
---这个task的核心业务逻辑是:初始化SPI,初始化以太网卡,并在以太网卡上开启动态主机配置协议
-local function netdrv_eth_spi_task_func()
-    -- 初始化SPI1
-    local result = spi.setup(
-        1,--spi_id
-        nil,
-        0,--CPHA
-        0,--CPOL
-        8,--数据宽度
-        25600000--,--频率
-        -- spi.MSB,--高低位顺序    可选,默认高位在前
-        -- spi.master,--主模式     可选,默认主
-        -- spi.full--全双工       可选,默认全双工
-    )
-    log.info("netdrv_eth_spi", "spi open result", result)
-    --返回值为0,表示打开成功
-    if result ~= 0 then
-        log.error("netdrv_eth_spi", "spi open error",result)
-        return
-    end
-
-    --初始化以太网卡
-
-    --以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
-    --各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    --以太网断网后,内核固件会产生一个"IP_LOSE"消息
-    --各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    -- socket.LWIP_ETH 指定网络适配器编号
-    -- netdrv.CH390外挂CH390
-    -- SPI ID 1, 片选 GPIO12
-    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=1, cs=12})
-
-    --在以太上开启动态主机配置协议
-    netdrv.dhcp(socket.LWIP_ETH, true)
-end
-
---创建并且启动一个task
---task的处理函数为netdrv_eth_spi_task_func
-sys.taskInit(netdrv_eth_spi_task_func)

+ 0 - 95
module/Air8000/demo/mqttv2/netdrv/netdrv_multiple.lua

@@ -1,95 +0,0 @@
---[[
-@module  netdrv_multiple
-@summary 多网卡(4G网卡、WIFI STA网卡、通过SPI外挂CH390H芯片的以太网卡)驱动模块 
-@version 1.0
-@date    2025.07.24
-@author  朱天华
-@usage
-本文件为多网卡驱动模块 ,核心业务逻辑为:
-1、调用exnetif.set_priority_order配置多网卡的控制参数以及优先级;
-
-直接使用Air8000开发板硬件测试即可;
-
-本文件没有对外接口,直接在其他功能模块中require "netdrv_multiple"就可以加载运行;
-]]
-
-
-local exnetif = require "exnetif"
-
--- 网卡状态变化通知回调函数
--- 当exnetif中检测到网卡切换或者所有网卡都断网时,会触发调用此回调函数
--- 当网卡切换切换时:
---     net_type:string类型,表示当前使用的网卡字符串
---     adapter:number类型,表示当前使用的网卡id
--- 当所有网卡断网时:
---     net_type:为nil
---     adapter:number类型,为-1
-local function netdrv_multiple_notify_cbfunc(net_type,adapter)
-    if type(net_type)=="string" then
-        log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
-    elseif type(net_type)=="nil" then
-        log.warn("netdrv_multiple_notify_cbfunc", "no available adapter", net_type, adapter)
-    else
-        log.warn("netdrv_multiple_notify_cbfunc", "unknown status", net_type, adapter)
-    end
-end
-
-local function netdrv_multiple_task_func()
-    --设置网卡优先级
-    exnetif.set_priority_order(
-        {
-            -- “通过SPI外挂CH390H芯片”的以太网卡,使用Air8000开发板验证
-            {
-                ETHERNET = {
-                    -- 供电使能GPIO
-                    pwrpin = 140,
-                    -- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
-                    -- 如果没有传入此参数,exnetif会使用默认值10秒
-                    ping_time = 3000,
-
-                    -- 连通性检测ip(选填参数);
-                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",     
-                    
-                    -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
-                    tp = netdrv.CH390, 
-                    opts = {spi=1, cs=12}
-                }
-            },
-
-            -- WIFI STA网卡
-            {
-                WIFI = {
-                    -- 要连接的WIFI路由器名称
-                    ssid = "茶室-降功耗,找合宙!",
-                    -- 要连接的WIFI路由器密码
-                    password = "Air123456", 
-
-                    -- 连通性检测ip(选填参数);
-                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
-                }
-            },
-
-            -- 4G网卡
-            {
-                LWIP_GP = true
-            }
-        }
-    )    
-end
-
--- 设置网卡状态变化通知回调函数netdrv_multiple_notify_cbfunc
-exnetif.notify_status(netdrv_multiple_notify_cbfunc)
-
--- 如果存在udp网络应用,并且udp网络应用中,根据应用层的心跳能够判断出来udp数据通信出现了异常;
--- 可以在判断出现异常的位置,调用一次exnetif.check_network_status()接口,强制对当前正式使用的网卡进行一次连通性检测;
--- 如果存在tcp网络应用,不需要用户调用exnetif.check_network_status()接口去控制,exnetif会在tcp网络应用通信异常时自动对当前使用的网卡进行连通性检测。
-
-
--- 启动一个task,task的处理函数为netdrv_multiple_task_func
--- 在处理函数中调用exnetif.set_priority_order设置网卡优先级
--- 因为exnetif.set_priority_order要求必须在task中被调用,所以此处启动一个task
-sys.taskInit(netdrv_multiple_task_func)

+ 0 - 50
module/Air8000/demo/mqttv2/netdrv/netdrv_wifi.lua

@@ -1,50 +0,0 @@
---[[
-@module  netdrv_wifi
-@summary “WIFI STA网卡”驱动模块 
-@version 1.0
-@date    2025.07.01
-@author  朱天华
-@usage
-本文件为WIFI STA网卡驱动模块,核心业务逻辑为:
-1、初始化WIFI网络;
-2、连接WIFI路由器;
-3、和WIFI路由器之间的连接状态发生变化时,在日志中进行打印;
-
-本文件没有对外接口,直接在其他功能模块中require "netdrv_wifi"就可以加载运行;
-]]
-
-local function ip_ready_func()
-    log.info("netdrv_wifi.ip_ready_func", "IP_READY", json.encode(wlan.getInfo()))
-end
-
-local function ip_lose_func()
-    log.warn("netdrv_wifi.ip_lose_func", "IP_LOSE")
-end
-
-
-
---此处订阅"IP_READY"和"IP_LOSE"两种消息
---在消息的处理函数中,仅仅打印了一些信息,便于实时观察WIFI的连接状态
---也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
-sys.subscribe("IP_READY", ip_ready_func)
-sys.subscribe("IP_LOSE", ip_lose_func)
-
-
--- 设置默认网卡为socket.LWIP_STA
-socket.dft(socket.LWIP_STA)
-
-
-wlan.init()
---连接WIFI热点,连接结果会通过"IP_READY"或者"IP_LOSE"消息通知
---Air8000仅支持2.4G的WIFI,不支持5G的WIFI
---此处前两个参数表示WIFI热点名称以及密码,更换为自己测试时的真实参数即可
---第三个参数1表示WIFI连接异常时,内核固件会自动重连
-wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1)
-
---WIFI联网成功(做为STATION成功连接AP,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
---各个功能模块可以订阅"IP_READY"消息实时处理WIFI联网成功的事件
---也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功
-
---WIFI断网后,内核固件会产生一个"IP_LOSE"消息
---各个功能模块可以订阅"IP_LOSE"消息实时处理WIFI断网的事件
---也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功

+ 0 - 33
module/Air8000/demo/mqttv2/netdrv_device.lua

@@ -1,33 +0,0 @@
---[[
-@module  netdrv_device
-@summary 网络驱动设备功能模块 
-@version 1.0
-@date    2025.07.24
-@author  朱天华
-@usage
-本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
-1、netdrv_4g:socket.LWIP_GP,4G网卡;
-2、netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-3、netdrv_ethernet_spi:socket.LWIP_USER1,通过SPI外挂CH390H芯片的以太网卡;
-4、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
-
-根据自己的项目需求,只需要require以上四种中的一种即可;
-
-
-本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
-]]
-
-
--- 根据自己的项目需求,只需要require以下四种中的一种即可;
-
--- 加载“4G网卡”驱动模块
-require "netdrv_4g"
-
--- 加载“WIFI STA网卡”驱动模块
--- require "netdrv_wifi"
-
--- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
--- require "netdrv_eth_spi"
-
--- 加载“可以配置优先级的多种网卡”驱动模块
--- require "netdrv_multiple"

+ 0 - 64
module/Air8000/demo/mqttv2/network_watchdog.lua

@@ -1,64 +0,0 @@
---[[
-@module  network_watchdog
-@summary 网络环境检测看门狗功能模块 
-@version 1.0
-@date    2025.07.23
-@author  朱天华
-@usage
-本文件为网络环境检测看门狗功能模块,监控网络环境是否工作正常(设备和服务器双向通信正常,或者至少单向通信正常),核心业务逻辑为:
-1、启动一个网络环境检测看门狗task,等待其他mqtt网络应用功能模块来喂狗,如果喂狗超时,则控制软件重启;
-2、如何确定“喂狗超时时间”,一般来说,有以下几个原则;
-   (1) 先确定一个最小基准值T1,2分钟或者5分钟或者10分钟,这个取值取决于具体项目需求,但是不能太短,因为开机后,在网络环境不太好的地方,网络初始化可能需要比较长的时间,一般推荐这个值不能小于2分钟;
-   (2) 再确定一个和产品业务逻辑有关的一个值T2,这个值和产品的应用业务逻辑息息相关,假设你的产品业务中:
-       <1> 服务器会定时下发数据给设备,例如设备连接上业务服务器之后,每隔3分钟,设备都会给服务器发送一次心跳,然后服务器都会立即回复一个心跳应答包;
-           这种情况下,可以取3分钟的大于等于1的倍数(例如1倍,1.5倍,2倍等等)+一段时间(例如10秒钟,如果前面是1倍,则此处必须加一段时间,给网络数据传输过程留够充足的时间);
-       <2> mqtt本身有keep alive的心跳机制,例如设备连接上业务服务器之后,默认每隔2分钟,设备都会给服务器发送一次心跳,服务器也会回复一个心跳应答数据;
-           这种情况下,可以取2分钟的大于等于1的倍数(例如1倍,1.5倍,2倍等等)+一段时间(例如10秒钟,如果前面是1倍,则此处必须加一段时间,给网络数据传输过程留够充足的时间);
-    (3) 取T1和T2的最大值,就是“喂狗超时时间”
-3、其他mqtt网络业务功能模块的喂狗时机,和上面2.2的描述相对应,一般来说,可以在以下几种时间点执行喂狗动作:
-   (1) 设备收到服务器下发的数据时
-   (2) 设备收到服务器回复的mqtt心跳应答数据时
-4、最重要的一点是:以上所说的原则,仅仅是建议,要根据自己的实际项目业务逻辑以及自己的需求最终确定看门狗方案
-
-5、具体到本demo
-   (1) 产品业务逻辑为:
-       <1> 创建了一个mqtt连接,设备每隔5秒钟发送一次数据到服务器,服务器何时下发应用数据给设备不确定;
-       <2> 创建了一个mqtt ssl、不需要证书校验的连接,设备每隔5秒钟发送一次数据到服务器,服务器何时下发应用数据给设备不确定;
-       <3> 创建了一个mqtt ssl、client单向校验server证书的连接,设备每隔5秒钟发送一次数据到服务器,服务器何时下发应用数据给设备不确定;
-       <4> 每隔3分钟,这三路mqtt连接都会发送一次mqtt心跳给server,server收到心跳后回复心跳应答给client;
-   (2) 确定喂狗超时时间:
-       <1> 本demo支持单WIFI、单以太网、单4G网络连接外网,网络环境准备就绪预留2分钟的时间已经足够,所以最小基准值T1取值2分钟;
-       <2> 本demo中存在3路mqtt连接,但是这3路mqtt连接都没有定时或者至少一段时间,服务器下发应用数据给设备,所以无法基于服务器下发应用数据的业务逻辑来确定T2的值;
-       <3> 本demo中存在3路mqtt连接,每1路mqtt连接,设备都是3分钟发送一次mqtt心跳数据给服务器,服务器收到后会立即回复一个mqtt心跳应答数据给设备;
-           所以可以通过3分钟的大于等于1的倍数(例如1倍,1.5倍,2倍等等)+一段时间(例如10秒钟,如果前面是1倍,则此处必须加一段时间,给网络数据传输过程留够充足的时间)来确定T2的值;
-           在这个demo中,我能接受的网络连续异常时长是5分钟,所以,T2取值5分钟;
-       <4> 取T1 2分钟和T2 5分钟的最大值,最终的喂狗超时时间就是5分钟;
-   (3) 确定喂狗时机:
-       <1> 3路mqtt连接中,任何1路收到服务器的下发的应用数据时;       
-       <2> 3路mqtt连接中,任何1路收到服务器的回复的心跳应答数据时;
-6、本demo设计的网络环境检测看门狗功能模块,可以检测以下两种种的任意一种网络环境异常:
-   (1) 网络环境连续超过5分钟没有准备就绪   
-   (2) mqtt、mqtt ssl、mqtt ssl单向校验证书3路连接中,连续5分钟没有收到服务器下发的应用数据或者服务器回复的心跳应答数据; 
-      
-
-本文件没有对外接口,直接在main.lua中require "network_watchdog"就可以加载运行;
-外部功能模块喂狗时,直接调用sys.publish("FEED_NETWORK_WATCHDOG")
-]]
-
--- 网络环境检测看门狗task处理函数
-local function network_watchdog_task_func()
-    while true do
-        --如果等待180秒没有等到"FEED_NETWORK_WATCHDOG"消息,则看门狗超时
-        if not sys.waitUntil("FEED_NETWORK_WATCHDOG", 300000) then            
-            log.error("network_watchdog_task_func timeout")
-            -- 等待3秒钟,然后软件重启
-            sys.wait(3000)
-            rtos.reboot()
-        end
-    end
-end
-
---创建并且启动一个task
---运行这个task的处理函数network_watchdog_task_func
-sys.taskInit(network_watchdog_task_func)
-

+ 0 - 144
module/Air8000/demo/mqttv2/readme.md

@@ -1,144 +0,0 @@
-## 功能模块介绍
-
-1、main.lua:主程序入口;
-
-2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的四种网卡(单4g网卡,单wifi网卡,单spi以太网卡,多网卡)中的任何一种网卡;
-
-3、mqtt文件夹:mqtt client连接以及数据收发处理逻辑;
-
-4、mqtts文件夹:mqtt ss client(不支持证书校验)连接以及数据收发处理逻辑;
-
-5、mqtts_ca文件夹:mqtt ss client(仅单向校验server端证书)连接以及数据收发处理逻辑;
-
-6、network_watchdog.lua:网络环境检测看门狗;
-
-7、timer_app.lua:通知三个mqtt client定时发送数据到服务器;
-
-8、uart_app.lua:在三个mqtt client和uart外设之间透传数据;
-
-
-
-## 系统消息介绍
-
-1、"IP_READY":某种网卡已经获取到ip信息,仅仅获取到了ip信息,能否和外网连通还不确认;
-
-2、"IP_LOSE":某种网卡已经掉网;
-
-
-
-## 用户消息介绍
-
-1、"RECV_DATA_FROM_SERVER":mqtt client收到服务器下发的publish数据后,通过此消息发布出去,给其他应用模块(uart_app)处理;
-
-2、"SEND_DATA_REQ":其他应用模块(uart_app,timer_app)发布此消息,通知mqtt client发送publish数据给服务器;
-
-3、"FEED_NETWORK_WATCHDOG":网络环境检测看门狗的喂狗消息,在需要喂狗的地方发布此消息;
-
-
-
-## 演示功能概述
-
-1、创建三路mqtt连接,详情如下
-
-- 创建一个mqtt client,连接mqtt server;
-
-- 创建一个mqtt ssl client,连接mqtt ssl server,不做证书校验;
-
-- 创建一个mqtt ssl client,连接mqtt ssl server,client仅单向校验server的证书,server不校验client的证书和密钥文件;
-
-2、每一路mqtt连接出现异常后,自动重连;
-
-3、每一路mqtt连接,client按照以下几种逻辑发送数据给server
-
-- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后,使用mobile.imei().."/uart/up"主题,发送给server;
-
-- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer:前缀后,使用mobile.imei().."/timer/up"主题,发送给server;
-
-4、每一路mqtt连接,client收到server数据后,将数据增加recv from mqtt/mqtt ssl/mqtt ssl ca(三选一)server: 前缀后,通过uart1发送出去;
-
-5、启动一个网络业务逻辑看门狗task,用来监控网络环境,如果连续长时间工作不正常,重启整个软件系统;
-
-6、netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
-
-   (1) netdrv_4g:4G网卡
-
-   (2) netdrv_wifi:WIFI STA网卡
-
-   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
-
-   (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
-
-
-
-## 演示硬件环境
-
-![](https://docs.openluat.com/air8000/luatos/app/image/netdrv_multi.jpg)
-
-1、Air8000开发板一块+可上网的sim卡一张+4g天线一根+wifi天线一根+网线一根:
-
-- sim卡插入开发板的sim卡槽
-
-- 天线装到开发板上
-
-- 网线一端插入开发板网口,另外一端连接可以上外网的路由器网口
-
-2、TYPE-C USB数据线一根 + USB转串口数据线一根,Air8000开发板和数据线的硬件接线方式为:
-
-- Air8000开发板通过TYPE-C USB口供电;(外部供电/USB供电 拨动开关 拨到 USB供电一端)
-
-- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
-
-- USB转串口数据线,一般来说,白线连接开发板的UART1_TX,绿线连接开发板的UART1_RX,黑线连接核心板的GND,另外一端连接电脑USB口;
-
-
-## 演示软件环境
-
-1、Luatools下载调试工具
-
-2、[Air8000 V2011版本固件)](https://docs.openluat.com/air8000/luatos/firmware/)(理论上,2025年7月26日之后发布的固件都可以)
-
-3、PC端的串口工具,例如SSCOM、LLCOM等都可以
-
-4、[MQTT客户端软件MQTTX](https://docs.openluat.com/air8000/luatos/common/swenv/#27-mqttmqttx)
-
-
-## 演示核心步骤
-
-1、搭建好硬件环境
-
-2、demo脚本代码netdrv_device.lua中,按照自己的网卡需求启用对应的Lua文件
-
-- 如果需要单4G网卡,打开require "netdrv_4g",其余注释掉
-
-- 如果需要单WIFI STA网卡,打开require "netdrv_wifi",其余注释掉;同时netdrv_wifi.lua中的wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1),前两个参数,修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
-
-- 如果需要以太网卡,打开require "netdrv_eth_spi",其余注释掉
-
-- 如果需要多网卡,打开require "netdrv_multiple",其余注释掉;同时netdrv_multiple.lua中的ssid = "茶室-降功耗,找合宙!", password = "Air123456", 修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
-
-3、Luatools烧录内核固件和修改后的demo脚本代码
-
-4、烧录成功后,自动开机运行,如果出现以下日志,表示三路mqtt连接成功
-
-``` lua
-I/user.mqtt_client_main_task_func connect success
-
-I/user.mqtts_client_main_task_func connect success
-
-I/user.mqtts_ca__client_main_task_func connect success
-```
-
-5、启动两个MQTTX工具,分别连接上mqtt client和mqtts client对应的server,订阅$imei/up主题,$imei表示设备的imei号;
-   可以看到,每隔5秒钟,会接收到一段类似于 send from timer: 1 的数据,最后面的数字每次加1;
-
-6、打开PC端的串口工具,选择对应的端口,配置波特率115200,数据位8,停止位1,无奇偶校验位;
-
-7、PC端的串口工具输入一段数据,点击发送,在MQTTX工具订阅的$imei/up主题下可以接收到数据;
-
-8、在MQTTX工具上,在主题$imei/down下publish一段数据,点击发送,在PC端的串口工具上可以接收到主题和数据,并且也能看到是哪一个server发送的,类似于以下效果:
-
-``` lua
-recv from mqtt server: 864793080144269/down,123456798012345678901234567830
-recv from mqtt ssl server: 864793080144269/down,123456798012345678901234567830
-recv from mqtt ca ssl server: 864793080144269/down,123456798012345678901234567830
-```

+ 0 - 44
module/Air8000/demo/mqttv2/timer_app.lua

@@ -1,44 +0,0 @@
---[[
-@module  timer_app
-@summary 定时器应用功能模块 
-@version 1.0
-@date    2025.07.01
-@author  朱天华
-@usage
-本文件为定时器应用功能模块,核心业务逻辑为:
-创建一个5秒的循环定时器,每次产生一段数据,通知三个mqtt client进行处理;
-
-本文件的对外接口有一个:
-1、sys.publish("SEND_DATA_REQ", "timer", mobile.imei().."/timer/up", payload, 0, {func=send_data_cbfunc, para="timer"..payload})
-   通过publish通知三路mqtt client数据发送功能模块publish数据;
-   数据发送结果通过执行回调函数send_data_cbfunc通知本功能模块;
-]]
-
-local payload = 1
-
--- 数据发送结果回调函数
--- result:发送结果,true为发送成功,false为发送失败
--- para:回调参数,sys.publish("SEND_DATA_REQ", "timer", mobile.imei().."/timer/up", payload, 0, {func=send_data_cbfunc, para="timer"..payload})中携带的para
-local function send_data_cbfunc(result, para)
-    log.info("send_data_cbfunc", result, para)
-    -- 无论上一次发送成功还是失败,启动一个5秒的定时器,5秒后发送下次数据
-    sys.timerStart(send_data_req_timer_cbfunc, 5000)
-end
-
--- 定时器回调函数
-function send_data_req_timer_cbfunc()
-    -- 发布消息"SEND_DATA_REQ"
-    -- 携带的第一个参数"timer"表示是定时器应用模块发布的消息
-    -- 携带的第二个参数mobile.imei().."/timer/up"为要publish的topic
-    -- 携带的第三个参数payload为要publish的payload
-    -- 携带的第四个参数0为publish的qos
-    -- 携带的第五个参数cb为发送结果回调(可以为空,如果为空,表示不关心mqtt client发送数据成功还是失败),其中:
-    --       cb.func为回调函数(可以为空,如果为空,表示不关心mqtt client发送数据成功还是失败)
-    --       cb.para为回调函数的第二个参数(可以为空),回调函数的第一个参数为发送结果(true表示成功,false表示失败)
-    sys.publish("SEND_DATA_REQ", "timer", mobile.imei().."/timer/up", payload, 0, {func=send_data_cbfunc, para="timer"..payload})
-    payload = payload+1
-end
-
--- 启动一个5秒的单次定时器
--- 时间到达后,执行一次send_data_req_timer_cbfunc函数
-sys.timerStart(send_data_req_timer_cbfunc, 5000)

+ 0 - 80
module/Air8000/demo/mqttv2/uart_app.lua

@@ -1,80 +0,0 @@
---[[
-@module  uart_app
-@summary 串口应用功能模块 
-@version 1.0
-@date    2025.07.28
-@author  朱天华
-@usage
-本文件为串口应用功能模块,核心业务逻辑为:
-1、打开uart1,波特率115200,数据位8,停止位1,无奇偶校验位;
-2、uart1和pc端的串口工具相连;
-3、从uart1接收到pc端串口工具发送的数据后,通知三个mqtt client进行处理;
-4、收到三个mqtt client从socket server接收到的数据后,将数据通过uart1发送到pc端串口工具;
-
-本文件的对外接口有两个:
-1、sys.publish("SEND_DATA_REQ", "uart", mobile.imei().."/uart/up", read_buf, 1)
-   通知mqtt client数据发送模块,在mobile.imei().."/uart/up"的topic上publish数据read_buf,不关心数据发送成功还是失败;
-2、sys.subscribe("RECV_DATA_FROM_SERVER", recv_data_from_server_proc),订阅RECV_DATA_FROM_SERVER消息,处理消息携带的数据;
-]]
-
-
--- 使用UART1
-local UART_ID = 1
--- 串口接收数据缓冲区
-local read_buf = ""
-
--- 将前缀prefix和topic,payload数据拼接
--- 然后末尾增加回车换行两个字符,通过uart发送出去,方便在PC端换行显示查看
-local function recv_data_from_server_proc(prefix, topic, payload)
-    uart.write(UART_ID, prefix..topic..","..payload.."\r\n")
-end
-
-
-local function concat_timeout_func()
-    -- 如果存在尚未处理的串口缓冲区数据;
-    -- 将数据通过publish通知其他应用功能模块处理;
-    -- 然后清空本文件的串口缓冲区数据
-    if read_buf:len() > 0 then
-        sys.publish("SEND_DATA_REQ", "uart", mobile.imei().."/uart/up", read_buf, 1)
-        read_buf = ""
-    end
-end
-
-
--- UART1的数据接收中断处理函数,UART1接收到数据时,会执行此函数
-local function read()
-    local s
-    while true do
-        -- 非阻塞读取UART1接收到的数据,最长读取1024字节
-        s = uart.read(UART_ID, 1024)
-        
-        -- 如果从串口没有读到数据
-        if not s or s:len() == 0 then
-            -- 启动50毫秒的定时器,如果50毫秒内没收到新的数据,则处理当前收到的所有数据
-            -- 这样处理是为了防止将一大包数据拆分成多个小包来处理
-            -- 例如pc端串口工具下发1100字节的数据,可能会产生将近20次的中断进入到read函数,才能读取完整
-            -- 此处的50毫秒可以根据自己项目的需求做适当修改,在满足整包拼接完整的前提下,时间越短,处理越及时
-            sys.timerStart(concat_timeout_func, 50)
-            -- 跳出循环,退出本函数
-            break
-        end
-
-        log.info("uart_app.read len", s:len())
-        -- log.info("uart_app.read", s)
-
-        -- 将本次从串口读到的数据拼接到串口缓冲区read_buf中
-        read_buf = read_buf..s
-    end
-end
-
-
-
--- 初始化UART1,波特率115200,数据位8,停止位1
-uart.setup(UART_ID, 115200, 8, 1)
-
--- 注册UART1的数据接收中断处理函数,UART1接收到数据时,会执行read函数
-uart.on(UART_ID, "receive", read)
-
--- 订阅"RECV_DATA_FROM_SERVER"消息的处理函数recv_data_from_server_proc
--- 收到"RECV_DATA_FROM_SERVER"消息后,会执行函数recv_data_from_server_proc
-sys.subscribe("RECV_DATA_FROM_SERVER", recv_data_from_server_proc)

+ 71 - 0
module/Air8000/demo/rndis_ecm/main.lua

@@ -0,0 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+演示功能概述
+RNDIS是指Remote NDIS,基于USB实现RNDIS实际上就是TCP/IP over USB,就是在USB设备上跑TCP/IP,让USB设备看上去像一块网卡。从而使Windows /Linux可以通过 USB 设备连接网络。
+ECM(Ethernet Control Model)是一种基于 USB 的通信设备类(CDC)子类协议,它将 “TCP/IP over USB” 抽象成一条虚拟以太网链路:USB 设备端实现 ECM 功能后,会在主机侧呈现为一块标准的以太网卡(如 usb0)。主机操作系统(Linux、macOS 等)无需额外专用驱动,即可通过该虚拟网卡发送/接收以太网帧,从而经 USB 设备连接到网络。
+1、功能使用说明
+由于 Air8000 只支持 LUATOS 模式,且 RNDIS 网卡应用默认关闭,所以在使用 RNIDS 之前,需要使用接口打开,本demo将为大家讲解如何使用 RNIDS 功能。
+本demo仅演示在 Windows系统上运行 RNDIS 功能,如果需要在 Linux系统上使用功能,请查看文档:xxxxxxxxx
+2、ECM 功能说明
+由于Windows系统没有测试环境无法测试 ECM 功能,所以 open_ecm.lua 没有完整测试。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+更多说明参考本目录下的readme.md文件
+]]
+PROJECT = "RNDIS_ECM"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- 加载 open_rndis 主应用功能模块
+require "open_rndis"
+
+-- 加载 open_ecm 主应用功能模块
+-- require "open_ecm"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 41 - 0
module/Air8000/demo/rndis_ecm/open_ecm.lua

@@ -0,0 +1,41 @@
+--[[
+@module  open_ecm
+@summary ecm 服务启动功能模块
+@version 1.0
+@date    2025.08.26
+@author  拓毅恒
+@usage
+用法实例
+
+启动 ECM 服务
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+注:由于Windows系统没有测试环境无法测试 ECM 功能,所以本demo没有完整测试。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_ecm" 即可加载运行。
+]]
+
+-- 运行 ECM 模式任务
+local function ecm_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开ECM模式")
+        -- 调用 mobile.config 函数启用 ECM 功能
+        -- 传入的第二个参数 7 ,实际为二进制的 0111
+        -- 蜂窝网络模块的usb以太网卡控制,bit0开关,1开0关,bit1模式,1NAT0独立IP(在usb以太网卡开启前可以修改,开启过就不行),bit2协议1 ECM,0 RNDIS,飞行模式里设置。
+        log.info("我看看 ECM 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 7))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 ecm_task 函数
+sys.taskInit(ecm_task)

+ 39 - 0
module/Air8000/demo/rndis_ecm/open_rndis.lua

@@ -0,0 +1,39 @@
+--[[
+@module  open_rndis
+@summary rndis 服务启动功能模块
+@version 1.0
+@date    2025.08.25
+@author  拓毅恒
+@usage
+用法实例
+
+启动 RNDIS 服务
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+本文件没有对外接口,直接在 main.lua 中 require "open_rndis" 即可加载运行。
+]]
+
+-- 运行 RNDIS 模式任务
+local function rndis_task()
+    -- 初始化重试计数器,用于记录进入飞行模式失败的重试次数
+    local count = 0
+    -- 尝试进入飞行模式,获取操作结果标志
+    local fly_sign = mobile.flymode(0, true)
+    -- 判断是否成功进入飞行模式
+    if fly_sign then
+        log.info("进入飞行模式成功,打开RNDIS模式")
+        -- 调用 mobile.config 函数启用 RNDIS 功能
+        log.info("我看看 RNDIS 是否启动成功:", mobile.config(mobile.CONF_USB_ETHERNET, 3))
+        log.info("退出飞行模式")
+        mobile.flymode(0, false)
+    else
+        log.info("进入飞行模式失败")
+    end
+end
+
+-- 初始化一个系统任务,执行 rndis_task 函数
+sys.taskInit(rndis_task)

+ 112 - 0
module/Air8000/demo/rndis_ecm/readme.md

@@ -0,0 +1,112 @@
+## 演示功能概述
+
+本demo支持两种基于USB的网络连接模式:RNDIS和ECM。
+
+- **RNDIS**(Remote NDIS):基于USB实现的TCP/IP over USB,让USB设备在Windows系统上呈现为一块网卡,从而使Windows/Linux可以通过USB设备连接网络。
+
+- **ECM**(Ethernet Control Model):一种基于USB的通信设备类(CDC)子类协议,将"TCP/IP over USB"抽象成一条虚拟以太网链路,在主机侧呈现为一块标准的以太网卡。Linux、macOS等操作系统无需额外专用驱动即可使用。
+
+#### 1、功能使用说明
+
+本demo已将功能拆分为三个文件:
+- `main.lua`:主入口文件,负责加载和调度各个功能模块
+- `open_rndis.lua`:RNDIS功能实现模块
+- `open_ecm.lua`:ECM功能实现模块
+
+由于 Air8000 只支持 LUATOS 模式,且RNDIS/ECM网卡应用默认关闭,需要使用接口打开。
+
+**注意:**
+- 本demo在Windows系统上主要测试RNDIS功能
+- ECM功能由于Windows系统缺少测试环境,无法在Windows上完整测试
+
+#### 2、启动 RNDIS 服务
+
+- 运行 rndis_task 任务,来执行开启 RNDIS 的操作。
+
+- RNDIS 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 3) 来启用 RNDIS 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 3)
+传入的第二个参数 3 ,实际为二进制的 0011
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为0,则开启RNDIS模式。
+
+#### 3、启动 ECM 服务
+
+- 运行 ecm_task 任务,来执行开启 ECM 的操作。
+
+- ECM 需要在飞行模式下开启,所以首先进入飞行模式。
+
+- 进入飞行模式后,使用 mobile.config(mobile.CONF_USB_ETHERNET, 7) 来启用 ECM 功能。
+
+> 函数讲解:mobile.config(mobile.CONF_USB_ETHERNET, 7)
+传入的第二个参数 7 ,实际为二进制的 0111
+从右往前数第0个bit位为1,则开启USB以太网卡控制,第一个bit位为1,则使用NAT模式(基站分配ip),第二个bit位为1,则开启ECM模式。
+
+> 特别说明:由于Windows系统缺少测试环境,ECM功能无法在Windows系统上完整测试。在Linux、macOS等系统上可能需要不同的配置和测试方法。
+>
+>注:在v2013以下固件使用mobile.config()的返回值有bug,无论是否开启成功,返回值均为false,需要烧录V2013及以上固件才能完整验证此功能。
+
+#### 4、运行效果
+
+- **飞行模式进入成功**:日志打印 “进入飞行模式成功”
+
+- **RNDIS 创建成功**:日志中会打印“我看看 RNDIS 是否启动成功: true”,并且在电脑网络上显示出RNDIS联网图标。
+
+- **ECM 创建**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。在日志中会打印“我看看 ECM 是否启动成功: [结果]”,但无法在Windows系统上验证网络连接状态。
+
+> **注意**:在main.lua中,RNDIS和ECM功能默认只启用了RNDIS。如需测试ECM功能,请修改main.lua文件,注释掉`require "open_rndis"`并取消注释`require "open_ecm"`
+
+## 演示硬件环境
+
+1、Air8000核心板/开发板一块
+
+2、配套天线一套
+
+3、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 版本固件](https://docs.openluat.com/air8000/luatos/firmware/)(V2013以下固件使用mobile.config()的返回值有bug,需要烧录V2013及以上固件才能完整验证此demo)
+
+3、确保插入的sim卡可以正常上网。
+
+## 演示核心步骤
+
+### RNDIS功能测试步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中(默认启用RNDIS功能)
+
+3、烧录好后,板子开机同时在luatools上查看日志,确认是否进入飞行模式、RNDIS是否启用成功。
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开RNDIS模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 RNDIS 是否启动成功: true
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、日志提示成功后,可以在**Windows** → **设备管理器** → **网络适配器** 中查看是否有 **“Remote NDIS based Internet Sharing Device”** 来确认 RNDIS是否开启成功,如果被禁用请手动开启。
+
+### ECM功能测试说明
+
+1、**修改配置**:在测试ECM功能前,需要修改main.lua文件,注释掉`require = "open_rndis"`并取消注释`require = "open_ecm"`
+
+2、**烧录程序**:通过Luatools将修改后的demo与固件烧录到核心板中
+
+3、**查看日志**:板子开机后在luatools上查看日志,确认是否进入飞行模式、ECM是否尝试启动
+
+`
+[2025-08-22 09:55:54.459][000000000.210] I/user.main RNDIS_ECM 1.0.0
+[2025-08-22 09:55:54.529][000000000.661] I/user.进入飞行模式成功,打开ECM模式
+[2025-08-22 09:55:54.533][000000000.661] I/user.我看看 ECM 是否启动成功: [结果]
+[2025-08-22 09:55:54.649][000000000.815] I/user.退出飞行模式 false
+
+`
+
+4、**特别说明**:由于Windows系统缺少测试环境,ECM功能在Windows系统上无法完整测试。即使日志显示ECM启动成功,也无法在Windows系统上验证网络连接状态。ECM功能主要适用于Linux、macOS等操作系统。

+ 1 - 1
module/Air8000/demo/socket/client/long_connection/netdrv/netdrv_wifi.lua

@@ -39,7 +39,7 @@ wlan.init()
 --Air8000仅支持2.4G的WIFI,不支持5G的WIFI
 --此处前两个参数表示WIFI热点名称以及密码,更换为自己测试时的真实参数即可
 --第三个参数1表示WIFI连接异常时,内核固件会自动重连
-wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1)
+wlan.connect("iPhone", "xiaoshuai", 1)
 
 --WIFI联网成功(做为STATION成功连接AP,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
 --各个功能模块可以订阅"IP_READY"消息实时处理WIFI联网成功的事件

+ 2 - 2
module/Air8000/demo/socket/client/long_connection/netdrv_device.lua

@@ -21,7 +21,7 @@
 -- 根据自己的项目需求,只需要require以下四种中的一种即可;
 
 -- 加载“4G网卡”驱动模块
-require "netdrv_4g"
+-- require "netdrv_4g"
 
 -- 加载“WIFI STA网卡”驱动模块
 -- require "netdrv_wifi"
@@ -30,4 +30,4 @@ require "netdrv_4g"
 -- require "netdrv_eth_spi"
 
 -- 加载“可以配置优先级的多种网卡”驱动模块
--- require "netdrv_multiple"
+require "netdrv_multiple"

+ 1 - 1
module/Air8000/demo/socket/client/long_connection/tcp/tcp_client_main.lua

@@ -24,7 +24,7 @@ local tcp_client_sender = require "tcp_client_sender"
 -- 点击 打开TCP 按钮,会创建一个TCP server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 42610
+local SERVER_PORT = 42145
 
 -- tcp_client_main的任务名
 local TASK_NAME = tcp_client_sender.TASK_NAME

+ 1 - 1
module/Air8000/demo/socket/client/long_connection/tcp_ssl/tcp_ssl_main.lua

@@ -24,7 +24,7 @@ local tcp_ssl_sender = require "tcp_ssl_sender"
 -- 点击 打开TCP SSL 按钮,会创建一个TCP SSL server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 42429
+local SERVER_PORT = 43428 
 
 -- tcp_ssl_main的任务名
 local TASK_NAME = tcp_ssl_sender.TASK_NAME

+ 1 - 1
module/Air8000/demo/socket/client/long_connection/udp/udp_client_main.lua

@@ -24,7 +24,7 @@ local udp_client_sender = require "udp_client_sender"
 -- 点击 打开UDP 按钮,会创建一个UDP server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 46819
+local SERVER_PORT = 47708 
 
 -- udp_client_main的任务名
 local TASK_NAME = udp_client_sender.TASK_NAME

+ 0 - 142
module/Air8000/demo/tcp/TCP-UART/main.lua

@@ -1,142 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 43919                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-              local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-               if len <= 0 then    -- 接收到的字节长度为0 则退出
-                   break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                   sys_send(taskName, socket.EVENT, 0)
-                end
-                break
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 145
module/Air8000/demo/tcp/TCP单向认证/main.lua

@@ -1,145 +0,0 @@
--- main.lua文件
-
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46428            -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = true                     -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 141
module/Air8000/demo/tcp/TCP断链续连/main.lua

@@ -1,141 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_tcp"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-sys = require("sys")
-
-_G.sysplus = require("sysplus")
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46244                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 130
module/Air8000/demo/udp/main.lua

@@ -1,130 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "scdemo"
-VERSION = "1.0.0"
-log.info("main", PROJECT, VERSION)
--- 一定要添加sys.lua !!!!
-sys = require("sys")
-_G.sysplus = require("sysplus")
-local taskName = "UDP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-----------------------------网络配置---------------------------
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接UDP服务器的ip地址
-local port = 46139                      -- 连接UDP服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = true                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)     -- 发送至UDP服务器的数据
-local rx_buff = zbuff.create(1024)     -- 从UDP服务器接收到的数据
---==============================================================
---Uart初始化  
-local uartid = 1 -- 根据实际设备选取不同的uartid
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-function UDP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    -- 串口和UDP服务器的交互逻辑
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl) -- 此配置为UDP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        local result = libnet.connect(taskName, 15000, socket_client, ip, port)
-        -----查询网络状态
-        local status = mobile.status()    
-        log.info("status", status) 
-        
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        log.info("connect ip: 等待连接 ",result)
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            log.info("connect ip: 连接成功")
-            connect_state = true
-           libnet.tx(taskName, 0, socket_client, "UDP CONNECT")
-        end
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-               uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给UDP待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(taskName, 5000, socket_client)
-        socket.release(netc)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-end
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(UDP_TASK, taskName, tcp_client_main_cbfunc)
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 1 - 1
module/Air8000/project/整机开发板出厂工程/user/aircamera.lua

@@ -162,7 +162,7 @@ local function aircamera_ui()
 end
 
 function aircamera.run()
-    log.info("aircamera.run")
+    log.info("aircamera.run")   
     while true do
         if aircamera_ui() then
             return true

+ 2 - 2
module/Air8101/demo/socket/client/long_connection/netdrv_device.lua

@@ -22,7 +22,7 @@
 -- 根据自己的项目需求,只需要require以下五种中的一种即可;
 
 -- 加载“WIFI STA网卡”驱动模块
-require "netdrv_wifi"
+-- require "netdrv_wifi"
 
 -- 加载“通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡”驱动模块
 -- require "netdrv_eth_rmii"
@@ -31,7 +31,7 @@ require "netdrv_wifi"
 -- require "netdrv_eth_spi"
 
 -- 加载“通过SPI外挂4G模组的4G网卡”驱动模块
--- require "netdrv_4G"
+require "netdrv_4g"
 
 -- 加载“可以配置优先级的多种网卡”驱动模块
 -- require "netdrv_multiple"

+ 1 - 1
module/Air8101/demo/socket/client/long_connection/tcp/tcp_client_main.lua

@@ -24,7 +24,7 @@ local tcp_client_sender = require "tcp_client_sender"
 -- 点击 打开TCP 按钮,会创建一个TCP server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 43582
+local SERVER_PORT = 43187
 
 -- tcp_client_main的任务名
 local TASK_NAME = tcp_client_sender.TASK_NAME

+ 1 - 1
module/Air8101/demo/socket/client/long_connection/tcp_ssl/tcp_ssl_main.lua

@@ -24,7 +24,7 @@ local tcp_ssl_sender = require "tcp_ssl_sender"
 -- 点击 打开TCP SSL 按钮,会创建一个TCP SSL server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 43312
+local SERVER_PORT = 46909  
 
 -- tcp_ssl_main的任务名
 local TASK_NAME = tcp_ssl_sender.TASK_NAME

+ 1 - 1
module/Air8101/demo/socket/client/long_connection/udp/udp_client_main.lua

@@ -24,7 +24,7 @@ local udp_client_sender = require "udp_client_sender"
 -- 点击 打开UDP 按钮,会创建一个UDP server
 -- 将server的地址和端口赋值给下面这两个变量
 local SERVER_ADDR = "112.125.89.8"
-local SERVER_PORT = 46392
+local SERVER_PORT = 45468  
 
 -- udp_client_main的任务名
 local TASK_NAME = udp_client_sender.TASK_NAME

+ 0 - 161
module/Air8101/demo/tcp/TCP_Uart/main.lua

@@ -1,161 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "Wifi_TCP_Uart"
-VERSION = "1.0.0"
-
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-local uartid = 1 -- 根据实际设备选取不同的uartid    
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46646             -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-local data_buf
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-sys.taskInit(function()
-    sys.wait(1000)
-    -----------------------------
-    ---------wifi 联网-----------
-    -----------------------------
-    if wlan and wlan.connect then
-        -- wifi 联网, ESP32系列均支持
-        local ssid = "test"
-        local password = "waljy2333"
-        log.info("wifi", ssid, password)
-        -- TODO 改成esptouch配网
-        -- LED = gpio.setup(12, 0, gpio.PULLUP)
-        wlan.init()
-        wlan.setMode(wlan.STATION)
-        wlan.connect(ssid, password, 1)
-        local result, data = sys.waitUntil("IP_READY")
-        log.info("wlan", "IP_READY", result, data)
-        device_id = wlan.getMac()
-    end
-    log.info("已联网")
-    sys.publish("net_ready")
-end)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-              local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-               if len <= 0 then    -- 接收到的字节长度为0 则退出
-                   break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                   sys_send(taskName, socket.EVENT, 0)
-                end
-                break
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
-
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 164
module/Air8101/demo/tcp/TCP单向认证/main.lua

@@ -1,164 +0,0 @@
--- main.lua文件
-
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "Wifi_TCP_Uart"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 46428            -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = true                     -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-sys.taskInit(function()
-    sys.wait(1000)
-    -----------------------------
-    ---------wifi 联网-----------
-    -----------------------------
-if wlan and wlan.connect then
-        -- wifi 联网, ESP32系列均支持
-        local ssid = "test"
-        local password = "waljy2333"
-        log.info("wifi", ssid, password)
-        -- TODO 改成esptouch配网
-        -- LED = gpio.setup(12, 0, gpio.PULLUP)
-        wlan.init()
-        wlan.setMode(wlan.STATION)
-        wlan.connect(ssid, password, 1)
-        local result, data = sys.waitUntil("IP_READY")
-        log.info("wlan", "IP_READY", result, data)
-        device_id = wlan.getMac()
-    end
-    log.info("已联网")
-    sys.publish("net_ready")
-end)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 164
module/Air8101/demo/tcp/TCP断链续连/main.lua

@@ -1,164 +0,0 @@
--- main.lua文件
-
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "Wifi_TCP_Uart"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 43115                -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-sys.taskInit(function()
-    sys.wait(1000)
-    -----------------------------
-    ---------wifi 联网-----------
-    -----------------------------
-    if wlan and wlan.connect then
-        -- wifi 联网, ESP32系列均支持
-        local ssid = "test"                 --wifi 名
-        local password = "waljy2333"        --wifi 密码
-        log.info("wifi", ssid, password)
-        -- TODO 改成esptouch配网
-        -- LED = gpio.setup(12, 0, gpio.PULLUP)
-        wlan.init()
-        wlan.setMode(wlan.STATION)
-        wlan.connect(ssid, password, 1)
-        local result, data = sys.waitUntil("IP_READY")
-        log.info("wlan", "IP_READY", result, data)
-        device_id = wlan.getMac()
-    end
-    log.info("已联网")
-    sys.publish("net_ready")
-end)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    sys.waitUntil("IP_READY")                -- 等待联网成功
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-                local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-                if len <= 0 then    -- 接收到的字节长度为0 则退出
-                    break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                    sys_send(taskName, socket.EVENT, 0)
-                end
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

Некоторые файлы не были показаны из-за большого количества измененных файлов