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

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

This reverts commit 084c006e4ad104d58601cdee28a544be84f621bd, reversing
changes made to 9cdb2532e94c5c317330ab209d89339e6cd14b6a.
Wendal Chen 7 месяцев назад
Родитель
Сommit
10492b8cab
87 измененных файлов с 1408 добавлено и 3348 удалено
  1. 3 3
      components/airlink/src/exec/luat_airlink_bt_exec_task.c
  2. 1 1
      components/bluetooth/drv/luat_drv_ble_port.c
  3. 14 5
      components/bluetooth/include/luat_ble.h
  4. 192 27
      components/bluetooth/src/luat_lib_ble.c
  5. 115 15
      components/bluetooth/src/luat_lib_bluetooth.c
  6. 1 2
      components/lcd/luat_lib_lcd.c
  7. 1 0
      components/network/adapter_lwip2/net_lwip2.c
  8. 10 1
      components/network/libhttp/luat_http_client.c
  9. 1 0
      components/network/libhttp/luat_lib_http.c
  10. 7 4
      components/wlan/luat_lib_wlan.c
  11. 4 0
      components/ymodem/luat_ymodem.c
  12. BIN
      luat/demo/airlink/air8000_airlink_fota/air8000s_v10.bin
  13. 2 2
      luat/demo/airlink/air8000_airlink_fota/main.lua
  14. 16 1
      luat/demo/airlink/air8000_ble/peripheral/main.lua
  15. 23 23
      luat/demo/airlink/for_ccc/main.lua
  16. 1 0
      luat/include/luat_log.h
  17. 5 1
      luat/include/luat_mcu.h
  18. 2 0
      luat/include/luat_pm.h
  19. 1 0
      luat/include/luat_rtos_legacy.h
  20. 4 0
      luat/modules/luat_lib_pm.c
  21. 15 13
      module/Air780EHV/DEMO/CC/main.lua
  22. 90 52
      module/Air780EHV/DEMO/audio/main.lua
  23. 107 85
      module/Air780EHV/DEMO/record/main.lua
  24. 4 4
      module/Air780EHV/DEMO/tts/main.lua
  25. BIN
      module/Air8000/core/LuatOS-SoC_V2008_Air8000_FS_0623.soc
  26. BIN
      module/Air8000/core/LuatOS-SoC_V2008_Air8000_LVGL_0623.soc
  27. BIN
      module/Air8000/core/LuatOS-SoC_V2008_Air8000_VOLTE_0623.soc
  28. 7 0
      module/Air8000/core/changeLog.md
  29. 0 0
      module/Air8000/core/old_core/LuatOS-SoC_V2007_Air8000_VOLTE_0610.soc
  30. 0 0
      module/Air8000/core/old_core/LuatOS-SoC_V2008_Air8000_FS_0621.soc
  31. 0 0
      module/Air8000/core/old_core/LuatOS-SoC_V2008_Air8000_LVGL_0621.soc
  32. 13 12
      module/Air8000/demo/can/main.lua
  33. 32 76
      module/Air8000/project/整机开发板出厂工程/user/airble.lua
  34. 1 1
      module/Air8000/project/整机开发板出厂工程/user/main.lua
  35. 26 0
      module/Air8101/demo/socket/client/long_connection/E6.crt
  36. 31 0
      module/Air8101/demo/socket/client/long_connection/ISRG Root X1.crt
  37. 99 0
      module/Air8101/demo/socket/client/long_connection/main.lua
  38. 103 0
      module/Air8101/demo/socket/client/long_connection/readme.md
  39. 132 0
      module/Air8101/demo/socket/client/long_connection/tcp_client_main.lua
  40. 57 0
      module/Air8101/demo/socket/client/long_connection/tcp_client_receiver.lua
  41. 104 0
      module/Air8101/demo/socket/client/long_connection/tcp_client_sender.lua
  42. 32 0
      module/Air8101/demo/socket/client/long_connection/test_app.lua
  43. 22 0
      module/Air8101/demo/socket/client/long_connection/timer_app.lua
  44. 73 0
      module/Air8101/demo/socket/client/long_connection/uart_app.lua
  45. 42 0
      module/Air8101/demo/socket/client/long_connection/wifi_app.lua
  46. 0 0
      script/libs/agps_icoe.lua
  47. 15 6
      script/libs/httpdns.lua
  48. 0 21
      script/turnkey/EinkBook/LICENSE
  49. 0 52
      script/turnkey/EinkBook/README.md
  50. 0 354
      script/turnkey/EinkBook/Scripts/main.lua
  51. 0 53
      script/turnkey/EinkBook/Scripts/wifiLib.lua
  52. 0 3
      script/turnkey/EinkBook/Server/README.md
  53. 0 9
      script/turnkey/air780eg_gnss_qcloud/README.md
  54. 0 280
      script/turnkey/air780eg_gnss_qcloud/main.lua
  55. 0 4
      script/turnkey/air780eg_irtu_gps/README.md
  56. 0 209
      script/turnkey/air780eg_irtu_gps/main.lua
  57. 0 6
      script/turnkey/eink-calendar/README.md
  58. 0 92
      script/turnkey/eink-calendar/main.lua
  59. 0 11
      script/turnkey/eink-calendar/meta.json
  60. BIN
      script/turnkey/lcd-0.96-lvgl/16_test_fonts.bin
  61. 0 39
      script/turnkey/lcd-0.96-lvgl/about.lua
  62. 0 33
      script/turnkey/lcd-0.96-lvgl/animation.lua
  63. 0 88
      script/turnkey/lcd-0.96-lvgl/device.lua
  64. 0 115
      script/turnkey/lcd-0.96-lvgl/home.lua
  65. 0 31
      script/turnkey/lcd-0.96-lvgl/key.lua
  66. 0 37
      script/turnkey/lcd-0.96-lvgl/main.lua
  67. 0 6
      script/turnkey/programmer/README.md
  68. 0 137
      script/turnkey/programmer/air101.lua
  69. 0 30
      script/turnkey/programmer/main.lua
  70. 0 11
      script/turnkey/programmer/meta.json
  71. 0 127
      script/turnkey/programmer/xmodem.lua
  72. 0 175
      script/turnkey/qcloud100_switch/main.lua
  73. 0 6
      script/turnkey/remote_pc_poweron/README.md
  74. 0 124
      script/turnkey/remote_pc_poweron/main.lua
  75. 0 11
      script/turnkey/remote_pc_poweron/meta.json
  76. 0 11
      script/turnkey/scanner_air105/README.md
  77. 0 11
      script/turnkey/scanner_air105/meta.json
  78. 0 284
      script/turnkey/scanner_air105/src/GC032A_InitReg_Gray.txt
  79. 0 97
      script/turnkey/scanner_air105/src/main.lua
  80. 0 12
      script/turnkey/thermal_imaging/README.md
  81. 0 86
      script/turnkey/thermal_imaging/main.lua
  82. 0 11
      script/turnkey/thermal_imaging/meta.json
  83. 0 191
      script/turnkey/web_audio/audio_play.lua
  84. 0 159
      script/turnkey/web_audio/main.lua
  85. 0 30
      script/turnkey/ws2812_nimble/README.md
  86. 0 47
      script/turnkey/ws2812_nimble/main.lua
  87. 0 11
      script/turnkey/ws2812_nimble/meta.json

+ 3 - 3
components/airlink/src/exec/luat_airlink_bt_exec_task.c

@@ -288,15 +288,15 @@ static void drv_bt_task(void *param) {
                 break;
             case LUAT_DRV_BT_CMD_BLE_WRITE_NOTIFY:
                 ret = drv_ble_write_notify(msg);
-                LLOGD("ble wrtite notify %d", ret);
+                LLOGD("ble write notify %d", ret);
                 break;
             case LUAT_DRV_BT_CMD_BLE_WRITE_INDICATION:
                 ret = drv_ble_write_indication(msg);
-                LLOGD("ble wrtite indication %d", ret);
+                LLOGD("ble write indication %d", ret);
                 break;
             case LUAT_DRV_BT_CMD_BLE_WRITE_VALUE:
                 ret = drv_ble_write_value(msg);
-                LLOGD("ble wrtite value %d", ret);
+                LLOGD("ble write value %d", ret);
                 break;
                 
             // case LUAT_DRV_BT_CMD_BLE_SEND_READ_RESP:

+ 1 - 1
components/bluetooth/drv/luat_drv_ble_port.c

@@ -518,7 +518,7 @@ int luat_ble_disconnect(void* args) {
     return -1;
 }
 
-int luat_ble_read_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t *data, uint16_t* len) {
+int luat_ble_read_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t **data, uint16_t* len) {
     LLOGE("not support yet -> luat_ble_read_value");
     return -1;
 }

+ 14 - 5
components/bluetooth/include/luat_ble.h

@@ -203,6 +203,12 @@ typedef enum {
     LUAT_BLE_ACTIVE_SCANNING,       // Active scanning. Scanning PDUs may be sent
 }luat_ble_scan_type_t;
 
+typedef enum {
+    LUAT_BLE_MODE_NONE,
+    LUAT_BLE_MODE_SLAVER,
+    LUAT_BLE_MODE_MASTER,
+}luat_ble_mode_t;
+
 typedef struct {
     luat_ble_scan_type_t scan_type;
     luat_ble_addr_mode_t addr_mode;
@@ -263,7 +269,7 @@ typedef struct luat_ble_disconn_ind{
 
 typedef struct luat_ble_gatt_done_ind{
     uint8_t gatt_service_num;
-    luat_ble_gatt_service_t* gatt_service;
+    luat_ble_gatt_service_t** gatt_service;
     void* user_data;
 }luat_ble_gatt_done_ind_t;
 
@@ -289,6 +295,7 @@ typedef struct {
 typedef void (*luat_ble_cb_t)(luat_ble_t* luat_ble, luat_ble_event_t ble_event, luat_ble_param_t* ble_param);
 
 struct luat_ble{
+    luat_ble_mode_t mode;
     uint8_t actv_idx;
     luat_ble_actv_state state;
     luat_ble_cb_t cb;
@@ -306,6 +313,8 @@ int luat_ble_set_name(void* args, char* name, uint8_t len);
 
 int luat_ble_set_max_mtu(void* args, uint16_t max_mtu);
 
+luat_ble_mode_t luat_ble_get_mode(void* args);
+
 // advertise
 int luat_ble_create_advertising(void* args, luat_ble_adv_cfg_t* adv_cfg);
 
@@ -325,10 +334,10 @@ int luat_ble_handle2uuid(uint16_t handle, luat_ble_uuid_t* uuid_service, luat_bl
 int luat_ble_uuid2handle(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint16_t* handle);
 
 // slaver
-int luat_ble_write_notify_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t *data, uint16_t len);
-int luat_ble_write_indicate_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t *data, uint16_t len);
-int luat_ble_write_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t *data, uint16_t len);
-int luat_ble_read_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t *data, uint16_t* len);
+int luat_ble_write_notify_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t* data, uint16_t len);
+int luat_ble_write_indicate_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t* data, uint16_t len);
+int luat_ble_write_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t* data, uint16_t len);
+int luat_ble_read_value(luat_ble_uuid_t* uuid_service, luat_ble_uuid_t* uuid_characteristic, luat_ble_uuid_t* uuid_descriptor, uint8_t** data, uint16_t* len);
 
 
 // master

+ 192 - 27
components/bluetooth/src/luat_lib_ble.c

@@ -1,3 +1,47 @@
+/*
+@module ble
+@summary 低功耗蓝牙
+@version 1.0
+@date    2025.6.21
+@usage
+-- 本库用于操作BLE对象, 需要搭配bluetooth.init()使用
+-- 详细用法请查阅demo
+
+-- 模式解释
+-- 从机模式(peripheral), 设备会被扫描到, 并且可以被连接
+-- 主机模式(central), 设备会扫描其他设备, 并且可以连接其他设备
+-- 广播者模式(ibeacon), 设备会周期性的广播beacon信息, 但不会被扫描到, 也不会连接其他设备
+-- 观察者模式(scan), 设备会扫描其他设备, 但不会连接其他设备
+
+-- 从机模式(peripheral)的基本流程(概要描述)
+-- 1. 初始化蓝牙框架
+-- 2. 创建BLE对象
+-- local ble_device = bluetooth_device:ble(ble_event_cb)
+-- 3. 创建GATT描述
+-- local att_db = {xxx}
+-- 4. 创建广播信息
+-- ble_device:adv_create(adv_data)
+-- 5. 开始广播
+-- ble_device:adv_start()
+-- 6. 等待连接
+-- 7. 在回调函数中处理连接事件, 如接收数据, 发送数据等
+
+-- 主机模式(central)的基本流程(概要描述)
+-- TODO
+
+-- 广播者模式(ibeacon)的基本流程(概要描述)
+-- TODO
+
+-- 观察者模式(scan)的基本流程(概要描述)
+-- 1. 初始化蓝牙框架
+-- 2. 创建BLE对象
+-- local ble_device = bluetooth_device:ble(ble_event_cb)
+-- 3. 开始扫描
+-- ble_device:scan_start()
+-- 4. 在回调函数中处理扫描事件, 如接收设备信息等
+-- 5. 按需停止扫描
+-- ble_device:scan_stop()
+*/
 #include "luat_base.h"
 #include "luat_mem.h"
 #include "luat_rtos.h"
@@ -22,31 +66,22 @@ int l_ble_callback(lua_State *L, void *ptr)
     uint8_t tmpbuff[16] = {0};
 
     lua_geti(L, LUA_REGISTRYINDEX, g_ble_lua_cb_ref);
