Bläddra i källkod

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

马亚丹 3 månader sedan
förälder
incheckning
19d8e7f1cd
100 ändrade filer med 3758 tillägg och 1635 borttagningar
  1. 3 0
      components/airlink/src/task/luat_airlink_spi_master_task.c
  2. 1 1
      components/camera/luat_lib_camera.c
  3. 4 2
      components/crypto/luat_crc.c
  4. 2 0
      components/lcd/luat_lcd_sh8601z.c
  5. 88 1
      components/lcd/luat_lib_lcd.c
  6. 0 1
      components/lfs/lfs_sfd.c
  7. 119 87
      components/mreport/src/luat_mreport.c
  8. 1 1
      components/multimedia/luat_lib_multimedia_codec.c
  9. 61 12
      components/network/adapter/luat_lib_socket.c
  10. 20 2
      components/network/adapter/luat_network_adapter.c
  11. 1 0
      components/network/adapter/luat_network_adapter.h
  12. 101 19
      components/network/adapter_lwip2/net_lwip2.c
  13. 6 5
      components/network/netdrv/binding/luat_lib_netdrv.c
  14. 1 0
      components/network/netdrv/src/ch390h_api.c
  15. 0 327
      components/network/posix/luat_network_posix.c
  16. 0 20
      components/network/posix/luat_network_posix.h
  17. 1 1
      components/statem/luat_lib_statem.c
  18. 622 636
      components/tp/cst92xx_fw.h
  19. 1 1
      components/tp/luat_lib_tp.c
  20. 23 110
      components/tp/luat_tp_cst9220.c
  21. 1 1
      luat/include/luat_crypto.h
  22. 1 0
      luat/include/luat_libs.h
  23. 4 0
      luat/include/luat_sfd.h
  24. 51 13
      luat/modules/luat_lib_crypto.c
  25. 1 1
      luat/modules/luat_lib_ir.c
  26. 1 1
      luat/modules/luat_lib_mcu.c
  27. 2 2
      module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/cc_app.lua
  28. 8 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/main.lua
  29. 24 18
      module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/readme.md
  30. 8 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHV_cc/main.lua
  31. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/10.amr
  32. 19 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/main.lua
  33. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/pins_air780ehm.json
  34. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_file.lua
  35. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_stream.lua
  36. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_tts.lua
  37. 212 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/readme.md
  38. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/record_file.lua
  39. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/record_stream.lua
  40. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/sample-6s.mp3
  41. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/test.pcm
  42. 0 123
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/readme.md
  43. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/10.amr
  44. 19 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/main.lua
  45. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_file.lua
  46. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_stream.lua
  47. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_tts.lua
  48. 98 14
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/readme.md
  49. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/record_file.lua
  50. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/record_stream.lua
  51. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/sample-6s.mp3
  52. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/test.pcm
  53. 31 14
      module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/fastlz_app.lua
  54. 24 18
      module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/main.lua
  55. 46 20
      module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/readme.md
  56. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/test.txt
  57. 1 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/http_download_flash.lua
  58. 1 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/readme.md
  59. 71 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm2.lua
  60. 43 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm2sign.lua
  61. 26 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm3.lua
  62. 53 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm4.lua
  63. 78 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/main.lua
  64. 92 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/readme.md
  65. 24 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/hmeta_app.lua
  66. 60 19
      module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/main.lua
  67. 54 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/readme.md
  68. 74 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/main.lua
  69. 64 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/mcu_test.lua
  70. 53 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/readme.md
  71. 60 30
      module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/main.lua
  72. 47 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/miniz_app.lua
  73. 55 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/readme.md
  74. 0 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/test.txt
  75. 2 2
      module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/main.lua
  76. 8 10
      module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/readme.md
  77. 78 46
      module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/ymodem_receive.lua
  78. 1 1
      module/Air780EPM/demo/fs_io/http_download_flash.lua
  79. 71 0
      module/Air780EPM/demo/gmssl/gmssl_sm2.lua
  80. 43 0
      module/Air780EPM/demo/gmssl/gmssl_sm2sign.lua
  81. 26 0
      module/Air780EPM/demo/gmssl/gmssl_sm3.lua
  82. 53 0
      module/Air780EPM/demo/gmssl/gmssl_sm4.lua
  83. 78 0
      module/Air780EPM/demo/gmssl/main.lua
  84. 88 0
      module/Air780EPM/demo/gmssl/readme.md
  85. 24 0
      module/Air780EPM/demo/hmeta/hmeta_app.lua
  86. 60 19
      module/Air780EPM/demo/hmeta/main.lua
  87. 50 0
      module/Air780EPM/demo/hmeta/readme.md
  88. 74 0
      module/Air780EPM/demo/mcu/main.lua
  89. 64 0
      module/Air780EPM/demo/mcu/mcu_test.lua
  90. 53 0
      module/Air780EPM/demo/mcu/readme.md
  91. 60 30
      module/Air780EPM/demo/miniz/main.lua
  92. 47 0
      module/Air780EPM/demo/miniz/miniz_app.lua
  93. 51 0
      module/Air780EPM/demo/miniz/readme.md
  94. 0 0
      module/Air780EPM/demo/miniz/test.txt
  95. 0 2
      module/Air8000/demo/accessory_board/AirETH_1000/http/readme.md
  96. 1 3
      module/Air8000/demo/accessory_board/AirETH_1000/network_routing/4g_out_ethernet_in_wifi_in/readme.md
  97. 1 1
      module/Air8000/demo/accessory_board/AirETH_1000/readme.md
  98. 18 1
      module/Air8000/demo/audio/main.lua
  99. 250 0
      module/Air8000/demo/audio/pins_air8000.json
  100. 96 14
      module/Air8000/demo/audio/readme.md

+ 3 - 0
components/airlink/src/task/luat_airlink_spi_master_task.c