-    if (lua_isfunction(L, -1))
-    {
+    if (lua_isfunction(L, -1)){
         lua_geti(L, LUA_REGISTRYINDEX, g_bt_ble_ref);
         lua_pushinteger(L, evt);
-    }
-    else
-    {
+    }else{
         LLOGE("用户回调函数不存在");
         goto exit;
     }
 
-    switch (evt)
-    {
-    case LUAT_BLE_EVENT_WRITE:
-    {
+    switch (evt){
+    case LUAT_BLE_EVENT_WRITE:{
         luat_ble_write_req_t *write_req = &(param->write_req);
 
         lua_createtable(L, 0, 5);
         lua_pushliteral(L, "handle");
         lua_pushinteger(L, write_req->handle);
         lua_settable(L, -3);
-        // luat_ble_uuid_t uuid_service = {0};
-        // luat_ble_uuid_t uuid_characteristic = {0};
-        // luat_ble_uuid_t uuid_descriptor = {0};
-        // luat_ble_handle2uuid(write_req->handle, &uuid_service, &uuid_characteristic, &uuid_descriptor);
 
         lua_pushliteral(L, "uuid_service");
         lua_pushlstring(L, (const char *)write_req->uuid_service.uuid, write_req->uuid_service.uuid_type);
@@ -54,8 +89,7 @@ int l_ble_callback(lua_State *L, void *ptr)
         lua_pushliteral(L, "uuid_characteristic");
         lua_pushlstring(L, (const char *)write_req->uuid_characteristic.uuid, write_req->uuid_characteristic.uuid_type);
         lua_settable(L, -3);
-        if (write_req->uuid_descriptor.uuid[0] != 0 || write_req->uuid_descriptor.uuid[1] != 0)
-        {
+        if (write_req->uuid_descriptor.uuid[0] != 0 || write_req->uuid_descriptor.uuid[1] != 0){
             lua_pushliteral(L, "uuid_descriptor");
             lua_pushlstring(L, (const char *)write_req->uuid_descriptor.uuid, write_req->uuid_descriptor.uuid_type);
             lua_settable(L, -3);
@@ -124,20 +158,17 @@ int l_ble_callback(lua_State *L, void *ptr)
         // uint8_t evt_type;     /**< Event type (see enum \ref adv_report_info and see enum \ref adv_report_type)*/
 
         lua_call(L, 3, 0);
-        if (adv_req->data)
-        {
+        if (adv_req->data){
             luat_heap_free(adv_req->data);
             adv_req->data = NULL;
         }
         break;
     }
-    case LUAT_BLE_EVENT_GATT_DONE:
-    {
-        luat_ble_gatt_service_t **gatt_services = &param->gatt_done_ind.gatt_service;
+    case LUAT_BLE_EVENT_GATT_DONE:{
+        luat_ble_gatt_service_t **gatt_services = param->gatt_done_ind.gatt_service;
         uint8_t gatt_service_num = param->gatt_done_ind.gatt_service_num;
         lua_createtable(L, gatt_service_num, 0);
-        for (size_t i = 0; i < gatt_service_num; i++)
-        {
+        for (size_t i = 0; i < gatt_service_num; i++){
             luat_ble_gatt_service_t *gatt_service = gatt_services[i];
             lua_newtable(L);
             // servise uuid
@@ -145,14 +176,14 @@ int l_ble_callback(lua_State *L, void *ptr)
             lua_rawseti(L, -2, 1);
             // characteristics
             uint8_t characteristics_num = gatt_service->characteristics_num;
-            for (size_t m = 0; m < characteristics_num; m++)
-            {
+            for (size_t m = 0; m < characteristics_num; m++){
                 luat_ble_gatt_chara_t *gatt_chara = &gatt_service->characteristics[m];
                 lua_newtable(L);
                 lua_pushlstring(L, (const char *)gatt_chara->uuid, gatt_service->uuid_type);
                 lua_seti(L, -2, 1);
                 // Properties
-                // lua_seti(L, -2, 2);
+                lua_pushnumber(L, gatt_chara->perm);
+                lua_seti(L, -2, 2);
 
                 lua_seti(L, -2, m + 2);
             }
@@ -230,6 +261,26 @@ void luat_ble_cb(luat_ble_t *args, luat_ble_event_t ble_event, luat_ble_param_t
     luat_msgbus_put(&msg, 0);
 }
 
+/*
+创建一个BLE GATT服务
+@api ble.gatt_create(opts)
+@table GATT服务的描述信息
+@return boolean 是否创建成功
+@usage
+local att_db = { -- Service
+    string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
+    -- Characteristic
+    { -- Characteristic 1
+        string.fromHex("EA01"), -- Characteristic UUID Value, 特征的UUID值, 可以是16位、32位或128位
+        ble.NOTIFY | ble.READ | ble.WRITE -- Properties, 对应蓝牙特征的属性, 可以是以下值的组合:
+        -- ble.READ: 可读
+        -- ble.WRITE: 可写
+        -- ble.NOTIFY: 可通知
+        -- ble.INDICATE: 可指示
+    }
+}
+ble_device:gatt_create(att_db)
+*/
 static int l_ble_gatt_create(lua_State *L){
     if (!lua_isuserdata(L, 1)){
         return 0;
@@ -357,6 +408,7 @@ static int l_ble_gatt_create(lua_State *L){
                 if (LUA_TSTRING == lua_type(L, -1)){
                     const char *value = luaL_checklstring(L, -1, &len);
                     characteristics[characteristics_num].value = luat_heap_malloc(len);
+                    memcpy(characteristics[characteristics_num].value, value, len);
                     characteristics[characteristics_num].value_len = len;
                 }
                 lua_pop(L, 1);
@@ -381,6 +433,26 @@ error_exit:
     return 0;
 }
 
+/*
+创建一个BLE广播
+@api ble.adv_create(opts)
+@table 广播的描述信息
+@return boolean 是否创建成功
+@usage
+-- 创建广播信息
+ble_device:adv_create({
+    addr_mode = ble.PUBLIC, -- 广播地址模式, 可选值: ble.PUBLIC, ble.RANDOM, ble.RPA, ble.NRPA
+    channel_map = ble.CHNLS_ALL, -- 广播的通道, 可选值: ble.CHNLS_37, ble.CHNLS_38, ble.CHNLS_39, ble.CHNLS_ALL
+    intv_min = 120, -- 广播间隔最小值, 单位为0.625ms, 最小值为20, 最大值为10240
+    intv_max = 120, -- 广播间隔最大值, 单位为0.625ms, 最小值为20, 最大值为10240
+    adv_data = {
+        {ble.FLAGS, string.char(0x06)},
+        {ble.COMPLETE_LOCAL_NAME, "LuatOS123"}, -- 广播的设备名
+        {ble.SERVICE_DATA, string.fromHex("FE01")}, -- 广播的服务数据
+        {ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
+    }
+})
+*/
 static int l_ble_advertising_create(lua_State *L){
     if (!lua_isuserdata(L, 1)){
         return 0;
@@ -491,16 +563,48 @@ end:
     return 0;
 }
 
+/*
+开始广播
+@api ble.adv_start()
+@return boolean 是否成功
+@usage
+-- 开始广播
+ble_device:adv_start()
+
+-- 提醒, 对于从机模式, 如果被断开了连接, 则需要重新开始广播, 才能被重新搜索到
+*/
 static int l_ble_advertising_start(lua_State *L){
     lua_pushboolean(L, luat_ble_start_advertising(NULL) ? 0 : 1);
     return 1;
 }
 
+/*
+主动停止广播
+@api ble.adv_stop()
+@return boolean 是否成功
+@usage
+-- 停止广播
+ble_device:adv_stop()
+*/
 static int l_ble_advertising_stop(lua_State *L){
     lua_pushboolean(L, luat_ble_stop_advertising(NULL) ? 0 : 1);
     return 1;
 }
 
+/*
+写入带通知的特征值
+@api ble.write_notify(opts, value)
+@table 特征值的描述信息
+@string value 要写入的值
+@return boolean 是否成功
+@usage
+-- 写入带通知的特征值
+ble_device:write_notify({
+    uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
+    uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
+    uuid_descriptor = "2902" -- 可选, 描述符的UUID值, 可以是16位、32位或128位
+}, "Hello BLE") -- 要写入的值
+*/
 static int l_ble_write_notify(lua_State *L){
     uint16_t ret = 0;
     const char *service_uuid = NULL;
@@ -561,6 +665,20 @@ end_error:
     return 0;
 }
 
+/*
+写入带指示的特征值
+@api ble.write_indicate(opts, value)
+@table 特征值的描述信息
+@string value 要写入的值
+@return boolean 是否成功
+@usage
+-- 写入带指示的特征值
+ble_device:write_indicate({
+    uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
+    uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
+    uuid_descriptor = "2902" -- 可选, 描述符的UUID值, 可以是16位、32位或128位
+}, "Hello BLE") -- 要写入的值
+*/
 static int l_ble_write_indicate(lua_State *L){
     uint16_t ret = 0;
     const char *service_uuid = NULL;
@@ -621,6 +739,20 @@ end_error:
     return 0;
 }
 
+/*
+写入特征值
+@api ble.write_value(opts, value)
+@table 特征值的描述信息
+@string value 要写入的值
+@return boolean 是否成功
+@usage
+-- 写入特征值,填充预设值,被动读取
+ble_device:write_value({
+    uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
+    uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
+    uuid_descriptor = "2902" -- 可选, 描述符的UUID值, 可以是16位、32位或128位
+}, "Hello BLE") -- 要写入的值
+*/
 static int l_ble_write_value(lua_State *L){
     uint16_t ret = 0;
     const char *service_uuid = NULL;
@@ -727,15 +859,18 @@ static int l_ble_read_value(lua_State *L){
             descriptor.uuid_type = tmp;
             memcpy(descriptor.uuid, descriptor_uuid, descriptor.uuid_type);
             LLOGD("uuid_descriptor: %02X %02X", descriptor.uuid[0], descriptor.uuid[1]);
-            ret = luat_ble_read_value(&service, &characteristic, &descriptor, value, &len);
+            ret = luat_ble_read_value(&service, &characteristic, &descriptor, &value, &len);
 
         }else{
-            ret = luat_ble_read_value(&service, &characteristic, NULL, value, &len);
+            ret = luat_ble_read_value(&service, &characteristic, NULL, &value, &len);
         }
         lua_pop(L, 1);
         if (ret == 0){
             lua_pushlstring(L, (const char *)value, len);
             return 1;
+        }else{
+            LLOGE("ble read value error");
+            return 0;
         }
     }
 end_error:
@@ -743,6 +878,16 @@ end_error:
     return 0;
 }
 
+/*创建一个BLE扫描
+@api ble.scan_create(addr_mode, scan_interval, scan_window)
+@number addr_mode 广播地址模式, 可选值: ble.PUBLIC, ble.RANDOM, ble.RPA, ble.NRPA
+@number scan_interval 扫描间隔, 单位为0.625ms, 最小值为20, 最大值为10240
+@number scan_window 扫描窗口, 单位为0.625ms, 最小值为20, 最大值为10240
+@return boolean 是否创建成功
+@usage
+-- 创建BLE扫描
+ble_device:scan_create(ble.PUBLIC, 100, 100)
+*/
 static int l_ble_scanning_create(lua_State *L){
     if (!lua_isuserdata(L, 1)){
         return 0;
@@ -770,11 +915,31 @@ static int l_ble_scanning_create(lua_State *L){
     }
     return 0;
 }
+
+/*
+开始BLE扫描
+@api ble.scan_start()
+@return boolean 是否成功
+@usage
+-- 开始BLE扫描
+ble_device:scan_start()
+-- 提醒, 扫描会一直进行, 直到调用ble.scan_stop()停止扫描
+-- 扫描结果会立即执行回调, 同一个设备不会去重, 扫描到数据就会执行回调
+*/
 static int l_ble_scanning_start(lua_State *L){
     lua_pushboolean(L, luat_ble_start_scanning(NULL) ? 0 : 1);
     return 1;
 }
 
+/*
+停止BLE扫描
+@api ble.scan_stop()
+@return boolean 是否成功
+@usage
+-- 停止BLE扫描
+ble_device:scan_stop()
+-- 提醒, 扫描会一直进行, 直到调用ble.scan_stop()停止扫描
+*/
 static int l_ble_scanning_stop(lua_State *L){
     lua_pushboolean(L, luat_ble_stop_scanning(NULL) ? 0 : 1);
     return 1;

+ 115 - 15
components/bluetooth/src/luat_lib_bluetooth.c

@@ -1,3 +1,44 @@
+/*
+@module  bluetooth
+@summary 蓝牙(总库)
+@version 1.0
+@date    2025.6.21
+@usage
+-- 本库用于初始化/反初始化整个蓝牙模块, 以及创建BLE对象(低功耗蓝牙)/BT对象(经典蓝牙)
+-- 当前仅支持BLE, 经典蓝牙未实现
+
+-- 初始化蓝牙框架
+bluetooth_device = bluetooth.init()
+-- 创建BLE对象
+ble_device = bluetooth_device:ble(ble_event_cb)
+
+-- 从机模式(peripheral)下, 设备会被扫描到, 并且可以被连接
+-- 创建GATT描述
+local att_db = { -- Service
+    string.fromHex("FA00"), -- Service UUID
+    -- Characteristic
+    { -- Characteristic 1
+        string.fromHex("EA01"), -- Characteristic UUID Value
+        ble.NOTIFY | ble.READ | ble.WRITE -- Properties
+    }
+}
+ble_device:gatt_create(att_db)
+-- 创建广播信息
+ble_device:adv_create({
+    addr_mode = ble.PUBLIC,
+    channel_map = ble.CHNLS_ALL,
+    intv_min = 120,
+    intv_max = 120,
+    adv_data = {
+        {ble.FLAGS, string.char(0x06)},
+        {ble.COMPLETE_LOCAL_NAME, "LuatOS123"}, -- 广播的设备名
+        {ble.SERVICE_DATA, string.fromHex("FE01")}, -- 广播的服务数据
+        {ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
+    }
+})
+-- 开始广播
+ble_device:adv_start()
+*/
 #include "luat_base.h"
 #include "luat_mem.h"
 #include "luat_rtos.h"
@@ -14,6 +55,80 @@ static int s_bt_ref;
 int g_bt_ble_ref;
 int g_ble_lua_cb_ref;
 
+/*
+初始化蓝牙框架, 仅需要调用一次
+@api bluetooth.init()
+@return userdata 蓝牙代理对象
+@usage
+-- 初始化蓝牙框架, 仅需要调用一次
+-- 若创建失败, 会返回nil, 请检查内存是否足够
+bluetooth_device = bluetooth.init()
+*/
+static int l_bluetooth_init(lua_State* L) {
+    void* bt = lua_newuserdata(L, 4);
+    if (bt) {
+        luat_bluetooth_init(NULL);
+        luaL_setmetatable(L, LUAT_BLUETOOTH_TYPE);
+        lua_pushvalue(L, -1);
+        s_bt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+        return 1;
+    }
+    else {
+        LLOGE("创建BT代理对象失败,内存不足");
+    }
+    return 0;
+}
+
+/*
+创建BLE对象, 需要先调用bluetooth.init()
+@api bluetooth.ble(cb)
+@function 回调函数, 用于接收BLE事件
+@return userdata BLE对象
+@usage
+-- 创建BLE对象, 需要先调用bluetooth.init()
+bluetooth_device = bluetooth.init()
+
+-- ble_callback 是自定义函数, 用于处理BLE事件
+-- BLE事件回调函数, 回调时的参数如下:
+function ble_callback(dev, evt, param)
+    -- dev 是BLE设备对象, 可以通过dev:adv_create()等方法进行操作
+    -- evt 是BLE事件类型, 可以是以下几种:
+    -- ble.EVENT_CONN: 连接成功
+        -- param 是事件参数, 包含以下字段:
+        -- param.addr: 对端设备的地址, 6字节的二进制数据, 代表BLE设备的MAC地址
+    -- ble.EVENT_DISCONN: 断开连接
+        -- param 是事件参数, 包含以下字段:
+        -- param.reason: 断开连接的原因
+    -- ble.EVENT_WRITE_REQ: 收到写请求
+        -- param 是事件参数, 包含以下字段:
+        -- param.uuid_service: 服务的UUID
+        -- param.uuid_characteristic: 特征的UUID
+        -- param.uuid_descriptor: 描述符的UUID, 可选, 不一定存在
+        -- param.data: 写入的数据
+    -- ble.EVENT_SCAN_REPORT: 扫描到设备
+        -- param 是事件参数, 包含以下字段:
+        -- param.rssi: 信号强度
+        -- param.adv_addr: 广播地址, 6字节的二进制数据
+        -- param.data: 广播数据, 二进制数据
+
+    if evt == ble.EVENT_CONN then
+        log.info("ble", "connect 成功", param, param and param.addr and param.addr:toHex() or "unknow")
+        ble_stat = true
+    elseif evt == ble.EVENT_DISCONN then
+        log.info("ble", "disconnect")
+        ble_stat = false
+        -- 1秒后重新开始广播
+        sys.timerStart(function() dev:adv_start() end, 1000)
+    elseif ble_event == ble.EVENT_SCAN_REPORT then
+        log.info("ble", "scan report", param.rssi, param.adv_addr:toHex(), param.data:toHex())
+    elseif evt == ble.EVENT_WRITE_REQ then
+        -- 收到写请求
+        log.info("ble", "接收到写请求", param.uuid_service:toHex(), param.uuid_characteristic:toHex(), param.data:toHex())
+    end
+end
+-- 创建BLE对象
+ble_device = bluetooth_device:ble(ble_event_cb)
+*/
 static int l_bluetooth_create_ble(lua_State* L) {
     int ret = 0;
     
@@ -38,21 +153,6 @@ static int l_bluetooth_create_ble(lua_State* L) {
     return 1;
 }
 
-static int l_bluetooth_init(lua_State* L) {
-    void* bt = lua_newuserdata(L, 4);
-    if (bt) {
-        luat_bluetooth_init(NULL);
-        luaL_setmetatable(L, LUAT_BLUETOOTH_TYPE);
-        lua_pushvalue(L, -1);
-        s_bt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
-        return 1;
-    }
-    else {
-        LLOGE("创建BT代理对象失败,内存不足");
-    }
-    return 0;
-}
-
 static int _bluetooth_struct_newindex(lua_State *L);
 
 void luat_bluetooth_struct_init(lua_State *L) {

+ 1 - 2
components/lcd/luat_lib_lcd.c

@@ -93,9 +93,8 @@ lcd显示屏初始化
 @api lcd.init(tp, args, spi_dev, init_in_service)
 @string lcd类型,当前支持:<br>st7796<br>st7789<br>st7735<br>st7735v<br>st7735s<br>gc9a01<br>gc9106l<br>gc9306x<br>ili9486<br>custom
 @table 附加参数,与具体设备有关:<br>pin_pwr(背光)为可选项,可不设置<br>port:驱动端口,rgb:lcd.RGB spi:例如0,1,2...如果为device方式则为"device"<br>pin_dc:lcd数据/命令选择引脚<br>pin_rst:lcd复位引脚<br>pin_pwr:lcd背光引脚 可选项,可不设置<br>direction:lcd屏幕方向 0:0° 1:180° 2:270° 3:90°<br>w:lcd 水平分辨率<br>h:lcd 竖直分辨率<br>xoffset:x偏移(不同屏幕ic 不同屏幕方向会有差异)<br>yoffset:y偏移(不同屏幕ic 不同屏幕方向会有差异)<br>direction0:0°方向命令,(不同屏幕ic会有差异)<br>direction90:90°方向命令,(不同屏幕ic会有差异)<br>direction180:180°方向命令,(不同屏幕ic会有差异)<br>direction270:270°方向命令,(不同屏幕ic会有差异) <br>sleepcmd:睡眠命令,默认0X10<br>wakecmd:唤醒命令,默认0X11 <br>interface_mode lcd模式,默认lcd.WIRE_4_BIT_8_INTERFACE_I <br>bus_speed:qspi/rgb总线速率 <br>hbp:水平后廊 <br>hspw:水平同步脉冲宽度 <br>hfp:水平前廊,<br>vbp:垂直后廊 <br>vspw:垂直同步脉冲宽度 <br>vfp:垂直前廊
-
 @userdata spi设备,当port = "device"时有效
-@boolean 允许初始化在lcd service里运行,默认是false
+@boolean 允许初始化在lcd service里运行,在后台初始化LCD,默认是false
 @usage
 -- 初始化spi0的st7735s 注意:lcd初始化之前需要先初始化spi
 spi_lcd = spi.deviceSetup(0,20,0,0,8,2000000,spi.MSB,1,1)

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

@@ -557,6 +557,7 @@ static void net_lwip2_dns_tx_next(uint8_t adapter_index, Buffer_Struct *tx_msg_b
 		}
 		else {
 			pbuf_take(p, tx_msg_buf->Data, tx_msg_buf->Pos);
+			prvlwip.dns_udp[adapter_index]->local_ip = prvlwip.lwip_netif[adapter_index]->ip_addr;
 			ipaddr_ntoa_r(&prvlwip.dns_udp[adapter_index]->local_ip, ipstr2, sizeof(ipstr2));
 			ipaddr_ntoa_r(&prvlwip.dns_client.dns_server[i], ipstr, sizeof(ipstr));
 			LLOGD("dns udp sendto %s:%d from %s", ipstr, DNS_SERVER_PORT, ipstr2);

+ 10 - 1
components/network/libhttp/luat_http_client.c

@@ -3,6 +3,7 @@
 
 #include "luat_rtos.h"
 // #include "luat_msgbus.h"
+#include "luat_debug.h"
 
 #include "luat_mem.h"
 #include "http_parser.h"
@@ -19,6 +20,7 @@
 
 #define LUAT_LOG_TAG "http"
 #include "luat_log.h"
+
 extern void DBG_Printf(const char* format, ...);
 extern void luat_http_client_onevent(luat_http_ctrl_t *http_ctrl, int error_code, int arg);
 #undef LLOGD
@@ -146,7 +148,14 @@ static void http_network_error(luat_http_ctrl_t *http_ctrl)
 		http_ctrl->state = HTTP_STATE_IDLE;
 		http_ctrl->error_code = HTTP_ERROR_CONNECT;
 		network_close(http_ctrl->netc, 0);
-		http_cb(http_ctrl->error_code, NULL, 0, http_ctrl->http_cb_userdata);
+		if (http_cb)
+		{
+			http_cb(http_ctrl->error_code, NULL, 0, http_ctrl->http_cb_userdata);
+		}
+		else
+		{
+			luat_debug_assert(__FUNCTION__, __LINE__, "http no cb");
+		}
 	}
 }
 static void http_network_close(luat_http_ctrl_t *http_ctrl)

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

@@ -491,6 +491,7 @@ exit:
 
 void luat_http_client_onevent(luat_http_ctrl_t *http_ctrl, int error_code, int arg) {
 	// network_close(http_ctrl->netc, 0);
+	if (!http_ctrl->luatos_mode) return;
 	rtos_msg_t msg = {0};
 	msg.handler = l_http_callback;
 	msg.ptr = http_ctrl;

+ 7 - 4
components/wlan/luat_lib_wlan.c

@@ -197,12 +197,15 @@ end)
 */
 static int l_wlan_scan(lua_State* L){
     (void)L;
-    // TODO 对于没有wifi的Air8000模组, 要走自身的wifiscan
     #ifdef LUAT_USE_DRV_WLAN
-    luat_drv_wlan_scan();
-    #else
-    luat_wlan_scan();
+    #ifdef LUAT_USE_AIRLINK
+    if (luat_airlink_has_wifi()) {
+        luat_drv_wlan_scan();
+        return 0;
+    }
+    #endif
     #endif
+    luat_wlan_scan();
     return 0;
 }
 

+ 4 - 0
components/ymodem/luat_ymodem.c

@@ -270,6 +270,10 @@ int luat_ymodem_receive(void *handler, uint8_t *data, uint32_t len, uint8_t *ack
 				goto DATA_RECIEVE_ERROR;
 				break;
 			}
+			if (len > (XMODEM_STX_DATA_LEN + 8))	//防止溢出死机
+			{
+				len = XMODEM_STX_DATA_LEN + 8;
+			}
 			memcpy(ctrl->packet_data, data, len);
 			ctrl->data_pos += len;
 			if (len >= ctrl->data_max) goto YMODEM_DATA_CHECK;

BIN
luat/demo/airlink/air8000_airlink_fota/air8000s_v10.bin


+ 2 - 2
luat/demo/airlink/air8000_airlink_fota/main.lua

@@ -1,7 +1,7 @@
 
 -- LuaTools需要PROJECT和VERSION这两个信息
 PROJECT = "wififota"
-VERSION = "1.0.9"
+VERSION = "1.0.10"
 
 -- sys库是标配
 _G.sys = require("sys")
@@ -24,7 +24,7 @@ end, gpio.PULLDOWN)
 sys.taskInit(function()
     sys.wait(1000)
     airlink.debug(1)
-    airlink.sfota("/luadb/air8000s_v9.bin")
+    airlink.sfota("/luadb/air8000s_v10.bin")
 end)
 
 

+ 16 - 1
luat/demo/airlink/air8000_ble/peripheral/main.lua

@@ -48,7 +48,7 @@ local function ble_callback(dev, evt, param)
         sys.timerStart(function() dev:adv_start() end, 1000)
     elseif evt == ble.EVENT_WRITE_REQ then
         -- 收到写请求
-        log.info("ble", "接收到写请求", param.uuid_service:toHex(), param.data:toHex(),param.uuid_characteristic:toHex())
+        log.info("ble", "接收到写请求", param.uuid_service:toHex(), param.uuid_characteristic:toHex(), param.data:toHex())
     end
 end
 
@@ -91,6 +91,15 @@ sys.taskInit(function()
     log.info("开始广播")
     ble_device:adv_start()
 
+        
+    -- 放入预设值, 注意是有READ属性的特性才能读取
+    -- 手机APP设置MTU到256
+    local wt = {
+        uuid_service = string.fromHex("FA00"),
+        uuid_characteristic = string.fromHex("EA01"), 
+    }
+    ble_device:write_value(wt, "12345678901234567890")
+
     while 1 do
         sys.wait(3000)
         if ble_stat then
@@ -103,6 +112,12 @@ sys.taskInit(function()
         else
             -- log.info("等待连接成功之后发送数据")
         end
+        
+        local wt = {
+            uuid_service = string.fromHex("FA00"),
+            uuid_characteristic = string.fromHex("EA03"), 
+        }
+        ble_device:write_value(wt, "8888 123454")
     end
 end)
 

+ 23 - 23
luat/demo/airlink/for_ccc/main.lua

@@ -25,6 +25,8 @@ uart.setup(
     1--停止位
 )
 
+-- gpio.setup(140, 1, gpio.PULLUP)
+
 local topic_uart_receive = "air8000_uart1_receive"
 
 -- --循环发数据
@@ -60,7 +62,7 @@ sys.taskInit(function()
     while 1 do
         local ret, data = sys.waitUntil(topic_uart_receive)
         if ret then
-            if data:sub(1,11) == "AT+WIFI_OFF" then--关闭wifi------------
+            if data:sub(1,10) == "AT+WIFIOFF" then--关闭wifi------------
                 local result = airlink.power(false)
                 log.info("关闭wifi")
                 if not result then
@@ -68,7 +70,7 @@ sys.taskInit(function()
                 else
                     uart.write(uartid, "ERROR\r\n")
                 end
-            elseif data:sub(1,10) == "AT+WIFI_ON" then--开启wifi
+            elseif data:sub(1,9) == "AT+WIFION" then--开启wifi
                 airlink.power(true)
                 while airlink.ready() ~= true do
                     sys.wait(100)
@@ -80,7 +82,7 @@ sys.taskInit(function()
                 else
                     uart.write(uartid, "ERROR\r\n")--------------
                 end
-            elseif data:sub(1,12) == "AT+WIFI_SCAN" then--wifi扫描---------------
+            elseif data:sub(1,11) == "AT+WIFISCAN" then--wifi扫描---------------
                 while airlink.ready() ~= true do
                     sys.wait(100)
                 end
@@ -89,36 +91,34 @@ sys.taskInit(function()
                 log.info("扫描wifi")
                 sys.waitUntil("WLAN_SCAN_DONE", 5000)
                 local results = wlan.scanResult()
-                for k,v in pairs(results) do
-                    uart.write(uartid, string.format("+WIFISCAN: %s,%s,%s\r\n",
-                                    v["bssid"]:toHex(), v["rssi"], v["channel"]))
-                end
                 if results then
                     uart.write(uartid, "OK\r\n")
                 else
                     uart.write(uartid, "ERROR\r\n")
                 end
-            elseif data:sub(1,16) == "AT+WIFI_CONNECT=" then -- 连接指定ssid/passwd--------
+            elseif data:sub(1,8) == "AT+WIFI=" then -- 连接指定ssid/passwd--------
                 wlan.init()
 
-                local SSID = data:sub(17,data:find(",")-1)
+                local SSID = data:sub(9,data:find(",")-1)
                 local PWD = data:sub(data:find(",")+1,data:find('\r')-1)
 
                 log.info("SSID", SSID,"PWD", PWD)
-                wlan.connect(SSID, PWD)
-                sys.wait(8000)
-                iperf.server(socket.LWIP_STA)
-                sys.wait(5000)
-                log.info("连接指定wifi")
-                local code, headers, body = http.request("GET", "https://httpbin.air32.cn/get", nil, nil, {adapter=socket.LWIP_STA}).wait()
-                log.info("http", code, headers, body and #body)
-                if code == 200 then
-                    uart.write(uartid, "OK\r\n")
-                else
+                local result = wlan.connect(SSID, PWD)
+                log.info("连接指定wifi",result)
+
+                local result, ip, adapter = sys.waitUntil("IP_READY",5000)
+                log.info("ready?", result, ip, adapter)
+
+                if not result then
                     uart.write(uartid, "ERROR\r\n")
+                else
+                    -- netdrv.ipv4(socket.LWIP_STA)
+                    log.info("IP地址", netdrv.ipv4(socket.LWIP_STA))
+
+                    uart.write(uartid, "OK\r\n")
                 end
 
-            elseif data:sub(1,11) == "AT+BLE_Init" then--初始化蓝牙
+            elseif data:sub(1,10) == "AT+BLEINIT" then--初始化蓝牙
                 bluetooth_device = bluetooth.init()
                 ble_device = bluetooth_device:ble(ble_callback)
                 log.info("初始化蓝牙")
@@ -127,7 +127,7 @@ sys.taskInit(function()
                 else
                     uart.write(uartid, "ERROR\r\n")
                 end
-            elseif data:sub(1,11) == "AT+BLE_Scan" then--蓝牙扫描
+            elseif data:sub(1,10) == "AT+BLESCAN" then--蓝牙扫描
 
                 -- 扫描模式
                 sys.wait(1000)
@@ -146,8 +146,8 @@ sys.taskInit(function()
                     uart.write(uartid, "ERROR\r\n")
                 end
 
-            elseif data:sub(1,11) == "AT+ResetAll" then--整体复位
-                uart.write(uartid, "Reset all\r\n")
+            elseif data:sub(1,11) == "AT+RESETALL" then--整体复位
+                uart.write(uartid, "OK\r\n")
                 sys.wait(500)
                 rtos.reboot()
 

+ 1 - 0
luat/include/luat_log.h

@@ -4,6 +4,7 @@
 #define LUAT_LOG_H
 
 #include "luat_base.h"
+
 #define LUAT_LOG_DEBUG 1
 #define LUAT_LOG_INFO  2
 #define LUAT_LOG_WARN  3

+ 5 - 1
luat/include/luat_mcu.h

@@ -52,7 +52,11 @@ uint8_t luat_mcu_iomux_is_default(uint8_t type, uint8_t sn);
  */
 void luat_mcu_iomux_ctrl(uint8_t type, uint8_t sn, int pad_index, uint8_t alt, uint8_t is_input);
 
-
+/**
+ * @brief 死机后处理模式
+ * @param mode 0死机后停机 1死机后立刻重启 2死机后尽量将错误信息提交给外部工具后重启
+ * @return 无
+ */
 void luat_mcu_set_hardfault_mode(int mode);
 /**
  * @brief 外部晶振参考信号输出

+ 2 - 0
luat/include/luat_pm.h

@@ -47,6 +47,8 @@ enum
 	LUAT_PM_POWER_POWERKEY_MODE,
 	LUAT_PM_POWER_WORK_MODE,
 	LUAT_PM_POWER_LDO_CTL_PIN,
+	LUAT_PM_POWER_WIFI_STA_DTIM,
+	LUAT_PM_POWER_WIFI_AP_DTIM,
 };
 
 // 电平类

+ 1 - 0
luat/include/luat_rtos_legacy.h

@@ -40,6 +40,7 @@ void luat_mutex_release(void *mutex);
 /* ----------------------------------- timer ----------------------------------- */
 void *luat_create_rtos_timer(void *cb, void *param, void *task_handle);
 int luat_start_rtos_timer(void *timer, uint32_t ms, uint8_t is_repeat);
+int luat_start_rtos_timer_v2(void *timer, uint64_t tick, uint8_t is_repeat, uint8_t is_cb_in_irq);
 int luat_start_rtos_timer_us(void *timer, uint32_t us);
 void luat_stop_rtos_timer(void *timer);
 void luat_release_rtos_timer(void *timer);

+ 4 - 0
luat/modules/luat_lib_pm.c

@@ -494,6 +494,10 @@ static const rotable_Reg_t reg_pm[] =
     //@const ID_WIFI number PM控制的ID, WIFI芯片, 仅Air8000可用
     { "ID_WIFI",        ROREG_INT(1)},
 
+    //@const WIFI_STA_DTIM number wifi芯片控制STA模式下的DTIM间隔,单位100ms,默认值是1
+    { "WIFI_STA_DTIM",  ROREG_INT(LUAT_PM_POWER_WIFI_STA_DTIM)},
+    { "WIFI_AP_DTIM",   ROREG_INT(LUAT_PM_POWER_WIFI_AP_DTIM)},
+
 	{ NULL,             ROREG_INT(0) }
 };
 

+ 15 - 13
module/Air780EHV/DEMO/CC/main.lua

@@ -3,19 +3,24 @@
 PROJECT = "ccdemo"
 VERSION = "1.0.0"
 log.style(1)
---[[
-    本demo暂时只在air780ep测试过
-    本demo需要外挂ES8311 codec芯片
+--[[]
+运行环境:Air780EHV核心板+AirAUDIO_1000配件板
+最后修改时间:2025-6-17
+使用了如下IO口:
+[3, "MIC+", " PIN3脚, 用于麦克风正极"],
+[4, "MIC-", " PIN4脚, 用于麦克风负极"],
+[5, "spk+", " PIN5脚, 用于喇叭正极"],
+[6, "spk-", " PIN6脚, 用于喇叭负极"],
+[20, "AudioPA_EN", " PIN20脚, 用于PA使能脚"],
+3.3V
+GND
+执行逻辑为:
+设置i2s和音频参数,读取文件qianzw.txt里面的内容,然后播放出来
 ]]
 
 -- sys库是标配
 sys = require("sys")
 
-if wdt then
-    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
-    --wdt.init(9000)--初始化watchdog设置为9s
-    --sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
-end
 local up1 = zbuff.create(6400,0)
 local up2 = zbuff.create(6400,0)
 local down1 = zbuff.create(6400,0)
@@ -55,7 +60,7 @@ sys.taskInit(function()
     local multimedia_id = 0
  local i2c_id = 0 -- i2c_id 0
 
-    local pa_pin = 28 -- 喇叭pa功放脚
+    local pa_pin = gpio.AUDIOPA_EN -- 喇叭pa功放脚
     local power_pin = 20 -- es8311电源脚
 
     local i2s_id = 0 -- i2s_id 0
@@ -78,9 +83,6 @@ sys.taskInit(function()
     gpio.setup(power_pin, 1, gpio.PULLUP)
     gpio.setup(pa_pin, 1, gpio.PULLUP)
 
-    pins.setup(58, "I2C0_SDA")
-    pins.setup(57, "I2C0_SCL")
-
     sys.wait(200)
 
 
@@ -103,7 +105,7 @@ sys.taskInit(function()
     sys.waitUntil("CC_READY")
     log.info("一切就绪,5S后准备打电话")
     sys.wait(5000)   
-    cc.dial(0,"15821341112") --拨打电话
+    -- cc.dial(0,"12345678910) --拨打电话
 
 
 

+ 90 - 52
module/Air780EHV/DEMO/audio/main.lua

@@ -1,4 +1,3 @@
-
 -- LuaTools需要PROJECT和VERSION这两个信息
 PROJECT = "audio"
 VERSION = "1.0.0"
@@ -9,7 +8,7 @@ VERSION = "1.0.0"
 使用了如下IO口:
 [5, "spk+", " PIN5脚, 用于喇叭正极"],
 [6, "spk-", " PIN6脚, 用于喇叭负极"],
-[78, "gpio28", " PIN78脚, 用于PA使能脚"],
+[20, "AudioPA_EN", " PIN20脚, 用于PA使能脚"],
 3.3V
 GND
 SD卡的使用IO口:
@@ -26,14 +25,19 @@ GND
 3、通过HTTP下载到文件区,播放文件区中的文件
 4、通过HTTP下载到内存里面,播放内存中的文件
 ]]
-
 -- sys库是标配
 _G.sys = require("sys")
 _G.sysplus = require("sysplus")
 
+--目前代码里面提供了4种播放方式,对应mode的值,默认是1
+--1:播放脚本区的文件
+--2:挂载SD卡,通过HTTP下载到SD卡,播放SD卡中的文件
+--3:通过HTTP下载到文件区,播放文件区中的文件
+--4:通过HTTP下载到内存里面,播放内存中的文件
+local mode = 1
 local i2c_id = 0 -- i2c_id 0
 
-local pa_pin = 28 -- 喇叭pa功放脚
+local pa_pin = gpio.AUDIOPA_EN -- 喇叭pa功放脚
 local power_pin = 20 -- es8311电源脚
 
 local i2s_id = 0 -- i2s_id 0
@@ -54,24 +58,34 @@ local power_time_delay = 100 -- 音频播放完毕时,PA与DAC关闭的时间
 local voice_vol = 50 -- 喇叭音量
 local mic_vol = 80 -- 麦克风音量
 
-gpio.setup(power_pin, 1, gpio.PULLUP)   -- 设置功放电源脚
-gpio.setup(pa_pin, 1, gpio.PULLUP)      -- 设置功放PA脚
+gpio.setup(power_pin, 1, gpio.PULLUP) -- 设置ES83111电源脚
+gpio.setup(pa_pin, 1, gpio.PULLUP) -- 设置功放PA脚
 
 function audio_setup()
     log.info("audio_setup")
     sys.wait(200)
 
     i2c.setup(i2c_id, i2c.FAST)
-    i2s.setup(i2s_id, i2s_mode, i2s_sample_rate, i2s_bits_per_sample, i2s_channel_format, i2s_communication_format,
-        i2s_channel_bits)
+    i2s.setup(
+        i2s_id,
+        i2s_mode,
+        i2s_sample_rate,
+        i2s_bits_per_sample,
+        i2s_channel_format,
+        i2s_communication_format,
+        i2s_channel_bits
+    )
 
     audio.config(multimedia_id, pa_pin, pa_on_level, power_delay, pa_delay, power_pin, power_on_level, power_time_delay)
-    audio.setBus(multimedia_id, audio.BUS_I2S, {
-        chip = "es8311",
-        i2cid = i2c_id,
-        i2sid = i2s_id
-    }) -- 通道0的硬件输出通道设置为I2S
-
+    audio.setBus(
+        multimedia_id,
+        audio.BUS_I2S,
+        {
+            chip = "es8311",
+            i2cid = i2c_id,
+            i2sid = i2s_id
+        }
+    ) -- 通道0的硬件输出通道设置为I2S
     audio.vol(multimedia_id, voice_vol)
     audio.micVol(multimedia_id, mic_vol)
     sys.publish("AUDIO_READY")
@@ -85,48 +99,69 @@ local taskName = "task_audio"
 local MSG_MD = "moreData" -- 播放缓存有空余
 local MSG_PD = "playDone" -- 播放完成所有数据
 
-audio.on(0, function(id, event)
-    -- 使用play来播放文件时只有播放完成回调
-    local succ, stop, file_cnt = audio.getError(0)
-    if not succ then
-        if stop then
-            log.info("用户停止播放")
-        else
-            log.info("第", file_cnt, "个文件解码失败")
+audio.on(0,function(id, event)
+        -- 使用play来播放文件时只有播放完成回调
+        local succ, stop, file_cnt = audio.getError(0)
+        if not succ then
+            if stop then
+                log.info("用户停止播放")
+            else
+                log.info("第", file_cnt, "个文件解码失败")
+            end
         end
+        sysplus.sendMsg(taskName, MSG_PD)
     end
-    sysplus.sendMsg(taskName, MSG_PD)
-end)
+)
 
 local function audio_task()
-    local result    
+    local result
     sys.waitUntil("AUDIO_READY")
-    --以下内容为SD卡挂载的方式,如果有需要用到SD卡可以打开下面的挂载流程
-    -- -- 此为spi方式
-    -- local spi_id, pin_cs=0,8
-    -- -- 仅SPI方式需要自行初始化spi, sdio不需要
-    -- spi.setup(spi_id, nil, 0, 0, pin_cs, 400 * 1000)
-    -- gpio.setup(pin_cs, 1)
-    -- fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000)
-    -- -- 等待IP准备好,此段内容为通过http下载播放文件
-    -- local result=sys.waitUntil("IP_READY",15000)
-    -- if result then
-    --     local code, headers, body = http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3",nil,nil,{dst="/1.mp3"}).wait()--存到本地文件区,适用于多次播放
-    --     -- local code, headers, body = http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3",nil,nil,{dst="/ram/1.mp3"}).wait()--存到内存里面,适用于下载播放一次,然后不需要再次播放或者不重启的时候可以继续播放,重启后需要重新下载
-    --     -- local code, headers, body = http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3",nil,nil,{dst="/sd/1.mp3"}).wait()--存到sd卡里面
-    --     log.info("下载完成", code, headers, body)
-    -- end
+    result = sys.waitUntil("IP_READY", 15000)
+    if result then
+        if mode == 1 then
+        elseif mode == 2 then
+            --以下内容为SD卡挂载的方式,如果有需要用到SD卡可以打开下面的挂载流程
+            -- -- 此为spi方式
+            local spi_id, pin_cs = 0, 8
+            -- 仅SPI方式需要自行初始化spi, sdio不需要
+            spi.setup(spi_id, nil, 0, 0, pin_cs, 400 * 1000)
+            gpio.setup(pin_cs, 1)
+            fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000)
+            local code, headers, body =
+                http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3", nil, nil, {dst = "/sd/1.mp3"}).wait()
+            --存到sd卡里面
+            log.info("下载完成", code, headers, body)
+        elseif mode == 3 then
+            local code, headers, body =
+                http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3", nil, nil, {dst = "/1.mp3"}).wait()
+            --存到本地文件区,适用于多次播放
+            log.info("下载完成", code, headers, body)
+        elseif mode == 4 then
+            local code, headers, body =
+                http.request("GET", "http://airtest.openluat.com:2900/download/1.mp3", nil, nil, {dst = "/ram/1.mp3"}).wait()
+            --存到内存里面,适用于下载播放一次,然后不需要再次播放或者不重启的时候可以继续播放,重启后需要重新下载
+            log.info("下载完成", code, headers, body)
+        end
+    end
+
     while true do
         log.info("开始播放")
-        -- result = audio.play(0,"/1.mp3") --播放HTTP下载的文件
-        -- result = audio.play(0,"/ram/1.mp3") --播放HTTP下载到内存的文件
-        result = audio.play(0,"/luadb/1.mp3") -- 播放本地脚本区文件
-        -- result = audio.play(0,"/sd/1.mp3") -- 播放sd卡里面文件
         if result then
-        --等待音频通道的回调消息,或者切换歌曲的消息
+            if mode == 1 then
+                result = audio.play(0, "/luadb/1.mp3") -- 播放本地脚本区文件
+            elseif mode == 2 then
+                result = audio.play(0, "/sd/1.mp3") -- 播放sd卡里面文件
+            elseif mode == 3 then
+                result = audio.play(0, "/1.mp3") --播放HTTP下载的文件
+            elseif mode == 4 then
+                result = audio.play(0, "/ram/1.mp3") --播放HTTP下载到内存的文件
+            end
+        end
+        if result then
+            --等待音频通道的回调消息,或者切换歌曲的消息
             while true do
                 msg = sysplus.waitMsg(taskName, nil)
-                if type(msg) == 'table' then
+                if type(msg) == "table" then
                     if msg[1] == MSG_PD then
                         log.info("播放结束")
                         break
@@ -144,19 +179,22 @@ local function audio_task()
             audio.playStop(0)
         end
         if audio.pm then
-		    audio.pm(0,audio.STANDBY)       --PM模式 待机模式,PA断电,codec待机状态,系统不能进低功耗状态,如果PA不可控,codec进入静音模式
+            audio.pm(0, audio.STANDBY) --PM模式 待机模式,PA断电,codec待机状态,系统不能进低功耗状态,如果PA不可控,codec进入静音模式
         end
-		-- audio.pm(0,audio.SHUTDOWN)	--低功耗可以选择SHUTDOWN或者POWEROFF,如果codec无法断电用SHUTDOWN
+        -- audio.pm(0,audio.SHUTDOWN)	--低功耗可以选择SHUTDOWN或者POWEROFF,如果codec无法断电用SHUTDOWN
         log.info("mem", "sys", rtos.meminfo("sys"))
         log.info("mem", "lua", rtos.meminfo("lua"))
         sys.wait(1000)
     end
 end
 
-sys.timerLoopStart(function()
-    log.info("mem.lua", rtos.meminfo())
-    log.info("mem.sys", rtos.meminfo("sys"))
- end, 3000)
+sys.timerLoopStart(
+    function()
+        log.info("mem.lua", rtos.meminfo())
+        log.info("mem.sys", rtos.meminfo("sys"))
+    end,
+    3000
+)
 
 sysplus.taskInitEx(audio_task, taskName)
 

+ 107 - 85
module/Air780EHV/DEMO/record/main.lua

@@ -2,10 +2,31 @@
 PROJECT = "record"
 VERSION = "1.0.0"
 
+--[[]
+运行环境:Air780EHV核心板+AirAUDIO_1000配件板
+最后修改时间:2025-6-17
+使用了如下IO口:
+[3, "MIC+", " PIN3脚, 用于麦克风正极"],
+[4, "MIC-", " PIN4脚, 用于麦克风负极"],
+[5, "spk+", " PIN5脚, 用于喇叭正极"],
+[6, "spk-", " PIN6脚, 用于喇叭负极"],
+[20, "AudioPA_EN", " PIN20脚, 用于PA使能脚"],
+3.3V
+GND
+执行逻辑为:
+设置i2s和音频参数,提供了两种录音方式,录音到文件区或者录音到内存,然后播放,然后
+]]
 -- sys库是标配
 _G.sys = require("sys")
 _G.sysplus = require("sysplus")
-
+--代码提供了2种方式录音,对应recordmode的值
+--1:直接录音到文件
+--2:录音到内存,然后保存到文件
+local recordmode = 1
+--代码提供了2种方式对录音文件做处理
+--1:发送到服务器
+--2:发送到串口
+local recordhandle = 1
 local taskName = "task_audio"
 
 local MSG_MD = "moreData" -- 播放缓存有空余
@@ -17,32 +38,32 @@ amr_buff = zbuff.create(20 * 1024)
 encoder = nil
 pcm_buff0 = zbuff.create(16000)
 pcm_buff1 = zbuff.create(16000)
-audio.on(0, function(id, event, point)
-    -- 使用play来播放文件时只有播放完成回调
-    if event == audio.RECORD_DATA then -- 录音数据
-        if point == 0 then
-            log.info("buff", point, pcm_buff0:used())
-            codec.encode(encoder, pcm_buff0, amr_buff)
-        else
-            log.info("buff", point, pcm_buff1:used())
-            codec.encode(encoder, pcm_buff1, amr_buff)
-        end
-
-    elseif event == audio.RECORD_DONE then -- 录音完成
-        sys.publish("AUDIO_RECORD_DONE")
-    else
-        local succ, stop, file_cnt = audio.getError(0)
-        if not succ then
-            if stop then
-                log.info("用户停止播放")
+audio.on(0,function(id, event, point)
+        -- 使用play来播放文件时只有播放完成回调
+        if event == audio.RECORD_DATA then -- 录音数据
+            if point == 0 then
+                log.info("buff", point, pcm_buff0:used())
+                codec.encode(encoder, pcm_buff0, amr_buff)
             else
-                log.info("第", file_cnt, "个文件解码失败")
+                log.info("buff", point, pcm_buff1:used())
+                codec.encode(encoder, pcm_buff1, amr_buff)
             end
+        elseif event == audio.RECORD_DONE then -- 录音完成
+            sys.publish("AUDIO_RECORD_DONE")
+        else
+            local succ, stop, file_cnt = audio.getError(0)
+            if not succ then
+                if stop then
+                    log.info("用户停止播放")
+                else
+                    log.info("第", file_cnt, "个文件解码失败")
+                end
+            end
+            -- log.info("播放完成一个音频")
+            sysplus.sendMsg(taskName, MSG_PD)
         end
-        -- log.info("播放完成一个音频")
-        sysplus.sendMsg(taskName, MSG_PD)
     end
-end)
+)
 
 ---- MultipartForm上传文件
 -- url string 请求URL地址
@@ -54,8 +75,10 @@ local function postMultipartFormData(url, filename, filePath)
         ["Content-Type"] = "multipart/form-data; boundary=" .. boundary
     }
     local body = {}
-    table.insert(body,
-        "--" .. boundary .. "\r\nContent-Disposition: form-data; name=\"file\"; filename=\"" .. filename .. "\"\r\n\r\n")
+    table.insert(
+        body,
+        "--" .. boundary .. '\r\nContent-Disposition: form-data; name="file"; filename="' .. filename .. '"\r\n\r\n'
+    )
     table.insert(body, io.readFile(filePath))
     table.insert(body, "\r\n")
     table.insert(body, "--" .. boundary .. "--\r\n")
@@ -69,7 +92,7 @@ end
 function audio_setup()
     local i2c_id = 0 -- i2c_id 0
 
-    local pa_pin = 28 -- 喇叭pa功放脚
+    local pa_pin = gpio.AUDIOPA_EN -- 喇叭pa功放脚
     local power_pin = 20 -- es8311电源脚
 
     local i2s_id = 0 -- i2s_id 0
@@ -87,27 +110,35 @@ function audio_setup()
     local power_on_level = 1 -- 电源控制IO的电平,默认拉高
     local power_time_delay = 100 -- 音频播放完毕时,PA与DAC关闭的时间间隔,单位1ms
 
-    local voice_vol = 70 -- 喇叭音量
+    local voice_vol = 80 -- 喇叭音量
     local mic_vol = 80 -- 麦克风音量
-    gpio.setup(power_pin, 1, gpio.PULLUP)
-    gpio.setup(pa_pin, 1, gpio.PULLUP)
 
-    pins.setup(58, "I2C0_SDA")
-    pins.setup(57, "I2C0_SCL")
+    gpio.setup(power_pin, 1, gpio.PULLUP) -- 设置ES83111电源脚
+    gpio.setup(pa_pin, 1, gpio.PULLUP) -- 设置功放PA脚
 
     sys.wait(200)
 
-
     i2c.setup(i2c_id, i2c.FAST) -- 设置i2c
-    i2s.setup(i2s_id, i2s_mode, i2s_sample_rate, i2s_bits_per_sample, i2s_channel_format, i2s_communication_format,
-        i2s_channel_bits) -- 设置i2s
+    i2s.setup(
+        i2s_id,
+        i2s_mode,
+        i2s_sample_rate,
+        i2s_bits_per_sample,
+        i2s_channel_format,
+        i2s_communication_format,
+        i2s_channel_bits
+    ) -- 设置i2s
 
     audio.config(multimedia_id, pa_pin, pa_on_level, power_delay, pa_delay, power_pin, power_on_level, power_time_delay)
-    audio.setBus(multimedia_id, audio.BUS_I2S, {
-        chip = "es8311",
-        i2cid = i2c_id,
-        i2sid = i2s_id,
-    }) -- 通道0的硬件输出通道设置为I2S
+    audio.setBus(
+        multimedia_id,
+        audio.BUS_I2S,
+        {
+            chip = "es8311",
+            i2cid = i2c_id,
+            i2sid = i2s_id
+        }
+    ) -- 通道0的硬件输出通道设置为I2S
 
     audio.vol(multimedia_id, voice_vol)
     audio.micVol(multimedia_id, mic_vol)
@@ -124,48 +155,30 @@ local function audio_task()
 
     -- 下面为录音demo,根据适配情况选择性开启
     local recordPath = "/record.amr"
-
-    -- -- 直接录音到文件
-    -- err = audio.record(0, audio.AMR, 5, 7, recordPath)
-    -- sys.waitUntil("AUDIO_RECORD_DONE")
-    -- log.info("record","录音结束")
-    -- result = audio.play(0, {recordPath})
-    -- if result then
-    --     --等待音频通道的回调消息,或者切换歌曲的消息
-    --     while true do
-    --         msg = sysplus.waitMsg(taskName, nil)
-    --         if type(msg) == 'table' then
-    --             if msg[1] == MSG_PD then
-    --                 log.info("播放结束")
-    --                 break
-    --             end
-    --         else
-    --             log.error(type(msg), msg)
-    --         end
-    --     end
-    -- else
-    --     log.debug("解码失败!")
-    --     sys.wait(1000)
-    -- end
-
-    -- -- 录音到内存自行编码
-
-    encoder = codec.create(codec.AMR, false, 7)
-    log.info("encoder", encoder)
-    log.info("开始录音")
-    err = audio.record(0, audio.AMR, 5, 7, nil, nil, pcm_buff0, pcm_buff1)
-    sys.waitUntil("AUDIO_RECORD_DONE")
-    log.info("record", "录音结束")
-    os.remove(recordPath)
-    io.writeFile(recordPath, "#!AMR\n")
-    io.writeFile(recordPath, amr_buff:query(), "a+b")
+    if recordmode == 1 then
+        -- -- 直接录音到文件
+        err = audio.record(0, audio.AMR, 5, 7, recordPath)
+        sys.waitUntil("AUDIO_RECORD_DONE")
+        log.info("record", "录音结束")
+    elseif recordmode == 2 then
+        -- 录音到内存自行编码
+        encoder = codec.create(codec.AMR, false, 7)
+        log.info("encoder", encoder)
+        log.info("开始录音")
+        err = audio.record(0, audio.AMR, 5, 7, nil, nil, pcm_buff0, pcm_buff1)
+        sys.waitUntil("AUDIO_RECORD_DONE")
+        log.info("record", "录音结束")
+        os.remove(recordPath)
+        io.writeFile(recordPath, "#!AMR\n")
+        io.writeFile(recordPath, amr_buff:query(), "a+b")
+    end
 
     result = audio.play(0, {recordPath})
     if result then
         -- 等待音频通道的回调消息,或者切换歌曲的消息
         while true do
             msg = sysplus.waitMsg(taskName, nil)
-            if type(msg) == 'table' then
+            if type(msg) == "table" then
                 if msg[1] == MSG_PD then
                     log.info("播放结束")
                     break
@@ -180,16 +193,25 @@ local function audio_task()
     end
 
     -- 下面的演示是将音频文件发送到服务器上,如有需要,可以将下面代码注释打开,这里的url是合宙的文件上传测试服务器,上传的文件到http://tools.openluat.com/tools/device-upload-test查看
-    --[[ 
-		local timeTable = os.date("*t", os.time())
-		local nowTime = string.format("%4d%02d%02d_%02d%02d%02d", timeTable.year, timeTable.month, timeTable.day, timeTable.hour, timeTable.min, timeTable.sec)
-		local filename = mobile.imei() .. "_" .. nowTime .. ".amr"
-		postMultipartFormData("http://tools.openluat.com/api/site/device_upload_file", filename, recordPath)
- 	]]
-    -- 该方法为从串口1,把录音数据传给串口1
-    --  uart.setup(1, 115200)								-- 开启串口1
-    --  uart.write(1, io.readFile(recordPath))				-- 向串口发送录音文件
-
+    if recordhandle == 1 then
+        local timeTable = os.date("*t", os.time())
+        local nowTime =
+            string.format(
+            "%4d%02d%02d_%02d%02d%02d",
+            timeTable.year,
+            timeTable.month,
+            timeTable.day,
+            timeTable.hour,
+            timeTable.min,
+            timeTable.sec
+        )
+        local filename = mobile.imei() .. "_" .. nowTime .. ".amr"
+        postMultipartFormData("http://tools.openluat.com/api/site/device_upload_file", filename, recordPath)
+    elseif recordhandle == 2 then
+        -- 该方法为从串口1,把录音数据传给串口1
+        uart.setup(1, 115200) -- 开启串口1
+        uart.write(1, io.readFile(recordPath)) -- 向串口发送录音文件
+    end
 end
 
 sysplus.taskInitEx(audio_task, taskName)

+ 4 - 4
module/Air780EHV/DEMO/tts/main.lua

@@ -8,7 +8,7 @@ VERSION = "1.0.0"
 使用了如下IO口:
 [5, "spk+", " PIN5脚, 用于喇叭正极"],
 [6, "spk-", " PIN6脚, 用于喇叭负极"],
-[78, "gpio28", " PIN78脚, 用于PA使能脚"],
+[20, "AudioPA_EN", " PIN20脚, 用于PA使能脚"],
 3.3V
 GND
 执行逻辑为:
@@ -23,7 +23,7 @@ _G.sysplus = require("sysplus")
 
 local i2c_id = 0 -- i2c_id 0
 
-local pa_pin = 28 -- 喇叭pa功放脚
+local pa_pin = gpio.AUDIOPA_EN -- 喇叭pa功放脚
 local power_pin = 20 -- es8311电源脚
 
 local i2s_id = 0 -- i2s_id 0
@@ -44,7 +44,7 @@ local power_time_delay = 100 -- 音频播放完毕时,PA与DAC关闭的时间
 local voice_vol = 50 -- 喇叭音量
 local mic_vol = 80 -- 麦克风音量
 
-gpio.setup(power_pin, 1, gpio.PULLUP)   -- 设置功放电源脚
+gpio.setup(power_pin, 1, gpio.PULLUP)   -- 设置ES83111电源脚
 gpio.setup(pa_pin, 1, gpio.PULLUP)      -- 设置功放PA脚
 
 function audio_setup()
@@ -108,7 +108,7 @@ local function audio_task()
                 fd = nil
             end
         end
-        if line == nil then
+        if line == nil then --如果没有找到千字文,播放以下文本
             line =
                 "一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十"
         end

BIN
module/Air8000/core/LuatOS-SoC_V2008_Air8000_FS_0623.soc


BIN
module/Air8000/core/LuatOS-SoC_V2008_Air8000_LVGL_0623.soc


BIN
module/Air8000/core/LuatOS-SoC_V2008_Air8000_VOLTE_0623.soc


+ 7 - 0
module/Air8000/core/changeLog.md

@@ -1,5 +1,12 @@
 # Air8000模块固件更新 --- 修改记录
 
+## 2025.06.23
+
+1. VOLTE固件 修复接收短信死机和电信卡只能接收一条短信的问题。
+2. 修复无法控制GPIO141。
+
+
+
 ## 2025.06.21
 
 1. 目前可支持ble低功耗蓝牙广播、从机模式、扫描蓝牙功能。(当前的蓝牙api功能仍处于调试阶段,后续可能还会对api做改动)

+ 0 - 0
module/Air8000/core/LuatOS-SoC_V2007_Air8000_VOLTE_0610.soc → module/Air8000/core/old_core/LuatOS-SoC_V2007_Air8000_VOLTE_0610.soc


+ 0 - 0
module/Air8000/core/LuatOS-SoC_V2008_Air8000_FS_0621.soc → module/Air8000/core/old_core/LuatOS-SoC_V2008_Air8000_FS_0621.soc


+ 0 - 0
module/Air8000/core/LuatOS-SoC_V2008_Air8000_LVGL_0621.soc → module/Air8000/core/old_core/LuatOS-SoC_V2008_Air8000_LVGL_0621.soc


+ 13 - 12
module/Air8000/demo/can/main.lua

@@ -2,12 +2,12 @@ PROJECT = "candemo"
 VERSION = "1.0.0"
 sys = require("sys")
 log.style(1)
-local SELF_TEST_FLAG = false --自测模式标识,写true就进行自收自发模式,写false就进行正常收发模式
-local node_a = false   -- A节点写true, B节点写false
+local SELF_TEST_FLAG = true --自测模式标识,写true就进行自收自发模式,写false就进行正常收发模式
+local node_a = true   -- A节点写true, B节点写false
 local can_id = 0
 local rx_id
 local tx_id
-local stb_pin = 27		-- stb引脚根据实际情况写,不用的话,也可以不写
+local stb_pin = 28		-- stb引脚根据实际情况写,不用的话,也可以不写
 if node_a then          -- A/B节点区分,互相传输测试
     rx_id = 0x12345678
     tx_id = 0x12345677
@@ -16,7 +16,7 @@ else
     tx_id = 0x12345678
 end
 local test_cnt = 0
-local tx_buf = zbuff.create(8)  --创建zbuff
+local tx_buf = zbuff.create(8)
 local function can_cb(id, cb_type, param)
     if cb_type == can.CB_MSG then
         log.info("有新的消息")
@@ -51,17 +51,17 @@ local function can_tx_test(data)
 	if test_cnt > 8 then
 		test_cnt = 1
 	end
-	tx_buf:set(0,test_cnt)  --zbuff的类似于memset操作,类似于memset(&buff[start], num, len)
-	tx_buf:seek(test_cnt)   --zbuff设置光标位置(可能与当前指针位置有关;执行后指针会被设置到指定位置)
+	tx_buf:set(0,test_cnt)
+	tx_buf:seek(test_cnt)
     can.tx(can_id, tx_id, can.EXT, false, true, tx_buf)
 end
 -- can.debug(true)
-gpio.setup(stb_pin,0)   -- 配置STB引脚为输出低电平
+gpio.setup(stb_pin,0)
 -- gpio.setup(stb_pin,1)	-- 如果开发板上STB信号有逻辑取反,则要配置成输出高电平
-
-can.init(can_id, 128)            -- 初始化CAN,参数为CAN ID,接收缓存消息数的最大值
-can.on(can_id, can_cb)            -- 注册CAN的回调函数
-can.timing(can_id, 1000000, 5, 4, 3, 2)     --CAN总线配置时序
+can.init(can_id, 128)
+can.on(can_id, can_cb)
+can.timing(can_id, 1000000, 6, 6, 4, 2)
+-- can.timing(can_id, 100000, 6, 6, 3, 2)
 if SELF_TEST_FLAG then
 	can.node(can_id, tx_id, can.EXT)	-- 测试模式下,允许接收的ID和发送ID一致才会有新数据提醒
 	can.mode(can_id, can.MODE_TEST)     -- 如果只是自身测试硬件好坏,可以用测试模式来验证,如果发送成功就OK
@@ -69,5 +69,6 @@ else
 	can.node(can_id, rx_id, can.EXT)
 	can.mode(can_id, can.MODE_NORMAL)   -- 一旦设置mode就开始正常工作了,此时不能再设置node,timing,filter等
 end
-sys.timerLoopStart(can_tx_test, 2000)
+
+sys.timerLoopStart(can_tx_test, 1000)
 sys.run()

+ 32 - 76
module/Air8000/project/整机开发板出厂工程/user/airble.lua

@@ -5,24 +5,23 @@ dhcpsrv =  require("dhcpsrv")
 httpplus = require("httpplus")
 local run_state = false  -- 判断本UI DEMO 是否运行
 local ble_state = "未初始"
-local ble_flag = "false"
 
 local Characteristic1 = "EA01"
-local Characteristic1_read = ""
-local Characteristic1_write = ""
+local Characteristic1_read = nil
+local Characteristic1_write = nil
 local Characteristic2 = "EA02"
-local Characteristic2_write = ""
+local Characteristic2_write = nil
 local Characteristic3 = "EA03"
-local Characteristic3_read = ""
+local Characteristic3_read = nil
 local Characteristic4 = "EA04"
-local Characteristic4_read = ""
-local Characteristic4ind = ""
+local Characteristic4_read = nil
+local Characteristic4ind = nil
 
 
 local att_db = nil
 
 
-
+ble_stat = false
 
 local function set_att_db()
     att_db = { -- Service
@@ -43,75 +42,47 @@ end
 
 local function ble_callback(dev, evt, param)
     if evt == ble.EVENT_CONN then
-        ble_state = "蓝牙链接成功"
-        log.info("ble", ble_state, param, param and param.addr and param.addr:toHex() or "unknow")
-        ble_flag = true
+        log.info("ble", "connect 成功", param, param and param.addr and param.addr:toHex() or "unknow")
+        ble_stat = true
     elseif evt == ble.EVENT_DISCONN then
-        ble_state = "蓝牙已断开"
-        log.info("ble", ble_state)
-        ble_flag = false
+        log.info("ble", "disconnect")
+        ble_stat = false
         -- 1秒后重新开始广播
         sys.timerStart(function() dev:adv_start() end, 1000)
     elseif evt == ble.EVENT_WRITE_REQ then
         -- 收到写请求
-        ble_state = "接收到写请求"
-        log.info("ble", "接收到写请求", param.uuid_service:toHex(), param.data:toHex(),param.uuid_characteristic:toHex())
-        if param.uuid_characteristic:toHex() == Characteristic1 then
+        log.info("ble", "接收到写请求", param.uuid_service:toHex(), param.data:toHex())
+        if param.uuid_service == Characteristic1 then
             Characteristic1_write = param.data:toHex()
-        elseif param.uuid_characteristic:toHex() == Characteristic2 then
+        elseif param.uuid_service == Characteristic2 then
             Characteristic2_write = param.data:toHex()
         end
 
     end
 end
 
-local function write_read()
-    local wr = {
-        uuid_service = string.fromHex("FA00"),
-        uuid_characteristic = string.fromHex("EA01"), 
-    }
-    ble_device:write_value(wr, "FA00EA01 HELLO" .. os.date())
-
-    wr = {
-        uuid_service = string.fromHex("FA00"),
-        uuid_characteristic = string.fromHex("EA03"), 
-    }   
-    ble_device:write_value(wr, "FA00EA03 HELLO" .. os.date())
-    
-    wr = {
-        uuid_service = string.fromHex("FA00"),
-        uuid_characteristic = string.fromHex("EA04"), 
-    }
-    ble_device:write_value(wr, "FA00EA04 HELLO" .. os.date())
-    
-end
 
 local function ble_peripheral_setup()
     local ret = 0
     set_att_db()
     sys.wait(500)
-    
-    ble_state = "开始初始化蓝牙核心"
-    log.info(ble_state)
+    log.info("开始初始化蓝牙核心")
     bluetooth_device = bluetooth.init()
     sys.wait(100)
-    ble_state = "初始化BLE功能"
-    log.info(ble_state)
+    log.info("初始化BLE功能")
     ble_device = bluetooth_device:ble(ble_callback)
     if ble_device == nil then
-        ble_state = "当前固件不支持完整的BLE"
-        log.error(ble_state)
+        log.error("当前固件不支持完整的BLE")
         return
     end
     sys.wait(100)
-    ble_state = '开始创建GATT'
-    log.info(ble_state)
+
+    log.info('开始创建GATT')
     ret = ble_device:gatt_create(att_db)
     log.info("创建的GATT", ret)
 
     sys.wait(100)
-    ble_state = "开始设置广播内容"
-    log.info(ble_state)
+    log.info("开始设置广播内容")
     ble_device:adv_create({
         addr_mode = ble.PUBLIC,
         channel_map = ble.CHNLS_ALL,
@@ -119,38 +90,24 @@ local function ble_peripheral_setup()
         intv_max = 120,
         adv_data = {
             {ble.FLAGS, string.char(0x06)},
-            {ble.COMPLETE_LOCAL_NAME, "LuatOS_Air8000"},
+            {ble.COMPLETE_LOCAL_NAME, "LuatOS123"},
             {ble.SERVICE_DATA, string.fromHex("FE01")},
             {ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
         }
     })
+
     sys.wait(100)
-    ble_state = "开始广播"
-    log.info(ble_state)
+    log.info("开始广播")
     ble_device:adv_start()
-    write_read()
+
 end
 
-local function start_notify_and_ind()
-    if ble_flag then
-        local wt = {
-            uuid_service = string.fromHex("FA00"),
-            uuid_characteristic = string.fromHex("EA01"), 
-        }
-        local result = ble_device:write_notify(wt, "123456" .. os.date())
-        log.info("ble", "发送通知数据", result)
+local function start_notify()
 
-        local wi = {
-            uuid_service = string.fromHex("FA00"),
-            uuid_characteristic = string.fromHex("EA04"), 
-        }
-        local result = ble_device:write_indicate(wi, "please read" .. os.date())
-        log.info("ble", "发送指示数据", result)
-        ble_state = "通知指示数据已经发送完毕"
-    end
 end
 
 
+
 function airble.run()       
     log.info("airble.run")
     lcd.setFont(lcd.font_opposansm12_chinese) -- 设置中文字体
@@ -160,10 +117,10 @@ function airble.run()
         sys.wait(10)
         lcd.clear(_G.bkcolor) 
         lcd.drawStr(0,80,"当前蓝牙状态:" .. ble_state )
-        lcd.drawStr(0,100,"服务:FA00,特征:" .. Characteristic1  .. ",可读数据为:" ..  Characteristic1_read.. "被写入数据为:" .. Characteristic1_write)
-        lcd.drawStr(0,120,"服务:FA00,特征:" .. Characteristic2   .. "被写入数据为:" .. Characteristic2_write)
-        lcd.drawStr(0,140,"服务:FA00,特征:" .. Characteristic3   .. ",可读数据为:" .. Characteristic3_read)
-        lcd.drawStr(0,160,"服务:FA00,特征:" .. Characteristic4   .. "可读数据为:" .. Characteristic4_read)
+        lcd.drawStr(0,100,"特征:" .. Characteristic1  .. ",可读数据为:" ..  Characteristic1_read.. "被写入数据为:" .. Characteristic1_write)
+        lcd.drawStr(0,120,"特征:" .. Characteristic2   .. "被写入数据为:" .. Characteristic2_write)
+        lcd.drawStr(0,140,"特征:" .. Characteristic3   .. ",可读数据为:" .. Characteristic3_read)
+        lcd.drawStr(0,160,"特征:" .. Characteristic4   .. "可读数据为:" .. Characteristic4_read)
 
 
 
@@ -179,11 +136,10 @@ end
 
 
 function airble.tp_handal(x,y,event)       
-    log.info("airble.tp_handal",x,y)
     if x > 20 and  x < 100 and y > 360  and  y < 440 then
         run_state = false
-    elseif x > 130 and  x < 239 and y > 350  and  y < 393 then
-        sysplus.taskInitEx(start_notify_and_ind, "start_notify_and_ind")
+    elseif x > 130 and  x < 230 and y > 397  and  y < 444 then
+        sysplus.taskInitEx(start_notify, "start_notify")
     end
 end
 

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

@@ -484,7 +484,7 @@ local function draw()
     draw_power()
   elseif cur_fun == "multi_network" then
     draw_multi_network()    
-  elseif cur_fun == "airble" then
+  elseif cur_fun == "multi_network" then
     draw_airble()
   end
   

+ 26 - 0
module/Air8101/demo/socket/client/long_connection/E6.crt

@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
+WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
+RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G
+h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV
+6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw
+gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
+ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj
+v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
+AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
+BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
+Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAfYt7SiA1sgWGCIpunk46r4AExIRc
+MxkKgUhNlrrv1B21hOaXN/5miE+LOTbrcmU/M9yvC6MVY730GNFoL8IhJ8j8vrOL
+pMY22OP6baS1k9YMrtDTlwJHoGby04ThTUeBDksS9RiuHvicZqBedQdIF65pZuhp
+eDcGBcLiYasQr/EO5gxxtLyTmgsHSOVSBcFOn9lgv7LECPq9i7mfH3mpxgrRKSxH
+pOoZ0KXMcB+hHuvlklHntvcI0mMMQ0mhYj6qtMFStkF1RpCG3IPdIwpVCQqu8GV7
+s8ubknRzs+3C/Bm19RFOoiPpDkwvyNfvmQ14XkyqqKK5oZ8zhD32kFRQkxa8uZSu
+h4aTImFxknu39waBxIRXE4jKxlAmQc4QjFZoq1KmQqQg0J/1JF8RlFvJas1VcjLv
+YlvUB2t6npO6oQjB3l+PNf0DpQH7iUx3Wz5AjQCi6L25FjyE06q6BZ/QlmtYdl/8
+ZYao4SRqPEs/6cAiF+Qf5zg2UkaWtDphl1LKMuTNLotvsX99HP69V2faNyegodQ0
+LyTApr/vT01YPE46vNsDLgK+4cL6TrzC/a4WcmF5SRJ938zrv/duJHLXQIku5v0+
+EwOy59Hdm0PT/Er/84dDV0CSjdR/2XuZM3kpysSKLgD1cKiDA+IRguODCxfO9cyY
+Ig46v9mFmBvyH04=
+-----END CERTIFICATE-----

+ 31 - 0
module/Air8101/demo/socket/client/long_connection/ISRG Root X1.crt

@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
+WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
+ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
+MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
+h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
+A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
+T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
+B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
+B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
+KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
+OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
+jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
+qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
+rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
+hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
+3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
+NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
+ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
+TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
+jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
+oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
+4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
+mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
+emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----

+ 99 - 0
module/Air8101/demo/socket/client/long_connection/main.lua

@@ -0,0 +1,99 @@
+--[[
+本demo演示的核心功能为:
+1、创建四路socket连接,详情如下
+- 创建一个tcp client,连接tcp server;
+- 创建一个udp client,连接udp server;
+- 创建一个tcp ssl client,连接tcp ssl server,不做证书校验;
+- 创建一个tcp ssl client,连接tcp ssl server,client仅单向校验server的证书,server不校验client的证书和密钥文件;
+2、每一路socket连接出现异常后,自动重连;
+3、每一路socket连接,client按照以下几种逻辑发送数据给server
+- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后发送给server;
+- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer:前缀后发送给server;
+4、每一路socket连接,client收到server数据后,将数据增加recv from tcp/udp/tcp ssl/tcp ssl ca(四选一)server: 前缀后,通过uart1发送出去;
+5、每一路socket连接,启动一个网络业务逻辑看门狗task,用来监控socket工作状态,如果连续长时间工作不正常,重启整个软件系统(后续补充);
+
+更多说明参考本目录下的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 = "SOCKET_LONG_CONNECTION"
+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)
+
+-- 加载WIFI网络连接管理应用功能模块
+require "wifi_app"
+
+-- 加载串口应用功能模块
+require "uart_app"
+-- 加载定时器应用功能模块
+require "timer_app"
+-- 加载测试应用功能模块(只有调试某些接口时才需要)
+-- require "test_app"
+
+-- 加载tcp client socket主应用功能模块
+require "tcp_client_main"
+
+-- 加载udp client socket主应用功能模块
+-- require "udp_client_main"
+
+-- 打开内核固件中ssl的调试日志(需要分析问题时再打开)
+-- socket.sslLog(3)
+-- 加载tcp ssl client socket主应用功能模块
+-- require "tcp_ssl_main"
+
+-- 加载sntp时间同步应用功能模块(ca证书校验的ssl socket需要时间同步功能)
+-- require "sntp_app"
+-- 加载tcp ssl ca client socket主应用功能模块
+-- require "tcp_ssl_ca_main"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 103 - 0
module/Air8101/demo/socket/client/long_connection/readme.md

@@ -0,0 +1,103 @@
+
+## 演示功能概述
+1、创建四路socket连接,详情如下
+
+- 创建一个tcp client,连接tcp server;
+
+- 创建一个udp client,连接udp server;
+
+- 创建一个tcp ssl client,连接tcp ssl server,不做证书校验;
+
+- 创建一个tcp ssl client,连接tcp ssl server,client仅单向校验server的证书,server不校验client的证书和密钥文件;
+
+2、每一路socket连接出现异常后,自动重连;
+
+3、每一路socket连接,client按照以下几种逻辑发送数据给server
+
+- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后发送给server;
+
+- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer:前缀后发送给server;
+
+4、每一路socket连接,client收到server数据后,将数据增加recv from tcp/udp/tcp ssl/tcp ssl ca(四选一)server: 前缀后,通过uart1发送出去;
+
+5、每一路socket连接,启动一个网络业务逻辑看门狗task,用来监控socket工作状态,如果连续长时间工作不正常,重启整个软件系统(后续补充);
+
+
+## 演示硬件环境
+
+1、Air8101核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、USB转串口数据线一根
+
+4、Air8101核心板和数据线的硬件接线方式为
+
+- Air8101核心板通过TYPE-C USB口供电;(核心板背面的功耗测试开关拨到OFF一端)
+
+- 如果测试发现软件频繁重启,重启原因值为:poweron reason 0,可能是供电不足,此时再通过直流稳压电源对核心板的vbat管脚进行4V供电,或者VIN管脚进行5V供电;
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+- USB转串口数据线,一般来说,白线连接核心板的12/U1TX,绿线连接核心板的11/U1RX,黑线连接核心板的gnd,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8101 V1004版本固件](https://docs.openluat.com/air8101/luatos/firmware/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录V1004固件对比验证)
+
+3、PC端的串口工具,例如SSCOM、LLCOM等都可以;
+
+4、PC端浏览器访问[合宙TCP/UDP web测试工具](https://netlab.luatos.com/);
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、PC端浏览器访问[合宙TCP/UDP web测试工具](https://netlab.luatos.com/),点击 打开TCP 按钮,会创建一个TCP server,将server的地址和端口赋值给tcp_client_main.lua中的SERVER_ADDR和SERVER_PORT两个变量
+
+3、PC端浏览器访问[合宙TCP/UDP web测试工具](https://netlab.luatos.com/),点击 打开UDP 按钮,会创建一个UDP server,将server的地址和端口赋值给udp_client_main.lua中的SERVER_ADDR和SERVER_PORT两个变量
+
+4、PC端浏览器访问[合宙TCP/UDP web测试工具](https://netlab.luatos.com/),点击 打开TCP SSL 按钮,会创建一个TCP SSL server,将server的地址和端口赋值给tcp_ssl_main.lua中的SERVER_ADDR和SERVER_PORT两个变量
+
+5、PC端浏览器访问[合宙TCP/UDP web测试工具](https://netlab.luatos.com/),点击 打开TCP SSL 按钮,会创建一个TCP SSL server,将server的地址和端口赋值给tcp_ssl_ca_main.lua中的SERVER_ADDR和SERVER_PORT两个变量
+
+6、demo脚本代码wifi_app.lua中的wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1),前两个参数,修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
+
+7、Luatools烧录内核固件和修改后的demo脚本代码
+
+8、烧录成功后,自动开机运行
+
+9、[合宙TCP/UDP web测试工具](https://netlab.luatos.com/)上创建的TCP server、UDP server、TCP SSL server、TCP SSL server,一共四个server,可以看到有设备连接上来,每隔5秒钟,会接收到一段类似于 send from timer: 1 的数据,最后面的数字每次加1,类似于以下效果:
+
+``` lua
+[2025-06-24 16:47:39.085]send from timer: 1
+73656E642066726F6D2074696D65723A2031
+
+[2025-06-24 16:47:43.247]send from timer: 2
+73656E642066726F6D2074696D65723A2032
+
+[2025-06-24 16:47:48.241]send from timer: 3
+73656E642066726F6D2074696D65723A2033
+```
+
+
+10、打开PC端的串口工具,选择对应的端口,配置波特率115200,数据位8,停止位1,无奇偶校验位;
+
+11、PC端的串口工具输入一段数据,点击发送,在[合宙TCP/UDP web测试工具](https://netlab.luatos.com/)上的四个server页面都可以接收到数据,类似于以下效果:
+
+``` lua
+[2025-06-24 17:19:58.402]send from uart: kerjkjwr
+73656E642066726F6D20756172743A206B65726A6B6A7772
+```
+
+12、在[合宙TCP/UDP web测试工具](https://netlab.luatos.com/)的发送编辑框内,输入一段数据,点击发送,在PC端的串口工具上可以接收到这段数据,并且也能看到是哪一个server发送的,类似于以下效果:
+
+``` lua
+recv from tcp server: 123456798012345678901234567830
+recv from udp server: 123456798012345678901234567830   
+recv from tcp_ssl server: 123456789901234
+```

+ 132 - 0
module/Air8101/demo/socket/client/long_connection/tcp_client_main.lua

@@ -0,0 +1,132 @@
+--[[
+本文件为tcp client socket主应用功能模块,核心业务逻辑为:
+1、创建一个tcp client socket,连接server;
+2、处理连接异常,出现异常后执行重连动作;
+3、调用tcp_client_receiver和tcp_client_sender中的外部接口,进行数据收发处理;
+
+本文件没有对外接口,直接在main.lua中require "tcp_client_main"就可以加载运行;
+]]
+
+local libnet = require "libnet"
+
+-- 加载tcp client socket数据接收功能模块
+local tcp_client_receiver = require "tcp_client_receiver"
+-- 加载tcp client socket数据发送功能模块
+local tcp_client_sender = require "tcp_client_sender"
+
+-- 电脑访问:https://netlab.luatos.com/
+-- 点击 打开TCP 按钮,会创建一个TCP server
+-- 将server的地址和端口赋值给下面这两个变量
+local SERVER_ADDR = "112.125.89.8"
+local SERVER_PORT = 42264
+
+-- tcp_client_main的任务名
+local TASK_NAME = tcp_client_sender.TASK_NAME
+
+
+-- 处理未识别的消息
+local function tcp_client_main_cbfunc(msg)
+	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
+end
+
+-- tcp client socket的任务处理函数
+local function tcp_client_main_task_func() 
+
+    local socket_client
+    local result, para1, para2
+
+    while true do
+        -- 如果WIFI还没有连接成功,一直在这里循环等待
+        while not socket.adapter(socket.LWIP_STA) do
+            log.warn("tcp_client_main_task_func", "wait IP_READY")
+            -- 在此处阻塞等待WIFI连接成功的消息"IP_READY"
+            -- 或者等待30秒超时退出阻塞等待状态
+            sys.waitUntil("IP_READY", 30000)
+        end
+
+        -- 检测到了IP_READY消息
+        log.warn("tcp_client_main_task_func", "recv IP_READY")
+
+        -- 创建socket client对象
+        socket_client = socket.create(socket.LWIP_STA, TASK_NAME)
+        -- 如果创建socket client对象失败
+        if not socket_client then
+            log.error("tcp_client_main_task_func", "socket.create error")
+            goto EXCEPTION_PROC
+        end
+
+        -- 配置socket client对象为tcp client
+        result = socket.config(socket_client)
+        -- 如果配置失败
+        if not result then
+            log.error("tcp_client_main_task_func", "socket.config error")
+            goto EXCEPTION_PROC
+        end
+
+        -- 连接server
+        result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
+        -- 如果连接server失败
+        if not result then
+            log.error("tcp_client_main_task_func", "libnet.connect error")
+            goto EXCEPTION_PROC
+        end
+
+        log.info("tcp_client_main_task_func", "libnet.connect success")
+
+        -- 数据收发以及网络连接异常事件总处理逻辑
+        while true do
+            -- 数据接收处理(接收处理必须写在libnet.wait之前,因为老版本的内核固件要求必须这样,新版本的内核固件没这个要求,为了不出问题,写在libnet.wait之前就行了)
+            -- 如果处理失败,则退出循环
+            if not tcp_client_receiver.proc(socket_client) then
+                log.error("tcp_client_main_task_func", "tcp_client_receiver.proc error")
+                break
+            end
+
+            -- 数据发送处理
+            -- 如果处理失败,则退出循环
+            if not tcp_client_sender.proc(TASK_NAME, socket_client) then
+                log.error("tcp_client_main_task_func", "tcp_client_sender.proc error")
+                break
+            end
+
+            -- 阻塞等待socket.EVENT事件或者15秒钟超时
+            -- 以下三种业务逻辑会发布事件:
+            -- 1、socket client和server之间的连接出现异常(例如server主动断开,网络环境出现异常等),此时在内核固件中会发布事件socket.EVENT
+            -- 2、socket client接收到server发送过来的数据,此时在内核固件中会发布事件socket.EVENT
+            -- 3、socket client需要发送数据到server, 在tcp_client_sender.lua中会发布事件socket.EVENT
+			result, para1, para2 = libnet.wait(TASK_NAME, 15000, socket_client)
+            log.info("tcp_client_main_task_func", "libnet.wait", result, para1, para2)
+			
+			-- 如果连接异常,则退出循环
+			if not result then
+				log.warn("tcp_client_main_task_func", "connection exception")
+				break
+            end
+        end
+
+
+        -- 出现异常    
+        ::EXCEPTION_PROC::
+
+        -- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
+        tcp_client_sender.exception_proc()
+
+        -- 如果存在socket client对象
+        if socket_client then
+            -- 关闭socket client连接
+            libnet.close(TASK_NAME, 5000, socket_client)
+
+            -- 释放socket client对象
+            socket.release(socket_client)
+            socket_client = nil
+        end
+        
+        -- 5秒后跳转到循环体开始位置,自动发起重连
+        sys.wait(5000)
+    end
+end
+
+--创建并且启动一个task
+--运行这个task的主函数tcp_client_main_task_func
+sysplus.taskInitEx(tcp_client_main_task_func, TASK_NAME, tcp_client_main_cbfunc)
+

+ 57 - 0
module/Air8101/demo/socket/client/long_connection/tcp_client_receiver.lua

@@ -0,0 +1,57 @@
+--[[
+本文件为tcp client socket数据接收应用功能模块,核心业务逻辑为:
+从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
+
+本文件的对外接口有2个:
+1、tcp_client_receiver.proc(socket_client):数据接收应用逻辑处理入口,在tcp_client_main.lua中调用;
+2、sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data):
+   将接收到的数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
+   需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
+]]
+
+local tcp_client_receiver = {}
+
+-- socket数据接收缓冲区
+local recv_buff = nil
+
+-- 数据接收应用入口函数
+function tcp_client_receiver.proc(socket_client)
+    -- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
+    if recv_buff==nil then
+        recv_buff = zbuff.create(1024)
+        -- 当recv_buff不再使用时,不需要主动调用recv_buff:free()去释放
+        -- 因为Lua的垃圾处理器会自动释放recv_buff所申请的内存空间
+        -- 如果等不及垃圾处理器自动处理,在确定以后不会再使用recv_buff时,则可以主动调用recv_buff:free()释放内存空间
+    end
+
+    -- 从内核的缓冲区中读取数据到recv_buff中
+    -- 如果recv_buff的存储空间不足,会自动扩容
+    local result = socket.rx(socket_client, recv_buff)
+
+    -- 读取数据失败
+    -- 有两种情况:
+    -- 1、recv_buff扩容失败
+    -- 2、socket client和server之间的连接断开
+    if not result then
+        log.error("tcp_client_receiver.proc", "socket.rx error")
+        return false
+    end
+
+    -- 如果读取到了数据, used()就必然大于0, 进行处理
+    if recv_buff:used() > 0 then
+        log.info("tcp_client_receiver.proc", "recv data len", recv_buff:used())
+
+        -- 读取socket数据接收缓冲区中的数据,赋值给data
+        local data = recv_buff:query()
+
+        -- 将数据data通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
+        sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data)
+
+        -- 清空socket数据接收缓冲区中的数据
+        recv_buff:del()
+    end
+
+    return true
+end
+
+return tcp_client_receiver

+ 104 - 0
module/Air8101/demo/socket/client/long_connection/tcp_client_sender.lua

@@ -0,0 +1,104 @@
+--[[
+本文件为tcp client socket数据发送应用功能模块,核心业务逻辑为:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
+2、tcp_client_main主任务调用tcp_client_sender.proc接口,遍历队列send_queue,逐条发送数据到server;
+3、tcp client socket和server之间的连接如果出现异常,tcp_client_main主任务调用tcp_client_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
+4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
+
+本文件的对外接口有3个:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
+   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和毁掉参数一起publish出去;
+   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+2、tcp_client_sender.proc:数据发送应用逻辑处理入口,在tcp_client_main.lua中调用;
+3、tcp_client_sender.exception_proc:数据发送应用逻辑异常处理入口,在tcp_client_main.lua中调用;
+]]
+
+local tcp_client_sender = {}
+
+local libnet = require "libnet"
+
+--[[
+数据发送队列,数据结构为:
+{
+    [1] = {data="data1", cb={func=callback_function1, para=callback_para1}},
+    [2] = {data="data2", cb={func=callback_function2, para=callback_para2}},
+}
+data的内容为真正要发送的数据,必须存在;
+func的内容为数据发送结果的用户回调函数,可以不存在
+para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
+]]
+local send_queue = {}
+
+-- tcp_client_main的任务名
+tcp_client_sender.TASK_NAME = "tcp_client_main"
+
+-- "SEND_DATA_REQ"消息的处理函数
+local function send_data_req_proc_func(tag, data, cb)
+    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
+    table.insert(send_queue, {data="send from "..tag..": "..data, cb=cb})
+    -- 通知tcp_client_main主任务有数据需要发送
+    -- tcp_client_main主任务如果处在libnet.wait调用的阻塞等待状态,就会退出阻塞状态
+    sysplus.sendMsg(tcp_client_sender.TASK_NAME, socket.EVENT, 0)
+end
+
+-- 数据发送应用逻辑处理入口
+function tcp_client_sender.proc(task_name, socket_client)
+    local send_item
+    local result, buff_full
+
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        -- 取出来第一条数据赋值给send_item
+        -- 同时从队列send_queue中删除这一条数据
+        send_item = table.remove(send_queue,1)
+
+        -- 发送这条数据,超时时间15秒钟
+        result, buff_full = libnet.tx(task_name, 15000, socket_client, send_item.data)
+
+        -- 发送失败
+        if not result then
+            log.error("tcp_client_sender.proc", "libnet.tx error")
+
+            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
+            if send_item.cb and send_item.cb.func then
+                send_item.cb.func(false, send_item.cb.para)
+            end
+
+            return false
+        end
+
+        -- 如果内核固件中缓冲区满了,则将send_item再次插入到send_queue的队首位置,等待下次尝试发送
+        if buff_full then
+            log.error("tcp_client_sender.proc", "buffer is full, wait for the next time")
+            table.insert(send_queue, 1, send_item)
+            return true
+        end
+
+        log.info("tcp_client_sender.proc", "send success")
+        -- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(true, send_item.cb.para)
+        end
+    end
+
+    return true
+end
+
+-- 数据发送应用逻辑异常处理入口
+function tcp_client_sender.exception_proc()
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        local send_item = table.remove(send_queue,1)
+        -- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(false, send_item.cb.para)
+        end
+    end
+end
+
+-- 订阅"SEND_DATA_REQ"消息;
+-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和毁掉参数一起publish出去;
+-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
+
+return tcp_client_sender

+ 32 - 0
module/Air8101/demo/socket/client/long_connection/test_app.lua

@@ -0,0 +1,32 @@
+--[[
+本文件为测试应用功能模块,用来测试其他功能模块的外部接口;
+仅调试需要,项目量产时不需要;
+]]
+
+
+-- 模拟四个socket client从server收到了数据,然后publish消息"RECV_DATA_FROM_SERVER"
+sys.taskInit(function()
+    local cnt = 0
+
+    while true do
+        cnt = cnt+1
+
+        sys.wait(1000)
+        sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", cnt)
+
+        sys.wait(1000)
+        sys.publish("RECV_DATA_FROM_SERVER", "recv from udp server: ", cnt)
+
+        sys.wait(1000)
+        sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp ssl server: ", cnt)
+
+        sys.wait(1000)
+        sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp ssl ca server: ", cnt)
+    end
+
+end)
+
+-- 模拟订阅处理串口应用功能模块和定时器应用功能模块的"SEND_DATA_REQ"消息
+sys.subscribe("SEND_DATA_REQ", function(tag, data)
+    log.info("test_app.SEND_DATA_REQ", "send from "..tag..": "..data)
+end)

+ 22 - 0
module/Air8101/demo/socket/client/long_connection/timer_app.lua

@@ -0,0 +1,22 @@
+--[[
+本文件为定时器应用功能模块,核心业务逻辑为:
+创建一个5秒的循环定时器,每次产生一段数据,通知四个socket client进行处理;
+
+本文件的对外接口有一个:
+1、sys.publish("SEND_DATA_REQ", "timer", data),通过publish通知其他应用功能模块处理data数据;
+]]
+
+local data = 1
+
+-- 循环定时器处理函数
+local function send_data_req_timer_loop_func()
+    -- 发布消息"SEND_DATA_REQ"
+    -- 携带的第一个参数"timer"表示是定时器应用模块发布的消息
+    -- 携带的第一个参数data为要发送的原始数据
+    sys.publish("SEND_DATA_REQ", "timer", data)
+    data = data+1
+end
+
+-- 启动一个5秒的循环定时器
+-- 每隔5秒执行一次send_data_req_timer_loop_func函数
+sys.timerLoopStart(send_data_req_timer_loop_func, 5000)

+ 73 - 0
module/Air8101/demo/socket/client/long_connection/uart_app.lua

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

+ 42 - 0
module/Air8101/demo/socket/client/long_connection/wifi_app.lua

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

+ 0 - 0
module/Air780EGH/demo/libgnss/AGPS/agps_icoe.lua → script/libs/agps_icoe.lua


+ 15 - 6
script/libs/httpdns.lua

@@ -18,16 +18,20 @@ local httpdns = {}
 
 --[[
 通过阿里DNS获取结果
-@api httpdns.ali(domain_name)
+@api httpdns.ali(domain_name, opts)
 @string 域名
+@table opts 可选参数, 与http.request的opts参数一致
 @return string ip地址
 @usage
 local ip = httpdns.ali("air32.cn")
 log.info("httpdns", "air32.cn", ip)
+-- 指定网络适配器
+local ip = httpdns.ali("air32.cn", {adapter=socket.LWIP_STA, timeout=3000})
+log.info("httpdns", "air32.cn", ip)
 ]]
-function httpdns.ali(n)
+function httpdns.ali(n, opts)
     if n == nil then return end
-    local code, _, body = http.request("GET", "http://223.5.5.5/resolve?short=1&name=" .. tostring(n)).wait()
+    local code, _, body = http.request("GET", "http://223.5.5.5/resolve?short=1&name=" .. tostring(n), nil, nil, opts).wait()
     if code == 200 and body and #body > 2 then
         local jdata = json.decode(body)
         if jdata and #jdata > 0 then
@@ -39,16 +43,21 @@ end
 
 --[[
 通过腾讯DNS获取结果
-@api httpdns.tx(domain_name)
+@api httpdns.tx(domain_name, opts)
 @string 域名
+@table opts 可选参数, 与http.request的opts参数一致
 @return string ip地址
 @usage
 local ip = httpdns.tx("air32.cn")
 log.info("httpdns", "air32.cn", ip)
+
+-- 指定网络适配器
+local ip = httpdns.tx("air32.cn", {adapter=socket.LWIP_STA, timeout=3000})
+log.info("httpdns", "air32.cn", ip)
 ]]
-function httpdns.tx(n)
+function httpdns.tx(n, opts)
     if n == nil then return end
-    local code, _, body = http.request("GET", "http://119.29.29.29/d?dn=" .. tostring(n)).wait()
+    local code, _, body = http.request("GET", "http://119.29.29.29/d?dn=" .. tostring(n), nil, nil, opts).wait()
     if code == 200 and body and #body > 2 then
         local tmp = body:split(",")
         if tmp then return tmp[1] end

+ 0 - 21
script/turnkey/EinkBook/LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2022 Jeremy
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 52
script/turnkey/EinkBook/README.md

@@ -1,52 +0,0 @@
-# EinkBook-LuatOS
-
-### 介绍
-
-使用LuatOS-ESP32制作一个电纸书
-
-#### 效果展示
-
-![](https://cdn.openluat-luatcommunity.openluat.com/images/20220313202435046_IMG_20220310_154336.jpg)
-
-### 硬件
-
-+ 合宙ESP32-C3开发板
-+ MODEL_1in54 墨水屏
-
-### 软件
-
-+ [LuatOS-ESP32](https://gitee.com/dreamcmi/LuatOS-ESP32/tree/master)
-+ [GoFrame](https://goframe.org/display/gf)
-
-### 部署方法
-
-#### 服务端
-
-> 请先自行配置Golang工具链
-
-+ 将想要阅读的小说放到`Server\books`目录下(目前仅支持txt格式)
-+ 开启小说服务端程序
-
-```bat
-cd Server
-windows:
-    ./run.bat
-linux or macos:
-    ./run.sh
-```
-
-#### 电纸书
-
-> 需要解锁ESP32C3的GPIO11,详情参考这里[ESP32C3解锁使用IO11](https://gitee.com/dreamcmi/LuatOS-ESP32/blob/master/doc/VDD_SPI_AS_GPIO.md)
-
-> 注意: 需要使用带有`sarasa_regular_12`字体的固件,本地没有LuatOS-ESP32编译环境可以参考[云编译](https://wiki.luatos.com/develop/compile/Cloud_compilation.html)
-
-使用LuaTools将Scripts目录下所有文件烧录到ESP32-C3模块中
-
-### 电纸书使用方法
-
-使用BOOT键(GPIO 9)作为功能按键
-
-+ 单击:下一个
-+ 双击:上一个
-+ 长按:进入/退出

+ 0 - 354
script/turnkey/EinkBook/Scripts/main.lua

@@ -1,354 +0,0 @@
-PROJECT = "EinkBook-LuatOS"
-VERSION = "1.0.0"
-MOD_TYPE = rtos.bsp()
-log.info("MOD_TYPE", MOD_TYPE)
-sys = require("sys")
-require("sysplus")
-wifiLib = require("wifiLib")
-
-
--- 兼容V1001固件的
-if http == nil and http2 then
-    http = http2
-end
-
-
--- 兼容V1001固件的
-if http == nil and http2 then
-    http = http2
-end
-
-tag = "EINKBOOK"
--- 是否启用配网功能(配合esptouch使用)
-USE_SMARTCONFIG = false
--- 这是已有的电纸书服务端地址,如果自己搭建或下面这个服务失效了,请修改
-serverAdress = "http://47.96.229.157:2333/"
--- 改为需要连接的WiFi名称和密码(使用2.4Ghz频段,ESP32C3无法使用5GHz WiFi)
-SSID, PASSWD = "Xiaomi_AX6000", "Air123456"
-
-waitHttpTask, waitDoubleClick = false, false
-einkPrintTime = 0
-PAGE, gpage = "LIST", 1
-onlineBooksTable, onlineBooksShowTable, onlineBooksShowTableTmp, einkBooksIndex, onlineBooksTableLen = {}, {}, {}, 1, 0
-gBTN, gPressTime, gShortCb, gLongCb, gDoubleCb, gBtnStatus = 0, 1000, nil, nil, nil, "IDLE"
-
-function printTable(tbl, lv)
-    lv = lv and lv .. "\t" or ""
-    print(lv .. "{")
-    for k, v in pairs(tbl) do
-        if type(k) == "string" then
-            k = "\"" .. k .. "\""
-        end
-        if "string" == type(v) then
-            local qv = string.match(string.format("%q", v), ".(.*).")
-            v = qv == v and '"' .. v .. '"' or "'" .. v:toHex() .. "'"
-        end
-        if type(v) == "table" then
-            print(lv .. "\t" .. tostring(k) .. " = ")
-            printTable(v, lv)
-        else
-
-            print(lv .. "\t" .. tostring(k) .. " = " .. tostring(v) .. ",")
-        end
-    end
-    print(lv .. "},")
-end
-
-function getTableSlice(intable, startIndex, endIndex)
-    local outTable = {}
-    for i = startIndex, endIndex do
-        table.insert(outTable, intable[i])
-    end
-    return outTable
-end
-
-function getTableLen(t)
-    local count = 0
-    for _, _ in pairs(t) do
-        count = count + 1
-    end
-    return count
-end
-
-function formatOnlineBooksTable(inTable)
-    local outTable = {}
-    local i = 1
-    for k, v in pairs(inTable) do
-        v["index"] = i
-        table.insert(outTable, {
-            [k] = v
-        })
-        i = i + 1
-    end
-    return outTable
-end
-
-function longTimerCb()
-    gBtnStatus = "LONGPRESSED"
-    gLongCb()
-end
-
-function btnHandle(val)
-    if val == 0 then
-        if waitDoubleClick == true then
-            sys.timerStop(gShortCb)
-            gDoubleCb()
-            waitDoubleClick = false
-            return
-        end
-        sys.timerStart(longTimerCb, gPressTime)
-        gBtnStatus = "PRESSED"
-    else
-        sys.timerStop(longTimerCb)
-        if gBtnStatus == "PRESSED" then
-            sys.timerStart(gShortCb, 500)
-            waitDoubleClick = true
-            gBtnStatus = "IDLE"
-        elseif gBtnStatus == "LONGPRESSED" then
-            gBtnStatus = "IDLE"
-        end
-    end
-end
-
-function btnSetup(gpioNumber, pressTime, shortCb, longCb, doubleCb)
-    gpio.setup(gpioNumber, btnHandle, gpio.PULLUP)
-    gPressTime = pressTime
-    gShortCb = shortCb
-    gLongCb = longCb
-    gDoubleCb = doubleCb
-end
-
-function showBookList(index)
-    local firstIndex
-    for k, v in pairs(onlineBooksShowTableTmp[1]) do
-        firstIndex = v["index"]
-    end
-    if index > firstIndex + 10 then
-        onlineBooksShowTableTmp = getTableSlice(onlineBooksShowTable, index - 10, index)
-    end
-    if index < firstIndex then
-        onlineBooksShowTableTmp = getTableSlice(onlineBooksShowTable, index, index + 10)
-    end
-    einkShowStr(0, 16, "图书列表", 0, true)
-    local ifShow = false
-    local len = getTableLen(onlineBooksTable)
-    local showLen = getTableLen(onlineBooksShowTableTmp)
-    if len == 0 then
-        einkShowStr(0, 32, "暂无在线图书", 0, false, true)
-        return
-    end
-    local i = 1
-    for k, v in pairs(onlineBooksShowTableTmp) do
-        for name, info in pairs(v) do
-            local bookName = string.split(name, ".")[1]
-            local bookSize = tonumber(info["size"]) / 1024 / 1024
-            if i == showLen then
-                ifShow = true
-            end
-            if info["index"] == index then
-                eink.rect(0, 16 * i, 200, 16 * (i + 1), 0, 1, nil, ifShow)
-                einkShowStr(0, 16 * (i + 1), bookName .. "       " .. string.format("%.2f", bookSize) .. "MB", 1, nil,
-                    ifShow)
-            else
-                einkShowStr(0, 16 * (i + 1), bookName .. "       " .. string.format("%.2f", bookSize) .. "MB", 0, nil,
-                    ifShow)
-            end
-            i = i + 1
-        end
-    end
-end
-
-function showBook(bookName, bookUrl, page)
-    sys.taskInit(function()
-        waitHttpTask = true
-        for i = 1, 3 do
-            local code, headers, data = http.request("GET",bookUrl .. "/" .. page).wait()
-            log.info("SHOWBOOK", code)
-            if code ~= 200 then
-                log.error("SHOWBOOK", "获取图书内容失败 ", data)
-            else
-                local bookLines = json.decode(data)
-                for k, v in pairs(bookLines) do
-                    if k == 1 then
-                        einkShowStr(0, 16 * k, v, 0, true, false)
-                    elseif k == #bookLines then
-                        einkShowStr(0, 16 * k, v, 0, false, false)
-                    else
-                        einkShowStr(0, 16 * k, v, 0, false, false)
-                    end
-                end
-                einkShowStr(60, 16 * 12 + 2, page .. "/" .. onlineBooksTable[bookName]["pages"], 0, false, true)
-                break
-            end
-        end
-        waitHttpTask = false
-    end)
-end
-
-function btnShortHandle()
-    if waitHttpTask == true then
-        waitDoubleClick = false
-        return
-    end
-    if PAGE == "LIST" then
-        if einkBooksIndex == onlineBooksTableLen then
-            einkBooksIndex = 1
-        else
-            einkBooksIndex = einkBooksIndex + 1
-        end
-        showBookList(einkBooksIndex)
-    else
-        local i = 1
-        local bookName = nil
-        for k, v in pairs(onlineBooksTable) do
-            if i == einkBooksIndex then
-                bookName = k
-            end
-            i = i + 1
-        end
-        local thisBookPages = tonumber(onlineBooksTable[bookName]["pages"])
-        if thisBookPages == gpage then
-            waitDoubleClick = false
-            return
-        end
-        gpage = gpage + 1
-        showBook(bookName, serverAdress .. string.urlEncode(bookName), gpage)
-        log.info(bookName, gpage)
-        fdb.kv_set(bookName, gpage)
-    end
-    waitDoubleClick = false
-end
-
-function btnLongHandle()
-    if waitHttpTask == true then
-        return
-    end
-    if PAGE == "LIST" then
-        PAGE = "BOOK"
-        local i = 1
-        local bookName = nil
-        for k, v in pairs(onlineBooksTable) do
-            if i == einkBooksIndex then
-                bookName = k
-            end
-            i = i + 1
-        end
-        local pageCache = fdb.kv_get(bookName)
-        log.info(bookName, pageCache)
-        if pageCache == nil then
-            gpage = 1
-            showBook(bookName, serverAdress .. string.urlEncode(bookName), gpage)
-        else
-            gpage = pageCache
-            showBook(bookName, serverAdress .. string.urlEncode(bookName), pageCache)
-        end
-
-    elseif PAGE == "BOOK" then
-        PAGE = "LIST"
-        showBookList(einkBooksIndex)
-    end
-end
-
-function btnDoublehandle()
-    if waitHttpTask == true then
-        return
-    end
-    if PAGE == "LIST" then
-        if einkBooksIndex == 1 then
-            einkBooksIndex = onlineBooksTableLen
-        else
-            einkBooksIndex = einkBooksIndex - 1
-        end
-        showBookList(einkBooksIndex)
-    else
-        if gpage == 1 then
-            return
-        end
-        gpage = gpage - 1
-        local i = 1
-        local bookName = nil
-        for k, v in pairs(onlineBooksTable) do
-            if i == einkBooksIndex then
-                bookName = k
-            end
-            i = i + 1
-        end
-        log.info(bookName, gpage)
-        fdb.kv_set(bookName, gpage)
-        showBook(bookName, serverAdress .. string.urlEncode(bookName), gpage)
-    end
-end
-
-function einkShowStr(x, y, str, colored, clear, show)
-    if einkPrintTime > 20 then
-        einkPrintTime = 0
-        eink.rect(0, 0, 200, 200, 0, 1)
-        eink.show(0, 0, true)
-        eink.rect(0, 0, 200, 200, 1, 1)
-        eink.show(0, 0, true)
-    end
-    if clear == true then
-        eink.clear()
-    end
-    eink.print(x, y, str, colored)
-    if show == true then
-        einkPrintTime = einkPrintTime + 1
-        eink.show(0, 0, true)
-    end
-end
-
-sys.taskInit(function()
-    assert(fdb.kvdb_init("env", "onchip_flash") == true, tag .. ".kvdb_init ERROR")
-    eink.model(eink.MODEL_1in54)
-    if MOD_TYPE == "AIR101" then
-        eink.setup(1, 0, 16, 19, 17, 20)
-    elseif MOD_TYPE == "ESP32C3" then
-        eink.setup(1, 2, 11, 10, 6, 7)
-    end
-    eink.setWin(200, 200, 0)
-    eink.clear(0, true)
-    eink.show(0, 0)
-    eink.clear(1, true)
-    eink.show(0, 0)
-    -- eink.setFont(fonts.get("sarasa_regular_12"))
-    eink.setFont(eink.font_opposansm12_chinese)
-
-    if USE_SMARTCONFIG == true then
-        einkShowStr(0, 16, "开机中 等待配网...", 0, false, true)
-        local connectRes = wifiLib.connect()
-        if connectRes == false then
-            einkShowStr(0, 16, "配网失败 重启中...", 0, true, true)
-            rtos.reboot()
-        end
-    else
-        einkShowStr(0, 16, "开机中...", 0, false, true)
-        local connectRes = wifiLib.connect(SSID, PASSWD)
-        if connectRes == false then
-            einkShowStr(0, 16, "联网失败 重启中...", 0, true, true)
-            rtos.reboot()
-        end
-    end
-    for i = 1, 5 do
-        local code, headers, data = http.request("GET", serverAdress .. "getBooks").wait()
-        log.info("SHOWBOOK", code)
-        if code ~= 200 then
-            log.error(tag, "获取图书列表失败 ", data)
-            if i == 5 then
-                einkShowStr(0, 16, "连接图书服务器失败 正在重启", 0, true, true)
-                rtos.reboot()
-            end
-        else
-            onlineBooksTable = json.decode(data)
-            printTable(onlineBooksTable)
-            onlineBooksTableLen = getTableLen(onlineBooksTable)
-            onlineBooksShowTable = formatOnlineBooksTable(onlineBooksTable)
-            onlineBooksShowTableTmp = getTableSlice(onlineBooksShowTable, 1, 11)
-            showBookList(1)
-            btnSetup(9, 1000, btnShortHandle, btnLongHandle, btnDoublehandle)
-            break
-        end
-        sys.wait(1000)
-    end
-end)
-
-sys.run()

+ 0 - 53
script/turnkey/EinkBook/Scripts/wifiLib.lua

@@ -1,53 +0,0 @@
-local wifiConnect = {}
-
-function wifiConnect.connect(ssid, passwd)
-    local waitRes, data
-    if wlan.init() ~= 0 then
-        log.error(tag .. ".init", "ERROR")
-        return false
-    end
-    if wlan.setMode(wlan.STATION) ~= 0 then
-        log.error(tag .. ".setMode", "ERROR")
-        return false
-    end
-
-    if USE_SMARTCONFIG == true then
-        if wlan.smartconfig() ~= 0 then
-            log.error(tag .. ".connect", "ERROR")
-            return false
-        end
-        waitRes, data = sys.waitUntil("WLAN_STA_CONNECTED", 180 * 10000)
-        log.info("WLAN_STA_CONNECTED", waitRes, data)
-        if waitRes ~= true then
-            log.error(tag .. ".wlan ERROR")
-            return false
-        end
-        waitRes, data = sys.waitUntil("IP_READY", 10000)
-        if waitRes ~= true then
-            log.error(tag .. ".wlan ERROR")
-            return false
-        end
-        log.info("IP_READY", waitRes, data)
-        return true
-    end
-
-    if wlan.connect(ssid, passwd) ~= 0 then
-        log.error(tag .. ".connect", "ERROR")
-        return false
-    end
-    waitRes, data = sys.waitUntil("WLAN_STA_CONNECTED", 10000)
-    if waitRes ~= true then
-        log.error(tag .. ".wlan ERROR")
-        return false
-    end
-    log.info("WLAN_STA_CONNECTED", waitRes, data)
-    waitRes, data = sys.waitUntil("IP_READY", 10000)
-    if waitRes ~= true then
-        log.error(tag .. ".wlan ERROR")
-        return false
-    end
-    log.info("IP_READY", waitRes, data)
-    return true
-end
-
-return wifiConnect

+ 0 - 3
script/turnkey/EinkBook/Server/README.md

@@ -1,3 +0,0 @@
-# Server
-
-Server 代码 参考 https://gitee.com/HashJeremy/EinkBook-LuatOS/tree/master/Server

+ 0 - 9
script/turnkey/air780eg_gnss_qcloud/README.md

@@ -1,9 +0,0 @@
-# Air780EG + 腾讯连连小程序
-
-## 使用条件
-
-硬件条件: Air780EG 或 Air780E + Air530H, 或春节内测开发板
-
-## 固件要求
-
-若使用 Air780EG, V1105或以上

+ 0 - 280
script/turnkey/air780eg_gnss_qcloud/main.lua

@@ -1,280 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "gnsstest"
-VERSION = "1.0.1"
-
---[[
-Air780EG 对接 腾讯连连
-注意: 室内无信号!! 无法定位!!!
-]]
-
--- sys库是标配
-local sys = require("sys")
-require("sysplus")
-
-local gps_uart_id = 2
-local mqttc = nil
-
----------------------------------------------------------------------
---[[
-使用本代码需要自行调整下列配置参数:
-1. qcloud_pid 项目id
-2. qcloud_dev 默认是使用设备的IMEI,如果自定义了名字,改成固定的
-3. qcloud_key 设备密钥,在页面新建设备后,设备详情中可以查看到
-4. qcloud_host 默认值就是最常见的配置,一般不需要修改
-5. qcloud_port 密钥登录模式,只需要非加密的1883端口
-]]
-local qcloud_pid = "JTWPP5SPLA"
-local qcloud_dev = mobile.imei()
-local qcloud_key = "mZE56wmoBFG3J3gG7xvTsg=="
-local qcloud_host = qcloud_pid .. ".iotcloud.tencentdevices.com"
-local qcloud_port = 1883
----------------------------------------------------------------------
-
--- libgnss库初始化
-libgnss.clear() -- 清空数据,兼初始化
-
--- 初始化存储
-fskv.init()
-
--- LED和ADC初始化
-LED_GNSS = 24
-LED_VBAT = 26
-SWITCH_1 = 1
-SWITCH_2 = 22
-gpio.setup(LED_GNSS, 0) -- GNSS定位成功灯
-gpio.setup(LED_VBAT, 0) -- 低电压警告灯
-adc.open(adc.CH_VBAT)
--- adc.open(adc.CH_CPU)
-
--- 判断一下初始化配置
-if fskv.get("SWITCH_1") == nil then
-    fskv.set("SWITCH_1", 0)
-end
-if fskv.get("SWITCH_2") == nil then
-    fskv.set("SWITCH_2", 0)
-end
-
-gpio.setup(SWITCH_1, fskv.get("SWITCH_1"), gpio.PULLUP)
-gpio.setup(SWITCH_2, fskv.get("SWITCH_2"))
-
--- 串口初始化
-uart.setup(gps_uart_id, 115200)
-
-function exec_agnss()
-    local url = "http://download.openluat.com/9501-xingli/HXXT_GPS_BDS_AGNSS_DATA.dat"
-    if http then
-        -- AGNSS 已调通
-        while 1 do
-            local code, headers, body = http.request("GET", url).wait()
-            log.info("gnss", "AGNSS", code, body and #body or 0)
-            if code == 200 and body and #body > 1024 then
-                for offset = 1, #body, 512 do
-                    log.info("gnss", "AGNSS", "write >>>", #body:sub(offset, offset + 511))
-                    uart.write(gps_uart_id, body:sub(offset, offset + 511))
-                    -- sys.waitUntil("UART2_SEND", 100)
-                    sys.wait(100) -- 等100ms反而更成功
-                end
-                -- sys.waitUntil("UART2_SEND", 1000)
-                io.writeFile("/6228.bin", body)
-                break
-            end
-            sys.wait(60 * 1000)
-        end
-    end
-    sys.wait(20)
-    -- "$AIDTIME,year,month,day,hour,minute,second,millisecond"
-    local date = os.date("!*t")
-    if date.year > 2022 then
-        local str = string.format("$AIDTIME,%d,%d,%d,%d,%d,%d,000", date["year"], date["month"], date["day"],
-            date["hour"], date["min"], date["sec"])
-        log.info("gnss", str)
-        uart.write(gps_uart_id, str .. "\r\n")
-        sys.wait(20)
-    end
-    -- 读取之前的位置信息
-    local gnssloc = io.readFile("/gnssloc")
-    if gnssloc then
-        str = "$AIDPOS," .. gnssloc
-        log.info("POS", str)
-        uart.write(gps_uart_id, str .. "\r\n")
-        str = nil
-        gnssloc = nil
-    else
-        -- TODO 发起基站定位
-        uart.write(gps_uart_id, "$AIDPOS,3432.70,N,10885.25,E,1.0\r\n")
-    end
-end
-
-function upload_stat(is_first)
-    -- if mqttc == nil or not mqttc:ready() then return end
-    local cell = mobile.getCellInfo()
-    local rmc = libgnss.getRmc(2)
-    local params = {}
-    if libgnss.isFix() then
-        params["GPS_Info"]  = {
-            longitude = rmc.lng,
-            latitude = rmc.lat
-        }
-    end
-    if is_first then
-        params["switch_1"] = fskv.get("SWITCH_1")
-        params["switch_2"] = fskv.get("SWITCH_2")
-        params.networkType = 5
-    end
-    if mqttc and mqttc:ready() then
-        local topic = "$thing/up/property/" .. qcloud_pid .. "/" .. qcloud_dev
-        local payload = json.encode({
-            method = "report",
-            clientToken = "0",
-            params = params
-        })
-        mqttc:publish(topic, payload, 1)
-    end
-end
-
-function on_downlink(topic, payload) 
-    local jdata = json.decode(payload)
-    if not jdata then
-        return
-    end
-    if jdata.method == "control" and jdata.params then
-        local changed = false
-        if jdata.params.switch_1 then
-            gpio.set(SWITCH_1, jdata.params.switch_1)
-            fskv.set("SWITCH_1", jdata.params.switch_1)
-            changed = true
-        end
-        if jdata.params.switch_2 then
-            gpio.set(SWITCH_2, jdata.params.switch_2)
-            fskv.set("SWITCH_2", jdata.params.switch_2)
-            changed = true
-        end
-
-        -- 回报结果
-        local topic = "$thing/up/property/" .. qcloud_pid .. "/" .. qcloud_dev
-        local payload = json.encode({
-            method = "report",
-            clientToken = jdata.clientToken,
-            params = jdata.params
-        })
-        mqttc:publish(topic, payload, 1)
-    end
-end
-
-sys.taskInit(function()
-    -- Air780EG默认波特率是115200
-    log.info("GPS", "start")
-    pm.power(pm.GPS, true)
-    -- 调试日志,可选
-    libgnss.debug(true)
-    sys.wait(200) -- GPNSS芯片启动需要时间,大概150ms
-    -- 绑定uart,底层自动处理GNSS数据
-    -- 这里延后到设置命令发送完成后才开始处理数据,之前的数据就不上传了
-    libgnss.bind(gps_uart_id)
-    log.debug("提醒", "室内无GNSS信号,定位不会成功, 要到空旷的室外,起码要看得到天空")
-    exec_agnss()
-end)
-
--- 订阅GNSS状态编码
-sys.subscribe("GNSS_STATE", function(event, ticks)
-    -- event取值有 
-    -- FIXED 定位成功
-    -- LOSE  定位丢失
-    -- ticks是事件发生的时间,一般可以忽略
-    local onoff = libgnss.isFix() and 1 or 0
-    log.info("GNSS", "LED", onoff)
-    gpio.set(LED_GNSS, onoff)
-    log.info("gnss", "state", event, ticks)
-    if event == "FIXED" then
-        local locStr = libgnss.locStr()
-        log.info("gnss", "locStr", locStr)
-        if locStr then
-            io.writeFile("/gnssloc", locStr)
-        end
-        upload_stat()
-    end
-end)
-
--- mqtt 上传任务
-sys.taskInit(function()
-    sys.waitUntil("IP_READY", 15000)
-    mqttc = mqtt.create(nil, qcloud_host, qcloud_port) -- mqtt客户端创建
-    sys.wait(500) -- 等一下网络时间
-
-    local client_id, user, passwd = iotauth.qcloud(qcloud_pid, qcloud_dev, qcloud_key)
-    log.info("params", qcloud_pid, qcloud_dev, qcloud_key)
-    log.info("ret", client_id, user, passwd)
-    mqttc:auth(client_id, user, passwd) -- mqtt三元组配置
-    log.info("mqtt", client_id, user, passwd)
-    mqttc:keepalive(300) -- 默认值240s
-    mqttc:autoreconn(true, 3000) -- 自动重连机制
-
-    mqttc:on(function(mqtt_client, event, data, payload) -- mqtt回调注册
-        -- 用户自定义代码,按event处理
-        -- log.info("mqtt", "event", event, mqtt_client, data, payload)
-        if event == "conack" then -- mqtt成功完成鉴权后的消息
-            sys.publish("mqtt_conack") -- 小写字母的topic均为自定义topic
-            -- 属性下发与属性上报响应
-            mqtt_client:subscribe("$thing/down/property/" .. qcloud_pid .. "/" .. qcloud_dev)
-            -- 事件上报响应
-            mqtt_client:subscribe("$thing/event/property/" .. qcloud_pid .. "/" .. qcloud_dev)
-            -- 应用调用设备行为
-            mqtt_client:subscribe("$thing/action/property/" .. qcloud_pid .. "/" .. qcloud_dev)
-            -- OTA 下行
-            mqtt_client:subscribe("$ota/update/" .. qcloud_pid .. "/" .. qcloud_dev)
-            -- 	RRPC消息下行
-            mqtt_client:subscribe("$rrpc/rxd/" .. qcloud_pid .. "/" .. qcloud_dev .. "/+")
-            -- 广播消息下行
-            mqtt_client:subscribe("$broadcast/rxd/" .. qcloud_pid .. "/" .. qcloud_dev .. "/+")
-            upload_stat(true)
-        elseif event == "recv" then -- 服务器下发的数据
-            log.info("mqtt", "downlink", "topic", data, "payload", payload)
-            on_downlink(data, payload)
-        elseif event == "sent" then -- publish成功后的事件
-            log.info("mqtt", "sent", "pkgid", data)
-        end
-    end)
-
-    -- 发起连接之后,mqtt库会自动维护链接,若连接断开,默认会自动重连
-    mqttc:connect()
-    sys.waitUntil("mqtt_conack")
-    log.info("mqtt连接成功")
-    sys.timerLoopStart(upload_stat, 6 * 1000)
-    while true do
-        sys.wait(60*1000)
-    end
-    mqttc:close()
-    mqttc = nil
-end)
-
-sys.taskInit(function()
-    while 1 do
-        sys.wait(3600 * 1000) -- 一小时检查一次
-        local fixed, time_fixed = libgnss.isFix()
-        if not fixed then
-            exec_agnss()
-        end
-    end
-end)
-
--- 低电压报警
-sys.taskInit(function()
-    while 1 do
-        local vbat = adc.get(adc.CH_VBAT)
-        -- log.info("vbat", vbat)
-        if vbat < 3400 then
-            gpio.set(LED_VBAT, 1)
-            sys.wait(100)
-            gpio.set(LED_VBAT, 0)
-            sys.wait(900)
-            -- TODO 上报低电压事件
-        else
-            sys.wait(1000)
-        end
-    end
-end)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 4
script/turnkey/air780eg_irtu_gps/README.md

@@ -1,4 +0,0 @@
-# Air780EG对接iRTU寻物
-
-看源码吧-_-
-

+ 0 - 209
script/turnkey/air780eg_irtu_gps/main.lua

@@ -1,209 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "irtu_gnss"
-VERSION = "1.0.1"
-
---[[
-这个demo名字含irtu,实际上没有使用iRTU.
-
-网站是: https://gps.nutz.cn/ 连上之后,输入IMEI并回车,就能看到当前坐标
-小程序的名字: iRTU寻物 打开后扫码模块上的二维码,就能显示当前位置和历史轨迹
-服务器源码: https://gitee.com/wendal/irtu-gps 里面的硬件和配置描述是Air800的,可以无视.
-
-本demo需要Air780EG及V1003固件, 2023-1-11之后编译的版本
-
-所需要的库文件,在 script/libs里面, 全部加入就可以了
-]]
-
--- sys库是标配
-local sys = require("sys")
-local sysplus = require("sysplus")
-local libnet = require("libnet")
-
-local gps_uart_id = 2
-
--- libgnss库初始化
-libgnss.clear() -- 清空数据,兼初始化
-
--- GNSS串口初始化
-uart.setup(gps_uart_id, 115200)
-
-function exec_agnss()
-    local url = "http://download.openluat.com/9501-xingli/HXXT_GPS_BDS_AGNSS_DATA.dat"
-    if http then
-        -- AGNSS 已调通
-        while 1 do
-            local code, headers, body = http.request("GET", url).wait()
-            log.info("gnss", "AGNSS", code, body and #body or 0)
-            if code == 200 and body and #body > 1024 then
-                for offset = 1, #body, 512 do
-                    log.info("gnss", "AGNSS", "write >>>", #body:sub(offset, offset + 511))
-                    uart.write(gps_uart_id, body:sub(offset, offset + 511))
-                    sys.wait(100) -- 等100ms反而更成功
-                end
-                -- sys.waitUntil("UART2_SEND", 1000)
-                io.writeFile("/6228.bin", body)
-                break
-            end
-            sys.wait(60 * 1000)
-        end
-    end
-    sys.wait(20)
-    -- "$AIDTIME,year,month,day,hour,minute,second,millisecond"
-    local date = os.date("!*t")
-    if date.year > 2022 then
-        local str = string.format("$AIDTIME,%d,%d,%d,%d,%d,%d,000", date["year"], date["month"], date["day"],
-            date["hour"], date["min"], date["sec"])
-        log.info("gnss", str)
-        uart.write(gps_uart_id, str .. "\r\n")
-        sys.wait(20)
-    end
-    -- 读取之前的位置信息
-    local gnssloc = io.readFile("/gnssloc")
-    if gnssloc then
-        str = "$AIDPOS," .. gnssloc
-        log.info("POS", str)
-        uart.write(gps_uart_id, str .. "\r\n")
-        str = nil
-        gnssloc = nil
-    else
-        uart.write(gps_uart_id, "$AIDPOS,3432.70,N,10885.25,E,1.0\r\n")
-    end
-end
-
-sys.taskInit(function()
-    -- Air780EG默认波特率是115200
-    log.info("GPS", "start")
-    pm.power(pm.GPS, true)
-    -- 调试日志,可选
-    libgnss.debug(true)
-    sys.wait(200) -- GPNSS芯片启动需要时间,大概150ms
-    -- 增加显示的语句,可选
-    uart.write(gps_uart_id, "$CFGMSG,0,1,1\r\n") -- GLL
-    sys.wait(20)
-    uart.write(gps_uart_id, "$CFGMSG,0,5,1\r\n") -- VTG
-    sys.wait(20)
-    uart.write(gps_uart_id, "$CFGMSG,0,6,1\r\n") -- ZDA
-    sys.wait(20)
-    -- 定位成功后,使用GNSS时间设置RTC
-    libgnss.rtcAuto(true)
-    
-    -- 绑定uart,底层自动处理GNSS数据
-    libgnss.bind(gps_uart_id)
-    exec_agnss()
-end)
-
--- 单纯定时打印一下定位信息
-sys.taskInit(function()
-    while 1 do
-        sys.wait(5000)
-        log.info("RMC", json.encode(libgnss.getRmc(4) or {}))
-    end
-end)
-
--- 订阅GNSS状态编码
-sys.subscribe("GNSS_STATE", function(event, ticks)
-    -- event取值有 
-    -- FIXED 定位成功
-    -- LOSE  定位丢失
-    -- ticks是事件发生的时间,一般可以忽略
-    log.info("gnss", "state", event, ticks)
-    if event == "FIXED" then
-        local locStr = libgnss.locStr()
-        log.info("gnss", "locStr", locStr)
-        if locStr then
-            -- 存入文件,方便下次AGNSS快速定位
-            io.writeFile("/gnssloc", locStr)
-        end
-    end
-end)
-
--- 对接服务器
-local taskName = "gnsstask"
-function gnsstask()
-    local tx_buff = zbuff.create(1024)
-	local rx_buff = zbuff.create(1024)
-	local netc 
-	local result, param, succ
-    local host, port = "gps.nutz.cn", 19002
-    local netc = socket.create(nil, taskName)
-	-- socket.debug(netc, true)
-	socket.config(netc, nil, nil, nil)
-    while 1 do
-        result = libnet.waitLink(taskName, 0, netc)
-		result = libnet.connect(taskName, 15000, netc, host, port)
-        local jdata = {
-            imei = mobile.imei(),
-            iccid = mobile.iccid()
-        }
-        if result then
-            local data = json.encode(jdata)
-			log.info("服务器连上了", "上报注册注册信息", data)
-			libnet.tx(taskName, 0, netc, data)
-		end
-        while result do
-			succ, param = socket.rx(netc, rx_buff)
-			if not succ then
-				log.info("服务器断开了", succ, param, host, port)
-				break
-			end
-			if rx_buff:used() > 0 then
-				log.info("收到服务器数据,长度", rx_buff:used())
-				rx_buff:del()
-			end
-			if rx_buff:len() > 1024 then
-				rx_buff:resize(1024)
-			end
-			log.info("sys", rtos.meminfo("sys"))
-			result, param = libnet.wait(taskName, 1000, netc)
-			if not result then
-				log.info("服务器断开了", result, param)
-				break
-			end
-
-            -- 发送数据包
-            local msg = {libgnss.isFix(), os.time()}
-            local rmc = libgnss.getRmc(1)
-            local gsa = libgnss.getGsa()
-            local vtg = libgnss.getVtg()
-            table.insert(msg, rmc.lng)
-            table.insert(msg, rmc.lat)
-            local gll = libgnss.getGll()
-            table.insert(msg, 0) -- altitude
-            table.insert(msg, 0) -- azimuth
-            table.insert(msg, (vtg and vtg.speed_kph) and vtg.speed_kph or 0) -- speed
-            table.insert(msg, 0) -- sateCno
-            table.insert(msg, 0) -- sateCnt
-            --jdata.msg = msg
-            local data = json.encode({msg=msg})
-            log.info("report", data)
-            if data then
-                libnet.tx(taskName, 0, netc, data)
-            end
-		end
-		d1Online = false
-		libnet.close(taskName, 5000, netc)
-		log.info("sys", rtos.meminfo("sys"))
-		sys.wait(1000)
-    end
-end
-
-local function netCB(msg)
-	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
-end
-sysplus.taskInitEx(gnsstask, "gnsstask", netCB)
-
-sys.taskInit(function()
-    while 1 do
-        sys.wait(3600 * 1000) -- 一小时检查一次
-        local fixed, time_fixed = libgnss.isFix()
-        if not fixed then
-            exec_agnss()
-        end
-    end
-end)
-
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 6
script/turnkey/eink-calendar/README.md

@@ -1,6 +0,0 @@
-# 电子墨水屏日历
-
-请使用V0004固件, 压缩包里有
-
-下载脚本前, 务必按`main.lua`内的提示, 修改wifi参数和密钥信息
-

+ 0 - 92
script/turnkey/eink-calendar/main.lua

@@ -1,92 +0,0 @@
-PROJECT = "wifidemo"
-VERSION = "1.0.0"
-
---测试支持硬件:ESP32C3
---测试固件版本:LuatOS-SoC_V0003_ESP32C3[_USB].soc
-
-local sys = require "sys"
-require("sysplus")
-
-
--- 兼容V1001固件的
-if http == nil and http2 then
-    http = http2
-end
-
---需要自行填写的东西
---wifi信息
-local wifiName,wifiPassword = "Xiaomi_AX6000","Air123456"
---地区id,请前往https://api.luatos.org/luatos-calendar/v1/check-city/ 查询自己所在位置的id
-local location = "101020100"
---天气接口信息,需要自己申请,具体参数请参考https://api.luatos.org/ 页面上的描述
-local appid,appsecret = "27548549","3wdKWuRZ"
-
-local function connectWifi()
-    log.info("wlan", "wlan_init:", wlan.init())
-
-    wlan.setMode(wlan.STATION)
-    wlan.connect(wifiName,wifiPassword,1)
-
-    -- 等待连上路由,此时还没获取到ip
-    result, _ = sys.waitUntil("WLAN_STA_CONNECTED")
-    log.info("wlan", "WLAN_STA_CONNECTED", result)
-    -- 等到成功获取ip就代表连上局域网了
-    result, data = sys.waitUntil("IP_READY")
-    log.info("wlan", "IP_READY", result, data)
-end
-
-local function requestHttp()
-    local code, headers, body = http.request("GET","http://apicn.luatos.org:23328/luatos-calendar/v1?mac=111&battery=10&location="..location.."&appid="..appid.."&appsecret="..appsecret).wait()
-    if code == 200 then
-        return body
-    else
-        log.info("http get failed",code, headers, body)
-        sys.wait(500)
-        return ""
-    end
-end
-
-function refresh()
-    log.info("refresh","start!")
-    local data
-    for i=1,5 do--重试最多五次
-        collectgarbage("collect")
-        data = requestHttp()
-        collectgarbage("collect")
-        if #data > 100 then
-            break
-        end
-        log.info("load fail","retry!")
-    end
-    if #data < 100 then
-        log.info("load fail","exit!")
-        return
-    end
-    collectgarbage("collect")
-    eink.model(eink.MODEL_1in54)
-    log.info("eink.setup",eink.setup(0, 2,11,10,6,7))
-    eink.setWin(200, 200, 2)
-    eink.clear(1)
-    log.info("eink", "end setup")
-    eink.drawXbm(0, 0, 200, 200, data)
-    -- 刷屏幕
-    eink.show()
-    eink.sleep()
-    log.info("refresh","done")
-end
-
-
-sys.taskInit(function()
-    --先连wifi
-    connectWifi()
-    while true do
-        refresh()
-        sys.wait(3600*1000)--一小时刷新一次吧
-    end
-end)
-
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 11
script/turnkey/eink-calendar/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/eink_calendar_wifi",
-    "tags" : ["turnkey", "esp32c3", "墨水屏", "wlan", "wifi"],
-    "version" : "1.0.0",
-    "title" : "墨水屏日历,esp32c3版本",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["wlan"]
-}

BIN
script/turnkey/lcd-0.96-lvgl/16_test_fonts.bin


+ 0 - 39
script/turnkey/lcd-0.96-lvgl/about.lua

@@ -1,39 +0,0 @@
-local about = {}
-
-local obj_list = nil--存放新建的对象
-
---显示这一页内容
-function about.show()
-    local w = lvgl.win_create(scr)
-    lvgl.win_set_title(w, "About")
-    local t = lvgl.label_create(w)
-    lvgl.label_set_text(t, 
-[[Air10x core screen
-press OK return
-by luatos]])
-    obj_list = {t,w}
-end
-
---卸载掉该页面
-function about.unload()
-    if not obj_list then return end
-    for i=1,#obj_list do
-        lvgl.obj_del(obj_list[i])
-    end
-    obj_list = nil
-end
-
---按键处理事件
-function about.keyCb(k)
-    if k == "O" then--回到主页
-        about.unload()
-        home.show()
-        key.setCb(home.keyCb)
-    elseif k == "L" or k =="U" then--左右滚动
-        lvgl.win_scroll_hor(obj_list[2],30)
-    elseif k == "R" or k =="D" then
-        lvgl.win_scroll_hor(obj_list[2],-30)
-    end
-end
-
-return about

+ 0 - 33
script/turnkey/lcd-0.96-lvgl/animation.lua

@@ -1,33 +0,0 @@
-local animation = {}
-
---新建一个动画
-function animation.create(obj,obj_fn,from,to,cb,duration,path)
-    local anim = lvgl.anim_create()
-    lvgl.anim_set_var(anim,obj)
-    lvgl.anim_set_exec_cb(anim, obj_fn)
-    lvgl.anim_set_values(anim, from, to)
-    lvgl.anim_set_time(anim, duration or 1000)
-    lvgl.anim_set_path_str(anim, path or "ease_in")
-    if cb then
-        lvgl.anim_set_ready_cb(anim, cb)
-    end
-    return anim
-end
-
-function animation.free(anim)
-    lvgl.anim_del(anim)
-end
-
---新建一个动画并立即运行,最后删除
-function animation.once(obj,obj_fn,from,to,cb,duration,path)
-    local anim = animation.create(obj,obj_fn,from,to,nil,duration,path)
-    lvgl.anim_set_ready_cb(anim, function()
-        animation.free(anim)
-        if cb then
-            cb()
-        end
-    end)
-    lvgl.anim_start(anim)
-end
-
-return animation

+ 0 - 88
script/turnkey/lcd-0.96-lvgl/device.lua

@@ -1,88 +0,0 @@
-local device
---硬件兼容层
-
---有人没适配pin库,我不说是谁
-if not pin then pin = {} end
-
---LuatOS-SoC_V0006_air101 长这样
-local chips = {
-    air101 = {
-        useFont = true,
-        spi = 0,
-        spiCS = pin.PB04,
-        spiSpeed = 20*1000*1000,
-        lcdDC = pin.PB01,
-        lcdRST = pin.PB03,
-        lcdBL = pin.PB00,
-        keyL = pin.PB11,
-        keyR = pin.PA7,
-        keyU = pin.PA1,
-        keyD = pin.PA0,
-        keyO = pin.PA4,
-    },
-    air105 = {
-        useFont = true,
-        spi = 5,
-        spiCS = pin.PC14,
-        spiSpeed = 48*1000*1000,
-        lcdDC = pin.PE8,
-        lcdRST = pin.PC12,
-        lcdBL = pin.PE9,
-        keyL = pin.PB4,
-        keyR = pin.PC7,
-        keyU = pin.PE6,
-        keyD = pin.PA10,
-        keyO = pin.PE7,
-    },
-    esp32c3 = {
-        useFont = false,
-        spi = 2,
-        spiCS = 7,
-        spiSpeed = 40*1000*1000,
-        lcdDC = 6,
-        lcdRST = 10,
-        lcdBL = 11,
-        keyL = 13,
-        keyR = 8,
-        keyU = 5,
-        keyD = 9,
-        keyO = 4,
-    },
-    ec618 = {
-        useFont = false,
-        spi = 0,
-        spiCS = 8,
-        spiSpeed = 20*1000*1000,
-        lcdDC = 10,
-        lcdRST = 1,
-        lcdBL = 22,
-        keyL = 0xff,
-        keyR = 0xff,
-        keyU = 12,
-        keyD = 0xff,
-        keyO = 11,
-    },
-    --别的看着加吧
-}
---这俩兼容
-chips.air103 = chips.air101
-
---获取固件版本
-local firmware = rtos.firmware and rtos.firmware() or rtos.get_version()
-firmware = firmware:lower()--全转成小写
-log.info("firmware",firmware)
-
---匹配上就返回
-for name,info in pairs(chips) do
-    if firmware:find(name) then
-        device = info
-        log.info("device","match",name)
-        break
-    end
-end
-
-if not device then log.error("警告!","无法为该模块匹配兼容文件") return end
-
-chips = nil--释放掉省点地方
-
-return device

+ 0 - 115
script/turnkey/lcd-0.96-lvgl/home.lua

@@ -1,115 +0,0 @@
-local home = {}
-
-local obj_list = nil--存放新建的对象
-local selected = 1--当前选中的按钮
-
---显示这一页内容
-function home.show()
-    local theme_btn = lvgl.btn_create(scr)
-    lvgl.obj_set_size(theme_btn,70,46)
-    lvgl.obj_set_x(theme_btn,5)
-    lvgl.obj_set_y(theme_btn,-50)
-    local theme_label = lvgl.label_create(theme_btn)
-    lvgl.label_set_text(theme_label, "theme")
-
-    local game_btn = lvgl.btn_create(scr)
-    lvgl.obj_set_size(game_btn,70,46)
-    lvgl.obj_set_x(game_btn,5)
-    lvgl.obj_set_y(game_btn,-50)
-    local game_label = lvgl.label_create(game_btn)
-    lvgl.label_set_text(game_label, "reboot")
-
-    local about_btn = lvgl.btn_create(scr)
-    lvgl.obj_set_size(about_btn,70,46)
-    lvgl.obj_set_x(about_btn,5)
-    lvgl.obj_set_y(about_btn,-50)
-    local about_label = lvgl.label_create(about_btn)
-    lvgl.label_set_text(about_label, "about")
-
-    if not obj_list then--新建的对象存起来,给以后销毁用
-        obj_list = {--按顺序存,偶数下标为按钮对象
-            theme_label,
-            theme_btn,
-            game_label,
-            game_btn,
-            about_label,
-            about_btn,
-        }
-    end
-
-    home.selectChange()--显示一下现在按下的按键
-
-    --来个动画
-    animation.once(theme_btn,lvgl.obj_set_y,-50,5,nil,900)
-    animation.once(game_btn,lvgl.obj_set_y,-50,56,nil,700)
-    animation.once(about_btn,lvgl.obj_set_y,-50,109,nil,500)
-end
-
---卸载掉该页面
-function home.unload()
-    if not obj_list then return end
-    for i=1,#obj_list do
-        lvgl.obj_del(obj_list[i])
-    end
-    obj_list = nil
-end
-
---更改选中的按钮
-function home.selectChange(n)
-    if not n then n = 0 end
-    --还没显示呢
-    if not obj_list then home.show() end
-    --现在选了哪个?
-    selected = selected + n
-    if selected > 3 then selected = 1 end
-    if selected < 1 then selected = 3 end
-    --设置每个按钮的状态
-    for i=2,#obj_list,2 do
-        if i/2 == selected then
-            lvgl.btn_set_state(obj_list[i],lvgl.BTN_STATE_PRESSED)
-        else
-            lvgl.btn_set_state(obj_list[i],lvgl.BTN_STATE_RELEASED)
-        end
-    end
-end
-
---主题控制和切换
-local themes = {"material_light","material_dark"}
-local themeNow = 1
-function home.changeTheme()
-    themeNow = themeNow + 1
-    if themeNow > #themes then themeNow = 1 end
-    lvgl.theme_set_act(themes[themeNow])
-end
-
---事件列表
-local keyList = {
-    U = function ()
-        home.selectChange(-1)
-    end,
-    D = function ()
-        home.selectChange(1)
-    end,
-    O = function ()
-        --todo
-        if selected == 1 then
-            home.changeTheme()
-        elseif selected == 2 then
-            rtos.reboot()
-        elseif selected == 3 then
-            home.unload()
-            about.show()
-            key.setCb(about.keyCb)
-        end
-    end,
-}
-keyList.L = keyList.U
-keyList.R = keyList.D
-
---按键处理事件
-function home.keyCb(k)
-    if keyList[k] then keyList[k]() end
-end
-
-
-return home

+ 0 - 31
script/turnkey/lcd-0.96-lvgl/key.lua

@@ -1,31 +0,0 @@
-local key = {}
-
-local cb = nil--按键回调函数
-
---设置回调
-function key.setCb(f)
-    cb = f
-end
-
---消抖处理
-local dt = 200--过滤时间:20ms
-local isLock = nil--按键锁
-
---按键回调
-function key.cb(k,p)
-    log.info("key",k,p,isLock,cb)
-    if not cb or not p or isLock then return end
-    cb(k)
-    isLock = true
-    sys.timerStart(function() isLock = false end,dt)
-end
-
---几个按键 左L 右R 上U 下D 确定O
-gpio.setup(device.keyL, function(p) key.cb("L",p==0) end, gpio.PULLUP)
-gpio.setup(device.keyR, function(p) key.cb("R",p==0) end, gpio.PULLUP)
-gpio.setup(device.keyU, function(p) key.cb("U",p==0) end, gpio.PULLUP)
-gpio.setup(device.keyD, function(p) key.cb("D",p==0) end, gpio.PULLUP)
-gpio.setup(device.keyO, function(p) key.cb("O",p==0) end, gpio.PULLUP)
-
-
-return key

+ 0 - 37
script/turnkey/lcd-0.96-lvgl/main.lua

@@ -1,37 +0,0 @@
-PROJECT="LVGL"
-VERSION="0.0.1"
-sys=require"sys"
-
-device = require"device"
-key = require"key"
-animation = require"animation"
-
--- HSPI 即 SPI5, 最高96M, 部分屏不支持, 所以这里写48M
-spi_lcd = spi.deviceSetup(device.spi,device.spiCS,0,0,8,device.spiSpeed,spi.MSB,1,1)
-lcd.init("st7735v",{port = "device",pin_dc=device.lcdDC,pin_rst=device.lcdRST,pin_pwr=device.lcdBL,direction = 2,w = 80,h = 160,xoffset = 24,yoffset = 0},spi_lcd)
-lcd.invoff()--这个屏可能需要反显
-
-log.info("lvgl", lvgl.init())
-
-scr = lvgl.obj_create(nil, nil)
-
-if device.useFont then
-    local font_16 = lvgl.font_load("/luadb/16_test_fonts.bin")
-    if not font_16 then
-        log.info("font error","font not found")
-    else
-        lvgl.obj_set_style_local_text_font(scr, lvgl.LABEL_PART_MAIN, lvgl.STATE_DEFAULT, font_16)
-    end
-end
-
-home = require"home"
-about = require"about"
-
-lvgl.scr_load(scr)
-
-
-home.show()
-key.setCb(home.keyCb)
-
-
-sys.run()

+ 0 - 6
script/turnkey/programmer/README.md

@@ -1,6 +0,0 @@
-# 离线烧录器
-
-当前能刷air101/air103, 可运行在支持uart库的所有平台
-
-详细配置请看 main.lua
-

+ 0 - 137
script/turnkey/programmer/air101.lua

@@ -1,137 +0,0 @@
-
-local air101 = {}
-local xmodem = require "xmodem"
-local sys = require "sys"
-
-local boot
-local rst
-local led
-
-local led_state = 1
-air101.download_state = false
-
-local information = {} --firm model app_version wifi_mac_str unique_id_str 
-
-local function led_loop()
-    led(led_state%2)
-    led_state = led_state+1
-end
-
-local function uart_cb(id, len)
-    local data = uart.read(id, len)
-    if #data>60 then
-        local i = 1
-        for s in string.gmatch(data, '(%g+)\r\n') do 
-            information[i]=s
-            i = i+1
-        end
-        sys.publish("download", information)
-    else
-        print(data)
-    end
-end
-
-local function air101_rst()
-    rst(0)
-    sys.wait(50)
-    rst(1)
-end
-
-local function air101_boot()
-    boot(0)
-    sys.wait(50)
-    air101_rst()
-    sys.wait(50)
-    boot(1)
-end
-
-function air101.download(pin_boot,pin_rst,uart_id,file_path,app_version,led_func)
-    if led_func then
-        led = led_func
-    end
-    boot= gpio.setup(pin_boot, 0,gpio.PULLUP)
-    rst= gpio.setup(pin_rst, 0,gpio.PULLUP)
-    boot(1)
-    rst(1)
-
-
-    sys.wait(100)
-    air101_rst()
-    sys.wait(100)
-
-    uart.setup(uart_id,9600)
-    uart.on(uart_id, "receive", uart_cb)
-    local timeid = sys.timerLoopStart(uart.write,100,uart_id,"ATI+\r\n")
-    local result, data = sys.waitUntil("download", 500)
-    sys.timerStop(timeid)
-    if result then print(information[3]) end
-
-    if result and information[3]~=app_version then
-        air101_boot()
-        local ledid
-        air101.download_state = true
-        if led then ledid = sys.timerLoopStart(led_loop,200) end
-        local ret = xmodem.send(uart_id,115200,file_path)
-        if led then sys.timerStop(ledid) end
-        air101.download_state = false
-        if ret then
-            air101_rst()
-
-            uart.setup(uart_id,9600)
-            uart.on(uart_id, "receive", uart_cb)
-            local timeid = sys.timerLoopStart(uart.write,100,uart_id,"ATI+\r\n")
-            local result, data = sys.waitUntil("download", 500)
-            sys.timerStop(timeid)
-            if result then print(information[3]) end
-            if result and information[3]==app_version then
-                if led then led(0) end
-                return true
-            else
-                if led then led(1) end
-                return false
-            end
-        else
-            if led then led(1) end
-            return false
-        end
-    elseif result and information[3]==app_version then
-        if led then led(0) end
-        return true
-    else
-        if led then led(1) end
-        return false
-    end
-end
-
-function air101.download_force(pin_boot,pin_rst,uart_id,file_path,app_version,led_func)
-
-    air101_boot()
-    local ledid
-    air101.download_state = true
-    if led then ledid = sys.timerLoopStart(led_loop,200) end
-    local ret = xmodem.send(uart_id,115200,file_path)
-    if led then sys.timerStop(ledid) end
-    air101.download_state = false
-    if ret then
-        air101_rst()
-
-        uart.setup(uart_id,9600)
-        uart.on(uart_id, "receive", uart_cb)
-        local timeid = sys.timerLoopStart(uart.write,100,uart_id,"ATI+\r\n")
-        local result, data = sys.waitUntil("download", 1000)
-        sys.timerStop(timeid)
-        if result then print(information[3]) end
-        if result and information[3]==app_version then
-            if led then led(0) end
-            return true
-        else
-            if led then led(1) end
-            return false
-        end
-    else
-        if led then led(1) end
-        return false
-    end
-end
-
-return air101

+ 0 - 30
script/turnkey/programmer/main.lua

@@ -1,30 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "download"
-VERSION = "1.0.0"
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-local sys = require "sys"
-
-local air101 = require "air101"
-
-gpio.setup(pin.PA10, function()
-    sys.publish("download_force")
-end, gpio.PULLUP,gpio.RISING)
-
-sys.taskInit(function()
-    led_func= gpio.setup(pin.PB03, 0,gpio.PULLUP)
-    led_func(1)
-    while 1 do
-        air101.download(pin.PB05,pin.PB02,1,"/luadb/AIR101.fls","1.0.8",led_func)
-        local result = sys.waitUntil("download_force", 1000)
-        if result and air101.download_state==false then
-            log.info("download_force")
-            air101.download_force(pin.PB05,pin.PB02,1,"/luadb/AIR101.fls","1.0.8",led_func)
-        end
-    end
-end)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 11
script/turnkey/programmer/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/offline_programmer",
-    "tags" : ["turnkey", "air101", "离线烧录器"],
-    "version" : "1.0.0",
-    "title" : "离线烧录器,当前支持对air101/air103刷机",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["uart"]
-}

+ 0 - 127
script/turnkey/programmer/xmodem.lua

@@ -1,127 +0,0 @@
---[[
-@module xmodem
-@summary xmodem 驱动
-@version 1.0
-@date    2022.06.01
-@author  Dozingfiretruck
-@usage
---注意:因使用了sys.wait()所有api需要在协程中使用
--- 用法实例
-local xmodem = require "xmodem"
-sys.taskInit(function()
-    xmodem.send(2,115200,"/luadb/test.bin")
-    while 1 do
-        sys.wait(1000)
-    end
-end)
-]]
-local xmodem = {}
-
-local sys = require "sys"
-
-local HEAD
-local DATA_SIZE 
-
-local SOH           =   0x01    -- Modem数据头 128
-local STX           =   0x02    -- Modem数据头 1K
-local EOT           =   0x04    -- 发送结束
-local ACK           =   0x06    -- 应答
-local NAK           =   0x15    -- 非应答
-local CAN           =   0x18    -- 取消发送
-local CTRLZ         =   0x1A    -- 填充
-local CRC_CHR       =   0x43    -- C: ASCII字符C
-local CRC_SIZE      =   2
-local FRAME_ID_SIZE =   2
-local DATA_SIZE_SOH =   128
-local DATA_SIZE_STX =   1024
-
-local function uart_cb(id, len)
-    local data = uart.read(id, len)
-    data = data:byte(1,1)
-    sys.publish("xmodem", data)
-end
-
---[[
-xmodem 发送文件
-@api xmodem.send(uart_id, uart_br, file_path,type)
-@number uart_id uart端口号
-@number uart_br uart波特率
-@string file_path 文件路径
-@bool type 1k/128 默认1k
-@return bool 发送结果
-@usage
-xmodem.send(2,115200,"/luadb/test.bin")
-]]
-
-function xmodem.send(uart_id, uart_br, file_path,type)
-    local ret, flen, cnt, crc
-
-    if type then
-        HEAD = SOH
-        DATA_SIZE = DATA_SIZE_SOH
-    else
-        HEAD = STX
-        DATA_SIZE = DATA_SIZE_STX
-    end
-    local XMODEM_SIZE = 1+FRAME_ID_SIZE+DATA_SIZE+CRC_SIZE
-    local packsn = 0
-    local xmodem_buff = zbuff.create(XMODEM_SIZE)
-    local data_buff = zbuff.create(DATA_SIZE)
-    local fd = io.open(file_path, "rb")
-    if fd then
-        uart.setup(uart_id,uart_br)
-        uart.on(uart_id, "receive", uart_cb)
-        local result, data = sys.waitUntil("xmodem", 120000)
-        if result and data == CRC_CHR then
-            cnt = 1
-            while true do
-                data_buff:set(0, CTRLZ)
-                ret, flen = fd:fill(data_buff,0,DATA_SIZE)
-                log.info("发送第", cnt, "包")
-                if flen > 0 then
-                    data_buff:seek(0)
-                    crc = crypto.crc16("XMODEM",data_buff)
-                    packsn = (packsn+1) & 0xff
-                    xmodem_buff[0] = 0x02
-                    xmodem_buff[1] = packsn
-                    xmodem_buff[2] = 0xff-xmodem_buff[1]
-                    data_buff:seek(DATA_SIZE)
-                    xmodem_buff:copy(3, data_buff)
-                    xmodem_buff[1027] = crc>>8
-                    xmodem_buff[1028] = crc&0xff
-                    xmodem_buff:seek(XMODEM_SIZE)
-                    log.info(xmodem_buff:used())
-                    :: RESEND ::
-                    uart.tx(uart_id, xmodem_buff)
-                    result, data = sys.waitUntil("xmodem", 10000)
-                    if result and data == ACK then
-                        cnt = cnt + 1
-                    elseif result and data == NAK then
-                        goto RESEND
-                    else
-                        log.info("发送失败")
-                        return false
-                    end
-                    if flen ~= DATA_SIZE then
-                        log.info("传输完毕")
-                        break
-                    end
-                else
-                    log.info("传输完毕")
-                    break
-                end
-            end
-            uart.write(uart_id, string.char(EOT))
-            fd:close()
-            return true
-        else
-            log.info("不支持",data) 
-            return false
-        end
-    else
-        log.info("no file") 
-        return false
-    end
-end
-
-return xmodem

+ 0 - 175
script/turnkey/qcloud100_switch/main.lua

@@ -1,175 +0,0 @@
---[[
-这个代码对应公众号文档 https://mp.weixin.qq.com/s/ST_8Uej8R7qLUsikfh3Xtw
-
-针对的硬件是 ESP32系列
-]]
-
-PROJECT = "qcloud100"
-VERSION = "1.0.0"
-
---测试支持硬件:ESP32C3/Air105/Air780E
-
-local sys = require "sys"
-require("sysplus")
-
---[[
-使用指南
-1. 登录腾讯云 https://cloud.tencent.com/ 扫码登录
-2. 访问物联网平台 https://console.cloud.tencent.com/iotexplorer
-3. 进入公共实例, 如果没有就开通
-4. 如果没有项目, 点"新建项目", 名字随意, 例如 luatos
-5. 这时,新项目就好出现在列表里, 点击进去
-6. 接下来, 点"新建产品", 产品名称随意(例如abc), 品类选自定义品类, 通信方式选4G或者Wifi,认证方式选择密钥认证,数据协议选物模型
-7. 左侧菜单, 选"设备管理", "添加设备", 产品选刚刚建好的, 输入一个英文的设备名称, 例如 abcdf, 确定后新设备出现在列表里
-8. 点击该设备的"查看", 就能看到详情的信息, 逐个填好
-9. 如果是wifi设备, 在当前文件搜索ssid,填好wifi名称和密码
-10. 接下来刷机, 不懂刷机就到 wiki.luatos.com 看视频
-
-补充说明, 物模型的设置:
-1. 左侧菜单, "产品开发", 然后点之前建好的项目
-2. 页面往下拉到底, 选择"新建自定义功能"
-3. 为了跑通这个本例子, 需要新建3个属性, 对着界面逐个添加
-   |功能类型|功能名称|标识符       |数据类型|取值范围    |
-   |属性    |LED灯   |power_switch|布尔型  |不用选     |
-   |属性    |电压    |vbat        |整型    | -1, 100000|
-   |属性    |温度    |temp        |整型    | -1, 100000|
-
-不要输入"|",那是分割符
-]]
-product_key = "K7NURKF5J3" -- 产品ID, 一串英文字母,填前面的双引号以内
-device_id = "abcdf" -- 设备名称, 一定要改成自己的数据
-device_secret = "ChhVXLtSPiTKFzGatB80Jw==" -- 设备密钥
-
-
-sub_topic = "$thing/down/property/" .. product_key .. "/".. device_id
-pub_topic = "$thing/up/property/" .. product_key .. "/".. device_id
-
-adc.open(adc.CH_VBAT)
-adc.open(adc.CH_CPU)
-
-function on_btn()
-    log.info("btn", "按键触发")
-    -- 按一次, 上报一次电压值
-    -- 格式参考 https://cloud.tencent.com/document/product/1081/34916
-    if mqttc and mqttc:ready() then
-        
-        local data = {
-            method = "report",
-            clientToken = "123",
-            params = {
-                vbat = adc.get(adc.CH_VBAT), -- 读取电压值
-                temp = adc.get(adc.CH_CPU)
-                -- 如果新建更多物模型的属性, 这里可以继续填,注意格式,尤其是逗号
-            }
-        }
-        local jdata = (json.encode(data))
-        log.info("准备上传数据", jdata)
-        -- 可以直接调用mqttc对象进行上报
-        -- mqttc:publish(pub_topic, (json.encode(data)), 1)
-        -- 也可以通过消息机制,传递到sys.waitUntil("mqtt_pub", 30000)语句进行间接上报
-        sys.publish("mqtt_pub", pub_topic, jdata, 1)
-    end
-end
-
-sys.taskInit(function()
-    -- 统一联网函数
-    if wlan and wlan.connect then -- ESP32系列, C3/S3都可以
-        if rtos.bsp():startsWith("ESP32") then
-            LED = gpio.setup(12, 0, gpio.PULLUP) -- 控制的灯对应的GPIO号
-            gpio.debounce(9, 100, 1)
-            BTN = gpio.setup(9, on_btn, gpio.PULLUP, gpio.FALLING) -- BOOT按键当按钮用
-        else
-            -- air101/air103,内测用
-            LED = gpio.setup(pin.PB09, 0, gpio.PULLUP) -- 控制的灯对应的GPIO号
-            gpio.debounce(pin.PA0, 100, 1)
-            BTN = gpio.setup(pin.PA0, on_btn, gpio.PULLUP, gpio.FALLING) -- BOOT按键当按钮用
-        end
-        wlan.init()
-        --
-        -- ESP32系列, 这里要填wifi的名称和密码. 只支持2.4G频段
-        --
-        local ssid, password = "luatos1234", "12341234"
-        wlan.setMode(wlan.STATION)
-        wlan.connect(ssid, password, 1)
-    elseif rtos.bsp() == "AIR105" then -- Air105走网卡,W5500
-        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
-        w5500.config() --默认是DHCP模式
-        w5500.bind(socket.ETH0)
-        -- LED = gpio.setup(62, 0, gpio.PULLUP)
-        gpio.debounce(pin.PA10, 100, 1)
-        BTN = gpio.setup(pin.PA10, on_btn, gpio.PULLUP, gpio.FALLING) -- BOOT按键当按钮用
-        sys.wait(1000)
-    elseif mobile then -- Air780E,走4G一堆网络
-        -- mobile.simid(2) -- 自动选卡, 如果不清楚在哪个卡槽,就取消注释
-        -- LED = gpio.setup(27, 0, gpio.PULLUP)
-        gpio.debounce(0, 100, 1)
-        BTN = gpio.setup(0, on_btn, gpio.PULLUP, gpio.FALLING) -- BOOT按键当按钮用
-    else
-        while 1 do 
-            sys.wait(1000)
-            log.info("bsp", "未支持的模块", rtos.bsp())
-        end
-    end
-    log.info("等待联网")
-    local result, data = sys.waitUntil("IP_READY")
-    log.info("wlan", "IP_READY", result, data)
-    log.info("联网成功")
-    sys.publish("net_ready")
-end)
-
-sys.taskInit(function()
-    sys.waitUntil("net_ready")
-    -- 往下就是连接到腾讯云了
-
-    local client_id, user_name, password = iotauth.qcloud(product_key, device_id, device_secret, "sha1")
-    log.info("mqtt参数", client_id, user_name, password)
-
-    -- MQTT参数准备好了,开始连接,并监听数据下发
-    mqttc = mqtt.create(nil, product_key .. ".iotcloud.tencentdevices.com", 1883)
-    mqttc:auth(client_id, user_name, password)
-    mqttc:keepalive(240) -- 默认值240s
-    mqttc:autoreconn(true, 3000) -- 自动重连机制
-    mqttc:on(
-        function(mqtt_client, event, data, payload)
-            if event == "conack"then
-                -- 连上了,鉴权也ok
-                sys.publish("mqtt_conack")
-                log.info("mqtt", "mqtt已连接")
-                mqtt_client:subscribe(sub_topic)
-            elseif event == "recv" then
-                log.info("mqtt", "收到消息", data, payload)
-                local json = json.decode(payload)
-                if json.method == "control" then
-                    if json.params.power_switch == 1 then
-                        LED(1)
-                    elseif json.params.power_switch == 0 then
-                        LED(0)
-                    end
-                end
-            elseif event == "sent"then
-                log.info("mqtt", "sent", "pkgid", data)
-            end
-        end
-    )
-    mqttc:connect()
-    --sys.wait(1000)
-    sys.waitUntil("mqtt_conack")
-    while true do
-        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 30000)    
-        if ret then
-            if topic == "close" then
-                break
-            end
-            mqttc:publish(topic, data, qos)
-        end
-    end
-    mqttc:close()
-    mqttc = nil
-end)
-
-
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 6
script/turnkey/remote_pc_poweron/README.md

@@ -1,6 +0,0 @@
-# PC远程开机棒(esp32c3版)
-
-适用于esp32c3
-
-请按main.lua 内的注释修改网络参数!!
-

+ 0 - 124
script/turnkey/remote_pc_poweron/main.lua

@@ -1,124 +0,0 @@
-PROJECT = "poweron_tool"
-VERSION = "1.0.0"
-
---测试支持硬件:ESP32C3
---测试固件版本:LuatOS-SoC_V0003_ESP32C3[_USB].soc
-
-sys = require "sys"
-
----------------------------------------------------------------------------
---这些东西改成自己用的
-local wifiName,wifiPassword = "wifi", "password"--wifi账号密码
-local pcIp =  "255.255.255.255"--目标pc ip,广播就255.255.255.255
-local pcMac = "112233445566" --写mac的hex值就行
---服务器使用介绍详见https://api.luatos.org/#poweron
-local mqttAddr = "mqtt://apicn.luatos.org:1883"--这是公共服务器,只允许订阅和推送poweron/request/+、poweron/reply/+两个主题
-local mqttUser,mqttPassword = "13xxxxxxxxx","888888"--你的erp账号和密码,连接mqtt服务器用,默认八个8 erp.openluat.com
-local subscribeTopic,subscribePayload = "poweron/request/chenxuuu","poweron"
-local replyTopic,replyPayload = "poweron/reply/chenxuuu","ok"
----------------------------------------------------------------------------
-
-connected = false
-
--- 开发板上的2个LED
-local LED_D4 = gpio.setup(12, 0)
-local LED_D5 = gpio.setup(13, 0)
-
-sys.taskInit(function()
-    while true do
-        if connected then
-            LED_D4(1)
-            sys.wait(1000)
-        else
-            LED_D4(0)
-            sys.wait(200)
-            LED_D4(1)
-            sys.wait(200)
-        end
-    end
-end)
-
-
-function wakeUp(mac)
-    log.info("socket", "begin socket")
-    local sock = socket.create(socket.UDP) -- udp
-    log.info("socket.bind", socket.bind(sock, "0.0.0.0", 23333)) --udp必须绑定端口
-    local err = socket.connect(sock, pcIp, 7)--你电脑ip
-    if err ~= 0 then log.info("socket", err) return end
-
-    mac = mac:fromHex()
-    local msg = string.rep(string.char(0xff),6)..string.rep(mac,16)
-    local len = socket.send(sock, msg)
-    log.info("socket", "sendlen", len)
-    socket.close(sock)
-    return len == #msg, len
-end
-
-sys.taskInit(function()
-    log.info("wlan", "wlan_init:",  wlan.init())
-    wlan.setMode(wlan.STATION)
-    wlan.connect(wifiName,wifiPassword)
-    -- 等到成功获取ip就代表连上局域网了
-    local result, data = sys.waitUntil("IP_READY")
-    log.info("wlan", "IP_READY", result, data)
-
-
-    local mqttc = espmqtt.init({
-        uri = mqttAddr,
-        client_id = (esp32.getmac():toHex()),
-        username = mqttUser,
-        password = mqttPassword,
-    })
-    log.info("mqttc", mqttc)
-    if mqttc then
-        log.info("mqttc", "what happen")
-        local ok, err = espmqtt.start(mqttc)
-        log.info("mqttc", "start", ok, err)
-        if ok then
-            connected = true
-            while 1 do
-                log.info("mqttc", "wait ESPMQTT_EVT 30s")
-                local result, c, ret, topic, data = sys.waitUntil("ESPMQTT_EVT", 30000)
-                log.info("mqttc", result, c, ret)
-                if result == false then
-                    -- 没消息, 没动静
-                    log.info("mqttc", "wait timeout")
-                elseif ret == espmqtt.EVENT_DISCONNECTED then--断线了
-                    log.info("mqttc", "disconnected!!!")
-                    break
-                elseif c == mqttc then
-                    -- 是当前mqtt客户端的消息, 处理之
-                    if ret == espmqtt.EVENT_CONNECTED then
-                        -- 连接成功, 通常就是定义一些topic
-                        espmqtt.subscribe(mqttc, subscribeTopic)
-                    elseif ret == espmqtt.EVENT_DATA then
-                        -- 服务器来消息了, 如果data很长(超过4kb), 可能会分多次接收, 导致topic为空字符串
-                        log.info("mqttc", topic, data)
-                        if data == subscribePayload then--收到payload信息是开机
-                            LED_D5(1)
-                            log.info("poweron","发送开机请求啦!")
-                            wakeUp(pcMac)
-                            espmqtt.publish(mqttc, replyTopic, replyPayload)--回一条
-                            LED_D5(0)
-                        end
-                    else
-                        -- qos > 0 的订阅信息有响应, 会进这个分支
-                        -- 默认情况下mqtt是自动重连的, 不需要用户关心
-                        log.info("mqttc", "event", ret)
-                    end
-                else
-                    log.info("mqttc", "not this mqttc")
-                end
-            end
-            connected = false
-        else
-            log.warn("mqttc", "bad start", err)
-        end
-        espmqtt.destroy(mqttc)
-        log.warn("reboot", "device will reboot")
-        rtos.reboot()
-    end
-end)
-
-
-sys.run()

+ 0 - 11
script/turnkey/remote_pc_poweron/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/esp32c3_remote_poweron",
-    "tags" : ["turnkey", "esp32c3", "远程开机棒"],
-    "version" : "1.0.0",
-    "title" : "PC远程开机棒, esp32c3版本",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["wlan"]
-}

+ 0 - 11
script/turnkey/scanner_air105/README.md

@@ -1,11 +0,0 @@
-# Air105扫码枪turnkey方案
-
-## 所需硬件
-
-* Core-Air105 
-* 配套的GC032A摄像头
-* USB TYPEC 数据线
-
-## 代码说明
-
-源码位于 src 目录

+ 0 - 11
script/turnkey/scanner_air105/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/scanner_air105",
-    "tags" : ["turnkey", "scanner", "air105", "扫码枪"],
-    "version" : "1.0.0",
-    "title" : "扫码枪方案,适用于Air105+配套的摄像头",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["camera", "usbapp"]
-}

+ 0 - 284
script/turnkey/scanner_air105/src/GC032A_InitReg_Gray.txt

@@ -1,284 +0,0 @@
-0xf3,0xff,
-0xf7,0x01,
-0xf8,0x03,
-0xf9,0xce,
-0xfa,0x00,
-0xfc,0x02,
-0xfe,0x02,
-0x81,0x03,
-0xfe,0x00,
-0x03,0x01,
-0x04,0xc2,
-0x05,0x01,
-0x06,0xc2,
-0x07,0x00,
-0x08,0x08,
-0x0a,0x04,
-0x0c,0x04,
-0x0d,0x01,
-0x0e,0xe8,
-0x0f,0x02,
-0x10,0x88,
-0x17,0x54,
-0x19,0x04,
-0x1a,0x0a,
-0x1f,0x40,
-0x20,0x30,
-0x2e,0x80,
-0x2f,0x2b,
-0x30,0x1a,
-0xfe,0x02,
-0x03,0x02,
-0x06,0x60,
-0x05,0xd7,
-0x12,0x89,
-0xfe,0x00,
-0x18,0x02,
-0xfe,0x02,
-0x40,0x22,
-0x45,0x00,
-0x46,0x00,
-0x49,0x20,
-0xfe,0x01,
-0x0a,0xc5,
-0x45,0x00,
-0xfe,0x00,
-0x40,0xff,
-0x41,0x25,
-0x42,0x83,
-0x43,0x10,
-0x46,0x26,
-0x49,0x03,
-0x4f,0x01,
-0xde,0x84,
-0xfe,0x02,
-0x22,0xf6,
-0xfe,0x01,
-0x12,0xa0,
-0x13,0x3a,
-0xc1,0x3c,
-0xc2,0x50,
-0xc3,0x00,
-0xc4,0x32,
-0xc5,0x24,
-0xc6,0x16,
-0xc7,0x08,
-0xc8,0x08,
-0xc9,0x00,
-0xca,0x20,
-0xdc,0x8a,
-0xdd,0xa0,
-0xde,0xa6,
-0xdf,0x75,
-0xfe,0x01,
-0x7c,0x09,
-0x65,0x00,
-0x7c,0x08,
-0x56,0xf4,
-0x66,0x0f,
-0x67,0x84,
-0x6b,0x80,
-0x6d,0x12,
-0x6e,0xb0,
-0x86,0x00,
-0x87,0x00,
-0x88,0x00,
-0x89,0x00,
-0x8a,0x00,
-0x8b,0x00,
-0x8c,0x00,
-0x8d,0x00,
-0x8e,0x00,
-0x8f,0x00,
-0x90,0xef,
-0x91,0xe1,
-0x92,0x0c,
-0x93,0xef,
-0x94,0x65,
-0x95,0x1f,
-0x96,0x0c,
-0x97,0x2d,
-0x98,0x20,
-0x99,0xaa,
-0x9a,0x3f,
-0x9b,0x2c,
-0x9c,0x5f,
-0x9d,0x3e,
-0x9e,0xaa,
-0x9f,0x67,
-0xa0,0x60,
-0xa1,0x00,
-0xa2,0x00,
-0xa3,0x0a,
-0xa4,0xb6,
-0xa5,0xac,
-0xa6,0xc1,
-0xa7,0xac,
-0xa8,0x55,
-0xa9,0xc3,
-0xaa,0xa4,
-0xab,0xba,
-0xac,0xa8,
-0xad,0x55,
-0xae,0xc8,
-0xaf,0xb9,
-0xb0,0xd4,
-0xb1,0xc3,
-0xb2,0x55,
-0xb3,0xd8,
-0xb4,0xce,
-0xb5,0x00,
-0xb6,0x00,
-0xb7,0x05,
-0xb8,0xd6,
-0xb9,0x8c,
-0xfe,0x01,
-0xd0,0x40,
-0xd1,0xf8,
-0xd2,0x00,
-0xd3,0xfa,
-0xd4,0x45,
-0xd5,0x02,
-0xd6,0x30,
-0xd7,0xfa,
-0xd8,0x08,
-0xd9,0x08,
-0xda,0x58,
-0xdb,0x02,
-0xfe,0x00,
-0xfe,0x00,
-0xba,0x00,
-0xbb,0x04,
-0xbc,0x0a,
-0xbd,0x0e,
-0xbe,0x22,
-0xbf,0x30,
-0xc0,0x3d,
-0xc1,0x4a,
-0xc2,0x5d,
-0xc3,0x6b,
-0xc4,0x7a,
-0xc5,0x85,
-0xc6,0x90,
-0xc7,0xa5,
-0xc8,0xb5,
-0xc9,0xc2,
-0xca,0xcc,
-0xcb,0xd5,
-0xcc,0xde,
-0xcd,0xea,
-0xce,0xf5,
-0xcf,0xff,
-0xfe,0x00,
-0x5a,0x08,
-0x5b,0x0f,
-0x5c,0x15,
-0x5d,0x1c,
-0x5e,0x28,
-0x5f,0x36,
-0x60,0x45,
-0x61,0x51,
-0x62,0x6a,
-0x63,0x7d,
-0x64,0x8d,
-0x65,0x98,
-0x66,0xa2,
-0x67,0xb5,
-0x68,0xc3,
-0x69,0xcd,
-0x6a,0xd4,
-0x6b,0xdc,
-0x6c,0xe3,
-0x6d,0xf0,
-0x6e,0xf9,
-0x6f,0xff,
-0xfe,0x00,
-0x70,0x50,
-0xfe,0x00,
-0x4f,0x01,
-0xfe,0x01,
-0x44,0x04,
-0x1f,0x30,
-0x20,0x40,
-0x26,0x9a,
-0x27,0x02,
-0x28,0x0d,
-0x29,0x02,
-0x2a,0x0d,
-0x2b,0x02,
-0x2c,0x58,
-0x2d,0x07,
-0x2e,0xd2,
-0x2f,0x0b,
-0x30,0x6e,
-0x31,0x0e,
-0x32,0x70,
-0x33,0x12,
-0x34,0x0c,
-0x3c,0x20,
-0x3e,0x20,
-0x3f,0x2d,
-0x40,0x40,
-0x41,0x5b,
-0x42,0x82,
-0x43,0xb7,
-0x04,0x0a,
-0x02,0x79,
-0x03,0xc0,
-0xcc,0x08,
-0xcd,0x08,
-0xce,0xa4,
-0xcf,0xec,
-0xfe,0x00,
-0x81,0xb8,
-0x82,0x12,
-0x83,0x0a,
-0x84,0x01,
-0x86,0x25,
-0x87,0x18,
-0x88,0x10,
-0x89,0x70,
-0x8a,0x20,
-0x8b,0x10,
-0x8c,0x08,
-0x8d,0x0a,
-0xfe,0x00,
-0x8f,0xaa,
-0x90,0x9c,
-0x91,0x52,
-0x92,0x03,
-0x93,0x03,
-0x94,0x08,
-0x95,0x44,
-0x97,0x00,
-0x98,0x00,
-0xfe,0x00,
-0xa1,0x30,
-0xa2,0x41,
-0xa4,0x30,
-0xa5,0x20,
-0xaa,0x30,
-0xac,0x32,
-0xfe,0x00,
-0xd1,0x3c,
-0xd2,0x3c,
-0xd3,0x38,
-0xd6,0xf4,
-0xd7,0x1d,
-0xdd,0x73,
-0xde,0x84,
-0xfe,0x01,
-0x13,0x20,
-0xfe,0x00,
-0x4f,0x00,
-0x03,0x00,
-0x04,0xa0,
-0x71,0x60,
-0x72,0x40,
-0x42,0x80,
-0x77,0x64,
-0x78,0x40,
-0x79,0x60,
-0xfe,0x00,
-0x44,0x90,
-0x46,0x0f,

+ 0 - 97
script/turnkey/scanner_air105/src/main.lua

@@ -1,97 +0,0 @@
-
-
-PROJECT = "scanner"
-VERSION = "1.0.0"
-
-sys = require("sys")
-
---[[
--- LCD接法示例, 以Air105开发板的HSPI为例
-LCD管脚       Air105管脚
-GND          GND
-VCC          3.3V
-SCL          (PC15/HSPI_SCK)
-SDA          (PC13/HSPI_MOSI)
-RES          (PC12/HSPI_MISO)
-DC           (PE08) --开发板上的U3_RX
-CS           (PC14/HSPI_CS)
-BL           (PE09) --开发板上的U3_TX
-
-
-提示:
-1. 只使用SPI的时钟线(SCK)和数据输出线(MOSI), 其他均为GPIO脚
-2. 数据输入(MISO)和片选(CS), 虽然是SPI, 但已复用为GPIO, 并非固定,是可以自由修改成其他脚
-]]
-
-if wdt then
-    wdt.init(15000)--初始化watchdog设置为15s
-    sys.timerLoopStart(wdt.feed, 10000)--10s喂一次狗
-end
-
-spi_lcd = spi.deviceSetup(5,pin.PC14,0,0,8,48*1000*1000,spi.MSB,1,1)
-
--- log.info("lcd.init",
--- lcd.init("st7735s",{port = "device",pin_dc = pin.PE08 ,pin_rst = pin.PC12,pin_pwr = pin.PE09,direction = 2,w = 160,h = 80,xoffset = 1,yoffset = 26},spi_lcd))
-
--- log.info("lcd.init",
--- lcd.init("st7789",{port = "device",pin_dc = pin.PE08 ,pin_rst = pin.PC12,pin_pwr = pin.PE09,direction = 0,w = 240,h = 320,xoffset = 0,yoffset = 0},spi_lcd))
-
-log.info("lcd.init",
-lcd.init("st7735",{port = "device",pin_dc = pin.PE08 ,pin_rst = pin.PC12,pin_pwr = pin.PE09,direction = 0,w = 128,h = 160,xoffset = 0,yoffset = 0},spi_lcd))
-
--- log.info("lcd.init",
--- lcd.init("gc9306x",{port = "device",pin_dc = pin.PE08 ,pin_rst = pin.PC12,pin_pwr = pin.PE09,direction = 0,w = 240,h = 320,xoffset = 0,yoffset = 0},spi_lcd))
-
---GC032A输出灰度图像初始化命令
-local GC032A_InitReg_Gray =
-{
-	zbar_scan = 1,--是否为扫码
-    draw_lcd = 1,--是否向lcd输出
-    i2c_id = 0,
-	i2c_addr = 0x21,
-    pwm_id = 5;
-    pwm_period  = 24*1000*1000,
-    pwm_pulse = 0,
-	sensor_width = 640,
-	sensor_height = 480,
-    color_bit = 16,
-	init_cmd ="/luadb/GC032A_InitReg_Gray.txt"--此方法将初始化指令写在外部文件,支持使用 # 进行注释
-}
-
---注册摄像头事件回调
-local tick_scan = 0
-
-camera.on(0, "scanned", function(id, str)
-    if type(str) == 'string' then
-        log.info("扫码结果", str)
-        -- air105每次扫码仅需200ms, 当目标一维码或二维码持续被识别, 本函数会反复触发
-        -- 鉴于某些场景需要间隔时间输出, 下列代码就是演示间隔输出
-        -- if mcu.ticks() - tick < 1000 then
-        --     return
-        -- end
-        -- tick_scan = mcu.ticks()
-        -- 输出内容可以经过加工后输出, 例如带上换行(回车键)
-        usbapp.vhid_upload(0, str.."\r\n")
-        
-    elseif str == false then
-        log.error("摄像头没有数据")
-    end
-end)
-
-local camera_pwdn = gpio.setup(pin.PD06, 1, gpio.PULLUP) -- PD06 camera_pwdn引脚
-local camera_rst = gpio.setup(pin.PD07, 1, gpio.PULLUP) -- PD07 camera_rst引脚
-
-usbapp.start(0)
-
-sys.taskInit(function()
-    camera_rst(0)
-    local camera_id = camera.init(GC032A_InitReg_Gray)--屏幕输出灰度图像并扫码
-
-    log.info("摄像头启动")
-    camera.start(camera_id)--开始指定的camera
-end)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 12
script/turnkey/thermal_imaging/README.md

@@ -1,12 +0,0 @@
-# 热成像
-
-使用mlx90640实现的热成像,适用于air101/air103/air105/esp32-c3.
-
-## 关于固件
-
-云编译自行定制
-
-https://wiki.luatos.com/develop/compile/Cloud_compilation.html
-
-
-

+ 0 - 86
script/turnkey/thermal_imaging/main.lua

@@ -1,86 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "thermal_imaging"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-local sys = require "sys"
-
---[[
--- LCD接法示例, 以Air105开发板的HSPI为例
-LCD管脚       Air105管脚
-GND          GND
-VCC          3.3V
-SCL          (PC15/HSPI_SCK)
-SDA          (PC13/HSPI_MOSI)
-RES          (PC12/HSPI_MISO)
-DC           (PE08) --开发板上的U3_RX
-CS           (PC14/HSPI_CS)
-BL           (PE09) --开发板上的U3_TX
-
-
-提示:
-1. 只使用SPI的时钟线(SCK)和数据输出线(MOSI), 其他均为GPIO脚
-2. 数据输入(MISO)和片选(CS), 虽然是SPI, 但已复用为GPIO, 并非固定,是可以自由修改成其他脚
-]]
-
-local rtos_bsp = rtos.bsp():lower()
-if rtos_bsp=="air101" or rtos_bsp=="air103" then
-    mcu.setClk(240)
-    spi_lcd = spi.deviceSetup(0,pin.PB04,0,0,8,20*1000*1000,spi.MSB,1,0)
-    lcd.init("st7735",{port = "device",pin_dc = pin.PB01, pin_pwr = pin.PB00, pin_rst = pin.PB03,direction = 3,w = 160,h = 128,xoffset = 1,yoffset = 2},spi_lcd)
-elseif rtos_bsp=="air105" then
-    spi_lcd = spi.deviceSetup(5,pin.PC14,0,0,8,48*1000*1000,spi.MSB,1,0)
-    lcd.init("st7735",{port = "device",pin_dc = pin.PE08 ,pin_rst = pin.PC12,pin_pwr = pin.PE09,direction = 3,w = 160,h = 128,xoffset = 1,yoffset = 2},spi_lcd)
-    lcd.setupBuff()
-    lcd.autoFlush(false)
-elseif rtos_bsp=="esp32c3" then
-    spi_lcd = spi.deviceSetup(2, 7, 0, 0, 8, 40000000, spi.MSB, 1, 0)
-    lcd.init("st7735",{port = "device",pin_dc = 6, pin_pwr = 11,pin_rst = 10,direction = 3,w = 160,h = 128,xoffset = 1,yoffset = 2},spi_lcd)
-end
-
-lcd.clear(0x0000)
-
-sys.taskInit(function()
-    local skew_x = 16
-    local skew_y = 16
-    local fold = 4
-    if mlx90640.init(0,i2c.FAST,mlx90640.FPS4HZ) then
-        log.info("mlx90640", "init ok")
-        sys.wait(500) -- 稍等片刻
-        while 1 do
-            local temp_max = {temp = 0,x = 0,y = 0}
-            mlx90640.feed() -- 取一帧数据
-            local temp,index = mlx90640.max_temp()
-            mlx90640.draw2lcd(skew_x, skew_y, fold)
-            temp_max.temp = math.floor(temp)
-            temp_max.x = (index%32)*fold+skew_x
-            temp_max.y = (math.floor (index/32))*fold+skew_y
-            if temp_max.x-fold<skew_x then
-                temp_max.x = skew_x+fold
-            elseif temp_max.x+fold>32*fold+skew_x then
-                temp_max.x = 32*fold+skew_x-fold
-            end
-            if temp_max.y-fold<skew_y then
-                temp_max.y = skew_y+fold
-            elseif temp_max.y+fold>24*fold+skew_y then
-                temp_max.y = 24*fold+skew_y-fold
-            end
-            lcd.drawCircle(temp_max.x,temp_max.y,fold/2,0x001F)
-
-            lcd.drawStr(temp_max.x,temp_max.y,temp_max.temp)
-            if rtos_bsp=="air105" then lcd.flush() end
-            sys.wait(100)
-        end
-    else
-        log.info("mlx90640", "init fail")
-    end
-end)
-
-
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 11
script/turnkey/thermal_imaging/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/thermal_imaging",
-    "tags" : ["turnkey", "mlx90640", "air101", "air103", "air105","esp32-c3","热成像"],
-    "version" : "1.0.0",
-    "title" : "热成像,适用于air101/air103/air105/esp32-c3",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["mlx90640"]
-}

+ 0 - 191
script/turnkey/web_audio/audio_play.lua

@@ -1,191 +0,0 @@
-
---[[
-本demo当前仅支持Ar780E和Air600E
-## 提醒:
-1. 本demo需要2022.12.21及之后的源码所编译的LuatOS固件
-2. 本demo若使用外置TTS资源的LuatOS固件, 就必须有外挂的SPI Flash, 起码1M字节, 后面有刷写说明
-3. 下载脚本时, 把txt也加上一起下载
-4. 本demo需要音频扩展板, 780E只有I2S输出, 需要codec和PA才能驱动喇叭
-5. 内置TTS资源的LuatOS最低版本是V1104,且去掉了很多库, 尤其是UI方面的库
-
-## 使用本demo前,如果是外置TTS资源的LuatOS固件, 必须先刷tts.binpkg进行SPI Flash的刷写
-1. 下载链接 https://gitee.com/openLuat/luatos-soc-2022/attach_files
-2. 在LuaTools主界面, 用"下载固件"按钮进行下载.
-3. 下载前需要接好SPI Flash!!
-4. 下载前选日志模式 4G USB, luatools版本号2.1.85或以上
-
-## SPI Flash布局, 以1M字节为例,供参考:
-
------------------------------------
-64 k 保留空间, 用户自行分配
------------------------------------
-704k TTS数据
------------------------------------
-剩余空间, 256k,用户自行分配
------------------------------------
-
-## 基本流程:
-1. 初始化sfud, 本demo使用SPI0 + GPIO8
-2. 使用 audio.tts播放文本
-3. 等待 播放结束事件
-4. 从第二步重新下一个循环
-
-## 接线说明
-
-以780E开发板为例, 需要1.5版本或以上,团购版本均为1.5或以上.
-1.4版本SPI分布有所不同, 注意区分.
-
-https://wiki.luatos.com/chips/air780e/board.html
-
- xx脚指开发板pinout图上的顺序编号, 非GPIO编号
-
-Flash -- 开发板
-GND   -- 16脚, GND
-VCC   -- 15脚, 3.3V
-CLK   -- 14脚, GPIO11/SPI0_CLK/LCD_CLK, 时钟. 如果是1.4版本的开发板, 接05脚的GPIO11/UART2_TXD
-MOSI  -- 13脚, GPIO09/SPI0_MOSI/LCD_OUT,主控数据输出
-MISO  -- 11脚, GPIO10/SPI0_MISO/LCD_RS,主控数据输入. 如果是1.4版本的开发板, 接06脚的GPIO10/UART2_RXD
-CS    -- 10脚, GPIO08/SPI0_CS/LCD_CS,片选.
-
-注意: 12脚是跳过的, 接线完毕后请检查好再通电!!
-]]
-
-local taskName = "task_audio"
-local MSG_MD = "moreData" -- 播放缓存有空余
-local MSG_PD = "playDone" -- 播放完成所有数据
-
-audio.on(0, function(id, event)
-    -- 使用play来播放文件时只有播放完成回调
-    local succ, stop, file_cnt = audio.getError(0)
-    if not succ then
-        if stop then
-            log.info("用户停止播放")
-        else
-            log.info("第", file_cnt, "个文件解码失败")
-        end
-    end
-    sysplus.sendMsg(taskName, MSG_PD)
-end)
-
-local function audio_task()
-    --Air780E开发板配套+音频扩展板. ES7149
-    --由于音频扩展板的PA是长供电的,有塔塔声音是正常的,做产品的话有额外的参考设计
-    i2s.setup(0, 0, 0, 0, 0, i2s.MODE_I2S)
-
-    --如果用TM8211,打开下面的注释
-    -- i2s.setup(0, 0, 0, 0, 0, i2s.MODE_MSB)
-
-    --如果用软件DAC,打开下面的注释
-    -- if audio.setBus then
-    --     audio.setBus(audio.BUS_SOFT_DAC)
-    -- end
-    audio.config(0, 25, 1, 6, 200)
-    gpio.setup(24, 0)
-    gpio.setup(23, 0)
-    gpio.setup(27, 0)
-    gpio.setup(2, 0)
-
-    -- 初始化spi flash, 如果是极限版TTS_ONCHIP,就不需要初始化
-    -- if sfud then
-    --     spi_flash = spi.deviceSetup(0,8,0,0,8,25600000,spi.MSB,1,0)
-    --     local ret = sfud.init(spi_flash)
-    --     if ret then
-    --         log.info("sfud.init ok")
-    --     else
-    --         log.info("sfud.init error", ret)
-    --         return
-    --     end
-    -- end
-
-    log.info("开始播放音频")
-    result = audio.play(0, {"/audio.mp3"})
-    if result then
-        -- 等待音频通道的回调消息,或者切换歌曲的消息
-        while true do
-            msg = sysplus.waitMsg(taskName, nil)
-            if type(msg) == 'table' then
-                if msg[1] == MSG_PD then
-                    log.info("音频播放结束")
-                    sys.publish("audio_end")
-                    break
-                end
-            else
-                log.error(type(msg), msg)
-            end
-        end
-    else
-        log.debug("解码失败!")
-        sys.wait(1000)
-    end
-    if not audio.isEnd(0) then
-        log.info("手动关闭")
-        audio.playStop(0)
-    end
-    -- sys.wait(1000)
-    sysplus.taskDel(taskName)
-end
-
-
-local function tts_task()
-    --Air780E开发板配套+音频扩展板. ES7149
-    --由于音频扩展板的PA是长供电的,有塔塔声音是正常的,做产品的话有额外的参考设计
-    i2s.setup(0, 0, 0, 0, 0, i2s.MODE_I2S)
-
-    --如果用TM8211,打开下面的注释
-    -- i2s.setup(0, 0, 0, 0, 0, i2s.MODE_MSB)
-
-
-    --如果用软件DAC,打开下面的注释。  注意此功能适配pwm音频播放开发板,由于MP3文件是32K现在PWM还不支持,播出来的声音会比较慢
-    -- if audio.setBus then
-    --     audio.setBus(audio.BUS_SOFT_DAC)
-    -- end
-
-    audio.config(0, 25, 1, 6, 200)
-    gpio.setup(24, 0)
-    gpio.setup(23, 0)
-    gpio.setup(27, 0)
-    gpio.setup(2, 0)
-    -- 初始化spi flash, 如果是极限版TTS_ONCHIP,就不需要初始化,
-    -- if sfud then
-    --     spi_flash = spi.deviceSetup(0,8,0,0,8,25600000,spi.MSB,1,0)
-    --     local ret = sfud.init(spi_flash)
-    --     if ret then
-    --         log.info("sfud.init ok")
-    --     else
-    --         log.info("sfud.init error", ret)
-    --         return
-    --     end
-    -- end
-
-    log.info("开始播放TTS")
-    local result, data = sys.waitUntil("TTS_msg")
-    result = audio.tts(0, data)
-    if result then
-        -- 等待音频通道的回调消息,或者切换歌曲的消息
-        while true do
-            msg = sysplus.waitMsg(taskName, nil)
-            if type(msg) == 'table' then
-                if msg[1] == MSG_PD then
-                    log.info("TTS播放结束")
-                    sys.publish("audio_end")
-                    break
-                end
-            else
-                log.error(type(msg), msg)
-            end
-        end
-    else
-        log.debug("解码失败!")
-        sys.wait(1000)
-    end
-    if not audio.isEnd(0) then
-        log.info("手动关闭")
-        audio.playStop(0)
-    end
-    -- sys.wait(1000)
-    sysplus.taskDel(taskName)
-end
-sys.subscribe("Audio_msg",function() sysplus.taskInitEx(audio_task, taskName, task_cb) end)
-
-sys.subscribe("TTS_msg",function() sysplus.taskInitEx(tts_task, taskName, task_cb) end)
-

+ 0 - 159
script/turnkey/web_audio/main.lua

@@ -1,159 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "web_audio"
-VERSION = "1.0.0"
-
---[[
-    如果没有外挂spi flash,就选用后缀是不带外挂flash的固件;
-    如果外挂了spi flash,就选用后缀是带外挂flash的固件。
-    区别:不带外部flash的版本,因为内存空间小,删除了大部分功能,仅供测试web_audio使用
-	    带外部flash的版本功能齐全,和官方发布的固件功能相同。
-        固件地址:https://gitee.com/openLuat/LuatOS/attach_files/1342571/download
-]]
-
--- sys库是标配
-_G.sys = require("sys")
---[[特别注意, 使用mqtt库需要下列语句]]
-_G.sysplus = require("sysplus")
-require "audio_play"
--- 根据自己的服务器修改以下参数
-local mqtt_host = "lbsmqtt.airm2m.com"
-local mqtt_port = 1883
-local mqtt_isssl = false
-local client_id = mcu.unique_id():toHex()
-local user_name = "username"
-local password = "password"
-
-local mqttc = nil
-
--- ************************云端音频MQTT 负载消息类型***************************************
--- 0---4字节大端文字长度--文字的gbk编码--1--4字节大端音频url长度--url的gbk编码
--- 0表示后面是普通文字。1表示后面是音频。两种任意组合。长度是后面编码的长度
--- ************************云端音频MQTT 负载消息类型***************************************
--- ************************HTTP         音频下载处理**************************************
-
---- gb2312编码 转化为 utf8编码
--- @string gb2312s gb2312编码数据
--- @return string data,utf8编码数据
--- @usage local data = common.gb2312ToUtf8(gb2312s)
-function gb2312ToUtf8(gb2312s)
-    local cd = iconv.open("ucs2", "gb2312")
-    local ucs2s = cd:iconv(gb2312s)
-    cd = iconv.open("utf8", "ucs2")
-    return cd:iconv(ucs2s)
-end
-
-sys.subscribe("payload_msg", function()
-    sys.taskInit(function()
-        local result, data = sys.waitUntil("payload_msg")
-        payload_table, payload_table_len = {}, 0
-        local pbuff = zbuff.create(10240)
-        local plen = pbuff:write(data)
-        for i = 0, plen - 1, 1 do
-            if pbuff[i] == 0 or pbuff[i] == 1 then
-                if pbuff[i + 1] == 0 and pbuff[i + 2] == 0 and pbuff[i + 3] == 0 then
-                    log.info("111")
-                    payload_table[payload_table_len] = pbuff[i]
-                    payload_table_len = payload_table_len + 1
-                    payload_table[payload_table_len] = pbuff[i + 4]
-                    payload_table_len = payload_table_len + 1
-                    local a = pbuff[i + 4]
-                    local s = pbuff:toStr(i + 5, a)
-                    log.info("s", s)
-                    payload_table[payload_table_len] = s
-                    log.info("payload_table[payload_table_len]",
-                             payload_table[payload_table_len])
-                    payload_table_len = payload_table_len + 1
-                end
-            end
-            --log.info("测试", pbuff[i], i)
-        end
-        log.info("payload_table_len", payload_table_len)
-        for i = 0, payload_table_len, 3 do
-            if i ~= 0 then sys.waitUntil("audio_end") end
-            if payload_table[i] == 0 then -- tts播放
-                local ttstext = payload_table[i + 2]
-                log.info("音频", gb2312ToUtf8(ttstext))
-                sys.publish("TTS_msg", gb2312ToUtf8(ttstext))
-            elseif payload_table[i] == 1 then -- 音频文件播放
-                local url = tostring(payload_table[i + 2])
-                log.info("url", url)
-                sys.publish("HTTP_msg", url)
-            end
-
-        end
-    end)
-end)
-
-sys.taskInit(function()
-    sys.wait(1000)
-    LED = gpio.setup(27, 0, gpio.PULLUP)
-    device_id = mobile.imei()
-    local result= sys.waitUntil("IP_READY", 30000)
-    if not result then
-        log.info("网络连接失败")
-    end
-    mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
-    mqttc:auth(client_id, user_name, password) -- client_id必填,其余选填
-    mqttc:keepalive(30) -- 默认值240s
-    mqttc:autoreconn(true, 3000) -- 自动重连机制
-
-    mqttc:on(function(mqtt_client, event, data, payload)
-        -- 用户自定义代码
-        log.info("mqtt", "event", event, mqtt_client, data, payload)
-        if event == "conack" then
-            sys.publish("mqtt_conack")
-            mqtt_client:subscribe("test20220929/" .. device_id)
-        elseif event == "recv" then
-            log.info("mqtt", "downlink", "topic", data, "payload",
-                     payload:toHex())
-            sys.publish("payload_msg", payload)
-            -- mqttmsg(payload)
-        elseif event == "sent" then
-            log.info("mqtt", "sent", "pkgid", data)
-        -- elseif event == "disconnect" then
-        --     -- 非自动重连时,按需重启mqttc
-        --     log.info("mqtt链接断开")
-        --     -- mqtt_client:connect()
-        end
-    end)
-    mqttc:connect()
-    sys.wait(1000)
-    local error = mqttc:ready()
-    if not error then
-        log.info("mqtt 连接失败")
-    else
-        log.info("mqtt 连接成功")
-    end
-    sys.waitUntil("mqtt_conack")
-    while true do
-        -- mqttc自动处理重连
-        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 30000)
-    end
-    mqttc:close()
-    mqttc = nil
-end)
-
-sys.taskInit(function()
-    while 1 do
-        -- 最普通的Http GET请求
-        local result, data = sys.waitUntil("HTTP_msg")
-        if result then
-            log.info("data", data)
-            local code, headers, body = http.request("GET", data, {}, "",
-                                                     {dst = "/audio.mp3"})
-                                            .wait()
-            log.info("http", code, json.encode(headers or {}))
-            if code == 200 then
-                sys.wait(1000)
-                log.info("fsize", fs.fsize("/audio.mp3"))
-                sys.publish("Audio_msg")
-            else
-                log.info("http下载失败")
-            end
-        end
-    end
-end)
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 30
script/turnkey/ws2812_nimble/README.md

@@ -1,30 +0,0 @@
-# 蓝牙ws2812控制器
-
-适用于air101/air103, 但需要提醒的是, 绝非低功耗!!!
-
-## 关于Air101/Air103的蓝牙
-
-虽然开发板没有引出天线, 实际上这两款芯片是带蓝牙的, 但功耗很高,只能做简单的收发.
-
-Air103的pinout图链接 https://wiki.luatos.com/chips/air103/mcu.html#pinout
-
-其中的 14 脚, 标注为NC ,实际为ANT, 天线脚, 可飞线.
-
-Air101的pinout图链接 https://wiki.luatos.com/chips/air101/mcu.html
-
-其中的 8 脚, 标注为NC ,实际为ANT
-
-## 关于固件
-
-在发布版的固件压缩包里, 带BLE字样的固件才支持蓝牙, 也可以使用云编译自行定制
-
-https://gitee.com/openLuat/LuatOS/releases
-
-https://wiki.luatos.com/develop/compile/Cloud_compilation.html
-
-## 微信小程序
-
-搜 "LuatOS蓝牙" 就可以了.
-
-设备蓝牙名称默认 `LOS-` 开头, 若没有把天线飞线出来, 把手机贴到芯片上就能搜到.
-

+ 0 - 47
script/turnkey/ws2812_nimble/main.lua

@@ -1,47 +0,0 @@
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "uart_irq"
-VERSION = "1.0.0"
-
-log.info("main", PROJECT, VERSION)
-
--- 引入必要的库文件(lua编写), 内部库不需要require
-local sys = require "sys"
-
-mcu.setClk(240)
-log.info("main", "uart demo")
-
-sys.subscribe("BLE_STATE_INC", function(state)
-    log.info("ble", "ble state changed", state)
-    if state == 1 then
-        nimble.server_init()
-    else
-        nimble.server_deinit()
-    end
-end)
-
-local buff = zbuff.create({8,8,24},0x000000)
-
--- 监听GATT服务器的WRITE_CHR事件
-sys.subscribe("BLE_GATT_WRITE_CHR", function(info, data)
-    if data:len() == 0 then
-        return
-    end
-    local cmd = data:split(",")
-    if cmd[1]=="ws2812" then
-        local rgb = tonumber(cmd[2],16)
-        local grb = (rgb&0xff0000)>>8|(rgb&0xff00)<<8|(rgb&0xff)
-        buff:setFrameBuffer(8,8,24,grb)
-        sensor.ws2812b(pin.PB05,buff,0,300,300,300)
-    end
-end)
-
-sys.taskInit(function()
-    sys.wait(2000) -- 为了能看到日志,休眠2秒
-    nimble.debug(6) -- 开启日志
-    nimble.init() -- 初始化nimble, 会产生事件BLE_STATE_INC
-end)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 11
script/turnkey/ws2812_nimble/meta.json

@@ -1,11 +0,0 @@
-{
-    "type" : "lua",
-    "repo" : "luatos/ws2812_nimble",
-    "tags" : ["turnkey", "ws2812", "ble", "air101", "air103", "蓝牙", "nimble"],
-    "version" : "1.0.0",
-    "title" : "蓝牙ws2812控制器,适用于air101/air103",
-    "files" : {
-        "." : "*"
-    },
-    "dependency" : ["nimble"]
-}