@@ -221,8 +221,11 @@ __USER_FUNC_IN_RAM__ void airlink_transfer_and_exec(uint8_t *txbuff, uint8_t *rx
     g_airlink_statistic.tx_pkg.total++;
     // 拉低片选, 准备发送数据
     luat_gpio_set(AIRLINK_SPI_CS_PIN, 0);
+    
+    luat_spi_lock(MASTER_SPI_ID);
     // 发送数据
     luat_spi_transfer(MASTER_SPI_ID, (const char *)txbuff, TEST_BUFF_SIZE, (char *)rxbuff, TEST_BUFF_SIZE);
+    luat_spi_unlock(MASTER_SPI_ID);
     // 拉高片选之前,先检查一下是否有RDY事件未处理,如果有,则全部清除
     size_t qlen = 0;
     luat_rtos_queue_get_cnt(rdy_evt_queue, &qlen);

+ 1 - 1
components/camera/luat_lib_camera.c

@@ -580,7 +580,7 @@ static int l_camera_config(lua_State *L) {
 
 /*
 对于无法用GPIO控制camera pwdn脚的平台,手动控制camera pwdn脚拉高或者拉低,2025/9/6启用
-@api camera.pwdn_pin(level)
+@api camera.pwdn_pin(id, level)
 @int camera id,例如0
 @int pwdn脚电平,1高电平,0低电平
 @usage

+ 4 - 2
components/crypto/luat_crc.c

@@ -62,10 +62,12 @@ uint8_t luat_crc8(const void *data, uint32_t len, uint8_t start, uint8_t poly, u
 /************************************************************************/
 /*  CRC16                                                                */
 /************************************************************************/
-uint16_t luat_crc16(const void *data, uint32_t len, uint16_t start, uint16_t poly, uint8_t is_reverse)
+
+uint16_t luat_crc16(const void *data, uint32_t len, uint16_t start,uint16_t final, uint16_t poly, uint8_t is_reverse)
 {
 	uint32_t i;
 	uint16_t CRC16 = start;
+	uint16_t CRC16_out = final;
 	uint16_t wTemp = poly;
 	uint8_t *Src = (uint8_t *)data;
 	if (is_reverse)
@@ -123,7 +125,7 @@ uint16_t luat_crc16(const void *data, uint32_t len, uint16_t start, uint16_t pol
 		}
 	}
 
-	return CRC16;
+	return (uint16_t)(CRC16^CRC16_out);
 }
 
 

+ 2 - 0
components/lcd/luat_lcd_sh8601z.c

@@ -29,6 +29,8 @@ static int sh8601z_inited_init(luat_lcd_conf_t* conf)
     lcd_write_cmd_data(conf,0x53, &temp, 1);
     temp = 0xff;
     lcd_write_cmd_data(conf,0x51, &temp, 1);
+//    temp = 0x00;
+//    lcd_write_cmd_data(conf,0x36, &temp, 1);
 //    luat_lcd_clear(conf,LCD_BLACK);
     luat_lcd_display_on(conf);
     return 0;

+ 88 - 1
components/lcd/luat_lib_lcd.c

@@ -1531,6 +1531,89 @@ static int l_lcd_draw_gtfont_utf8_gray(lua_State* L) {
 
 #endif // LUAT_USE_GTFONT
 
+/* HzFont 接口(受 LUAT_USE_HZFONT 控制) */
+#ifdef LUAT_USE_HZFONT
+#include "luat_hzfont.h"
+/**
+使用HzFont绘制UTF-8字符串
+@api lcd.drawHzfontUtf8(x, y, str, fontSize, [color], [antialias])
+@int x 横坐标
+@int y 纵坐标(左下角为基准)
+@string str UTF-8字符串
+@int fontSize 字体大小(像素)
+@int color 颜色值(RGB565,缺省为黑色0x000000)
+@int antialias 抗锯齿级别(整数,可选):
+-- -1:自动(≤12号字 无抗锯齿,>12号字 2x2超采样)
+-- 1:无抗锯齿
+-- 2:2x2 超采样
+-- 4:4x4 超采样
+@return nil 无返回值
+@usage
+-- 默认黑色,自动抗锯齿
+lcd.drawHzfontUtf8(10, 50, "Hello世界", 24)
+-- 指定红色与2x2抗锯齿
+lcd.drawHzfontUtf8(10, 80, "Red文本", 24, 0xF800, 2)
+-- 仅指定抗锯齿(颜色位用nil占位)
+lcd.drawHzfontUtf8(10, 110, "锐利输出", 14, nil, 1)
+*/
+static int l_lcd_draw_hzfont_utf8(lua_State *L) {
+    int x = luaL_checkinteger(L, 1);
+    int y = luaL_checkinteger(L, 2);
+    size_t len = 0;
+    const char* str = luaL_checklstring(L, 3, &len);
+    int fontSize = luaL_checkinteger(L, 4);
+    uint32_t color = 0x000000; /* 默认黑色 */
+    if (!lua_isnoneornil(L, 5)) {
+        color = (uint32_t)luaL_checkinteger(L, 5);
+    }
+    int antialias = -1; /* -1 表示自动 */
+    if (!lua_isnoneornil(L, 6)) {
+        if (lua_isinteger(L, 6) || lua_isnumber(L, 6)) {
+            int v = (int)luaL_checkinteger(L, 6);
+            if (v == -1) antialias = -1;
+            else if (v <= 1) antialias = 1;
+            else if (v <= 2) antialias = 2;
+            else antialias = 4;
+        } else {
+            antialias = -1;
+        }
+    }
+    if (fontSize <= 0 || fontSize > 255) {
+        LLOGE("Invalid font size: %d", fontSize);
+        return 0;
+    }
+    if (lcd_dft_conf == NULL) {
+        LLOGE("lcd not init");
+        return 0;
+    }
+    (void)luat_hzfont_draw_utf8(x, y, str, (unsigned char)fontSize, color, antialias);
+    lcd_auto_flush(lcd_dft_conf);
+    return 0;
+}
+
+/**
+获取HzFont渲染下的UTF-8字符串宽度
+@api lcd.getHzFontStrWidth(str, fontSize)
+@string str UTF-8字符串
+@int fontSize 字体大小(像素)
+@return int 宽度(像素)
+@usage
+local w = lcd.getHzFontStrWidth("Hello世界", 24)
+*/
+static int l_lcd_get_hzfont_str_width(lua_State *L) {
+    size_t len = 0;
+    const char* str = luaL_checklstring(L, 1, &len);
+    int fontSize = luaL_checkinteger(L, 2);
+    if (fontSize <= 0 || fontSize > 255) {
+        lua_pushinteger(L, 0);
+        return 1;
+    }
+    unsigned int width = luat_hzfont_get_str_width(str, (unsigned char)fontSize);
+    lua_pushinteger(L, width);
+    return 1;
+}
+#endif /* LUAT_USE_HZFONT */
+
 static int l_lcd_set_default(lua_State *L) {
     if (lua_gettop(L) == 1) {
         lcd_dft_conf = lua_touserdata(L, 1);
@@ -1993,7 +2076,7 @@ static const int l_lcd_draw_utf8(lua_State *L) {
 
 /*
 硬件lcd qspi接口配置,需要在lcd.init前配置好
-@api lcd.qspi(1_wire_command, 1_wire_command, 1_wire_command_4_wire_data, 4_wire_command_4_wire_data, vsync_reg, hsync_cmd, hsync_reg)
+@api lcd.qspi(1_wire_command, 1_wire_command_4_wire_data, 4_wire_command_4_wire_data, vsync_reg, hsync_cmd, hsync_reg)
 @int lcd命令模式下的qspi指令
 @int lcd数据模式下,1线地址,4线数据的qspi指令,
 @int lcd数据模式下,4线地址,4线数据的qspi指令,可以留空,如果存在,发送数据时优先使用这个模式
@@ -2123,6 +2206,10 @@ static const rotable_Reg_t reg_lcd[] =
     { "drawGtfontUtf8Gray", ROREG_FUNC(l_lcd_draw_gtfont_utf8_gray)},
 #endif // LUAT_USE_GTFONT_UTF8
 #endif // LUAT_USE_GTFONT
+#ifdef LUAT_USE_HZFONT
+    { "drawHzfontUtf8", ROREG_FUNC(l_lcd_draw_hzfont_utf8)},
+    { "getHzFontStrWidth", ROREG_FUNC(l_lcd_get_hzfont_str_width)},
+#endif // LUAT_USE_HZFONT
     // 默认只带英文12号字体
     //@const font_opposansm12 font 12号字体
     { "font_opposansm12", ROREG_PTR((void*)u8g2_font_opposansm12)},

+ 0 - 1
components/lfs/lfs_sfd.c

@@ -1,5 +1,4 @@
 
-#
 #include "luat_base.h"
 #include "luat_sfd.h"
 #include "luat_mem.h"

+ 119 - 87
components/mreport/src/luat_mreport.c

@@ -19,13 +19,53 @@
 
 #define MREPORT_DOMAIN "47.94.236.172"
 #define MREPORT_PORT (12388)
-// #define MREPORT_DOMAIN "112.125.89.8"
-// #define MREPORT_PORT (42919)
 
-static struct udp_pcb* mreport_pcb;
-static luat_rtos_timer_t mreport_timer;
-const char *project_name = "unkonw";             // luatos项目名称
-const char *project_version = "";                   // luatos项目版本号
+typedef struct mreport_ctx {
+    struct udp_pcb* mreport_pcb;
+    luat_rtos_timer_t mreport_timer;
+    char project_name[64];             // luatos项目名称
+    char project_version[32];          // luatos项目版本号
+    int s_adapter_index;                  // 网络适配器索引
+} mreport_ctx_t;
+
+static mreport_ctx_t* s_mreport_ctx;
+
+static void luat_mreport_init(lua_State *L) {
+    if (s_mreport_ctx == NULL) {
+        s_mreport_ctx = (mreport_ctx_t*)luat_heap_malloc(sizeof(mreport_ctx_t));
+        if (s_mreport_ctx == NULL) {
+            LLOGE("mreport malloc ctx failed");
+            return;
+        }
+        memset(s_mreport_ctx, 0, sizeof(mreport_ctx_t));
+        memcpy(s_mreport_ctx->project_name, "unkonw", 6);
+        memcpy(s_mreport_ctx->project_version, "0.0.0", 6);
+        s_mreport_ctx->s_adapter_index = 0;
+    }
+    if (strcmp(s_mreport_ctx->project_name, "unkonw") == 0) {
+        lua_getglobal(L, "PROJECT");
+        if (LUA_TSTRING == lua_type(L, -1))
+        {
+            size_t project_len;
+            const char *project_name = luaL_tolstring(L, -1, &project_len);
+            size_t copy_len = project_len < sizeof(s_mreport_ctx->project_version) - 1  ? project_len : sizeof(s_mreport_ctx->project_version) - 1;
+            memcpy(s_mreport_ctx->project_name, project_name, copy_len);
+            s_mreport_ctx->project_name[copy_len] = '\0';
+        }
+    }
+
+    if (strcmp(s_mreport_ctx->project_version, "0.0.0") == 0) {
+        lua_getglobal(L, "VERSION");
+        if (LUA_TSTRING == lua_type(L, -1))
+        {
+            size_t version_len;
+            const char *project_version = luaL_tolstring(L, -1, &version_len);
+            size_t copy_len = version_len < sizeof(s_mreport_ctx->project_version) - 1  ? version_len : sizeof(s_mreport_ctx->project_version) - 1;
+            memcpy(s_mreport_ctx->project_version, project_version, version_len);
+            s_mreport_ctx->project_version[copy_len] = '\0';
+        }
+    }
+}
 
 static inline uint16_t u162bcd(uint16_t src) {
     uint8_t high = (src >> 8) & 0xFF;
@@ -45,8 +85,8 @@ static void luat_mreport_sys_basic(cJSON* mreport_data) {
     cJSON_AddNumberToObject(mreport_data, "localtime", t);
 
     // luatos项目信息
-    cJSON_AddStringToObject(mreport_data, "proj", project_name);
-    cJSON_AddStringToObject(mreport_data, "pver", project_version);
+    cJSON_AddStringToObject(mreport_data, "proj", s_mreport_ctx->project_name);
+    cJSON_AddStringToObject(mreport_data, "pver", s_mreport_ctx->project_version);
     
     // rndis
     cJSON_AddNumberToObject(mreport_data, "rndis", 0);
@@ -78,7 +118,7 @@ static void luat_mreport_mobile(cJSON* mreport_data) {
 
     // MUID
     char muid[33] = {0};
-    luat_mobile_get_muid(muid, 32);
+    luat_mobile_get_muid(muid, 32); // TODO 如果不是cat1,要从mcu库取.
     muid[32] = '\0';
     cJSON_AddStringToObject(mreport_data, "muid", muid);
 
@@ -134,47 +174,21 @@ static void luat_mreport_sim_network(cJSON* mreport_data, struct netif* netif) {
     }
 
     // 基站/小区
-    luat_mobile_get_cell_info_async(5);
-    luat_mobile_cell_info_t* cell_info = luat_heap_malloc(sizeof(luat_mobile_cell_info_t));
-    if (cell_info == NULL) {
-        LLOGE("out of memory when malloc cell_info");
-    }
-    else {
-        int ret = luat_mobile_get_last_notify_cell_info(cell_info);
-        if (ret != 0) {
-            LLOGI("none cell info found %d", ret);
-        }
-        else {
-            cJSON_AddNumberToObject(mreport_data, "cid", cell_info->lte_service_info.cid);
-            cJSON_AddNumberToObject(mreport_data, "pci", cell_info->lte_service_info.pci);
-            cJSON_AddNumberToObject(mreport_data, "tac", cell_info->lte_service_info.tac);
-            cJSON_AddNumberToObject(mreport_data, "band", cell_info->lte_service_info.band);
-            cJSON_AddNumberToObject(mreport_data, "earfcn", cell_info->lte_service_info.earfcn);
-            cJSON_AddNumberToObject(mreport_data, "mcc", u162bcd(cell_info->lte_service_info.mcc));
-            cJSON_AddNumberToObject(mreport_data, "mnc", u162bcd(cell_info->lte_service_info.mnc));
-            uint32_t eci;
-            if (luat_mobile_get_service_cell_identifier(&eci) == 0) {
-                cJSON_AddNumberToObject(mreport_data, "eci", eci);
-            }
-            
-            if (cell_info->lte_neighbor_info_num > 0) {
-                for (size_t i = 0; i < cell_info->lte_neighbor_info_num; i++) {
-                    cJSON * cell = cJSON_CreateObject();
-                    // 邻近小区的信息
-	                cJSON_AddNumberToObject(cell, "cid", cell_info->lte_info[i].cid);
-                    cJSON_AddNumberToObject(cell, "pci", cell_info->lte_info[i].pci);
-                    cJSON_AddNumberToObject(cell, "rsrp", cell_info->lte_info[i].rsrp);
-                    cJSON_AddNumberToObject(cell, "rsrq", cell_info->lte_info[i].rsrq);
-                    cJSON_AddNumberToObject(cell, "snr", cell_info->lte_info[i].snr);
-                    cJSON_AddNumberToObject(cell, "tac", cell_info->lte_info[i].tac);
-                    cJSON_AddItemToArray(cells, cell);
-                }
-                cJSON_AddItemToObject(mreport_data, "cells", cells);
-            }
-        }
-    }
-    if (cell_info != NULL) {
-        luat_heap_free(cell_info);
+    luat_mobile_scell_extern_info_t scell_info = {0};
+    if (luat_mobile_get_extern_service_cell_info(&scell_info) == 0) {
+        int band = 0;
+        uint32_t eci = 0;
+        uint16_t tac = 0;
+        band = luat_mobile_get_band_from_earfcn(scell_info.earfcn);
+        luat_mobile_get_service_cell_identifier(&eci);
+        luat_mobile_get_service_tac_or_lac(&tac);
+        cJSON_AddNumberToObject(mreport_data, "cid", eci);
+        cJSON_AddNumberToObject(mreport_data, "pci", scell_info.pci);
+        cJSON_AddNumberToObject(mreport_data, "tac", tac);
+        cJSON_AddNumberToObject(mreport_data, "band", band);
+        cJSON_AddNumberToObject(mreport_data, "earfcn", scell_info.earfcn);
+        cJSON_AddNumberToObject(mreport_data, "mcc", u162bcd(scell_info.mcc));
+        cJSON_AddNumberToObject(mreport_data, "mnc", u162bcd(scell_info.mnc));
     }
 
     // ip地址
@@ -281,29 +295,35 @@ void luat_mreport_send(void) {
     int ret = 0;
     size_t olen = 0;
     cJSON* mreport_data = cJSON_CreateObject();
+    int adapter_id = 0;
 
-    int adapter_index = network_register_get_default();
-	if (adapter_index < 0 || adapter_index >= NW_ADAPTER_QTY){
+    if (s_mreport_ctx->s_adapter_index == 0) 
+        adapter_id = network_register_get_default();
+    else
+        adapter_id = s_mreport_ctx->s_adapter_index;
+
+	if (adapter_id < 0 || adapter_id >= NW_ADAPTER_QTY){
 		LLOGE("尚无已注册的网络适配器");
         cJSON_Delete(mreport_data);
 		return;
 	}
-    luat_netdrv_t* netdrv = luat_netdrv_get(adapter_index);
+    luat_netdrv_t* netdrv = luat_netdrv_get(adapter_id);
     if (netdrv == NULL || netdrv->netif == NULL) {
+        LLOGE("当前使用的网络适配器id:%d, 还没初始化", adapter_id);
         cJSON_Delete(mreport_data);
         return;
     }
 
     struct netif *netif = netdrv->netif;
     if (ip_addr_isany(&netif->ip_addr)) {
-        LLOGD("还没联网");
+        LLOGE("当前使用的网络适配器id:%d, 还没分配到ip地址", adapter_id);
         cJSON_Delete(mreport_data);
         return;
     }
 
-    if (mreport_pcb == NULL) {
-        mreport_pcb = udp_new();
-        if (mreport_pcb == NULL) {
+    if (s_mreport_ctx->mreport_pcb == NULL) {
+        s_mreport_ctx->mreport_pcb = udp_new();
+        if (s_mreport_ctx->mreport_pcb == NULL) {
             LLOGE("创建,mreport udp pcb 失败, 内存不足?");
             cJSON_Delete(mreport_data);
             return;
@@ -311,7 +331,7 @@ void luat_mreport_send(void) {
     }
     // ipaddr_aton("47.94.236.172", &host);
     ipaddr_aton(MREPORT_DOMAIN, &host);
-    ret = udp_connect(mreport_pcb, &host, MREPORT_PORT);
+    ret = udp_connect(s_mreport_ctx->mreport_pcb, &host, MREPORT_PORT);
     if (ret) {
         LLOGD("udp_connect %d", ret);
         cJSON_Delete(mreport_data);
@@ -320,9 +340,9 @@ void luat_mreport_send(void) {
 
     // 基础信息
     luat_mreport_sys_basic(mreport_data);
-    // 模组信息
+    // 模组信息, TODO 有mobile库的才添加
     luat_mreport_mobile(mreport_data);
-    // sim卡和网络相关
+    // sim卡和网络相关, TODO 有mobile库的才添加
     luat_mreport_sim_network(mreport_data, netif);
     // adc信息
     luat_mreport_adc(mreport_data);
@@ -340,24 +360,24 @@ void luat_mreport_send(void) {
         cJSON_Delete(mreport_data);
         return;
     }
-    LLOGE("mreport json --- len: %d\r\n%s", strlen(json), json);
+    // 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);
+        luat_heap_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);
+    memcpy(&s_mreport_ctx->mreport_pcb->local_ip, &netif->ip_addr, sizeof(ip_addr_t));
+    ret = udp_sendto_if(s_mreport_ctx->mreport_pcb, p, &host, MREPORT_PORT, netif);
     pbuf_free(p);
-    free(json);
+    luat_heap_free(json);
     cJSON_Delete(mreport_data);
     if (ret) {
-        LLOGD("ret %d", ret);
+        LLOGE("send fail ret %d", ret);
     }
 }
 
@@ -367,12 +387,12 @@ static void mreport_timer_cb(void* params) {
 }
 
 void luat_mreport_start(void) {
-    int ret = luat_rtos_timer_create(&mreport_timer);
+    int ret = luat_rtos_timer_create(&s_mreport_ctx->mreport_timer);
     if (ret) {
         LLOGE("luat_rtos_timer_create %d", ret);
         return;
     }
-    ret = luat_rtos_timer_start(mreport_timer, 1*60*1000, 1, mreport_timer_cb, NULL);
+    ret = luat_rtos_timer_start(s_mreport_ctx->mreport_timer, 1*60*1000, 1, mreport_timer_cb, NULL);
     if (ret) {
         LLOGE("luat_rtos_timer_start %d", ret);
     }
@@ -380,15 +400,15 @@ void luat_mreport_start(void) {
 }
 
 void luat_mreport_stop(void) {
-    if (mreport_timer) {
-        luat_stop_rtos_timer(mreport_timer);
-        luat_rtos_timer_delete(mreport_timer);
-        mreport_timer = NULL;
+    if (s_mreport_ctx->mreport_timer) {
+        luat_stop_rtos_timer(s_mreport_ctx->mreport_timer);
+        luat_rtos_timer_delete(s_mreport_ctx->mreport_timer);
+        s_mreport_ctx->mreport_timer = NULL;
     }
 }
 
 void luat_mreport_config(const char* config, int val) {
-    LLOGD("luat_mreport_config %s %d", config, val);
+    // LLOGD("luat_mreport_config %s %d", config, val);
     if (strcmp(config, "enable") == 0) {
         if (val == 0) {
             luat_mreport_stop();
@@ -400,23 +420,35 @@ void luat_mreport_config(const char* config, int val) {
             LLOGE("luat_mreport enable %d error", val);
         }
     }
+    else if (strcmp(config, "adapter_id") == 0) {
+        if (val >= 0 && val < NW_ADAPTER_QTY) {
+			s_mreport_ctx->s_adapter_index = val;
+		}
+        else {
+            LLOGE("luat_mreport adapter_id %d error", val);
+            s_mreport_ctx->s_adapter_index = network_register_get_default(); // 默认使用默认网络适配器
+        }
+    }
 }
 
 int l_mreport_config(lua_State *L) {
-    char* config = luaL_checkstring(L, 1);
-    int value = lua_toboolean(L, 2);
-    lua_getglobal(L, "PROJECT");
-    size_t version_len, project_len;
-    if (LUA_TSTRING == lua_type(L, -1))
-    {
-    	project_name = luaL_tolstring(L, -1, &project_len);
+    int num_args = lua_gettop(L);
+    if (num_args == 0) {
+        luat_mreport_send();
     }
-    lua_getglobal(L, "VERSION");
-    if (LUA_TSTRING == lua_type(L, -1))
-    {
-    	project_version = luaL_tolstring(L, -1, &version_len);
+    else if (num_args == 2) {
+        char* config = luaL_checkstring(L, 1);
+        int value = -1;
+        if (lua_isboolean(L, 2))
+        {
+            value = lua_toboolean(L, 2);
+        }
+        else if (lua_isnumber(L, 2))
+        {
+            value = lua_tonumber(L, 2);
+        }
+        luat_mreport_init(L);
+        luat_mreport_config(config, value);
     }
-
-    luat_mreport_config(config, value);
     return 0;
-}
+}

+ 1 - 1
components/multimedia/luat_lib_multimedia_codec.c

@@ -292,7 +292,7 @@ static int l_codec_get_audio_info(lua_State *L) {
 
 /**
 decoder从文件中解析出原始音频数据,比如从MP3文件里解析出PCM数据,这里的文件路径已经在codec.info传入,不需要再次传入
-@api codec.data(decoder, out_buff)
+@api codec.data(decoder, out_buff, size)
 @userdata 解码用的decoder
 @zbuff 存放输出数据的zbuff,空间必须不少于16KB
 @int   最少解码出多少字节的音频数据,默认16384

+ 61 - 12
components/network/adapter/luat_lib_socket.c

@@ -931,38 +931,67 @@ static int l_socket_wait(lua_State *L)
 
 /*
 作为服务端开始监听
-@api socket.listen(ctrl)
+@api socket.listen(ctrl, multi_client)
 @user_data socket.create得到的ctrl
+@int 等待accept的客户端数量, 默认0不支持, 取值范围0~8
 @return boolean true没有异常发生,false失败了,如果false则不需要看下一个返回值了,如果false,后续要close
 @return boolean true已经connect,false没有connect,之后需要接收socket.ON_LINE消息
 @usage 
 local succ, result = socket.listen(ctrl)
+-- 注意, 当目标适配器不支持1对多时,multi_client参数无效,并返回错误
+-- 注意, multi_client参数是可选的, 不传或者传0则表示单客户端模式
+-- multi_client 参数是 2025.11.10新增的, 之前的版本不支持
+local succ, result = socket.listen(ctrl, 8)
 */
 static int l_socket_listen(lua_State *L)
 {
 	luat_socket_ctrl_t *l_ctrl = l_get_ctrl(L, 1);
 	L_CTRL_CHECK;
+	if (lua_isinteger(L, 2))
+	{
+		l_ctrl->netc->max_wait_accept = lua_tointeger(L, 2);
+		if (!network_accept_enable(l_ctrl->netc) && l_ctrl->netc->max_wait_accept > 0)
+		{
+			l_ctrl->netc->max_wait_accept = 0;
+			LLOGE("目标适配器不支持1对多客户端连接模式");
+			lua_pushboolean(L, 0);
+			lua_pushboolean(L, 0);
+			return 2;
+		}
+	}
 	int result = network_listen(l_ctrl->netc, 0);
 	lua_pushboolean(L, (result < 0)?0:1);
 	lua_pushboolean(L, result == 0);
+	if (result < 0) {
+		LLOGE("listen fail %d adapter %d port %d", result, l_ctrl->netc->adapter_index, l_ctrl->netc->local_port);
+	}
 	return 2;
 }
 
 /*
-作为服务端接收到一个新的客户端,注意,如果是类似W5500的硬件协议栈不支持1对多,则不需要第二个参数
-@api socket.accept(ctrl)
+作为服务端接收到一个新的客户端
+@api socket.accept(ctrl, args)
 @user_data socket.create得到的ctrl,这里是服务器端
 @string or function or nil string为消息通知的taskName,function则为回调函数,和socket.create参数一致
 @return boolean true没有异常发生,false失败了,如果false则不需要看下一个返回值了,如果false,后续要close
 @return user_data or nil 如果支持1对多,则会返回新的ctrl,自动create,如果不支持则返回nil
+@return string 客户端ip, 2025.11.10新增
+@return int 客户端port, 2025.11.10新增
 @usage 
 local succ, new_netc = socket.accept(ctrl, cb)
+-- 注意, 当目标适配器不支持1对多时,new_netc会是nil, 第二个参数无效
+-- 当第二个参数为nil时, 固定为一对一模式, new_netc也会是nil
+
+-- 新增客户端ip和port返回值
+local succ, new_netc, client_ip, client_port = socket.accept(ctrl, "taskName")
+log.info("accept", succ, new_netc, client_ip, client_port)
 */
 static int l_socket_accept(lua_State *L)
 {
 	luat_socket_ctrl_t *old_ctrl = l_get_ctrl(L, 1);
 	if (!old_ctrl) return 0;
-	if (network_accept_enable(old_ctrl->netc))
+	int result = 0;
+	if ((lua_isfunction(L, 2) || lua_isstring(L, 2)) && network_accept_enable(old_ctrl->netc))
 	{
 		luat_socket_ctrl_t *new_ctrl = (luat_socket_ctrl_t *)lua_newuserdata(L, sizeof(luat_socket_ctrl_t));
 		if (!new_ctrl)
@@ -997,25 +1026,45 @@ static int l_socket_accept(lua_State *L)
 			memset(new_ctrl->task_name, 0, len + 1);
 			memcpy(new_ctrl->task_name, buf, len);
 		}
-		if (network_socket_accept(old_ctrl, new_ctrl))
-		{
+		else {
+			LLOGE("accept模式必须传入回调函数或taskName");
+			network_release_ctrl(new_ctrl->netc);
+			new_ctrl->netc = NULL;
 			lua_pushboolean(L, 0);
-			lua_pushnil(L);
-			return 2;
+			return 1;
 		}
-		else
+		if (network_socket_accept(old_ctrl->netc, new_ctrl->netc))
 		{
-			lua_pushboolean(L, 1);
-			luaL_setmetatable(L, LUAT_NW_CTRL_TYPE);
+			network_release_ctrl(new_ctrl->netc);
+			new_ctrl->netc = NULL;
+			lua_pushboolean(L, 0);
+			lua_pushnil(L);
 			return 2;
 		}
-
+		// 恢复到可监听状态
+		LLOGD("accept success %p", new_ctrl->netc);
+		luaL_setmetatable(L, LUAT_NW_CTRL_TYPE);
+		lua_pushboolean(L, 1);
+		lua_pushvalue(L, -2);
+		#ifdef LUAT_USE_LWIP
+		lua_pushstring(L, ipaddr_ntoa(&new_ctrl->netc->remote_ip));
+		lua_pushinteger(L, new_ctrl->netc->remote_port);
+		return 4;
+		#else
+		return 2;
+		#endif
 	}
 	else
 	{
 		lua_pushboolean(L, !network_socket_accept(old_ctrl->netc, NULL));
 		lua_pushnil(L);
+		#ifdef LUAT_USE_LWIP
+		lua_pushstring(L, ipaddr_ntoa(&old_ctrl->netc->remote_ip));
+		lua_pushinteger(L, old_ctrl->netc->remote_port);
+		return 4;
+		#else
 		return 2;
+		#endif
 	}
 }
 

+ 20 - 2
components/network/adapter/luat_network_adapter.c

@@ -977,6 +977,9 @@ static int network_state_listen(network_ctrl_t *ctrl, OS_EVENT *event, network_a
 		break;
 	case EV_NW_SOCKET_NEW_CONNECT:
 	case EV_NW_SOCKET_CONNECT_OK:
+		if (ctrl->is_server_mode && ctrl->max_wait_accept > 0) {
+			return 0; // 对于多客户的tcpserver模式, 保持listen状态
+		}
 		ctrl->state = NW_STATE_ONLINE;
 		return 0;
 	default:
@@ -1627,13 +1630,23 @@ uint8_t network_accept_enable(network_ctrl_t *ctrl)
 int network_socket_accept(network_ctrl_t *ctrl, network_ctrl_t *accept_ctrl)
 {
 	network_adapter_t *adapter = &prv_adapter_table[ctrl->adapter_index];
-	if (adapter->opt->no_accept)
+	if (adapter->opt == NULL) {
+		DBG_ERR("adapter %d not register!", ctrl->adapter_index);
+		return -1;
+	}
+	if (adapter->opt->no_accept || accept_ctrl == NULL)
 	{
 //		DBG("%x,%d,%llu,%x,%x,%x",adapter->opt->socket_accept, ctrl->socket_id, ctrl->tag, &ctrl->remote_ip, &ctrl->remote_port, adapter->user_data);
 		adapter->opt->socket_accept(ctrl->socket_id, ctrl->tag, &ctrl->remote_ip, &ctrl->remote_port, adapter->user_data);
 		return 0;
 	}
-	accept_ctrl->socket_id = adapter->opt->socket_accept(ctrl->socket_id, ctrl->tag, &accept_ctrl->remote_ip, &accept_ctrl->remote_port, adapter->user_data);
+	if (adapter->opt->socket_accept == NULL)
+	{
+		DBG_ERR("adapter %d not support accept multiple", ctrl->adapter_index);
+		return -1;
+	}
+	DBG_ERR("执行accept操作 %p %p", adapter, accept_ctrl, adapter->opt->socket_accept);
+	accept_ctrl->socket_id = adapter->opt->socket_accept(ctrl->socket_id, 0, &accept_ctrl->remote_ip, &accept_ctrl->remote_port, accept_ctrl);
 	if (accept_ctrl->socket_id < 0)
 	{
 		return -1;
@@ -1648,6 +1661,7 @@ int network_socket_accept(network_ctrl_t *ctrl, network_ctrl_t *accept_ctrl)
 		accept_ctrl->tcp_timeout_ms = ctrl->tcp_timeout_ms;
 		accept_ctrl->local_port = ctrl->local_port;
 		accept_ctrl->state = NW_STATE_ONLINE;
+		DBG_ERR("accept_ctrl %p tag: %llu", accept_ctrl, accept_ctrl->tag);
 		return 0;
 	}
 }
@@ -2188,10 +2202,14 @@ int network_listen(network_ctrl_t *ctrl, uint32_t timeout_ms)
 	if (NW_STATE_LISTEN == ctrl->state)
 	{
 		DBG("socket %d is listen", ctrl->socket_id);
+		if (network_accept_enable(ctrl)) {
+			return 1;
+		}
 		return 0;
 	}
 	if (ctrl->socket_id >= 0)
 	{
+		DBG("socket %d busy, state %d", ctrl->socket_id, ctrl->state);
 		return -1;
 	}
 	NW_LOCK;

+ 1 - 0
components/network/adapter/luat_network_adapter.h

@@ -210,6 +210,7 @@ typedef struct
     uint8_t state;
     uint8_t is_debug;
     uint8_t domain_ipv6;
+	uint8_t max_wait_accept; // 作为server时,最多支持多少个等待accept的客户端
 }network_ctrl_t;
 
 typedef struct

+ 101 - 19
components/network/adapter_lwip2/net_lwip2.c

@@ -203,6 +203,7 @@ static void net_lwip2_callback_to_nw_task(uint8_t adapter_index, uint32_t event_
 		prvlwip.socket_busy &= ~(1 << param1);
 		break;
 	}
+	LLOGD("socket_cb event_id %08X param.tag %d param3 %ld", event_id, param.tag, param3);
 	prvlwip.socket_cb(&event, &param);
 }
 
@@ -411,11 +412,17 @@ static err_t net_lwip2_tcp_fast_accept_cb(void *arg, struct tcp_pcb *newpcb, err
 {
 	int socket_id = ((uint32_t)arg) & 0x0000ffff;
 	uint8_t adapter_index = ((uint32_t)arg) >> 16;
+	LLOGD("adapter %d socket %d new client", adapter_index, socket_id);
 	if (err || !newpcb)
 	{
 		net_lwip2_tcp_error(adapter_index, socket_id);
 		return 0;
 	}
+	if (prvlwip.socket[socket_id].pcb.tcp != NULL) {
+		LLOGE("accept fail, srv socket busy. from %s:%d", ipaddr_ntoa(&newpcb->remote_ip), newpcb->remote_port);
+		tcp_close(newpcb);
+		return ERR_OK;
+	}
 	prvlwip.socket[socket_id].pcb.tcp = newpcb;
 	// prvlwip.socket[socket_id].pcb.tcp->sockid = socket_id;
 	prvlwip.socket[socket_id].rx_wait_size = 0;
@@ -840,6 +847,11 @@ static void net_lwip2_task(void *param)
 		// LLOGD("event dns query 3");
 		break;
 	case EV_LWIP_SOCKET_LISTEN:
+		if (prvlwip.socket[socket_id].listen_tcp) {
+			// 已经在监听了, 不需要重复操作, 发送事件就行
+			net_lwip2_callback_to_nw_task(adapter_index, EV_NW_SOCKET_LISTEN, socket_id, 0, 0);
+			break;
+		}
 		if (!prvlwip.socket[socket_id].in_use || !prvlwip.socket[socket_id].pcb.ip)
 		{
 			NET_DBG("adapter %d socket %d cannot use! %d,%x", adapter_index, socket_id, prvlwip.socket[socket_id].in_use, prvlwip.socket[socket_id].pcb.ip);
@@ -1038,9 +1050,18 @@ static void net_lwip2_check_network_ready(uint8_t adapter_index)
 static int net_lwip2_check_socket(void *user_data, int socket_id, uint64_t tag)
 {
 	if ((uint32_t)user_data >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return -1;
-	if (socket_id >= MAX_SOCK_NUM) return -1;
-	if (prvlwip.socket[socket_id].tag != tag) return -1;
-	if (!prvlwip.socket[socket_id].in_use || prvlwip.socket[socket_id].state) return -1;
+	if (socket_id >= MAX_SOCK_NUM) {
+		LLOGD("socket id 超出范围 %d", socket_id);
+		return -1;
+	}
+	if (prvlwip.socket[socket_id].tag != tag) {
+		LLOGD("socket tag 不匹配 %llx != %llx", prvlwip.socket[socket_id].tag, tag);
+		return -1;
+	}
+	if (!prvlwip.socket[socket_id].in_use || prvlwip.socket[socket_id].state) {
+		LLOGD("socket 状态不正确 %d,%d,%d", socket_id, prvlwip.socket[socket_id].in_use, prvlwip.socket[socket_id].state);
+		return -1;
+	}
 	return 0;
 }
 
@@ -1156,14 +1177,9 @@ static void net_lwip2_create_socket_now(uint8_t adapter_index, uint8_t socket_id
 	}
 }
 
-static int net_lwip2_create_socket(uint8_t is_tcp, uint64_t *tag, void *param, uint8_t is_ipv6, void *user_data)
-{
-	// uint8_t index = (uint32_t)user_data;
-	uint8_t adapter_index = (uint32_t)user_data;
-	if ((uint32_t)adapter_index >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return 0;
-	int i, socket_id;
-	socket_id = -1;
-	// OS_LOCK;
+static int gen_next_socket_id() {
+	int socket_id = -1;
+	int i;
 	if (!prvlwip.socket[prvlwip.next_socket_index].in_use)
 	{
 		socket_id = prvlwip.next_socket_index;
@@ -1185,6 +1201,16 @@ static int net_lwip2_create_socket(uint8_t is_tcp, uint64_t *tag, void *param, u
 	{
 		prvlwip.next_socket_index = 0;
 	}
+	return socket_id;
+}
+
+static int net_lwip2_create_socket(uint8_t is_tcp, uint64_t *tag, void *param, uint8_t is_ipv6, void *user_data)
+{
+	// uint8_t index = (uint32_t)user_data;
+	uint8_t adapter_index = (uint32_t)user_data;
+	if ((uint32_t)adapter_index >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return 0;
+	int socket_id = gen_next_socket_id();
+	// OS_LOCK;
 	if (socket_id >= 0)
 	{
 		LWIP_ASSERT("socket must free before create", !prvlwip.socket[socket_id].pcb.ip);
@@ -1239,14 +1265,68 @@ static int net_lwip2_socket_listen(int socket_id, uint64_t tag,  uint16_t local_
 	return 0;
 }
 //作为server接受一个client
-static int net_lwip2_socket_accept(int socket_id, uint64_t tag,  luat_ip_addr_t *remote_ip, uint16_t *remote_port, void *user_data)
+static int net_lwip2_socket_accept(int srv_socket_id, uint64_t srv_tag,  luat_ip_addr_t *remote_ip, uint16_t *remote_port, void *user_data)
 {
-	int result = net_lwip2_check_socket(user_data, socket_id, tag);
-	if (result) return result;
-	uint8_t adapter_index = (uint32_t)user_data;
-	if (adapter_index >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return -1;
-	*remote_ip = prvlwip.socket[socket_id].pcb.tcp->remote_ip;
-	*remote_port = prvlwip.socket[socket_id].pcb.tcp->remote_port;
+	if (srv_tag == 0) {
+		uint64_t tag = 0;
+		LLOGD("accept tag 0, one to many");
+		if (prvlwip.socket[srv_socket_id].pcb.tcp == NULL) {
+			LLOGE("accept fail, srv socket not in wait-accept state");
+			return -1;
+		}
+		// 首先,分配新的socket id
+		int socket_id = gen_next_socket_id();
+		if (socket_id < 0) {
+			LLOGE("accept fail, too many socket");
+			return -1;
+		}
+		network_ctrl_t* accept_ctrl = (network_ctrl_t*)user_data;
+		// 然后, 把新的socket和老的socket绑定在一起
+		prvlwip.socket_busy &= (1 << socket_id);
+		prvlwip.socket_connect &= (1 << socket_id);
+		prvlwip.socket_tag++;
+		tag = prvlwip.socket_tag;
+		accept_ctrl->tag = tag;
+		prvlwip.socket[socket_id].in_use = 1;
+		prvlwip.socket[socket_id].tag = tag;
+		prvlwip.socket[socket_id].param = accept_ctrl;
+		prvlwip.socket[socket_id].is_tcp = 1;
+
+		LLOGI("accept new socket %d from srv socket %d", socket_id, srv_socket_id);
+		LLOGD("accept srv tag %llx, new tag %llx accept_ctrl->tag %llx", srv_tag, tag, accept_ctrl->tag);
+
+		//--------------------
+		// 把srv暂存的pcb给新的socket
+		prvlwip.socket[socket_id].pcb.tcp = prvlwip.socket[srv_socket_id].pcb.tcp;
+		prvlwip.socket[srv_socket_id].pcb.tcp = NULL; // 恢复成老的监听状态
+		prvlwip.socket[srv_socket_id].rx_wait_size = 0;
+		prvlwip.socket[srv_socket_id].tx_wait_size = 0;
+		//--------------------
+
+		PV_Union uPV;
+        uPV.u16[0] = socket_id;
+        uPV.u16[1] = accept_ctrl->adapter_index;
+		prvlwip.socket[socket_id].pcb.tcp->callback_arg = uPV.p;
+		llist_traversal(&prvlwip.socket[socket_id].wait_ack_head, net_lwip2_del_data_cache, NULL);
+		llist_traversal(&prvlwip.socket[socket_id].tx_head, net_lwip2_del_data_cache, NULL);
+		llist_traversal(&prvlwip.socket[socket_id].rx_head, net_lwip2_del_data_cache, NULL);
+		*remote_ip = prvlwip.socket[socket_id].pcb.tcp->remote_ip;
+		*remote_port = prvlwip.socket[socket_id].pcb.tcp->remote_port;
+
+		// 把srv_socket_id的对应的状态恢复好
+
+		return socket_id;
+	}
+	else {
+		// 一对一的情况, 兼容老的
+		int socket_id = srv_socket_id;
+		int result = net_lwip2_check_socket(user_data, socket_id, srv_tag);
+		if (result) return result;
+		uint8_t adapter_index = (uint32_t)user_data;
+		if (adapter_index >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return -1;
+		*remote_ip = prvlwip.socket[socket_id].pcb.tcp->remote_ip;
+		*remote_port = prvlwip.socket[socket_id].pcb.tcp->remote_port;
+	}
 	return 0;
 }
 //主动断开一个tcp连接,需要走完整个tcp流程,用户需要接收到close ok回调才能确认彻底断开
@@ -1364,6 +1444,7 @@ static int net_lwip2_socket_receive(int socket_id, uint64_t tag,  uint8_t *buf,
 static int net_lwip2_socket_send(int socket_id, uint64_t tag, const uint8_t *buf, uint32_t len, int flags, luat_ip_addr_t *remote_ip, uint16_t remote_port, void *user_data)
 {
 	int result = net_lwip2_check_socket(user_data, socket_id, tag);
+	// LLOGD("net_lwip2_socket_send check result %d socket %d", result, socket_id);
 	if (result) return result;
 	
 	uint8_t adapter_index = (uint32_t)user_data;
@@ -1372,6 +1453,7 @@ static int net_lwip2_socket_send(int socket_id, uint64_t tag, const uint8_t *buf
 	uint32_t save_len = 0;
 	uint32_t dummy_len = 0;
 	socket_data_t *p;
+	// LLOGD("socket %d send len %d", socket_id, len);
 	if (prvlwip.socket[socket_id].is_tcp)
 	{
 		while(save_len < len)
@@ -1614,7 +1696,7 @@ static const network_adapter_info prv_net_lwip2_adapter =
 		.socket_set_callback = net_lwip2_socket_set_callback,
 		.name = "lwip",
 		.max_socket_num = MAX_SOCK_NUM,
-		.no_accept = 1,
+		.no_accept = 0,
 		.is_posix = 1,
 		.check_ack = net_lwip2_check_ack
 };

+ 6 - 5
components/network/netdrv/binding/luat_lib_netdrv.c

@@ -380,7 +380,7 @@ static int l_netdrv_debug(lua_State *L) {
 }
 
 /*
-设置遥测功能(还未实现全部功能)
+设置遥测功能,开启后,会自动上报设备信息,2025/9/25启用
 @api netdrv.mreport(config, value)
 @string 配置项
 @boolean 设置功能开关
@@ -390,13 +390,14 @@ static int l_netdrv_debug(lua_State *L) {
 netdrv.mreport("enable", true)
 netdrv.mreport("enable", false)
 
+-- 设置使用的网络适配器,2025/10/30启用
+netdrv.mreport("adapter_id", socket.LWIP_GP)
+netdrv.mreport("adapter_id", socket.LWIP_STA)
+netdrv.mreport("adapter_id", socket.LWIP_ETH)
+
 -- 立即上报一次, 无参数的方式调用
 netdrv.mreport()
 
--- 设置自定义数据
-netdrv.mreport("custom", {abc=1234})
--- 清除自定义数据
-netdrv.mreport("custom")
 */
 extern int l_mreport_config(lua_State* L);
 

+ 1 - 0
components/network/netdrv/src/ch390h_api.c

@@ -227,6 +227,7 @@ int luat_ch390h_write_pkg(ch390h_t* ch, uint8_t *buff, uint16_t len) {
         }
         // return 1;
     }
+    luat_ch390h_write_reg(ch, 0x55, 2);     // 发数据之前重置一下tx的内存指针
     // 写入下一个数据
     luat_ch390h_write(ch, 0x78, len, buff);
     // TCR == 0之后, 才能写入长度

+ 0 - 327
components/network/posix/luat_network_posix.c

@@ -1,327 +0,0 @@
-#include "luat_base.h"
-#include "luat_network_adapter.h"
-#include "luat_mem.h"
-#include "luat_msgbus.h"
-#include "luat_crypto.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/select.h>
-
-#define LUAT_LOG_TAG "network"
-#include "luat_log.h"
-
-#include "luat_network_posix.h"
-
-CBFuncEx_t posix_network_cb;
-void * posix_network_param;
-uint8_t posix_network_ready;
-
-static luat_rtos_mutex_t* master_lock;
-
-static void posix_send_event(int id, int p1, int p2, int p3) {
-    luat_network_cb_param_t params = {0};
-    params.tag = 0;
-    params.param = posix_network_param;
-    // 触发一下回调
-    // if (ready) {
-    OS_EVENT event = {
-        .ID = id,
-        .Param1 = p1,
-        .Param2 = p2,
-        .Param3 = p3
-    };
-    LLOGD("posix event %d %d %d %d", id, p1, p2, p3);
-    posix_network_cb(&event, &params);
-}
-
-void posix_network_client_thread_entry(posix_socket_t *ps) {
-
-    luat_network_cb_param_t params = {0};
-    params.tag = 0;
-    params.param = posix_network_param;
-    // 触发一下回调
-    // if (ready) {
-    OS_EVENT event = {0};
-
-    struct sockaddr_in sockaddr = {0};
-    sockaddr.sin_family = AF_INET;
-    sockaddr.sin_port = htons(ps->remote_port);
-    sockaddr.sin_addr.s_addr = ps->remote_ip.ipv4;
-    luat_rtos_task_sleep(50);
-
-    LLOGD("ready to connect %d", ps->socket_id);
-    int ret = connect(ps->socket_id, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
-
-    LLOGD("connect ret %d", ret);
-    if (ret) {
-        // 失败了
-        LLOGD("connect FAIL ret %d", ret);
-        posix_send_event(EV_NW_SOCKET_ERROR, ps->socket_id, 0, 0);
-        luat_heap_free(ps);
-        return;
-    }
-    // 发送系统消息, 通知连接成功
-    posix_send_event(EV_NW_SOCKET_CONNECT_OK, ps->socket_id, 0, 0);
-    LLOGD("wait data now");
-
-    fd_set readfds;
-    fd_set writefds;
-    fd_set errorfds;
-    int maxsock;
-    struct timeval tv;
-    maxsock = ps->socket_id;
-    // timeout setting
-    tv.tv_sec = 0;
-    tv.tv_usec = 3000; //暂时3ms吧
-    while (1) {
-        // initialize file descriptor set
-        FD_ZERO(&readfds);
-        // FD_ZERO(&writefds);
-        FD_ZERO(&errorfds);
-        FD_SET(ps->socket_id, &readfds);
-        // FD_SET(ps->socket_id, &writefds);
-        FD_SET(ps->socket_id, &errorfds);
-
-        if (master_lock)
-            if (luat_rtos_mutex_lock(master_lock, 100))
-                continue;
-        ret = select(maxsock + 1, &readfds, NULL, &errorfds, &tv);
-        if (master_lock)
-            luat_rtos_mutex_unlock(master_lock);
-
-        if (ret < 0) {
-            LLOGE("select ret %d", ret);
-            break;
-        } else if (ret == 0) {
-            //printf("select timeout\n");
-            continue;
-        }
-
-        if (FD_ISSET(maxsock, &readfds)) {
-            // 发消息,可读了
-        }
-        // if (FD_ISSET(maxsock, &writefds)) {
-        //     // 发消息,发送完成了??
-        // }
-        if (FD_ISSET(maxsock, &errorfds)) {
-            // 发消息,出错了
-            break;
-        }
-    }
-
-    luat_heap_free(ps);
-    LLOGI("socket thread exit");
-}
-
-void posix_network_set_ready(uint8_t ready) {
-    LLOGD("CALL posix_network_set_ready");
-    posix_network_ready = ready;
-    luat_network_cb_param_t params = {0};
-    params.tag = 0;
-    params.param = posix_network_param;
-    // 触发一下回调
-    // if (ready) {
-        OS_EVENT event = {
-            .ID = EV_NW_STATE,
-            .Param1 = 0,
-            .Param2 = ready,
-            .Param3 = 0
-        };
-        posix_network_cb(&event, &params);
-    // }
-}
-
-//检查网络是否准备好,返回非0准备好,user_data是注册时的user_data,传入给底层api
-uint8_t (posix_check_ready)(void *user_data) {
-    LLOGD("CALL posix_check_ready %d", posix_network_ready);
-    return posix_network_ready;
-};
-
-//创建一个socket,并设置成非阻塞模式,user_data传入对应适配器, tag作为socket的合法依据,给check_socket_vaild比对用
-//成功返回socketid,失败 < 0
-int (posix_create_socket)(uint8_t is_tcp, uint64_t *tag, void *param, uint8_t is_ipv6, void *user_data) {
-    // TODO 支持IPV6
-    int s = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, is_tcp ? IPPROTO_TCP : IPPROTO_UDP);
-    LLOGD("CALL posix_create_socket %d %d", s, is_tcp);
-    return s;
-}
-
-//作为client绑定一个port,并连接remote_ip和remote_port对应的server
-//成功返回0,失败 < 0
-int (posix_socket_connect)(int socket_id, uint64_t tag, uint16_t local_port, luat_ip_addr_t *remote_ip, uint16_t remote_port, void *user_data) {
-    LLOGD("CALL posix_socket_connect %d", socket_id);
-    posix_socket_t *ps = luat_heap_malloc(sizeof(posix_socket_t));
-    if (ps == NULL) {
-        LLOGE("out of memory when malloc posix_socket_t");
-        return -1;
-    }
-    ps->socket_id = socket_id;
-    ps->tag = tag;
-    ps->local_port = local_port;
-    memcpy(&ps->remote_ip, remote_ip, sizeof(luat_ip_addr_t));
-    ps->remote_port = remote_port;
-    ps->user_data = user_data;
-
-    int ret = network_posix_client_thread_start(ps);
-    LLOGD("socket thread start %d", ret);
-
-    if (ret) {
-        luat_heap_free(ps);
-    }
-    return ret;
-}
-//作为server绑定一个port,开始监听
-//成功返回0,失败 < 0
-int (posix_socket_listen)(int socket_id, uint64_t tag, uint16_t local_port, void *user_data) {
-    // 尚未支持
-    return -1;
-}
-//作为server接受一个client
-//成功返回0,失败 < 0
-int (posix_socket_accept)(int socket_id, uint64_t tag, luat_ip_addr_t *remote_ip, uint16_t *remote_port, void *user_data) {
-    // 尚未支持
-    return -1;
-}
-
-//主动断开一个tcp连接,需要走完整个tcp流程,用户需要接收到close ok回调才能确认彻底断开
-//成功返回0,失败 < 0
-int (posix_socket_disconnect)(int socket_id, uint64_t tag, void *user_data) {
-    return close(socket_id);
-}
-
-//释放掉socket的控制权,除了tag异常外,必须立刻生效
-//成功返回0,失败 < 0
-int (posix_socket_close)(int socket_id, uint64_t tag, void *user_data) {
-    return close(socket_id);
-}
-
-//强行释放掉socket的控制权,必须立刻生效
-//成功返回0,失败 < 0
-int (posix_socket_force_close)(int socket_id, void *user_data) {
-    return close(socket_id);
-}
-
-//tcp时,不需要remote_ip和remote_port,如果buf为NULL,则返回当前缓存区的数据量,当返回值小于len时说明已经读完了
-//udp时,只返回1个block数据,需要多次读直到没有数据为止
-//成功返回实际读取的值,失败 < 0
-int (posix_socket_receive)(int socket_id, uint64_t tag, uint8_t *buf, uint32_t len, int flags, luat_ip_addr_t *remote_ip, uint16_t *remote_port, void *user_data) {
-    
-    struct timeval tv;
-    tv.tv_sec = 0;
-    tv.tv_usec = 1000; //暂时1ms吧
-    setsockopt(socket_id, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-
-    if (master_lock)
-        if (luat_rtos_mutex_lock(master_lock, 100))
-            return -1;
-    int ret = recv(socket_id, buf, len, flags);
-    if (master_lock)
-        luat_rtos_mutex_unlock(master_lock);
-    return ret;
-}
-
-//tcp时,不需要remote_ip和remote_port
-//成功返回>0的len,缓冲区满了=0,失败 < 0,如果发送了len=0的空包,也是返回0,注意判断
-int (posix_socket_send)(int socket_id, uint64_t tag, const uint8_t *buf, uint32_t len, int flags, luat_ip_addr_t *remote_ip, uint16_t remote_port, void *user_data) {
-    
-    struct timeval tv;
-    tv.tv_sec = 0;
-    tv.tv_usec = 1000; //暂时1ms吧
-    setsockopt(socket_id, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
-    if (master_lock)
-        if (luat_rtos_mutex_lock(master_lock, 100))
-            return -1;
-    int ret = send(socket_id, buf, len, flags);
-    if (master_lock)
-        luat_rtos_mutex_unlock(master_lock);
-    return ret;
-}
-
-//检查socket合法性,成功返回0,失败 < 0
-int (posix_socket_check)(int socket_id, uint64_t tag, void *user_data) {
-    // TODO 通过select errorfds?
-    LLOGD("CALL posix_socket_check %d %lld", socket_id, tag);
-    return 0;
-}
-
-//保留有效的socket,将无效的socket关闭
-void (posix_socket_clean)(int *vaild_socket_list, uint32_t num, void *user_data) {
-    
-}
-
-int (posix_getsockopt)(int socket_id, uint64_t tag, int level, int optname, void *optval, uint32_t *optlen, void *user_data) {
-    return getsockopt(socket_id, level, optname, optval, optlen);
-}
-
-int (posix_setsockopt)(int socket_id, uint64_t tag, int level, int optname, const void *optval, uint32_t optlen, void *user_data) {
-    return setsockopt(socket_id, level, optname, optval, optlen);
-}
-
-//非posix的socket,用这个根据实际硬件设置参数
-int (posix_user_cmd)(int socket_id, uint64_t tag, uint32_t cmd, uint32_t value, void *user_data) {
-    return 0; // 没有这些东西
-}
-
-
-int (posix_dns)(const char *domain_name, uint32_t len, void *param,  void *user_data) {
-    LLOGD("CALL posix_dns %.*s", len, domain_name);
-    return -1; // 暂不支持DNS
-}
-
-int (posix_set_dns_server)(uint8_t server_index, luat_ip_addr_t *ip, void *user_data) {
-    return 0; // 暂不支持设置DNS
-}
-
-#ifdef LUAT_USE_LWIP
-int (posix_set_mac)(uint8_t *mac, void *user_data);
-int (posix_set_static_ip)(luat_ip_addr_t *ip, luat_ip_addr_t *submask, luat_ip_addr_t *gateway, luat_ip_addr_t *ipv6, void *user_data);
-#endif
-int (posix_get_local_ip_info)(luat_ip_addr_t *ip, luat_ip_addr_t *submask, luat_ip_addr_t *gateway, void *user_data) {
-    ip->ipv4 = 0;
-    submask->ipv4 = 0;
-    gateway->ipv4 = 0;
-    return 0;
-}
-
-//所有网络消息都是通过cb_fun回调
-//cb_fun回调时第一个参数为OS_EVENT,包含了socket的必要信息,第二个是luat_network_cb_param_t,其中的param是这里传入的param(就是适配器序号)
-//OS_EVENT ID为EV_NW_XXX,param1是socket id param2是各自参数 param3是create_soceket传入的socket_param(就是network_ctrl *)
-//dns结果是特别的,ID为EV_NW_SOCKET_DNS_RESULT,param1是获取到的IP数据量,0就是失败了,param2是ip组,动态分配的, param3是dns传入的param(就是network_ctrl *)
-void (posix_socket_set_callback)(CBFuncEx_t cb_fun, void *param, void *user_data) {
-    LLOGD("call posix_socket_set_callback %p %p", cb_fun, param);
-    if (master_lock == NULL)
-        luat_rtos_mutex_create(master_lock);
-    posix_network_cb = cb_fun;
-    posix_network_param = param;
-}
-
-
-network_adapter_info network_posix = {
-    .check_ready = posix_check_ready,
-    .create_soceket = posix_create_socket,
-    .socket_connect  = posix_socket_connect,
-    .socket_accept = posix_socket_accept,
-    .socket_disconnect  = posix_socket_disconnect,
-    .socket_close = posix_socket_close,
-    .socket_force_close = posix_socket_force_close,
-    .socket_receive = posix_socket_receive,
-    .socket_send = posix_socket_send,
-    .socket_clean = posix_socket_clean,
-    .getsockopt = posix_getsockopt,
-    .setsockopt = posix_setsockopt,
-    .user_cmd  = posix_user_cmd,
-    .dns = posix_dns,
-    .set_dns_server = posix_set_dns_server,
-    .get_local_ip_info = posix_get_local_ip_info,
-    .socket_set_callback = posix_socket_set_callback,
-    .name = "posix",
-    .max_socket_num = 4,
-    .no_accept = 1, // 暂时不支持接收
-    .is_posix = 1,
-};

+ 0 - 20
components/network/posix/luat_network_posix.h

@@ -1,20 +0,0 @@
-#ifndef LUAT_NETWORK_POSIX_H
-#define LUAT_NETWORK_POSIX_H
-
-#include "luat_base.h"
-#include "luat_network_adapter.h"
-
-typedef struct posix_socket
-{
-    int socket_id;
-    uint64_t tag;
-    uint16_t local_port;
-    luat_ip_addr_t remote_ip;
-    uint16_t remote_port;
-    void *user_data;
-}posix_socket_t;
-
-int network_posix_client_thread_start(posix_socket_t* ps);
-void posix_network_client_thread_entry(posix_socket_t* args);
-
-#endif

+ 1 - 1
components/statem/luat_lib_statem.c

@@ -14,7 +14,7 @@
 
 /*
 创建一个新的状态机.
-@api statem.create(count, repeat)
+@api statem.create(count, repeats)
 @int 指令条数,默认32条
 @int 重复执行的次数, 0 代表不重复, 正整数代表具体重复执行的次数. 暂不支持永续执行
 @return some 若成功,返回状态机指针,否则返回nil

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 622 - 636
components/tp/cst92xx_fw.h


+ 1 - 1
components/tp/luat_lib_tp.c

@@ -36,7 +36,7 @@ static const tp_reg_t tp_regs[] = {
 	{"jd9261t_inited",  &tp_config_jd9261t_inited},
 	{"ft3x68", &tp_config_ft3x68},
     {"cst820", &tp_config_cst820},
-    // {"cst9220", &tp_config_cst92xx},
+    {"cst9220", &tp_config_cst92xx},
     #endif
 #endif
 #ifdef LUAT_USE_TP_PC

+ 23 - 110
components/tp/luat_tp_cst9220.c

@@ -11,8 +11,6 @@
 #define LUAT_LOG_TAG "cst92xx"
 #include "luat_log.h"
 
-#define HYN_POWER_ON_UPDATA           (0) //touch fw updata
-
 #define CST92XX_ADDRESS               (0x5A)
 
 #define CST9217_CHIP_ID_CODE          (0x9217)
@@ -107,19 +105,20 @@ static int hyn_wr_reg(luat_tp_config_t* luat_tp_config, uint32_t reg_addr, uint8
         reg_addr >>= 8;
     }
 
-    if (luat_tp_config->soft_i2c != NULL){
-        ret = i2c_soft_send(luat_tp_config->soft_i2c, luat_tp_config->address, (char *)wbuf, reg_len, 1);
-    }else{
-        ret = luat_i2c_send(luat_tp_config->i2c_id, luat_tp_config->address, wbuf, reg_len, 1);
-    }
-    if(rlen){
+    if (rlen){
         if (luat_tp_config->soft_i2c != NULL){
+            ret = i2c_soft_send(luat_tp_config->soft_i2c, luat_tp_config->address, (char *)wbuf, reg_len, 1);
             ret |= i2c_soft_recv(luat_tp_config->soft_i2c, luat_tp_config->address, (char *)rbuf, rlen);
         }else{
-            ret |= luat_i2c_recv(luat_tp_config->i2c_id, luat_tp_config->address, rbuf, rlen);
+            ret = luat_i2c_transfer(luat_tp_config->i2c_id, luat_tp_config->address, wbuf, reg_len, rbuf, rlen);
+        }
+    }else{
+        if (luat_tp_config->soft_i2c != NULL){
+            ret = i2c_soft_send(luat_tp_config->soft_i2c, luat_tp_config->address, (char *)wbuf, reg_len, 1);
+        }else{
+            ret = luat_i2c_send(luat_tp_config->i2c_id, luat_tp_config->address, wbuf, reg_len, 1);
         }
     }
-
     return ret;
 }
 
@@ -251,7 +250,7 @@ static int tp_cst92xx_updata_tpinfo(luat_tp_config_t* luat_tp_config){
 static int tp_cst92xx_hw_reset(luat_tp_config_t* luat_tp_config){
     if (luat_tp_config->pin_rst != LUAT_GPIO_NONE){
         luat_gpio_set(luat_tp_config->pin_rst, Luat_GPIO_LOW);
-        luat_rtos_task_sleep(8);
+        luat_rtos_task_sleep(1);
         luat_gpio_set(luat_tp_config->pin_rst, Luat_GPIO_HIGH);
     }
     return 0;
@@ -368,85 +367,6 @@ static int tp_cst92xx_read_chip_id(luat_tp_config_t* luat_tp_config){
     return 0;
 }
 
-static uint32_t cst92xx_read_checksum(luat_tp_config_t* luat_tp_config){
-    uint8_t i2c_buf[4] = {0};
-    uint32_t chip_checksum = 0;
-    uint8_t retry = 5;
-    
-    hyn_92xxdata.boot_is_pass = 0;
-
-    if (hyn_wr_reg(luat_tp_config,0xA00300,3,i2c_buf,0)) {
-        return -1;
-    }      
-    luat_rtos_task_sleep(2);    
-    while(retry--){
-        luat_rtos_task_sleep(5);
-        if (hyn_wr_reg(luat_tp_config,0xA000,2,i2c_buf,1)) {
-            continue;
-        }
-        if(i2c_buf[0]!=0) break;
-    }
-
-    luat_rtos_task_sleep(1);
-    if(i2c_buf[0] == 0x01){
-        hyn_92xxdata.boot_is_pass = 1;
-        memset(i2c_buf,0,sizeof(i2c_buf));
-
-        if (hyn_wr_reg(luat_tp_config,0xA008,2,i2c_buf,4)) {
-            return -1;
-        }      
-
-        chip_checksum = ((uint32_t)(i2c_buf[0])) |
-            (((uint32_t)(i2c_buf[1])) << 8) |
-            (((uint32_t)(i2c_buf[2])) << 16) |
-            (((uint32_t)(i2c_buf[3])) << 24);
-    }
-    else{
-        hyn_92xxdata.need_updata_fw = 1;
-    }
-
-    return chip_checksum;
-}
-
-static int cst92xx_updata_judge(luat_tp_config_t* luat_tp_config, uint8_t *p_fw, uint16_t len){
-    uint32_t f_checksum,f_fw_ver,f_ictype,f_fw_project_id;
-    uint8_t *p_data = p_fw + len - 28;   //7F64
-    struct tp_info *ic = &hyn_92xxdata.hw_info;
-
-    if (tp_cst92xx_enter_boot(luat_tp_config)){
-        LLOGI("cst92xx_enter_boot fail,need update");
-        return -1; 
-    }
-    hyn_92xxdata.hw_info.ic_fw_checksum = cst92xx_read_checksum(luat_tp_config);
-    if(hyn_92xxdata.boot_is_pass == 0){
-        LLOGI("boot_is_pass %d,need force update",hyn_92xxdata.boot_is_pass);
-        return -1; //need updata
-    }
-    
-    f_fw_project_id = U8TO16(p_data[1],p_data[0]);
-    f_ictype = U8TO16(p_data[3],p_data[2]);
-
-    f_fw_ver = U8TO16(p_data[7],p_data[6]);
-    f_fw_ver = (f_fw_ver<<16)|U8TO16(p_data[5],p_data[4]);
-
-    f_checksum = U8TO16(p_data[11],p_data[10]);
-    f_checksum = (f_checksum << 16)|U8TO16(p_data[9],p_data[8]);
-
-
-    LLOGI("Bin_info project_id:0x%04x ictype:0x%04x fw_ver:0x%x checksum:0x%x",f_fw_project_id,f_ictype,f_fw_ver,f_checksum);
-    if(f_ictype != ic->fw_chip_type || f_fw_project_id != ic->fw_project_id){
-        LLOGE("not update,please confirm: ic_type 0x%04x,ic_project_id 0x%04x",ic->fw_chip_type,ic->fw_project_id);
-        return 0; //not updata
-    }
-    if(f_checksum != ic->ic_fw_checksum && f_fw_ver > ic->fw_ver){
-        LLOGI("need update!");
-        return -1; //need updata
-    }
-    LLOGI("cst92xx_updata_judge done, no need update");
-    return 0;
-}
-
-
 static int tp_cst92xx_gpio_init(luat_tp_config_t* luat_tp_config){
     luat_gpio_mode(luat_tp_config->pin_rst, Luat_GPIO_OUTPUT, Luat_GPIO_DEFAULT, Luat_GPIO_HIGH);
     luat_gpio_mode(luat_tp_config->pin_int, Luat_GPIO_OUTPUT, Luat_GPIO_DEFAULT, Luat_GPIO_HIGH);
@@ -475,22 +395,6 @@ static int tp_cst92xx_init(luat_tp_config_t* luat_tp_config){
     tp_cst92xx_hw_reset(luat_tp_config);
     luat_rtos_task_sleep(40);
 
-#if HYN_POWER_ON_UPDATA
-    if(tp_cst92xx_read_chip_id(luat_tp_config)){
-        LLOGE("cst92xx_read_chip_id failed");
-        return ret;
-    }
-
-    ret = tp_cst92xx_updata_tpinfo(luat_tp_config);
-    if(ret){
-        LLOGE("cst92xx_updata_tpinfo failed");
-        return ret;
-    }
-    cst92xx_updata_judge(luat_tp_config,(uint8_t*)fw_bin,CST92XX_BIN_SIZE);
-    tp_cst92xx_hw_reset(luat_tp_config);
-    luat_rtos_task_sleep(40);
-#endif
-
     ret = tp_cst92xx_updata_tpinfo(luat_tp_config);
     if(ret){
         LLOGE("cst92xx_updata_tpinfo failed");
@@ -659,10 +563,19 @@ static int tp_cst92xx_read(luat_tp_config_t* luat_tp_config, luat_tp_data_t *lua
     if (hyn_wr_reg(luat_tp_config, 0xD000,2,read_buff,sizeof(read_buff))){
         goto exit_;
     }   
-        
-    if (hyn_wr_reg(luat_tp_config, 0xD000AB,3,read_buff,0)){
-        goto exit_;
-    }   
+    
+    if (read_buff[0] & 0x0F)
+    {
+        if (hyn_wr_reg(luat_tp_config, 0xD000AB,3,read_buff,0)){
+            goto exit_;
+        }
+    }
+    else
+    {
+        if (hyn_wr_reg(luat_tp_config, 0xD000CC,3,read_buff,0)){
+            goto exit_;
+        }
+    }
 
     // luat_rtos_task_sleep(8);
     // for (size_t i = 0; i < sizeof(read_buff); i++){

+ 1 - 1
luat/include/luat_crypto.h

@@ -161,7 +161,7 @@ uint8_t luat_crc8(const void *data, uint32_t len, uint8_t start, uint8_t poly, u
  * @param is_reverse 是否逆序计算,顺序从MSB算到LSB,逆序从LSB算到MSB,不清楚的2个都试试
  * @return 输出值
  */
-uint16_t luat_crc16(const void *data, uint32_t len, uint16_t start, uint16_t poly, uint8_t is_reverse);
+uint16_t luat_crc16(const void *data, uint32_t len, uint16_t start, uint16_t final, uint16_t poly, uint8_t is_reverse);
 
 /**
  * @brief crc32常用算法

+ 1 - 0
luat/include/luat_libs.h

@@ -103,6 +103,7 @@ LUAMOD_API int luaopen_coremark( lua_State *L );
 
 LUAMOD_API int luaopen_fonts( lua_State *L );
 LUAMOD_API int luaopen_gtfont( lua_State *L );
+LUAMOD_API int luaopen_hzfont( lua_State *L );
 
 LUAMOD_API int luaopen_pin( lua_State *L );
 LUAMOD_API int luaopen_pins( lua_State *L );

+ 4 - 0
luat/include/luat_sfd.h

@@ -5,7 +5,9 @@
 #include "luat_base.h"
 
 #include "luat_spi.h"
+#ifdef __LUATOS__
 #include "luat_zbuff.h"
+#endif
 
 typedef struct sdf_opts {
     int (*initialize) (void* userdata);
@@ -25,7 +27,9 @@ typedef struct sfd_drv {
             int id;
             int cs;
         } spi;
+#ifdef __LUATOS__
         luat_zbuff_t* zbuff;
+#endif
     } cfg;
     size_t sector_size;
     size_t sector_count;

+ 51 - 13
luat/modules/luat_lib_crypto.c

@@ -283,10 +283,31 @@ int l_crypto_cipher_decrypt(lua_State *L) {
 }
 
 #include "crc.h"
-
+typedef struct{
+const char *name;   //参数模型
+uint16_t crc16_polynomial;   //多项式
+uint16_t initial_value;  //初始值
+uint16_t finally_data;  //结果异或值
+uint8_t input_reverse; //输入数据反转
+uint8_t output_reverse; //输出数据反转
+} crc16method;
+
+static const crc16method crc16method_table[] = 
+{
+    {(const char*)"IBM", 0x8005, 0x0000, 0x0000, 1, 1},
+    {(const char*)"MAXIM", 0x8005, 0x0000, 0xffff, 1, 1}, 
+    {(const char*)"USB", 0x8005, 0xffff, 0xffff, 1, 1}, 
+    {(const char*)"MODBUS", 0x8005, 0xffff, 0x0000, 1, 1}, 
+    {(const char*)"CCITT", 0x1021, 0x0000, 0x0000, 1, 1}, 
+    {(const char*)"CCITT-FALSE", 0x1021, 0xffff, 0x0000, 0, 0}, 
+    {(const char*)"X25", 0x1021, 0xffff, 0xffff, 1, 1}, 
+    {(const char*)"XMODEM", 0x1021, 0x0000,0x0000, 0, 0}, 
+    {(const char*)"DNP", 0x3D65, 0x0000, 0xffff, 1, 1},
+    {(const char*)"USER-DEFINED", 0x0000, 0x0000,0x0000, 0, 0},
+};
 /**
 计算CRC16
-@api crypto.crc16(method, data, poly, initial, finally, inReversem outReverse)
+@api crypto.crc16(method, data, poly, initial, finally, inReversem, outReverse)
 @string CRC16模式("IBM","MAXIM","USB","MODBUS","CCITT","CCITT-FALSE","X25","XMODEM","DNP","USER-DEFINED")
 @string 字符串或者zbuff对象
 @int poly值,默认0x0000,范围0-0xFFFF
@@ -308,6 +329,11 @@ static int l_crypto_crc16(lua_State *L)
     size_t inputlen = 0;
     const unsigned char *inputData = NULL;
     const char  *inputmethod = (const char*)luaL_checkstring(L, 1);
+    uint16_t poly_default = 0x0000;
+    uint16_t initial_default = 0x0000;
+    uint16_t finally_default = 0x0000;
+    uint16_t in_reverse = 0;
+    uint16_t out_reverse = 0;
     if(lua_isuserdata(L, 2))
     {
         luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
@@ -315,13 +341,25 @@ static int l_crypto_crc16(lua_State *L)
         inputData = (const unsigned char *)(buff->addr + buff->cursor);
     }else{
         inputData = (const unsigned char*)lua_tolstring(L,2,&inputlen);
+    }    
+    for (int i = 0; i < sizeof(crc16method_table)/sizeof(crc16method_table[0]); i++)
+    {
+        if (strcmp(crc16method_table[i].name, inputmethod) == 0)
+        {
+            poly_default = crc16method_table[i].crc16_polynomial;
+            initial_default = crc16method_table[i].initial_value;
+            finally_default = crc16method_table[i].finally_data;
+            in_reverse = crc16method_table[i].input_reverse;
+            out_reverse = crc16method_table[i].output_reverse;
+        }
     }
-    uint16_t poly = (uint16_t)luaL_optnumber(L,3,0x0000);
-    uint16_t initial = (uint16_t)luaL_optnumber(L,4,0x0000);
-    uint16_t finally = (uint16_t)luaL_optnumber(L,5,0x0000);
-    uint8_t inReverse = (uint8_t)luaL_optnumber(L,6,0);
-    uint8_t outReverse = (uint8_t)luaL_optnumber(L,7,0);
-    lua_pushinteger(L, calcCRC16(inputData, inputmethod,inputlen,poly,initial,finally,inReverse,outReverse));
+    uint16_t poly = (uint16_t)luaL_optnumber(L,3,poly_default);
+    uint16_t initial = (uint16_t)luaL_optnumber(L,4,initial_default);
+    uint16_t finally = (uint16_t)luaL_optnumber(L,5,finally_default);
+    uint8_t inReverse = (uint8_t)luaL_optnumber(L,6,in_reverse);
+    uint8_t outReverse = (uint8_t)luaL_optnumber(L,7,out_reverse);
+    
+    lua_pushinteger(L, luat_crc16(inputData, inputlen, initial, finally, poly, inReverse));
     return 1;
 }
 
@@ -343,7 +381,7 @@ static int l_crypto_crc16_modbus(lua_State *L)
     const unsigned char *inputData = (const unsigned char*)luaL_checklstring(L, 1, &len);
     uint16_t crc_init = (uint16_t)luaL_optinteger(L, 2, 0xFFFF);
 
-    lua_pushinteger(L, calcCRC16_modbus(inputData, len, crc_init));
+    lua_pushinteger(L, luat_crc16_modbus(inputData, len));
     return 1;
 }
 
@@ -387,10 +425,10 @@ local crc = crypto.crc8(data, 0x31, 0xff, false)
  */
 static int l_crypto_crc8(lua_State *L)
 {
-    size_t len = 0;
+    size_t len = 0; 
     const unsigned char *inputData = (const unsigned char*)luaL_checklstring(L, 1, &len);
     if (!lua_isinteger(L, 2)) {
-        lua_pushinteger(L, calcCRC8(inputData, len));
+        lua_pushinteger(L, luat_crc8(inputData, len, 0x00, 0x07, 0));//poly默认值0x0000
     } else {
     	uint8_t poly = (uint8_t)lua_tointeger(L, 2);
     	uint8_t start = (uint8_t)luaL_optinteger(L, 3, 0);
@@ -400,7 +438,7 @@ static int l_crypto_crc8(lua_State *L)
     	}
 		lua_pushinteger(L, luat_crc8(inputData, len, start, poly, is_rev));
     }
-    return 1;
+    return 1; 
 }
 
 
@@ -671,7 +709,7 @@ static int l_crypto_md(lua_State *L) {
 
 /*
 创建流式hash用的stream
-@api crypto.hash_init(tp)
+@api crypto.hash_init(tp, hmac)
 @string hash类型, 大写字母, 例如 "MD5" "SHA1" "SHA256"
 @string hmac值,可选
 @return userdata 成功返回一个数据结构,否则返回nil

+ 1 - 1
luat/modules/luat_lib_ir.c

@@ -86,7 +86,7 @@ static void ir_nec_send(int pin, uint8_t code)
 
 /**
 发送NEC数据
-@api ir.sendNEC(pin, addr, cmd, repeat, disablePWM)
+@api ir.sendNEC(pin, addr, cmd, repeats, disablePWM)
 @int 使用的GPIO引脚编号
 @int 用户码(大于0xff则采用Extended NEC模式)
 @int 数据码

+ 1 - 1
luat/modules/luat_lib_mcu.c

@@ -402,7 +402,7 @@ static int l_mcu_xtal_ref_output(lua_State* L) {
 
 LUAT_WEAK int luat_mcu_muid(char* buf) {return -1;}
 static int l_mcu_muid(lua_State* L) {
-	char muid[20];
+	char muid[33] = {0};
 	luat_mcu_muid(muid);
 	// LLOGD("mcu muid %s", muid);
 	lua_pushstring(L, muid);

+ 2 - 2
module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/cc_app.lua

@@ -31,8 +31,8 @@ local audio_drv = require "audio_drv"
 -- 设置当前激活的场景(1-4),注释掉不需要的场景
 -- local ACTIVE_SCENARIO = 1  -- 场景1:呼入立即挂断
 -- local ACTIVE_SCENARIO = 2  -- 场景2:呼入自动接听,10秒后主动挂断
---local ACTIVE_SCENARIO = 3  -- 场景3:呼入自动接听,等待对方挂断
- local ACTIVE_SCENARIO = 4  -- 场景4:主动呼出,等待对方挂断
+local ACTIVE_SCENARIO = 3  -- 场景3:呼入自动接听,等待对方挂断
+-- local ACTIVE_SCENARIO = 4  -- 场景4:主动呼出,等待对方挂断
 
 -- 全局状态变量
 local call_counter = 0                 -- 响铃计数器(用于场景1-3)

+ 8 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/main.lua

@@ -54,12 +54,19 @@ end
 --     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)
+
 
 
 -- 仅加载必要的功能模块

+ 24 - 18
module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHM_cc/readme.md

@@ -1,13 +1,13 @@
 # CC_DEMO 项目说明
 
 ## 项目概述
-本项目是基于 Air780EHM 的语音通信演示demo,实现了基本的语音通话功能,包括音频设备初始化、通话建立、通话管理等核心功能。
+本项目是基于 Air780EHM/Air780EGH 的语音通信演示demo,实现了基本的语音通话功能,包括音频设备初始化、通话建立、通话管理等核心功能。
 
 ## 文件结构
 - main.lua: 主程序入口,仅加载初始化模块
 - audio_device.lua: 管理音频设备初始化与控制
 - cc_app.lua: 实现完整通话业务逻辑
-- pins_Air780EHM.json: IO复用描述文件,由LuatIO工具自动生成
+- pins_Air780EHM.json/pins_Air780EGH.json: IO复用描述文件,由LuatIO工具自动生成
 
 ## 功能说明
 1. **音频设备初始化与控制**:配置并管理ES8311音频编解码芯片和扬声器功放,包括I2C、I2S接口设置及音量控制。
@@ -28,35 +28,41 @@
 
 ## 演示硬件环境
  
- Air780EHM核心板+AirAUDIO_1010 音频扩展板+喇叭
+ Air780EHM核心板/Air780EGH核心板+AirAUDIO_1010 音频扩展板+喇叭
 
 ![alt text]( https://docs.openLuat.com/cdn/image/Air780EHM+Airaudio1010.jpg)
 
+
+![alt text]( https://docs.openLuat.com/cdn/image/Air780EGH-AIRAUDIO_1010.jpg)
+
 - 具备volte功能的电话卡插入开发板/核心板的sim卡槽
 
 2、TYPE-C USB数据线一根
 - Air780EHM核心板通过 TYPE-C USB 口供电;
 - TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
 
-3、可选AirAudio_1010 配件板一块,Air780EHM核心板和AirAudio_1010 配件板的硬件接线方式为:
-|  Air780EHM核心板 | AirAUDIO_1010配件板 |
-| --------------- | -----------------   |
-| 26/I2S_MCLK     | I2S_MCLK            |
-| 30/I2S_BCK      | I2S_BCK             |
-| 31/I2S_LRCK     | I2S_LRCK            |
-| 32/I2S_DIN      | I2S_DIN             |
-| 33/I2S_DOUT     | I2S_DOUT            |
-| 67/I2C1_SCL     | I2C_SCL             |
-| 66/I2C1_SDA     | I2C_SDA             |
-| 25/GPIO26       | PA_EN               |
-| 23/GPIO2        | 8311_EN             |
-| VDD_EXT         | VCC                 |
-| GND             | GND                 |
+3、可Air780EHM核心板/Air780EGH核心板和AirAudio_1010 扩展板的硬件接线方式为:
+|  Air780EHM核心板/Air780EGH核心板 | AirAUDIO_1010扩展板 |
+| ---------------                 | -----------------   |
+| 33/I2S_MCLK                     | I2S_MCLK            |
+| 30/I2S_BCK                      | I2S_BCK             |
+| 31/I2S_LRCK                     | I2S_LRCK            |
+| 32/I2S_DIN                      | I2S_DIN             |
+| 33/I2S_DOUT                     | I2S_DOUT            |
+| 67/I2C1_SCL                     | I2C_SCL             |
+| 66/I2C1_SDA                     | I2C_SDA             |
+| 25/GPIO26                       | PA_EN               |
+| 23/GPIO2                        | 8311_EN             |
+| VDD_EXT                         | VCC                 |
+| GND                             | GND                 |
 
 ## 演示软件环境
 1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/common/Luatools/)
 
-2、Air780EHM V2016版本固件(理论上,2025年7月26日之后发布的固件都可以)),选择支持Volte功能的1、2、13或101、102、113号固件。不同版本区别请见https://docs.openluat.com/air780epm/luatos/firmware/version/
+2、[Air780EHM V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air780EHM/LuatOS-SoC_V2016_Air780EHM.zip),选择支持Volte功能的1、2、13或101、102、113号固件。不同版本区别请见[Air780EHM LuatOS固件版本](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+
+ [Air780EGH V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air780EGH/LuatOS-SoC_V2016_Air780EGH.zip)选择支持Volte功能的1、2、13或101、102、113号固件。不同版本区别参考[Air780EGH LuatOS固件版本](https://docs.openluat.com/air780egh/luatos/firmware/version/)。
 
 3、[合宙 LuatIO 工具(GPIO 复用初始化配置)使用说明] (https://docs.openluat.com/air780epm/common/luatio/)
 

+ 8 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/CC/Air780EHV_cc/main.lua

@@ -55,12 +55,19 @@ end
 --     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)
+
 
 
 -- 仅加载必要的功能模块

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/10.amr → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/10.amr


+ 19 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/main.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/main.lua

@@ -37,7 +37,7 @@ VERSION:项目版本号,ascii string类型
 ]]
 
 --[[
-本demo可直接在Air8000整机开发板上运行
+本demo可使用Air780EHM核心板/Air780EGH核心板+AirAUDIO_1010 音频扩展板+喇叭两种硬件环境演示
 ]]
 
 PROJECT = "audio"
@@ -55,6 +55,24 @@ if wdt then
     sys.timerLoopStart(wdt.feed, 3000)
 end
 
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+
+
 
 require "play_file"     --   播放音频文件,可支持wav,amr,mp3 格式音频
 -- require "play_tts"      -- 支持文字转普通话输出需要固件支持

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/pins_air780ehm.json → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/pins_air780ehm.json


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/play_file.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_file.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/play_stream.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_stream.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/play_tts.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/play_tts.lua


+ 212 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/readme.md

@@ -0,0 +1,212 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、play_file.lua: 播放音频文件,可支持wav,amr,mp3 格式音频
+
+3、play_tts: 支持文字转普通话输出需要固件支持
+
+4、play_stream: 流式播放音频,仅支持PCM 格式
+
+5、record_file: 录音到文件,仅支持PCM 格式
+
+6、record_stream:  流式录音,仅支持PCM。
+
+7、sample-6s.mp3/10.amr: 用于测试本地mp3和amr文件播放
+
+8、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
+
+
+**注意:目前不支持录音和放音同时进行**
+
+
+## 常量的介绍
+
+1、exaudio.PLAY_DONE : 当播放音频结束时,会在回调函数返回播放完成的时间
+
+2、exaudio.RECORD_DONE : 当录音结束时,会在回调函数返回播放完成的时间
+
+3、exaudio.AMR_NB : 仅录音时有用,表示使用AMR_NB 方式录音
+
+4、exaudio.AMR_WB : 仅录音时有用,表示使用AMR_WB 方式录音
+
+5、exaudio.PCM_8000/exaudio.PCM_16000/exaudio.PCM_24000/exaudio.PCM_32000 :  仅录音时有用,表示使用8000/16000/24000/32000/秒 的速度对音频进行采样
+
+
+## 演示功能概述
+
+1、play_flie.lua 自动播放一个sample-6s.mp3音乐,点powerkey 按键进行音频切换,播放10.amr文件,点击boot 按键停止音频播放
+
+2、play_tts.lua 播放一个TTS,点powerkey 按键进行tts 的音色切换,点击boot 按键停止音频播放
+
+3、play_stream.lua 流式播放PCM,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加
+
+4、record_file.lua 录音到文件,演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+
+5、record_stream.lua 流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用
+
+
+## 演示硬件环境
+1、Air780EHM核心板/Air780EGH核心板+AirAUDIO_1010 音频配件板+喇叭
+
+![alt text]( https://docs.openLuat.com/cdn/image/Air780EHM+Airaudio1010.jpg)
+
+
+![alt text]( https://docs.openLuat.com/cdn/image/Air780EGH-AIRAUDIO_1010.jpg)
+
+Air780EHM核心板/Air780EGH核心板和AirAudio_1010 配件板的硬件接线方式为:
+|  Air780EHM核心板/Air780EGH核心板 | AirAUDIO_1010配件板 |
+| ---------------                 | -----------------   |
+| 33/I2S_MCLK                     | I2S_MCLK            |
+| 30/I2S_BCK                      | I2S_BCK             |
+| 31/I2S_LRCK                     | I2S_LRCK            |
+| 32/I2S_DIN                      | I2S_DIN             |
+| 33/I2S_DOUT                     | I2S_DOUT            |
+| 67/I2C1_SCL                     | I2C_SCL             |
+| 66/I2C1_SDA                     | I2C_SDA             |
+| 25/GPIO26                       | PA_EN               |
+| 23/GPIO2                        | 8311_EN             |
+| VDD_EXT                         | VCC                 |
+| GND                             | GND                 |
+
+2、TYPE-C USB数据线一根
+- Air780EHM核心板通过/Air780EGH核心板 TYPE-C USB 口供电;
+- TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air780EHM V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air780EHM/LuatOS-SoC_V2016_Air780EHM.zip),选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。不同版本区别参考[Air780EHM LuatOS固件版本](https://docs.openluat.com/air780epm/luatos/firmware/version/)。
+
+ [Air780EGH V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air780EGH/LuatOS-SoC_V2016_Air780EGH.zip),选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。不同版本区别参考[Air780EGH LuatOS固件版本](https://docs.openluat.com/air780egh/luatos/firmware/version/)。
+
+3、 luatos需要的脚本和资源文件
+- 脚本和资源文件[点我浏览所有文件](https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio)
+
+- 准备好软件环境之后,接下来查看[如何烧录项目文件到Air780EXX核心板](https://docs.openluat.com/air780epm/luatos/common/download/),将本篇文章中演示使用的项目文件烧录到Air780EHM/Air780EGH核心板中。
+
+4、[合宙 LuatIO 工具(GPIO 复用初始化配置)使用说明](https://docs.openluat.com/air780epm/common/luatio/)
+
+5、 lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、demo脚本代码main.lua中,按照自己的需求选择对应的功能
+
+- 如果需要测试播放音频文件,则选择play_file 文件
+
+- 如果需要测试播放tts,则选择play_tts 文件
+
+- 如果需要测试流式播放音频,则选择play_stream 文件
+
+- 如果需要测试录音频到文件,则选择record_file 文件
+
+- 如果需要测试流式录音,则选择record_stream 文
+
+
+3、Luatools烧录内核固件和修改后的demo脚本代码
+
+4、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
+
+5、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
+
+
+6、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
+
+7、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+
+8、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用。
+
+9、运行结果展示
+
+- 播放文件 (play_file.lua)
+
+自动播放一个sample-6s.mp3 音乐;
+
+点击powerkey 按键进行音频切换播放10.amr文件;
+
+点击boot 按键停止音频播放
+
+``` lua
+ I/user.开始播放音频文件
+ I/user.播放完成 true
+
+ I/user.切换播放
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+ ```
+
+ - 文字转语音 (play_tts.lua)
+
+ 播放一个TTS;
+
+点击powerkey 按键进行tts 的音色切换
+
+点击boot 按键停止音频播放
+
+``` lua
+ I/user.开始播放TTS
+ I/user.切换播放
+
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+
+```
+
+- 流式播放 (play_stream.lua)
+
+创建一个播放流式音频task(task_audio)和一个模拟获取流式音频的task(audio_get_data),此task通过流式传输不断向exaudio.play_stream_write填入播放的音频,播放task 不断播放传入流式音频。
+
+使用powerkey 按键进行音量减小,点击boot 按键进行音量增加
+
+``` lua
+ I/user.开始流式获取音频数据
+ I/user.开始流式播报
+
+ I/user.减小音量55
+ I/user.增大音量75
+
+ I/user.播放状态 true
+ I/user.播放完成 true
+
+```
+
+- 录音到文件  (record_file.lua)
+
+主程序录音到/record.amr 文件
+
+使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+
+``` lua
+ I/user.开始录制音频到文件
+
+ E/user.减小音量55
+ I/user.增大音量75
+
+ I/user.录音后文件大小 320000
+```
+
+- 流式录音(record_stream.lua),仅支持PCM格式
+
+主程序录音进行流式录音
+
+录音过程中不断的进行recode_data_callback回调,回调内容为音频流的地址和长度。
+
+``` lua
+ I/user.开始流式录制音频到文件
+ I/user.收到音频流,地址为: ZBUFF*:0C7F70A8 有效数据长度为: 9600
+ I/user.录音完成
+
+ E/user.减小音量55
+ I/user.增大音量75
+
+ I/user.录音后
+
+

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/record_file.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/record_file.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/record_stream.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/record_stream.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/sample-6s.mp3 → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/sample-6s.mp3


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/test.pcm → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_Air780EGH/test.pcm


+ 0 - 123
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHM_audio/readme.md

@@ -1,123 +0,0 @@
-## 功能模块介绍
-
-1、main.lua:主程序入口;
-
-2、play_file.lua: 播放音频文件,可支持wav,amr,mp3 格式音频
-
-3、play_tts: 支持文字转普通话输出需要固件支持
-
-4、play_stream: 流式播放音频,仅支持PCM 格式
-
-5、record_file: 录音到文件,仅支持PCM 格式
-
-6、record_stream:  流式录音,仅支持PCM。
-
-7、sample-6s.mp3/10.amr: 用于测试本地mp3文件播放
-
-8、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
-
-
-**注意:目前不支持录音和放音同时进行**
-
-
-## 常量的介绍
-
-1、exaudio.PLAY_DONE : 当播放音频结束时,会在回调函数返回播放完成的时间
-
-2、exaudio.RECORD_DONE : 当录音结束时,会在回调函数返回播放完成的时间
-
-3、exaudio.AMR_NB : 仅录音时有用,表示使用AMR_NB 方式录音
-
-4、exaudio.AMR_WB : 仅录音时有用,表示使用AMR_WB 方式录音
-
-5、exaudio.PCM_8000/exaudio.PCM_16000/exaudio.PCM_24000/exaudio.PCM_32000 :  仅录音时有用,表示使用8000/16000/24000/32000/秒 的速度对音频进行采样
-
-
-## 演示功能概述
-
-1、play_flie.lua 自动播放一个sample-6s.mp3音乐,点powerkey 按键进行音频切换,播放10.amr文件,点击boot 按键停止音频播放
-
-2、play_tts.lua 播放一个TTS,点powerkey 按键进行tts 的音色切换,点击boot 按键停止音频播放
-
-3、play_stream.lua 流式播放PCM,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加
-
-4、record_file.lua 录音到文件,演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
-
-5、record_stream.lua 流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用
-
-
-## 演示硬件环境
-1、Air780EHM核心板+AirAUDIO_1010 音频扩展板+喇叭
-
-![alt text]( https://docs.openLuat.com/cdn/image/Air780EHM+Airaudio1010.jpg)
-
-Air780EHM核心板和AirAudio_1010 配件板的硬件接线方式为:
-|  Air780EHM核心板 | AirAUDIO_1010配件板 |
-| --------------- | -----------------   |
-| 33/I2S_MCLK     | I2S_MCLK            |
-| 30/I2S_BCK      | I2S_BCK             |
-| 31/I2S_LRCK     | I2S_LRCK            |
-| 32/I2S_DIN      | I2S_DIN             |
-| 33/I2S_DOUT     | I2S_DOUT            |
-| 67/I2C1_SCL     | I2C_SCL             |
-| 66/I2C1_SDA     | I2C_SDA             |
-| 25/GPIO26       | PA_EN               |
-| 23/GPIO2        | 8311_EN             |
-| VDD_EXT         | VCC                 |
-| GND             | GND                 |
-
-2、YPE-C USB数据线一根
-- Air780EHM核心板通过 TYPE-C USB 口供电;
-- TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
-
-## 演示软件环境
-
-1、Luatools下载调试工具
-
-2、[Air780EHM V2016版本固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)(理论上,2025年7月26日之后发布的固件都可以),选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。不同版本区别参考Air8000 LuatOS固件版本。
-
-3、 luatos需要的脚本和资源文件
-- 脚本和资源文件[点我浏览所有文件](https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio)
-- lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件;
-- 准备好软件环境之后,接下来查看[如何烧录项目文件到Air8000核心板](https://docs.openluat.com/air8000/luatos/common/download/),将本篇文章中演示使用的项目文件烧录到Air8000开发板/核心板中。
-
-## 演示核心步骤
-
-1、搭建好硬件环境
-
-2、demo脚本代码main.lua中,按照自己的需求选择对应的功能
-
-- 如果需要测试播放音频文件,则选择play_file 文件
-
-- 如果需要测试播放tts,则选择play_tts 文件
-
-- 如果需要测试流式播放音频,则选择play_stream 文件
-
-- 如果需要测试录音频到文件,则选择record_file 文件
-
-- 如果需要测试流式录音,则选择record_stream 文件
-
-
-3、Luatools烧录内核固件和修改后的demo脚本代码
-
-4、烧录成功后,自动开机运行,如果出现以下日志,播放或者或者录音完成
-
-``` lua
-I/user.播放完成 true
-I/user.录音完成 
-I/user.录音后文件大小 
-```
-
-5、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
-
-6、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
-
-
-7、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
-
-8、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
-
-9、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用
-
-
-

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/10.amr → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/10.amr


+ 19 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/main.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/main.lua

@@ -37,7 +37,7 @@ VERSION:项目版本号,ascii string类型
 ]]
 
 --[[
-本demo可直接在Air8000整机开发板上运行
+本demo可使用Air780EHV核心板+AirAUDIO_1000 音频配件板+喇叭演示
 ]]
 
 PROJECT = "audio"
@@ -55,6 +55,24 @@ if wdt then
     sys.timerLoopStart(wdt.feed, 3000)
 end
 
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+
+
 
 require "play_file"     --   播放音频文件,可支持wav,amr,mp3 格式音频
 -- require "play_tts"      -- 支持文字转普通话输出需要固件支持

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/play_file.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_file.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/play_stream.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_stream.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/play_tts.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/play_tts.lua


+ 98 - 14
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/readme.md → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/readme.md

@@ -12,7 +12,7 @@
 
 6、record_stream:  流式录音,仅支持PCM。
 
-7、sample-6s.mp3/10.amr: 用于测试本地mp3文件播放
+7、sample-6s.mp3/10.amr: 用于测试本地mp3和amr文件播放
 
 8、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
 
@@ -63,7 +63,7 @@ Air780EHV核心板和AirAudio_1000 配件板的硬件接线方式为:
 | 3V3            |     VCC             |
 | GND            |     GND             |
 
-2、YPE-C USB数据线一根
+2、TYPE-C USB数据线一根
 - Air780EHM核心板通过 TYPE-C USB 口供电;
 - TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
 
@@ -71,11 +71,16 @@ Air780EHV核心板和AirAudio_1000 配件板的硬件接线方式为:
 
 1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/common/Luatools/) 
 
-2、Air780EHV V2016版本固件(理论上,2025年7月26日之后发布的固件都可以)。[不同版本区别请见](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
+2、[Air780EHV V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air780EHV/LuatOS-SoC_V2016_Air780EHV.zip)(理论上,2025年7月26日之后发布的固件都可以)选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。[不同版本区别请见](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
 
-3、[合宙 LuatIO 工具(GPIO 复用初始化配置)使用说明] (https://docs.openluat.com/air780epm/common/luatio/)
+3、 luatos需要的脚本和资源文件
+- 脚本和资源文件[点我浏览所有文件](https://gitee.com/openLuat/LuatOS_demo_v2_temp/tree/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio)
 
-4、 lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
+- 准备好软件环境之后,接下来查看[如何烧录项目文件到Air780EXX核心板](https://docs.openluat.com/air780epm/luatos/common/download/), 将本篇文章中演示使用的项目文件烧录到Air780EHV核心板中。
+
+4、[合宙 LuatIO 工具(GPIO 复用初始化配置)使用说明](https://docs.openluat.com/air780epm/common/luatio/)
+
+5、 lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
 
 
 ## 演示核心步骤
@@ -97,24 +102,103 @@ Air780EHV核心板和AirAudio_1000 配件板的硬件接线方式为:
 
 3、Luatools烧录内核固件和修改后的demo脚本代码
 
-4、烧录成功后,自动开机运行,如果出现以下日志,播放或者或者录音完成
+4、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
+
+5、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
+
+
+6、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
+
+7、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+
+8、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用。
+
+9、运行结果展示
+
+- 播放文件 (play_file.lua)
+
+自动播放一个sample-6s.mp3 音乐;
+
+点击powerkey 按键进行音频切换播放10.amr文件;
+
+点击boot 按键停止音频播放
+
+``` lua
+ I/user.开始播放音频文件
+ I/user.播放完成 true
+
+ I/user.切换播放
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+ ```
+
+ - 文字转语音 (play_tts.lua)
+
+ 播放一个TTS;
+
+点击powerkey 按键进行tts 的音色切换
+
+点击boot 按键停止音频播放
 
 ``` lua
-I/user.播放完成 true
-I/user.录音完成 
-I/user.录音后文件大小 
+ I/user.开始播放TTS
+ I/user.切换播放
+
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+
 ```
 
-5、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
+- 流式播放 (play_stream.lua)
+
+创建一个播放流式音频task(task_audio)和一个模拟获取流式音频的task(audio_get_data),此task通过流式传输不断向exaudio.play_stream_write填入播放的音频,播放task 不断播放传入流式音频。
+
+使用powerkey 按键进行音量减小,点击boot 按键进行音量增加
 
-6、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
+``` lua
+ I/user.开始流式获取音频数据
+ I/user.开始流式播报
+
+ I/user.减小音量55
+ I/user.增大音量75
+
+ I/user.播放状态 true
+ I/user.播放完成 true
+
+```
 
+- 录音到文件  (record_file.lua)
 
-7、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
+主程序录音到/record.amr 文件
 
-8、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
 
-9、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用
+``` lua
+ I/user.开始录制音频到文件
+
+ E/user.减小音量55
+ I/user.增大音量75
+
+ I/user.录音后文件大小 320000
+```
+
+- 流式录音(record_stream.lua),仅支持PCM格式
+
+主程序录音进行流式录音
+
+录音过程中不断的进行recode_data_callback回调,回调内容为音频流的地址和长度。
+
+``` lua
+ I/user.开始流式录制音频到文件
+ I/user.收到音频流,地址为: ZBUFF*:0C7F70A8 有效数据长度为: 9600
+ I/user.录音完成
 
+ E/user.减小音量55
+ I/user.增大音量75
 
+ I/user.录音后
 

+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/record_file.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/record_file.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/record_stream.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/record_stream.lua


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/sample-6s.mp3 → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/sample-6s.mp3


+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV_audio/test.pcm → module/Air780EHM_Air780EHV_Air780EGH/demo/audio/Air780EHV/test.pcm


+ 31 - 14
module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/fastlz_test.lua → module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/fastlz_app.lua

@@ -1,17 +1,28 @@
 --[[
-@module  fastlz_test
-@summary fastlz压缩与解压缩测试功能模块
+@module  fastlz_app
+@summary fastlz_app 
 @version 1.0
-@date    2025.07.01
-@author  孟伟
+@date    2025.10.28
+@author  沈园园
 @usage
-使用Air780EHM演示压缩与解压缩的流程。
+本文件为fastlz应用功能模块,核心业务逻辑为:
+1、演示压缩与解压缩的流程;
+
+本文件没有对外接口,直接在main.lua中require "fastlz_app"就可以加载运行;
 ]]
 
-function test_fastlz_func()
-    sys.wait(1000)
+
+function fastlz_compress_uncompress_func(mode)
     -- 原始数据
-    local originStr = io.readFile("/luadb/test.txt") or "q309pura;dsnf;asdouyf89q03fonaewofhaeop;fhiqp02398ryhai;ofinap983fyua0weo;ifhj3p908fhaes;iofaw789prhfaeiwop;fhaesp98fadsjklfhasklfsjask;flhadsfk"
+    local originStr
+    if mode == 1 then
+        log.info("原始数据文件读取2K数据")
+        originStr = io.readFile("/luadb/test.txt")          
+    else
+        log.info("原始数据108长度字符串")
+        originStr = "abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz"            
+    end
+    
     local maxOut = #originStr
     log.info("原始数据长度", #originStr)
 
@@ -29,8 +40,6 @@ function test_fastlz_func()
         log.info("压缩等级1:解压后的数据与原始数据不同")
     end
 
-    sys.wait(1000)
-
     -- 以压缩等级2 进行压缩
     local L2 = fastlz.compress(originStr, 2)
     log.info("压缩等级2:压缩后的数据长度", #L2)
@@ -44,8 +53,16 @@ function test_fastlz_func()
         log.info("压缩等级2:解压后的数据与原始数据相同")
     else
         log.info("压缩等级2:解压后的数据与原始数据不同")
-    end
+    end     
+end
+
+function fastlz_task_func()
+    -- 原始数据108长度字符串
+    fastlz_compress_uncompress_func()
+    -- 原始数据文件读取2K数据
+    fastlz_compress_uncompress_func(1)   
 end
---创建并且启动一个task
---运行这个task的主函数test_fastlz_func
-sys.taskInit(test_fastlz_func)
+
+
+--创建一个task,并且运行task的主函数fastlz_task_func
+sys.taskInit(fastlz_task_func)

+ 24 - 18
module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/main.lua

@@ -1,13 +1,16 @@
 --[[
 @module  main
-@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
 @version 1.0
-@date    2025.07.01
-@author  孟伟
+@date    2025.10.28
+@author  沈园园
 @usage
-本demo演示的功能为:
-实现使用Air780EHM来对文本/段落序列、原始像素数据序列或具有大量重复的任何其他数据块的快速压缩与解压缩。
+本demo演示的核心功能为:
+演示如何对数据压缩解压
+更多说明参考本目录下的readme.md文件
 ]]
+
+
 --[[
 必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
 PROJECT:项目名,ascii string类型
@@ -17,19 +20,25 @@ VERSION:项目版本号,ascii string类型
             X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
             因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
         如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
-
-
 ]]
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "FastLZ"
+PROJECT = "luatos_fastlz_app"
 VERSION = "001.000.000"
 
---添加硬狗防止程序卡死
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
+
 -- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
 -- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
 -- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
@@ -53,13 +62,10 @@ end
 --     log.info("mem.sys", rtos.meminfo("sys"))
 -- end, 3000)
 
-
---加载fastlz测试应用模块
-require "fastlz_test"
-
-
+-- 加载fastlz_app应用功能模块
+require "fastlz_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 46 - 20
module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/readme.md

@@ -1,40 +1,66 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、fastlz_app.lua:如何对数据压缩解压;
 
 ## 演示功能概述
 
-将使用Air780EHM核心板,演示FastLZ的压缩与解压缩的使用方法,实现读取文件系统中的文件,并演示压缩与解压缩的代码实现。
+1、创建一个task;
+
+2、演示如何对数据压缩解压;
+
 
 ## 演示硬件环境
 
-1、Air780EHM核心板一块
+![](https://docs.openluat.com/air780ehv/luatos/common/hwenv/image/Air780EHV2.png)
+
+1、Air780EHM/Air780EHV/Air780EGH核心板一块
 
 2、TYPE-C USB数据线一根
 
-3、Air780EHM核心板和数据线的硬件接线方式为
+3、Air780EHM/Air780EHV/Air780EGH核心板和数据线的硬件接线方式为
+
+- Air780EHM/Air780EHV/Air780EGH核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
 
-- Air780EHM核心板通过TYPE-C USB口供电;(核心板USB旁边的开关拨到on一端)
 
-- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
 ## 演示软件环境
 
-1、Luatools下载调试工具
+1、[Luatools下载调试工具](https://docs.openluat.com/air780ehv/luatos/common/download/)
 
-2、[Air780EHM V2007版本固件](https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHM/core)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录V2007固件对比验证)
+2、[Air780EHM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
 
-## 演示核心步骤
+3、[Air780EHV 最新版本的内核固件](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
 
-1、搭建好硬件环境
+4、[Air780EGH 最新版本的内核固件](https://docs.openluat.com/air780egh/luatos/firmware/version/)
 
-2、通过Luatools将demo与固件烧录到核心板中
 
-3、烧录好后,板子开机将会在Luatools上看到如下打印:
+## 演示核心步骤
 
-```lua
-[2025-06-30 14:10:53.447][000000001.239] I/user.原始数据长度	14525
-[2025-06-30 14:10:53.469][000000001.241] I/user.压缩等级1:压缩后的数据长度	212
-[2025-06-30 14:10:53.484][000000001.242] I/user.压缩等级1:解压后的的数据长度	14525
-[2025-06-30 14:10:53.509][000000001.243] I/user.压缩等级1:解压后的数据与原始数据相同
-[2025-06-30 14:10:54.166][000000002.244] I/user.压缩等级2:压缩后的数据长度	114
-[2025-06-30 14:10:54.178][000000002.246] I/user.压缩等级2:解压后的数据长度	14525
-[2025-06-30 14:10:54.191][000000002.247] I/user.压缩等级2:解压后的数据与原始数据相同
+1、搭建好硬件环境
 
-```
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-28 17:11:11.613][000000000.368] I/user.原始数据108长度字符串
+[2025-10-28 17:11:11.613][000000000.369] I/user.原始数据长度 108
+[2025-10-28 17:11:11.623][000000000.370] I/user.压缩等级1:压缩后的数据长度 47
+[2025-10-28 17:11:11.623][000000000.371] I/user.压缩等级1:解压后的的数据长度 108
+[2025-10-28 17:11:11.623][000000000.371] I/user.压缩等级1:解压后的数据与原始数据相同
+[2025-10-28 17:11:11.623][000000000.373] I/user.压缩等级2:压缩后的数据长度 47
+[2025-10-28 17:11:11.633][000000000.374] I/user.压缩等级2:解压后的数据长度 108
+[2025-10-28 17:11:11.637][000000000.374] I/user.压缩等级2:解压后的数据与原始数据相同
+[2025-10-28 17:11:11.637][000000000.374] I/user.原始数据文件读取2K数据
+[2025-10-28 17:11:11.643][000000000.375] I/user.原始数据长度 2048
+[2025-10-28 17:11:11.643][000000000.377] I/user.压缩等级1:压缩后的数据长度 128
+[2025-10-28 17:11:11.643][000000000.378] I/user.压缩等级1:解压后的的数据长度 2048
+[2025-10-28 17:11:11.653][000000000.378] I/user.压缩等级1:解压后的数据与原始数据相同
+[2025-10-28 17:11:11.653][000000000.379] I/user.压缩等级2:压缩后的数据长度 116
+[2025-10-28 17:11:11.693][000000000.380] I/user.压缩等级2:解压后的数据长度 2048
+[2025-10-28 17:11:11.713][000000000.380] I/user.压缩等级2:解压后的数据与原始数据相同
+```

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/fastlz/test.txt


+ 1 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/http_download_flash.lua

@@ -33,7 +33,7 @@ local function http_download_flash_task()
 
     -- 核心下载操作开始
     local code, headers, body_size = http.request("GET",
-                                    "https://gitee.com/openLuat/LuatOS/raw/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/sample-6s.mp3",
+                                    "https://www.air32.cn/demo/sample-6s.mp3",
                                     nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
 
     -- 阶段3: 记录下载结果

+ 1 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/readme.md

@@ -51,7 +51,7 @@
 
 - 下载状态码解析
 - 自动文件大小验证
-- 获取文件系统信息(fs.fsstat)
+- 获取文件系统信息( io.fsstat)
 
 ## **演示硬件环境**
 

+ 71 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm2.lua

@@ -0,0 +1,71 @@
+--[[
+@module  gmssl_sm2
+@summary gmssl_sm2 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm2应用功能模块,核心业务逻辑为:
+1、演示国密sm2加密和解码的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm2"就可以加载运行;
+]]
+
+
+function gmssl_sm2_encrypt_decrypt(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
+
+
+local function gmssl_sm2_task_func()
+    -- 未加密字符串
+    local originStr = "!!from LuatOS!!"
+
+    -- SM2 , 非对称加密, 类似于RSA,但属于椭圆算法
+    -- 就当前实现还是比较慢的
+    if gmssl.sm2encrypt then -- 部分BSP不支持
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+        gmssl_sm2_encrypt_decrypt(originStr, pkx, pky, private)
+    end
+
+    -- SM密钥生成
+    if gmssl.sm2keygen then
+        log.info("SM2密钥生成测试")
+        originStr = "32wrniosadnfvnadsio;fasiow"
+        local pkx, pky, private = gmssl.sm2keygen()
+        gmssl_sm2_encrypt_decrypt(originStr, pkx, pky, private)
+    end
+
+end
+
+sys.taskInit(gmssl_sm2_task_func)
+

+ 43 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm2sign.lua

@@ -0,0 +1,43 @@
+--[[
+@module  gmssl_sm2sign
+@summary gmssl_sm2sign 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm2sign应用功能模块,核心业务逻辑为:
+1、演示国密SM2签名和验签的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm2sign"就可以加载运行;
+]]
+
+
+local function gmssl_sm2sign_task_func()
+
+    -- 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
+
+sys.taskInit(gmssl_sm2sign_task_func)

+ 26 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm3.lua

@@ -0,0 +1,26 @@
+--[[
+@module  gmssl_sm3
+@summary gmssl_sm3
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm3应用功能模块,核心业务逻辑为:
+1、演示国密sm3算法;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm3"就可以加载运行;
+]]
+
+
+local function gmssl_sm3_task_func()
+    -- sm3算法,算HASH值
+    local encodeStr = gmssl.sm3("lqlq666lqlq946")
+    log.info("gmssl.sm3",string.toHex(encodeStr))
+    
+    -- sm3算法,算HASH值,但带HMAC
+    local encodeStr = gmssl.sm3hmac("lqlq666lqlq946", "123")
+    log.info("gmssl.sm3hmac",string.toHex(encodeStr))    
+
+end
+
+sys.taskInit(gmssl_sm3_task_func)

+ 53 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/gmssl_sm4.lua

@@ -0,0 +1,53 @@
+--[[
+@module  gmssl_sm4
+@summary gmssl_sm4 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm4应用功能模块,核心业务逻辑为:
+1、演示国密sm4加密和解码的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm4"就可以加载运行;
+]]
+
+
+local function gmssl_sm4_task_func()
+
+    if gmssl.sm4encrypt then
+        log.info("=== SM4测试")
+        local passwd = "1234567890123456"
+        local iv = "1234567890666666"
+        -- SM4 算法, 对称加密
+        originStr = ">>SM4 ECB ZeroPadding test<<"
+        --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;
+        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;
+        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;偏移量: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.taskInit(gmssl_sm4_task_func)

+ 78 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+演示有关gmssl国密算法的功能包含SM2,SM3,SM4
+更多说明参考本目录下的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 = "luatos_gmssl_app"
+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)
+
+
+-- 加载sm2算法, 含密钥生成应用功能模块
+require "gmssl_sm2"
+-- 加载sm3算法应用功能模块
+require "gmssl_sm3"
+-- 加载sm4算法应用功能模块
+require "gmssl_sm4"
+-- 加载sm2签名和验签应用功能模块
+require "gmssl_sm2sign"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 92 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/gmssl/readme.md

@@ -0,0 +1,92 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、gmssl_sm2.lua:sm2算法, 含密钥生成;
+
+3、gmssl_sm3:sm3算法;
+
+5、gmssl_sm4:sm4算法;
+
+6、gmssl_sm2sign:sm2签名和验签;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、演示gmssl国密算法包含SM2算法, 含密钥生成,SM3算法,SM4算法以及sm2签名和验签;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780ehv/luatos/common/hwenv/image/Air780EHV2.png)
+
+1、Air780EHM/Air780EHV/Air780EGH核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EHM/Air780EHV/Air780EGH核心板和数据线的硬件接线方式为
+
+- Air780EHM/Air780EHV/Air780EGH核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780ehv/luatos/common/download/)
+
+2、[Air780EHM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+3、[Air780EHV 最新版本的内核固件](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
+
+4、[Air780EGH 最新版本的内核固件](https://docs.openluat.com/air780egh/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-29 16:51:55.069][000000000.365] I/user.==== SM2 默认GMSSL模式
+[2025-10-29 16:51:55.296][000000000.912] I/user.sm2默认模式 加密后 3078022022F0E9C08C45EC2D456C184541900B2D069790DF554BD37183453306E49A474E022100A7220907D53AF4A580B6AEC7B8EA53FF5E51F5E56A8ACC440C86F58C4E3EB9110420A4FCAE7ECF86059FB63B0F82A502223E8B4C7CAECBE29E72C05A87DF8BA3C08F040F63EE6697093A495733939D4D68070F
+[2025-10-29 16:51:55.526][000000001.150] I/user.sm2默认模式 解密后 !!from LuatOS!!
+[2025-10-29 16:51:55.530][000000001.151] I/user.==== SM2 网站兼容模式
+[2025-10-29 16:51:55.977][000000001.601] I/user.sm2网站兼容模式 C1C3C2 加密后 7CD71EFCD699E81C5A320DD78357788BA4A4E87C02691EB73225B6E8CC3F1A95730359208D2E6A375E49D84321C9BB28F0D7B65BC348DD07A9ADE9C1F38D053CA5B4128EE908F4494DB1867F0C48D00FCFE3F6A9C38CDA696CABAF36E9D120244AAEC7B42200A0A9C8321EDEDC9010
+[2025-10-29 16:51:56.177][000000001.800] I/user.sm2网站兼容模式 C1C3C2 解密后 !!from LuatOS!!
+[2025-10-29 16:51:56.182][000000001.800] I/user.==== SM2 网站兼容模式, 但C1C2C3
+[2025-10-29 16:51:56.589][000000002.228] I/user.sm2网站兼容模式 C1C2C3 加密后 0429D777A89C474D468CBB4BDE604C5D0111EF6FEB9AD180A9A5167657C4CFD09A0CAAF6D3467CE2564C73A666EC4DE2CA2E28F5B2BBFA9FE5B30CCA39D0B453DB60AF6B2B6DC1E7D76F3E9FF048FEACC850B37144EC64840A84A1A81B4ACF4BDB851391ECC9F13974A76464C9F9624C
+[2025-10-29 16:51:56.788][000000002.425] I/user.sm2网站兼容模式 C1C2C3 解密后 !!from LuatOS!!
+[2025-10-29 16:51:56.794][000000002.425] I/user.SM2密钥生成测试
+[2025-10-29 16:51:57.048][000000002.660] I/user.==== SM2 默认GMSSL模式
+[2025-10-29 16:51:57.462][000000003.092] I/user.sm2默认模式 加密后 3081820220227403C3A196042379534047850F01BA8EC3603226AF18E0CE65729EBBBDC68C02201D1FBBD3998FDB2757AE55262F1CDD288C6C403766F77F6D7CB9017457E7EE660420B742677896DEDBBEAF55857603EB4C39FA9DFFDAD6E17AFA27FA0D7C7D2F7EF5041A79A2DF1D84C0B449459A4FE6BCC3A494F9F4CC2D00F9A4A7C4FE
+[2025-10-29 16:51:57.674][000000003.301] I/user.sm2默认模式 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:57.681][000000003.301] I/user.==== SM2 网站兼容模式
+[2025-10-29 16:51:58.092][000000003.717] I/user.sm2网站兼容模式 C1C3C2 加密后 A615127F2C18731AB83CA50CDC386C0F70506EA3BE6B1B1E74E1F417BCFB992AC9B4F91A4233181CD5C419CA21B5AD46BBA7F2E635D4AC317842E8762A19260218921AB2D4C02C8211E2AC28976B61D33E0AB826B2DE223E6E51729B31B02E02E0C73D5822F12FC4618E6E1F7110278CBD273C152B650C75A423
+[2025-10-29 16:51:58.306][000000003.927] I/user.sm2网站兼容模式 C1C3C2 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:58.313][000000003.927] I/user.==== SM2 网站兼容模式, 但C1C2C3
+[2025-10-29 16:51:58.748][000000004.372] I/user.sm2网站兼容模式 C1C2C3 加密后 045807522541AF430F7D0F3EE27D0718AA33D17E98F04121CC3039A6C7EA5B219751DA6CDC64B805C5BA08E97CFC7546D72BCBF1CD2329F26190A6CF33D76E37B1BFFEDBA05C31D8673F33CFA5925A5EC0DB37A58F74B30020DE25104E47001D02A23C45814230650A1D9961B5BDC69218DF8AEEB9A66266EF175C
+[2025-10-29 16:51:58.947][000000004.581] I/user.sm2网站兼容模式 C1C2C3 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:58.962][000000004.588] I/user.gmssl.sm3 E64FD76F4078E51DCA428323D3FADBD5D52723BBF1379184650DA5CE6002B2BF 64
+[2025-10-29 16:51:58.964][000000004.588] I/user.gmssl.sm3hmac FBB67FC936777011AA70336F0F0B6305D529A97A87D8ECA8880472CD2C30A721 64
+[2025-10-29 16:51:58.966][000000004.595] I/user.=== SM4测试
+[2025-10-29 16:51:58.971][000000004.596] I/user.sm4.ecb.zero 加密后 E8DF19897C0BF1FFA50910C5C548F5A4E9E34BED9F5CEE519CFA24C37A290B25 64
+[2025-10-29 16:51:58.973][000000004.596] I/user.sm4.ecb.zero 解密后 >>SM4 ECB ZeroPadding test<<
+[2025-10-29 16:51:58.975][000000004.597] I/user.sm4.ecb.pks5 加密后 25B3D6AB8C855115C3A8883FE3ADCC6B9004C83B86CE7A45517CA6736DBA4EFE 64
+[2025-10-29 16:51:58.976][000000004.598] I/user.sm4.ecb.pks5 解密后 >>SM4 ECB Pkcs5Padding test<<
+[2025-10-29 16:51:58.978][000000004.598] I/user.sm4.cbc.pks5 加密后 A11C24BB018C8124FADAFC9B6BF7932C05BA2F24E9DFB9D79D982A676F9C010C 64
+[2025-10-29 16:51:58.979][000000004.599] I/user.sm4.cbc.pks5 解密后 >>SM4 CBC Pkcs5Padding test<<
+[2025-10-29 16:51:58.981][000000004.600] I/user.sm4.ecb.pkcs7 B083DCC0A9F64BD9FAE2FA8C936E3D776C88F739AF2A29A735381F5677BADEF7 64
+[2025-10-29 16:51:58.983][000000004.600] I/user.sm4.ecb.pkcs5 B083DCC0A9F64BD9FAE2FA8C936E3D776C88F739AF2A29A735381F5677BADEF7 64
+[2025-10-29 16:51:58.987][000000004.601] I/user.sm4.ecb.zero B083DCC0A9F64BD9FAE2FA8C936E3D77D2D68ED9FE06CB40C9A150AA5917F15F 64
+[2025-10-29 16:51:58.988][000000004.601] I/user.sm4.ecb.none B083DCC0A9F64BD9FAE2FA8C936E3D77 32
+[2025-10-29 16:51:59.450][000000005.084] I/user.sm2sign 9C2303667887E45ABA016BBACFF1AF2F3ED764CE220A0B0D67CF9206BF48F26AA2797E5478919FB0C6140B89D7DDA33055428A7B3D40F49E0BAD410624D83199
+[2025-10-29 16:51:59.864][000000005.496] I/user.sm2verify true
+[2025-10-29 16:52:00.357][000000005.982] I/user.sm2sign 756D9F37525A543A6647370C22DD71ADEEFBF86D83CE87A28889EAC9F63F0C5CFF334A2D99B067EA676437EE1DEC86B8A8F109568A7CF3AFE70A8DD09562F7E2
+[2025-10-29 16:52:00.782][000000006.411] I/user.sm2verify true
+```

+ 24 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/hmeta_app.lua

@@ -0,0 +1,24 @@
+--[[
+@module  hmeta_app
+@summary hmeta_app应用功能模块 
+@version 1.0
+@date    2025.10.20
+@author  沈园园
+@usage
+本文件为hmeta应用功能模块,核心业务逻辑为:
+1、获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号;
+
+本文件没有对外接口,直接在main.lua中require "hmeta_app"就可以加载运行;
+]]
+
+
+local function hmeta_task_func()
+    while true do
+        -- 打印模组名称,硬件版本号,原始芯片型号
+        log.info("hmeta", hmeta.model(), hmeta.hwver(), hmeta.chip())
+        sys.wait(3000)
+    end
+end
+
+--创建一个task,并且运行task的主函数hmeta_task_func
+sys.taskInit(hmeta_task_func)

+ 60 - 19
module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/main.lua

@@ -1,30 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.20
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号
+更多说明参考本目录下的readme.md文件
+]]
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "hmetademo"
-VERSION = "1.0.0"
 
--- sys库是标配
-_G.sys = require("sys")
+--[[
+必须定义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 = "luatos_hmeta_app"
+VERSION = "001.000.000"
 
 
--- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
-if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
-    pm.power(pm.PWK_MODE, false)
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
 
-sys.taskInit(function()
-    while hmeta do
-        -- hmeta识别底层模组类型的
-        -- 不同的模组可以使用相同的bsp,但根据封装的不同,根据内部数据仍可识别出具体模块
-        log.info("hmeta", hmeta.model(), hmeta.hwver and hmeta.hwver())
-        log.info("bsp",   rtos.bsp())
-        sys.wait(3000)
-    end
-    log.info("这个bsp不支持hmeta库哦")
-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)
+
+-- 加载hmeta_app应用功能模块
+require "hmeta_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 54 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/hmeta/readme.md

@@ -0,0 +1,54 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、hmeta_app.lua:获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、在task中的任务处理函数中,每隔三秒钟通过日志输出一次模组名称,硬件版本号,原始芯片型号;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780ehv/luatos/common/hwenv/image/Air780EHV2.png)
+
+1、Air780EHM/Air780EHV/Air780EGH核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EHM/Air780EHV/Air780EGH核心板和数据线的硬件接线方式为
+
+- Air780EHM/Air780EHV/Air780EGH核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780ehv/luatos/common/download/)
+
+2、[Air780EHM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+3、[Air780EHV 最新版本的内核固件](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
+
+4、[Air780EGH 最新版本的内核固件](https://docs.openluat.com/air780egh/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-20 17:53:50.355][000000006.254] I/user.hmeta Air780EHV A11 EC718HM
+[2025-10-20 17:53:53.353][000000009.254] I/user.hmeta Air780EHV A11 EC718HM
+[2025-10-20 17:53:56.356][000000012.254] I/user.hmeta Air780EHV A11 EC718HM
+
+```

+ 74 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/main.lua

@@ -0,0 +1,74 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.10.21
+@author  孟伟
+@usage
+本demo演示的功能为:
+    MCU死机时的处理模式设置
+    唯一ID获取与显示
+    系统tick计数功能测试
+    64位tick计数和差值计算
+    微秒、毫秒、秒级别的时间计数
+    16进制字符串转换输出
+]]
+--[[
+必须定义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 = "mcu_demo"
+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)
+
+-- 加载mcu功能模块
+require "mcu_test"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 64 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/mcu_test.lua

@@ -0,0 +1,64 @@
+--[[
+@module  mcu_test
+@summary 测试mcu模块功能
+@version 1.0
+@date    2025.10.21
+@author  孟伟
+@usage
+本demo演示的功能为:
+    MCU死机时的处理模式设置
+    唯一ID获取与显示
+    系统tick计数功能测试
+    64位tick计数和差值计算
+    微秒、毫秒、秒级别的时间计数
+    16进制字符串转换输出
+
+    本文件没有对外接口,直接在main.lua中require "mcu_test"就可以加载运行;
+]]
+function mcu_test()
+    -- 测试MCU 死机时的处理模式
+    -- 死机后重启,一般用于正式产品_
+    mcu.hardfault(1)
+
+    -- 测试唯一ID
+    local unique_id = mcu.unique_id()
+    if #unique_id > 0 then
+        log.info("mcu", "Unique ID(hex):", unique_id:toHex())
+    else
+        log.warn("mcu", "Unique ID not supported")
+    end
+
+    -- 测试ticks相关函数
+    -- 获取启动后的 tick 数
+    log.info("mcu", "ticks:", mcu.ticks())
+    -- 获取每秒的 tick 数量
+    log.info("mcu", "获取每秒的tick数量:", mcu.hz())
+
+
+    -- 测试64位tick
+    local tick_str, tick_per = mcu.tick64()
+    log.info("mcu", "tick64:", tick_str:toHex(), "ticks per us:", tick_per)
+    -- 测试mcu.dtick64接口获取ticks差值计算
+    local tick1 = mcu.tick64()
+    sys.wait(100)
+    local tick2 = mcu.tick64()
+    local result, diff_tick = mcu.dtick64(tick1, tick2)
+    log.info("mcu", "dtick64 result:", result, "diff:", diff_tick)
+
+
+    -- 测试ticks2函数
+    local us_h, us_l = mcu.ticks2(0)
+    local ms_h, ms_l = mcu.ticks2(1)
+    local sec_h, sec_l = mcu.ticks2(2)
+    log.info("mcu", "us:", us_h, us_l)
+    log.info("mcu", "ms:", ms_h, ms_l)
+    log.info("mcu", "sec:", sec_h, sec_l)
+
+    -- 测试 转换 10 进制数为 16 进制字符串输出
+    local value = mcu.x32(0x2009FFFC) --输出"0x2009fffc"
+    log.info("mcu", "string", value)
+
+
+end
+
+sys.taskInit(mcu_test)

+ 53 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/mcu/readme.md

@@ -0,0 +1,53 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、mcu_test.lua:MCU功能测试模块;
+
+## 演示功能概述
+
+使用Air780EHM核心板测试MCU相关功能,包括:
+
+- MCU死机时的处理模式设置
+- 唯一ID获取与显示
+- 系统tick计数功能测试
+- 64位tick计数和差值计算
+- 微秒、毫秒、秒级别的时间计数
+- 16进制字符串转换输出
+
+## 演示硬件环境
+
+1、Air780EHM核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air780EHM V2016版本固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、通过luatools工具查看下面日志:
+
+```lua
+[2025-10-21 17:37:39.953][000000000.242] I/user.mcu ticks: 165
+[2025-10-21 17:37:39.962][000000000.242] I/user.mcu 获取每秒的tick数量: 1000
+[2025-10-21 17:37:39.969][000000000.243] I/user.mcu tick64: 625B600000000000 ticks per us: 26
+[2025-10-21 17:37:39.982][000000000.343] I/user.mcu dtick64 result: false diff: -2610447
+[2025-10-21 17:37:40.015][000000000.344] I/user.mcu us: 0 344087
+[2025-10-21 17:37:40.030][000000000.344] I/user.mcu ms: 0 344
+[2025-10-21 17:37:40.037][000000000.344] I/user.mcu sec: 0 0
+[2025-10-21 17:37:40.043][000000000.345] I/user.mcu string 0x2009fffc
+[2025-10-21 17:37:40.048][000000000.345] I/user.us_h 0 us_l 345086
+[2025-10-21 17:37:40.064][000000000.345] I/user.ms_h 0 ms_l 345
+[2025-10-21 17:37:40.085][000000000.345] I/user.sec_h 0 sec_l 0
+
+```

+ 60 - 30
module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/main.lua

@@ -1,41 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.28
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+演示如何对数据压缩解压
+更多说明参考本目录下的readme.md文件
+]]
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "minizdemo"
-VERSION = "1.0.0"
 
-sys = require("sys")
+--[[
+必须定义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 = "luatos_miniz_app"
+VERSION = "001.000.000"
 
---添加硬狗防止程序卡死
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
-sys.taskInit(function()
-    sys.wait(1000)
-    -- 压缩过的字符串, 为了方便演示, 这里用了base64编码
-    -- 大部分MCU设备的内存都比较小, miniz.compress 通常在服务器端完成,这里就不演示了
-    -- miniz能解压标准zlib数据流
-    local b64str = "eAEFQIGNwyAMXOUm+E2+OzjhCCiOjYyhyvbVR7K7IR0l+iau8G82eIW5jXVoPzF5pse/B8FaPXLiWTNxEMsKI+WmIR0l+iayEY2i2V4UbqqPh5bwimyEuY11aD8xeaYHxAquvom6VDFUXqQjG1Fek6efCFfCK0b0LUnQMjiCxhUT05GNL75dFUWCSMcjN3EE5c4Wvq42/36R41fa"
-    local str = b64str:fromBase64()
-
-    local dstr = miniz.uncompress(str)
-    -- 压缩过的数据长度 156
-    -- 解压后的数据长度,即原始数据的长度 235
-    log.info("miniz", "compressed", #str, "uncompressed", #dstr)
-
-    -- 演示压缩解压
-    local ostr = "abcd12345"
-    -- 压缩字符串
-    local zstr = miniz.compress(ostr)
-    log.info("压缩后的字符串:",zstr:toHex())
-    -- 解压字符串
-    local lstr = miniz.uncompress(zstr)
-    log.info("miniz","compress zstr",#zstr,"uncompress lstr data",lstr)
-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)
+
+-- 加载miniz_app应用功能模块
+require "miniz_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 47 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/miniz_app.lua

@@ -0,0 +1,47 @@
+--[[
+@module  miniz_app
+@summary miniz_app应用功能模块 
+@version 1.0
+@date    2025.10.28
+@author  沈园园
+@usage
+本文件为miniz应用功能模块,核心业务逻辑为:
+1、如何对数据压缩解压;
+
+本文件没有对外接口,直接在main.lua中require "miniz_app"就可以加载运行;
+]]
+
+
+local function miniz_task_func()
+    -- 压缩过的字符串, 为了方便演示, 这里用了base64编码
+    -- miniz能解压标准zlib数据流
+    -- 将字符串进行base64解码
+    local b64str = "eAEFQIGNwyAMXOUm+E2+OzjhCCiOjYyhyvbVR7K7IR0l+iau8G82eIW5jXVoPzF5pse/B8FaPXLiWTNxEMsKI+WmIR0l+iayEY2i2V4UbqqPh5bwimyEuY11aD8xeaYHxAquvom6VDFUXqQjG1Fek6efCFfCK0b0LUnQMjiCxhUT05GNL75dFUWCSMcjN3EE5c4Wvq42/36R41fa"
+    local str = b64str:fromBase64()
+    -- 快速解压
+    local dstr = miniz.uncompress(str) 
+    -- 压缩过的数据长度 156
+    -- 解压后的数据长度,即原始数据的长度 235
+    log.info("miniz", "压缩过的数据长度: ", #str, "解压后的数据长度:", #dstr)    
+    
+    -- 演示压缩解压
+    local ostr = "abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz"
+    log.info("压缩前的字符串:", #ostr, ostr)
+    -- 压缩字符串
+    local zstr = miniz.compress(ostr)
+    log.info("压缩后的字符串:",#zstr, zstr:toHex())
+    -- 解压字符串
+    local lstr = miniz.uncompress(zstr)
+    log.info("解压后的字符串:", #lstr, lstr)
+    
+    -- 演示从文件读取2K数据压缩
+    local ostr = io.readFile("/luadb/test.txt")
+    local zstr = miniz.compress(ostr)
+    if zstr then
+        log.info("miniz", "压缩前的数据长度: ", #ostr, "压缩后的数据长度: ", #zstr) 
+    end  
+end
+
+
+--创建一个task,并且运行task的主函数miniz_task_func
+sys.taskInit(miniz_task_func)

+ 55 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/readme.md

@@ -0,0 +1,55 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、miniz_app.lua:如何对数据压缩解压;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、演示如何对数据压缩解压;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780ehv/luatos/common/hwenv/image/Air780EHV2.png)
+
+1、Air780EHM/Air780EHV/Air780EGH核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EHM/Air780EHV/Air780EGH核心板和数据线的硬件接线方式为
+
+- Air780EHM/Air780EHV/Air780EGH核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780ehv/luatos/common/download/)
+
+2、[Air780EHM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+3、[Air780EHV 最新版本的内核固件](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
+
+4、[Air780EGH 最新版本的内核固件](https://docs.openluat.com/air780egh/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-28 11:39:11.816][000000000.379] I/user.miniz 压缩过的数据长度:  156 解压后的数据长度: 235
+[2025-10-28 11:39:11.821][000000000.380] I/user.压缩前的字符串: 108 abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz
+[2025-10-28 11:39:11.826][000000000.383] I/user.压缩后的字符串: 92 780105C0040D80B04A383CCEDDDD9F9E4184C97E9CD7FDBC1FD828E3422A6DACF321A65C6AEB632E8830D98FF3BA9FF7031B655C48A58D753EC4944B6D7DCC051126FB715EF7F37E60A38C0BA9B4B1CE879872A9AD8FB97E17A42785 184
+[2025-10-28 11:39:11.832][000000000.383] I/user.解压后的字符串: 108 abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz
+[2025-10-28 11:39:11.836][000000000.389] I/user.miniz 压缩前的数据长度:  2048 压缩后的数据长度:  1350
+```

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/miniz/test.txt


+ 2 - 2
module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/main.lua

@@ -2,8 +2,8 @@
 @module  main
 @summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
 @version 1.0
-@date    2025.07.01
-@author  杨鹏
+@date    2025.10.27
+@author  李源龙
 @usage
 本demo演示的核心功能为:
 使用Air780EHM核心板的UART1连接PC端的串口调试仿真工具SecureCRT,通过Ymodem协议接收文件。

+ 8 - 10
module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/readme.md

@@ -13,19 +13,17 @@
 
 4、Air780EHM核心板和数据线的硬件接线方式为
 
-- Air780EHM核心板通过TYPE-C USB口供电;(核心板背面的功耗测试开关拨到OFF一端)
-
-- 如果测试发现软件频繁重启,重启原因值为:poweron reason 0,可能是供电不足,此时再通过直流稳压电源对核心板的vbat管脚进行4V供电,或者VIN管脚进行5V供电;
+- Air780EHM核心板通过TYPE-C USB口供电;
 
 - TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
 
-- USB转串口数据线,一般来说,白线连接核心板的18/U1TX,绿线连接核心板的17/U1RX,黑线连接核心板的gnd,另外一端连接电脑USB口;
+- USB转串口数据线,一般来说,UART_RX连接核心板的UART1_TXD,UART1_TX连接核心板的UART1_RX,黑线连接核心板的gnd,另外一端连接电脑USB口;
 
-| Air780EHM核心板 | USB转串口数据线 |
-| -------------- | -------------- |
-| U1TX           | 白线           |
-| U1RX           | 绿线           |
-| GND            | GND            |
+| Air780EHM核心板  | USB转串口数据线 |
+| -------------- | --------------|
+| UART1_TXD      | UART_RX       |
+| UART1_RXD      | UART_TX       |
+| GND            | GND           |
 
 ## 演示软件环境
 
@@ -46,7 +44,7 @@
 
 4、烧录成功后,自动开机运行
 
-5、打开SecureCRT,连接上Air780EHM UATR1端口,等待窗口接收到Air780EHM发送的字符"C" 表示准备接收数据,选择.bin文件发送,等待传输完成,传输完成后,Luatools的运行日志输出:
+5、电脑上打开SecureCRT,连接上Air780EHM UATR1端口,等待窗口接收到Air780EHM发送的字符"C" 表示准备接收数据,选择.bin文件发送,代码里面初始化ymodem是保存为.bin文件,如果需要其他文件可以自行修改后缀,文件大小不可以大于模块本身的文件系统区域,等待传输完成,传输完成后,Luatools的运行日志输出:
 ``` lua
 [2025-06-25 11:28:30.664][000000185.351] I/main.lua:41	1029
 [2025-06-25 11:28:30.665][000000185.353] D/ymodem save.bin,1024,1

+ 78 - 46
module/Air780EHM_Air780EHV_Air780EGH/demo/ymodem/ymodem_receive.lua

@@ -2,63 +2,57 @@
 @module  main
 @summary ymodem 接收文件应用功能模块 
 @version 1.0
-@date    2025.07.01
-@author  杨鹏
+@date    2025.10.27
+@author  李源龙
 @usage
 本文件为Air780EHM核心板演示ymodem功能的代码示例,核心业务逻辑为:
-1. 初始化串口通信
-2. 创建Ymodem处理对象
-    local ymodem_handler = ymodem.create("/","save.bin")
-3. 启动请求发送任务
-    uart.write(uartid, "C")
-4. 监听串口数据接收
-    uart.on(uartid, "receive", ymodem_rx)
-5. 处理Ymodem数据包
-    local function ymodem_rx(id,len)
+1. 创建协程,调用ymodem_open函数打开ymodem接收功能,初始化zbuff,
+初始化串口,创建一个ymodem对象,然后开始往串口发送'C'字符,启动ymodem接收功能。
+2. 接收串口数据,并且保存到指定路径,接收完成后,自动关闭ymodem接收功能。
 ]]
 
 -- 根据实际设备选取不同的uartid
 local uartid = 1 
 
---初始化
-local result = uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-local taskName = "ymodem_to"
+local taskName = "ymodem_open"
 
 -- 处理未识别的消息
-local function ymodem_to_cb(msg)
-	log.info("ymodem_to_cb", msg[1], msg[2], msg[3], msg[4])
+local function ymodem_open_cb(msg)
+    log.info("ymodem_open_cb", msg[1], msg[2], msg[3], msg[4])
 end
 
 --  定义一个局部变量,用于表示Ymodem协议是否正在运行
 local ymodem_running = false 
 
---  创建一个缓冲区,大小为1024 + 32
-local rxbuff = zbuff.create(1024 + 32) 
+local rxbuff 
 
---  创建一个ymodem处理程序,保存路径为"/",文件名为"save.bin"
-local ymodem_handler = ymodem.create("/","save.bin")
+local ymodem_handler
 
---  定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序
-local function ymodem_to() 
-    while true do
-        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
-        if not ymodem_running then 
-            uart.write(uartid, "C")
-            ymodem.reset(ymodem_handler) 
-        end
-        sys.wait(500)
-    end
+local ymodem_result=false
+
+--定义一个ymodem_close函数,用于关闭ymodem接收功能,包括释放zbuff,关闭串口,释放ymodem对象等操作
+local function ymodem_close()
+    --释放rxbuff
+    rxbuff:free()
+    --关闭串口
+    uart.close(uartid)
+    --释放ymodem处理程序
+    ymodem.release(ymodem_handler)
 end
 
+
+
 --  定义一个ymodem_rx函数,用于接收数据
 local function ymodem_rx(id,len) 
     --  从uart接收数据到缓冲区
-    uart.rx(id,rxbuff) 
+    while 1 do
+        log.info("uart", "缓冲区", uart.rxSize(id)) -- 缓冲区中的数据数量
+        local len = uart.rx(id, rxbuff)
+        if len <= 0 then
+            break
+        end
+        log.info("uart", "receive", id, rxbuff:used(), rxbuff:toStr())
+    end
     --  打印缓冲区已使用的大小
     log.info(rxbuff:used()) 
     --  调用ymodem.receive函数,接收数据
@@ -66,6 +60,7 @@ local function ymodem_rx(id,len)
     ymodem_running = result
     log.info("result:",ymodem_running,ack,flag,file_done,all_done)
     rxbuff:del()
+    --成功就发送ack和flag
     if result then
         rxbuff:copy(0, ack,flag)
         uart.tx(id, rxbuff)
@@ -79,25 +74,62 @@ local function ymodem_rx(id,len)
         -- 判断/save.bin文件是否存在,存在则打印日志,显示/save.bin文件大小;不存在则打印日志,显示/save.bin文件不存在
         if exists then
             log.info("io", "save.bin file exists:", exists) 
+            --打印文件大小
             log.info("io", "save.bin file size:", io.fileSize("/save.bin")) 
         else
             log.info("io", "save.bin file not exists") 
         end
-        
+
         --ymodem_running置为false,再次开始接收
-        ymodem_running = false 
+        ymodem_running = false
+        --ymodem_result置为true,表示接收完成
+        ymodem_result=true
+        --关闭ymodem,释放资源
+        ymodem_close()
+        
     end
     rxbuff:del()
 end
 
---  监听串口接收事件
-uart.on(uartid, "receive", ymodem_rx) 
-
---  监听串口发送事件
-uart.on(uartid, "sent", function(id) 
+local function uart_sent_cb(id)
     log.info("uart", "sent", id) 
-end)
+end
+
+--开启ymodem接收,主要包括串口初始化,zbuff初始化,ymodem初始化等,初始化完毕之后开始发送'C',等待发送端发送数据
+local function ymodem_open()
+
+    --初始化
+    uart.setup(
+    uartid,--串口id
+    115200,--波特率
+    8,--数据位
+    1--停止位
+    )
+    --  监听串口接收事件
+    uart.on(uartid, "receive", ymodem_rx) 
+
+    --  监听串口发送事件
+    uart.on(uartid, "sent", uart_sent_cb)
+
+    --  创建一个缓冲区,大小为1024 + 32,接收数据为1k,32为剩下的协议数据,可能不到32,保险起见,留足够的大小
+    rxbuff = zbuff.create(1024 + 32) 
+
+    --  创建一个ymodem处理程序,保存路径为"/",文件名为"save.bin"
+    ymodem_handler = ymodem.create("/","save.bin")
+    
+    while not ymodem_result do
+        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
+        if not ymodem_running then 
+            --YMODEM 传输文件时,接收方会先发送一个字符 'C'来启动传输过程
+            uart.write(uartid, "C")
+            --发送完之后重置恢复到初始状态
+            ymodem.reset(ymodem_handler) 
+        end
+        sys.wait(500)
+    end
+    
+end
 
 --创建并且启动一个task
---运行这个task的主函数ymodem_to
-sysplus.taskInitEx(ymodem_to, taskName,ymodem_to_cb)
+--运行这个task的主函数ymodem_run
+sys.taskInit(ymodem_open, taskName,ymodem_open_cb)

+ 1 - 1
module/Air780EPM/demo/fs_io/http_download_flash.lua

@@ -33,7 +33,7 @@ local function http_download_flash_task()
 
     -- 核心下载操作开始
     local code, headers, body_size = http.request("GET",
-                                    "https://gitee.com/openLuat/LuatOS/raw/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/sample-6s.mp3",
+                                    "https://www.air32.cn/demo/sample-6s.mp3",
                                     nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
 
     -- 阶段3: 记录下载结果

+ 71 - 0
module/Air780EPM/demo/gmssl/gmssl_sm2.lua

@@ -0,0 +1,71 @@
+--[[
+@module  gmssl_sm2
+@summary gmssl_sm2 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm2应用功能模块,核心业务逻辑为:
+1、演示国密sm2加密和解码的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm2"就可以加载运行;
+]]
+
+
+function gmssl_sm2_encrypt_decrypt(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
+
+
+local function gmssl_sm2_task_func()
+    -- 未加密字符串
+    local originStr = "!!from LuatOS!!"
+
+    -- SM2 , 非对称加密, 类似于RSA,但属于椭圆算法
+    -- 就当前实现还是比较慢的
+    if gmssl.sm2encrypt then -- 部分BSP不支持
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+        gmssl_sm2_encrypt_decrypt(originStr, pkx, pky, private)
+    end
+
+    -- SM密钥生成
+    if gmssl.sm2keygen then
+        log.info("SM2密钥生成测试")
+        originStr = "32wrniosadnfvnadsio;fasiow"
+        local pkx, pky, private = gmssl.sm2keygen()
+        gmssl_sm2_encrypt_decrypt(originStr, pkx, pky, private)
+    end
+
+end
+
+sys.taskInit(gmssl_sm2_task_func)
+

+ 43 - 0
module/Air780EPM/demo/gmssl/gmssl_sm2sign.lua

@@ -0,0 +1,43 @@
+--[[
+@module  gmssl_sm2sign
+@summary gmssl_sm2sign 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm2sign应用功能模块,核心业务逻辑为:
+1、演示国密SM2签名和验签的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm2sign"就可以加载运行;
+]]
+
+
+local function gmssl_sm2sign_task_func()
+
+    -- 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
+
+sys.taskInit(gmssl_sm2sign_task_func)

+ 26 - 0
module/Air780EPM/demo/gmssl/gmssl_sm3.lua

@@ -0,0 +1,26 @@
+--[[
+@module  gmssl_sm3
+@summary gmssl_sm3
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm3应用功能模块,核心业务逻辑为:
+1、演示国密sm3算法;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm3"就可以加载运行;
+]]
+
+
+local function gmssl_sm3_task_func()
+    -- sm3算法,算HASH值
+    local encodeStr = gmssl.sm3("lqlq666lqlq946")
+    log.info("gmssl.sm3",string.toHex(encodeStr))
+    
+    -- sm3算法,算HASH值,但带HMAC
+    local encodeStr = gmssl.sm3hmac("lqlq666lqlq946", "123")
+    log.info("gmssl.sm3hmac",string.toHex(encodeStr))    
+
+end
+
+sys.taskInit(gmssl_sm3_task_func)

+ 53 - 0
module/Air780EPM/demo/gmssl/gmssl_sm4.lua

@@ -0,0 +1,53 @@
+--[[
+@module  gmssl_sm4
+@summary gmssl_sm4 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本文件为gmssl sm4应用功能模块,核心业务逻辑为:
+1、演示国密sm4加密和解码的应用;
+
+本文件没有对外接口,直接在main.lua中require "gmssl_sm4"就可以加载运行;
+]]
+
+
+local function gmssl_sm4_task_func()
+
+    if gmssl.sm4encrypt then
+        log.info("=== SM4测试")
+        local passwd = "1234567890123456"
+        local iv = "1234567890666666"
+        -- SM4 算法, 对称加密
+        originStr = ">>SM4 ECB ZeroPadding test<<"
+        --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;
+        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;
+        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;偏移量: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.taskInit(gmssl_sm4_task_func)

+ 78 - 0
module/Air780EPM/demo/gmssl/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.29
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+演示有关gmssl国密算法的功能包含SM2,SM3,SM4
+更多说明参考本目录下的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 = "luatos_gmssl_app"
+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)
+
+
+-- 加载sm2算法, 含密钥生成应用功能模块
+require "gmssl_sm2"
+-- 加载sm3算法应用功能模块
+require "gmssl_sm3"
+-- 加载sm4算法应用功能模块
+require "gmssl_sm4"
+-- 加载sm2签名和验签应用功能模块
+require "gmssl_sm2sign"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 88 - 0
module/Air780EPM/demo/gmssl/readme.md

@@ -0,0 +1,88 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、gmssl_sm2.lua:sm2算法, 含密钥生成;
+
+3、gmssl_sm3:sm3算法;
+
+5、gmssl_sm4:sm4算法;
+
+6、gmssl_sm2sign:sm2签名和验签;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、演示gmssl国密算法包含SM2算法, 含密钥生成,SM3算法,SM4算法以及sm2签名和验签;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780epm/luatos/common/hwenv/image/Air780EPM2.png)
+
+1、Air780EPM核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EPM核心板和数据线的硬件接线方式为
+
+- Air780EPM核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/luatos/common/download/)
+
+2、[Air780EPM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-29 16:51:55.069][000000000.365] I/user.==== SM2 默认GMSSL模式
+[2025-10-29 16:51:55.296][000000000.912] I/user.sm2默认模式 加密后 3078022022F0E9C08C45EC2D456C184541900B2D069790DF554BD37183453306E49A474E022100A7220907D53AF4A580B6AEC7B8EA53FF5E51F5E56A8ACC440C86F58C4E3EB9110420A4FCAE7ECF86059FB63B0F82A502223E8B4C7CAECBE29E72C05A87DF8BA3C08F040F63EE6697093A495733939D4D68070F
+[2025-10-29 16:51:55.526][000000001.150] I/user.sm2默认模式 解密后 !!from LuatOS!!
+[2025-10-29 16:51:55.530][000000001.151] I/user.==== SM2 网站兼容模式
+[2025-10-29 16:51:55.977][000000001.601] I/user.sm2网站兼容模式 C1C3C2 加密后 7CD71EFCD699E81C5A320DD78357788BA4A4E87C02691EB73225B6E8CC3F1A95730359208D2E6A375E49D84321C9BB28F0D7B65BC348DD07A9ADE9C1F38D053CA5B4128EE908F4494DB1867F0C48D00FCFE3F6A9C38CDA696CABAF36E9D120244AAEC7B42200A0A9C8321EDEDC9010
+[2025-10-29 16:51:56.177][000000001.800] I/user.sm2网站兼容模式 C1C3C2 解密后 !!from LuatOS!!
+[2025-10-29 16:51:56.182][000000001.800] I/user.==== SM2 网站兼容模式, 但C1C2C3
+[2025-10-29 16:51:56.589][000000002.228] I/user.sm2网站兼容模式 C1C2C3 加密后 0429D777A89C474D468CBB4BDE604C5D0111EF6FEB9AD180A9A5167657C4CFD09A0CAAF6D3467CE2564C73A666EC4DE2CA2E28F5B2BBFA9FE5B30CCA39D0B453DB60AF6B2B6DC1E7D76F3E9FF048FEACC850B37144EC64840A84A1A81B4ACF4BDB851391ECC9F13974A76464C9F9624C
+[2025-10-29 16:51:56.788][000000002.425] I/user.sm2网站兼容模式 C1C2C3 解密后 !!from LuatOS!!
+[2025-10-29 16:51:56.794][000000002.425] I/user.SM2密钥生成测试
+[2025-10-29 16:51:57.048][000000002.660] I/user.==== SM2 默认GMSSL模式
+[2025-10-29 16:51:57.462][000000003.092] I/user.sm2默认模式 加密后 3081820220227403C3A196042379534047850F01BA8EC3603226AF18E0CE65729EBBBDC68C02201D1FBBD3998FDB2757AE55262F1CDD288C6C403766F77F6D7CB9017457E7EE660420B742677896DEDBBEAF55857603EB4C39FA9DFFDAD6E17AFA27FA0D7C7D2F7EF5041A79A2DF1D84C0B449459A4FE6BCC3A494F9F4CC2D00F9A4A7C4FE
+[2025-10-29 16:51:57.674][000000003.301] I/user.sm2默认模式 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:57.681][000000003.301] I/user.==== SM2 网站兼容模式
+[2025-10-29 16:51:58.092][000000003.717] I/user.sm2网站兼容模式 C1C3C2 加密后 A615127F2C18731AB83CA50CDC386C0F70506EA3BE6B1B1E74E1F417BCFB992AC9B4F91A4233181CD5C419CA21B5AD46BBA7F2E635D4AC317842E8762A19260218921AB2D4C02C8211E2AC28976B61D33E0AB826B2DE223E6E51729B31B02E02E0C73D5822F12FC4618E6E1F7110278CBD273C152B650C75A423
+[2025-10-29 16:51:58.306][000000003.927] I/user.sm2网站兼容模式 C1C3C2 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:58.313][000000003.927] I/user.==== SM2 网站兼容模式, 但C1C2C3
+[2025-10-29 16:51:58.748][000000004.372] I/user.sm2网站兼容模式 C1C2C3 加密后 045807522541AF430F7D0F3EE27D0718AA33D17E98F04121CC3039A6C7EA5B219751DA6CDC64B805C5BA08E97CFC7546D72BCBF1CD2329F26190A6CF33D76E37B1BFFEDBA05C31D8673F33CFA5925A5EC0DB37A58F74B30020DE25104E47001D02A23C45814230650A1D9961B5BDC69218DF8AEEB9A66266EF175C
+[2025-10-29 16:51:58.947][000000004.581] I/user.sm2网站兼容模式 C1C2C3 解密后 32wrniosadnfvnadsio;fasiow
+[2025-10-29 16:51:58.962][000000004.588] I/user.gmssl.sm3 E64FD76F4078E51DCA428323D3FADBD5D52723BBF1379184650DA5CE6002B2BF 64
+[2025-10-29 16:51:58.964][000000004.588] I/user.gmssl.sm3hmac FBB67FC936777011AA70336F0F0B6305D529A97A87D8ECA8880472CD2C30A721 64
+[2025-10-29 16:51:58.966][000000004.595] I/user.=== SM4测试
+[2025-10-29 16:51:58.971][000000004.596] I/user.sm4.ecb.zero 加密后 E8DF19897C0BF1FFA50910C5C548F5A4E9E34BED9F5CEE519CFA24C37A290B25 64
+[2025-10-29 16:51:58.973][000000004.596] I/user.sm4.ecb.zero 解密后 >>SM4 ECB ZeroPadding test<<
+[2025-10-29 16:51:58.975][000000004.597] I/user.sm4.ecb.pks5 加密后 25B3D6AB8C855115C3A8883FE3ADCC6B9004C83B86CE7A45517CA6736DBA4EFE 64
+[2025-10-29 16:51:58.976][000000004.598] I/user.sm4.ecb.pks5 解密后 >>SM4 ECB Pkcs5Padding test<<
+[2025-10-29 16:51:58.978][000000004.598] I/user.sm4.cbc.pks5 加密后 A11C24BB018C8124FADAFC9B6BF7932C05BA2F24E9DFB9D79D982A676F9C010C 64
+[2025-10-29 16:51:58.979][000000004.599] I/user.sm4.cbc.pks5 解密后 >>SM4 CBC Pkcs5Padding test<<
+[2025-10-29 16:51:58.981][000000004.600] I/user.sm4.ecb.pkcs7 B083DCC0A9F64BD9FAE2FA8C936E3D776C88F739AF2A29A735381F5677BADEF7 64
+[2025-10-29 16:51:58.983][000000004.600] I/user.sm4.ecb.pkcs5 B083DCC0A9F64BD9FAE2FA8C936E3D776C88F739AF2A29A735381F5677BADEF7 64
+[2025-10-29 16:51:58.987][000000004.601] I/user.sm4.ecb.zero B083DCC0A9F64BD9FAE2FA8C936E3D77D2D68ED9FE06CB40C9A150AA5917F15F 64
+[2025-10-29 16:51:58.988][000000004.601] I/user.sm4.ecb.none B083DCC0A9F64BD9FAE2FA8C936E3D77 32
+[2025-10-29 16:51:59.450][000000005.084] I/user.sm2sign 9C2303667887E45ABA016BBACFF1AF2F3ED764CE220A0B0D67CF9206BF48F26AA2797E5478919FB0C6140B89D7DDA33055428A7B3D40F49E0BAD410624D83199
+[2025-10-29 16:51:59.864][000000005.496] I/user.sm2verify true
+[2025-10-29 16:52:00.357][000000005.982] I/user.sm2sign 756D9F37525A543A6647370C22DD71ADEEFBF86D83CE87A28889EAC9F63F0C5CFF334A2D99B067EA676437EE1DEC86B8A8F109568A7CF3AFE70A8DD09562F7E2
+[2025-10-29 16:52:00.782][000000006.411] I/user.sm2verify true
+```

+ 24 - 0
module/Air780EPM/demo/hmeta/hmeta_app.lua

@@ -0,0 +1,24 @@
+--[[
+@module  hmeta_app
+@summary hmeta_app应用功能模块 
+@version 1.0
+@date    2025.10.20
+@author  沈园园
+@usage
+本文件为hmeta应用功能模块,核心业务逻辑为:
+1、获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号;
+
+本文件没有对外接口,直接在main.lua中require "hmeta_app"就可以加载运行;
+]]
+
+
+local function hmeta_task_func()
+    while true do
+        -- 打印模组名称,硬件版本号,原始芯片型号
+        log.info("hmeta", hmeta.model(), hmeta.hwver(), hmeta.chip())
+        sys.wait(3000)
+    end
+end
+
+--创建一个task,并且运行task的主函数hmeta_task_func
+sys.taskInit(hmeta_task_func)

+ 60 - 19
module/Air780EPM/demo/hmeta/main.lua

@@ -1,30 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.20
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号
+更多说明参考本目录下的readme.md文件
+]]
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "hmetademo"
-VERSION = "1.0.0"
 
--- sys库是标配
-_G.sys = require("sys")
+--[[
+必须定义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 = "luatos_hmeta_app"
+VERSION = "001.000.000"
 
 
--- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
-if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
-    pm.power(pm.PWK_MODE, false)
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
 
-sys.taskInit(function()
-    while hmeta do
-        -- hmeta识别底层模组类型的
-        -- 不同的模组可以使用相同的bsp,但根据封装的不同,根据内部数据仍可识别出具体模块
-        log.info("hmeta", hmeta.model(), hmeta.hwver and hmeta.hwver())
-        log.info("bsp",   rtos.bsp())
-        sys.wait(3000)
-    end
-    log.info("这个bsp不支持hmeta库哦")
-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)
+
+-- 加载hmeta_app应用功能模块
+require "hmeta_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 50 - 0
module/Air780EPM/demo/hmeta/readme.md

@@ -0,0 +1,50 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、hmeta_app.lua:获取模块相关信息包括获取模组名称,硬件版本号,原始芯片型号;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、在task中的任务处理函数中,每隔三秒钟通过日志输出一次模组名称,硬件版本号,原始芯片型号;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780epm/luatos/common/hwenv/image/Air780EPM2.png)
+
+1、Air780EPM核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EPM核心板和数据线的硬件接线方式为
+
+- Air780EPM核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/luatos/common/download/)
+
+2、[Air780EPM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-21 09:53:28.552][000000003.209] I/user.hmeta Air780EPM A11 EC718PM
+[2025-10-21 09:53:31.548][000000006.209] I/user.hmeta Air780EPM A11 EC718PM
+[2025-10-21 09:53:34.555][000000009.209] I/user.hmeta Air780EPM A11 EC718PM
+
+```

+ 74 - 0
module/Air780EPM/demo/mcu/main.lua

@@ -0,0 +1,74 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.10.21
+@author  孟伟
+@usage
+本demo演示的功能为:
+    MCU死机时的处理模式设置
+    唯一ID获取与显示
+    系统tick计数功能测试
+    64位tick计数和差值计算
+    微秒、毫秒、秒级别的时间计数
+    16进制字符串转换输出
+]]
+--[[
+必须定义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 = "mcu_demo"
+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)
+
+-- 加载mcu功能模块
+require "mcu_test"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 64 - 0
module/Air780EPM/demo/mcu/mcu_test.lua

@@ -0,0 +1,64 @@
+--[[
+@module  mcu_test
+@summary 测试mcu模块功能
+@version 1.0
+@date    2025.10.21
+@author  孟伟
+@usage
+本demo演示的功能为:
+    MCU死机时的处理模式设置
+    唯一ID获取与显示
+    系统tick计数功能测试
+    64位tick计数和差值计算
+    微秒、毫秒、秒级别的时间计数
+    16进制字符串转换输出
+
+    本文件没有对外接口,直接在main.lua中require "mcu_test"就可以加载运行;
+]]
+function mcu_test()
+    -- 测试MCU 死机时的处理模式
+    -- 死机后重启,一般用于正式产品_
+    mcu.hardfault(1)
+
+    -- 测试唯一ID
+    local unique_id = mcu.unique_id()
+    if #unique_id > 0 then
+        log.info("mcu", "Unique ID(hex):", unique_id:toHex())
+    else
+        log.warn("mcu", "Unique ID not supported")
+    end
+
+    -- 测试ticks相关函数
+    -- 获取启动后的 tick 数
+    log.info("mcu", "ticks:", mcu.ticks())
+    -- 获取每秒的 tick 数量
+    log.info("mcu", "获取每秒的tick数量:", mcu.hz())
+
+
+    -- 测试64位tick
+    local tick_str, tick_per = mcu.tick64()
+    log.info("mcu", "tick64:", tick_str:toHex(), "ticks per us:", tick_per)
+    -- 测试mcu.dtick64接口获取ticks差值计算
+    local tick1 = mcu.tick64()
+    sys.wait(100)
+    local tick2 = mcu.tick64()
+    local result, diff_tick = mcu.dtick64(tick1, tick2)
+    log.info("mcu", "dtick64 result:", result, "diff:", diff_tick)
+
+
+    -- 测试ticks2函数
+    local us_h, us_l = mcu.ticks2(0)
+    local ms_h, ms_l = mcu.ticks2(1)
+    local sec_h, sec_l = mcu.ticks2(2)
+    log.info("mcu", "us:", us_h, us_l)
+    log.info("mcu", "ms:", ms_h, ms_l)
+    log.info("mcu", "sec:", sec_h, sec_l)
+
+    -- 测试 转换 10 进制数为 16 进制字符串输出
+    local value = mcu.x32(0x2009FFFC) --输出"0x2009fffc"
+    log.info("mcu", "string", value)
+
+
+end
+
+sys.taskInit(mcu_test)

+ 53 - 0
module/Air780EPM/demo/mcu/readme.md

@@ -0,0 +1,53 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、mcu_test.lua:MCU功能测试模块;
+
+## 演示功能概述
+
+使用Air780EPM核心板测试MCU相关功能,包括:
+
+- MCU死机时的处理模式设置
+- 唯一ID获取与显示
+- 系统tick计数功能测试
+- 64位tick计数和差值计算
+- 微秒、毫秒、秒级别的时间计数
+- 16进制字符串转换输出
+
+## 演示硬件环境
+
+1、Air780EPM核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air780EPM V2016版本固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、通过luatools工具查看下面日志:
+
+```lua
+[2025-10-21 17:37:39.953][000000000.242] I/user.mcu ticks: 165
+[2025-10-21 17:37:39.962][000000000.242] I/user.mcu 获取每秒的tick数量: 1000
+[2025-10-21 17:37:39.969][000000000.243] I/user.mcu tick64: 625B600000000000 ticks per us: 26
+[2025-10-21 17:37:39.982][000000000.343] I/user.mcu dtick64 result: false diff: -2610447
+[2025-10-21 17:37:40.015][000000000.344] I/user.mcu us: 0 344087
+[2025-10-21 17:37:40.030][000000000.344] I/user.mcu ms: 0 344
+[2025-10-21 17:37:40.037][000000000.344] I/user.mcu sec: 0 0
+[2025-10-21 17:37:40.043][000000000.345] I/user.mcu string 0x2009fffc
+[2025-10-21 17:37:40.048][000000000.345] I/user.us_h 0 us_l 345086
+[2025-10-21 17:37:40.064][000000000.345] I/user.ms_h 0 ms_l 345
+[2025-10-21 17:37:40.085][000000000.345] I/user.sec_h 0 sec_l 0
+
+```

+ 60 - 30
module/Air780EPM/demo/miniz/main.lua

@@ -1,41 +1,71 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.10.28
+@author  沈园园
+@usage
+本demo演示的核心功能为:
+演示如何对数据压缩解压
+更多说明参考本目录下的readme.md文件
+]]
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "minizdemo"
-VERSION = "1.0.0"
 
-sys = require("sys")
+--[[
+必须定义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 = "luatos_miniz_app"
+VERSION = "001.000.000"
 
---添加硬狗防止程序卡死
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
-sys.taskInit(function()
-    sys.wait(1000)
-    -- 压缩过的字符串, 为了方便演示, 这里用了base64编码
-    -- 大部分MCU设备的内存都比较小, miniz.compress 通常在服务器端完成,这里就不演示了
-    -- miniz能解压标准zlib数据流
-    local b64str = "eAEFQIGNwyAMXOUm+E2+OzjhCCiOjYyhyvbVR7K7IR0l+iau8G82eIW5jXVoPzF5pse/B8FaPXLiWTNxEMsKI+WmIR0l+iayEY2i2V4UbqqPh5bwimyEuY11aD8xeaYHxAquvom6VDFUXqQjG1Fek6efCFfCK0b0LUnQMjiCxhUT05GNL75dFUWCSMcjN3EE5c4Wvq42/36R41fa"
-    local str = b64str:fromBase64()
-
-    local dstr = miniz.uncompress(str)
-    -- 压缩过的数据长度 156
-    -- 解压后的数据长度,即原始数据的长度 235
-    log.info("miniz", "compressed", #str, "uncompressed", #dstr)
-
-    -- 演示压缩解压
-    local ostr = "abcd12345"
-    -- 压缩字符串
-    local zstr = miniz.compress(ostr)
-    log.info("压缩后的字符串:",zstr:toHex())
-    -- 解压字符串
-    local lstr = miniz.uncompress(zstr)
-    log.info("miniz","compress zstr",#zstr,"uncompress lstr data",lstr)
-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)
+
+-- 加载miniz_app应用功能模块
+require "miniz_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 47 - 0
module/Air780EPM/demo/miniz/miniz_app.lua

@@ -0,0 +1,47 @@
+--[[
+@module  miniz_app
+@summary miniz_app应用功能模块 
+@version 1.0
+@date    2025.10.28
+@author  沈园园
+@usage
+本文件为miniz应用功能模块,核心业务逻辑为:
+1、如何对数据压缩解压;
+
+本文件没有对外接口,直接在main.lua中require "miniz_app"就可以加载运行;
+]]
+
+
+local function miniz_task_func()
+    -- 压缩过的字符串, 为了方便演示, 这里用了base64编码
+    -- miniz能解压标准zlib数据流
+    -- 将字符串进行base64解码
+    local b64str = "eAEFQIGNwyAMXOUm+E2+OzjhCCiOjYyhyvbVR7K7IR0l+iau8G82eIW5jXVoPzF5pse/B8FaPXLiWTNxEMsKI+WmIR0l+iayEY2i2V4UbqqPh5bwimyEuY11aD8xeaYHxAquvom6VDFUXqQjG1Fek6efCFfCK0b0LUnQMjiCxhUT05GNL75dFUWCSMcjN3EE5c4Wvq42/36R41fa"
+    local str = b64str:fromBase64()
+    -- 快速解压
+    local dstr = miniz.uncompress(str) 
+    -- 压缩过的数据长度 156
+    -- 解压后的数据长度,即原始数据的长度 235
+    log.info("miniz", "压缩过的数据长度: ", #str, "解压后的数据长度:", #dstr)    
+    
+    -- 演示压缩解压
+    local ostr = "abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz"
+    log.info("压缩前的字符串:", #ostr, ostr)
+    -- 压缩字符串
+    local zstr = miniz.compress(ostr)
+    log.info("压缩后的字符串:",#zstr, zstr:toHex())
+    -- 解压字符串
+    local lstr = miniz.uncompress(zstr)
+    log.info("解压后的字符串:", #lstr, lstr)
+    
+    -- 演示从文件读取2K数据压缩
+    local ostr = io.readFile("/luadb/test.txt")
+    local zstr = miniz.compress(ostr)
+    if zstr then
+        log.info("miniz", "压缩前的数据长度: ", #ostr, "压缩后的数据长度: ", #zstr) 
+    end  
+end
+
+
+--创建一个task,并且运行task的主函数miniz_task_func
+sys.taskInit(miniz_task_func)

+ 51 - 0
module/Air780EPM/demo/miniz/readme.md

@@ -0,0 +1,51 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、miniz_app.lua:如何对数据压缩解压;
+
+## 演示功能概述
+
+1、创建一个task;
+
+2、演示如何对数据压缩解压;
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air780epm/luatos/common/hwenv/image/Air780EPM2.png)
+
+1、Air780EPM核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air780EPM核心板和数据线的硬件接线方式为
+
+- Air780EPM核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
+- 核心板正面的 ON/OFF 拨动开关 拨到ON一端;
+
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/luatos/common/download/)
+
+2、[Air780EPM 最新版本的内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools烧录内核固件和demo脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、出现类似于下面的日志,就表示运行成功:
+
+``` lua
+[2025-10-28 11:39:11.816][000000000.379] I/user.miniz 压缩过的数据长度:  156 解压后的数据长度: 235
+[2025-10-28 11:39:11.821][000000000.380] I/user.压缩前的字符串: 108 abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz
+[2025-10-28 11:39:11.826][000000000.383] I/user.压缩后的字符串: 92 780105C0040D80B04A383CCEDDDD9F9E4184C97E9CD7FDBC1FD828E3422A6DACF321A65C6AEB632E8830D98FF3BA9FF7031B655C48A58D753EC4944B6D7DCC051126FB715EF7F37E60A38C0BA9B4B1CE879872A9AD8FB97E17A42785 184
+[2025-10-28 11:39:11.832][000000000.383] I/user.解压后的字符串: 108 abcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyzabcd1234567890efghijklmnopqrstuvwxyz
+[2025-10-28 11:39:11.836][000000000.389] I/user.miniz 压缩前的数据长度:  2048 压缩后的数据长度:  1350
+```

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
module/Air780EPM/demo/miniz/test.txt


+ 0 - 2
module/Air8000/demo/accessory_board/AirETH_1000/http/readme.md

@@ -14,8 +14,6 @@
 
 1、Air8000核心板一块+可上网的sim卡一张+网线一根+AirETH_1000板子一个;
 
-[](https://docs.openLuat.com/cdn/image/AirETH_1000.jpg)
-
 ![](https://docs.openLuat.com/cdn/image/AirETH_1000.jpg)
 
 2、TYPE-C USB数据线一根 + 杜邦线若干;

+ 1 - 3
module/Air8000/demo/accessory_board/AirETH_1000/network_routing/4g_out_ethernet_in_wifi_in/readme.md

@@ -14,9 +14,7 @@
 
 1、Air8000核心板一块+可上网的sim卡一张+网线一根+AirETH_1000板子一个;
 
-[](https://docs.openLuat.com/cdn/image/AirETH_1000.jpg)
-
-![](https://docs.openLuat.com/cdn/image/AirETH_1000.jpg)
+![](https://docs.openLuat.com/cdn/image/AirETH_1000.jpg)
 
 2、TYPE-C USB数据线一根 + 杜邦线若干;
 

+ 1 - 1
module/Air8000/demo/accessory_board/AirETH_1000/readme.md

@@ -12,4 +12,4 @@
 
 (2)wifi_out_ethernet_in_wifi_in
 
-使用网络路由功能,以太网提供网络供以太网和wifi设备上网
+使用网络路由功能,模组连接外部wifi提供网络供以太网和wifi设备上网

+ 18 - 1
module/Air8000/demo/audio/main.lua

@@ -17,7 +17,7 @@
 
 5、record_stream:  流式录音,仅支持PCM,可以将音频流不断的拉取,可用来对接大模型
 
-6、sample-6s: 用于测试本地mp3文件播放
+6、sample-6s、10.amr: 用于测试本地mp3文件播放
 
 7、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
 
@@ -55,6 +55,23 @@ if wdt then
     sys.timerLoopStart(wdt.feed, 3000)
 end
 
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+
 
  require "play_file"     --   播放音频文件,可支持wav,amr,mp3 格式音频
 -- require "play_tts"      -- 支持文字转普通话输出需要固件支持

+ 250 - 0
module/Air8000/demo/audio/pins_air8000.json

@@ -0,0 +1,250 @@
+{
+  "model": "Air8000",
+  "pins": [
+    [
+      1,
+      "USB_BOOT",
+      ""
+    ],
+    [
+      2,
+      "VBUS",
+      ""
+    ],
+    [
+      14,
+      "PWR_KEY",
+      ""
+    ],
+    [
+      16,
+      "UART1_TXD",
+      ""
+    ],
+    [
+      17,
+      "UART1_RXD",
+      ""
+    ],
+    [
+      18,
+      "I2S_BCLK",
+      ""
+    ],
+    [
+      19,
+      "I2S_LRCK",
+      ""
+    ],
+    [
+      20,
+      "I2S_DIN",
+      ""
+    ],
+    [
+      21,
+      "I2S_DOUT",
+      ""
+    ],
+    [
+      22,
+      "I2S_MCLK",
+      ""
+    ],
+    [
+      23,
+      "GPIO20",
+      ""
+    ],
+    [
+      24,
+      "GPIO21",
+      ""
+    ],
+    [
+      25,
+      "LCD_CLK",
+      ""
+    ],
+    [
+      26,
+      "LCD_CS",
+      ""
+    ],
+    [
+      27,
+      "LCD_RST",
+      ""
+    ],
+    [
+      28,
+      "LCD_SDA",
+      ""
+    ],
+    [
+      29,
+      "LCD_RS",
+      ""
+    ],
+    [
+      30,
+      "GPIO2",
+      ""
+    ],
+    [
+      31,
+      "GPIO1",
+      ""
+    ],
+    [
+      35,
+      "CAN_STB",
+      ""
+    ],
+    [
+      36,
+      "CAN_TXD",
+      ""
+    ],
+    [
+      37,
+      "CAN_RXD",
+      ""
+    ],
+    [
+      38,
+      "SPI1_SCLK",
+      ""
+    ],
+    [
+      39,
+      "SPI1_MISO",
+      ""
+    ],
+    [
+      40,
+      "SPI1_MOSI",
+      ""
+    ],
+    [
+      41,
+      "SPI1_CS",
+      ""
+    ],
+    [
+      43,
+      "WAKEUP6",
+      ""
+    ],
+    [
+      44,
+      "WAKEUP0",
+      ""
+    ],
+    [
+      46,
+      "DBG_TXD",
+      ""
+    ],
+    [
+      47,
+      "DBG_RXD",
+      ""
+    ],
+    [
+      48,
+      "UART11_RXD",
+      ""
+    ],
+    [
+      49,
+      "UART11_TXD",
+      ""
+    ],
+    [
+      52,
+      "GPIO153",
+      ""
+    ],
+    [
+      53,
+      "GPIO147",
+      ""
+    ],
+    [
+      54,
+      "GPIO146",
+      ""
+    ],
+    [
+      55,
+      "GPIO141",
+      ""
+    ],
+    [
+      56,
+      "GPIO140",
+      ""
+    ],
+    [
+      59,
+      "UART12_RXD",
+      ""
+    ],
+    [
+      60,
+      "UART12_TXD",
+      ""
+    ],
+    [
+      66,
+      "I2C1_SCL",
+      ""
+    ],
+    [
+      67,
+      "I2C1_SDA",
+      ""
+    ],
+    [
+      73,
+      "GPIO162",
+      ""
+    ],
+    [
+      74,
+      "GPIO164",
+      ""
+    ],
+    [
+      80,
+      "I2C0_SCL",
+      ""
+    ],
+    [
+      81,
+      "I2C0_SDA",
+      ""
+    ],
+    [
+      82,
+      "GPIO17",
+      ""
+    ],
+    [
+      83,
+      "GPIO16",
+      ""
+    ],
+    [
+      96,
+      "GPIO160",
+      ""
+    ],
+    [
+      98,
+      "GPIO3",
+      ""
+    ]
+  ]
+}

+ 96 - 14
module/Air8000/demo/audio/readme.md

@@ -12,7 +12,7 @@
 
 6、record_stream:  流式录音,仅支持PCM。
 
-7、sample-6s.mp3/10.amr: 用于测试本地mp3文件播放
+7、sample-6s.mp3/10.amr: 用于测试本地mp3和amr文件播放
 
 8、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
 
@@ -51,7 +51,7 @@
 
 ![]( https://docs.openLuat.com/cdn//image/Air8000%E5%BC%80%E5%8F%91%E6%9D%BF.jpg)
 
-或者Air8000核心板+AirAUDIO_1010 音频扩展板+喇叭
+或者Air8000核心板+AirAUDIO_1010 音频配件板+喇叭
 
 ![alt text]( https://docs.openLuat.com/cdn/image/Air8000%E6%A0%B8%E5%BF%83%E6%9D%BF+1010.jpg)
 
@@ -72,7 +72,7 @@ Air8000核心板和AirAudio_1010 配件板的硬件接线方式为:
 | GND             | GND                 |
 
 
-2、YPE-C USB数据线一根
+2、TYPE-C USB数据线一根
 - Air8000开发板/核心板通过 TYPE-C USB 口供电;
 - TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
 
@@ -81,13 +81,17 @@ Air8000核心板和AirAudio_1010 配件板的硬件接线方式为:
 
 1、Luatools下载调试工具
 
-2、[Air8000 V2016版本固件](https://docs.openluat.com/air8000/luatos/firmware/)(理论上,2025年7月26日之后发布的固件都可以),选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。不同版本区别参考Air8000 LuatOS固件版本。
+2、[Air8000 V2016版本固件](https://cdn6.vue2.cn/Luat_tool_src/v2tools/LuatOS_Air8000/LuatOS-SoC_V2016_Air8000.zip)(理论上,2025年7月26日之后发布的固件都可以),选择支持TTS功能的1、3、5、7、13或101、103、105、107、113号固件。不同版本区别参考[Air8000 LuatOS固件版本](https://docs.openluat.com/air8000/luatos/firmware/)
 
 3、 luatos需要的脚本和资源文件
 - 脚本和资源文件[点我浏览所有文件](https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/audio)
-- lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件;
+
 - 准备好软件环境之后,接下来查看[如何烧录项目文件到Air8000核心板](https://docs.openluat.com/air8000/luatos/common/download/),将本篇文章中演示使用的项目文件烧录到Air8000开发板/核心板中。
 
+4、[合宙 LuatIO 工具(GPIO 复用初始化配置)使用说明](https://docs.openluat.com/air780epm/common/luatio/)
+
+5、 lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
+
 ## 演示核心步骤
 
 1、搭建好硬件环境
@@ -107,24 +111,102 @@ Air8000核心板和AirAudio_1010 配件板的硬件接线方式为:
 
 3、Luatools烧录内核固件和修改后的demo脚本代码
 
-4、烧录成功后,自动开机运行,如果出现以下日志,播放或者或者录音完成
+4、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
+
+5、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
+
+
+6、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
+
+7、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+
+8、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用。
+
+9、运行结果展示
+
+- 播放文件 (play_file.lua)
+
+自动播放一个sample-6s.mp3 音乐;
+
+点击powerkey 按键进行音频切换播放10.amr文件;
+
+点击boot 按键停止音频播放
 
 ``` lua
-I/user.播放完成 true
-I/user.录音完成 
-I/user.录音后文件大小 
+ I/user.开始播放音频文件
+ I/user.播放完成 true
+
+ I/user.切换播放
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+ ```
+
+ - 文字转语音 (play_tts.lua)
+
+ 播放一个TTS;
+
+点击powerkey 按键进行tts 的音色切换
+
+点击boot 按键停止音频播放
+
+``` lua
+ I/user.开始播放TTS
+ I/user.切换播放
+
+ E/user.是否完成播放 true
+ I/user.播放完成 true
+
+ I/user.停止播放
+
 ```
 
-5、 在测试播放音频文件的时候,点powerkey 按键进行音频切换,切换内容是MP3,AMR格式,切换是通过播放优先级进行区分的,注意音频格式仅仅支持:MP3,WAV,AMR,点击boot 按键停止音频播放
+- 流式播放 (play_stream.lua)
+
+创建一个播放流式音频task(task_audio)和一个模拟获取流式音频的task(audio_get_data),此task通过流式传输不断向exaudio.play_stream_write填入播放的音频,播放task 不断播放传入流式音频。
 
-6、 在测试播放TTS的时候,点powerkey 按键进行TTS 音色切换,点击boot 按键停止音频播放,注意:仅支持中文TTS。
+使用powerkey 按键进行音量减小,点击boot 按键进行音量增加
 
+``` lua
+ I/user.开始流式获取音频数据
+ I/user.开始流式播报
+
+ I/user.减小音量55
+ I/user.增大音量75
+
+ I/user.播放状态 true
+ I/user.播放完成 true
+
+```
 
-7、在进行流式播放测试的时候,使用test.pcm 模拟音频来源,通过流式传输不断填入播放的音频,使用powerkey 按键进行音量减小,点击boot 按键进行音量增加,注意流式播放目前仅支持PCM 格式音频,可选择不同的采样率,以及位深
+- 录音到文件  (record_file.lua)
 
-8、在测试录音到文件(仅支持PCM),演示了pcm 录音到文件,使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
+主程序录音到/record.amr 文件
 
-9、在测试流式录音(仅支持PCM),不断输出录音的数据地址和录音长度,供给应用层调用
+使用powerkey 按键进行录音音量减小,点击boot 按键进行录音音量增加
 
+``` lua
+ I/user.开始录制音频到文件
+
+ E/user.减小音量55
+ I/user.增大音量75
+
+ I/user.录音后文件大小 320000
+```
+
+- 流式录音(record_stream.lua),仅支持PCM格式
+
+主程序录音进行流式录音
+
+录音过程中不断的进行recode_data_callback回调,回调内容为音频流的地址和长度。
+
+``` lua
+ I/user.开始流式录制音频到文件
+ I/user.收到音频流,地址为: ZBUFF*:0C7F70A8 有效数据长度为: 9600
+ I/user.录音完成
 
+ E/user.减小音量55
+ I/user.增大音量75
 
+ I/user.录音后

Vissa filer visades inte eftersom för många filer har ändrats