Przeglądaj źródła

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

alienwalker 3 lat temu
rodzic
commit
a3531ca67d
43 zmienionych plików z 2357 dodań i 925 usunięć
  1. 64 0
      .github/workflows/esp32c3-idf5.yml
  2. 3 2
      README.md
  3. 6 7
      README_FULL.md
  4. 1 1
      components/epaper/EPD_7in5bc.c
  5. 29 13
      components/lua-cjson/lua_cjson.c
  6. 32 121
      components/lua-cjson/strbuf.c
  7. 9 3
      components/lua-cjson/strbuf.h
  8. 13 13
      components/lvgl/binding/luat_lv_fs.c
  9. 0 80
      components/minmea/luat_lib_libgnss.c
  10. 60 0
      components/network/httpsrv/inc/luat_httpsrv.h
  11. 87 0
      components/network/httpsrv/src/luat_lib_httpsrv.c
  12. 34 0
      components/nimble/inc/luat_nimble.h
  13. 179 0
      components/nimble/src/luat_lib_nimble.c
  14. 749 0
      components/nimble/src/luat_nimble_mode_ble_server.c
  15. 22 24
      components/serialization/protobuf/luat_lib_protobuf.c
  16. 21 18
      components/serialization/protobuf/pb.h
  17. 59 28
      components/u8g2/luat_lib_u8g2.c
  18. 2 2
      components/u8g2/u8g2.h
  19. 211 0
      components/wlan/luat_lib_wlan.c
  20. 71 0
      components/wlan/luat_wlan.h
  21. 7 0
      demo/camera/Air105/README.md
  22. 0 336
      demo/camera/Air105/capture_usb/GC032A_InitReg.txt
  23. 3 0
      demo/camera/Air105/capture_usb/README.md
  24. 0 110
      demo/camera/Air105/capture_usb/main.lua
  25. 13 0
      demo/camera/Air105/scanner/main.lua
  26. 23 24
      demo/camera/Air105/video/camera_test.lua
  27. 27 3
      demo/camera/Air105/video/main.lua
  28. 14 4
      demo/crypto/main.lua
  29. 58 0
      demo/nimble/esp32c3/main.lua
  30. 27 0
      demo/wlan/esp32c3/ap_get_start/index.html
  31. 45 0
      demo/wlan/esp32c3/ap_get_start/main.lua
  32. 43 0
      demo/wlan/esp32c3/hello_world/main.lua
  33. 27 0
      demo/wlan/esp32c3/httpsrv/index.html
  34. 55 0
      demo/wlan/esp32c3/httpsrv/main.lua
  35. 76 0
      demo/wlan/esp32c3/iotda/main.lua
  36. 127 0
      demo/wlan/esp32c3/smartconfig_esptouch/main.lua
  37. 30 0
      demo/wlan/esp32c3/wifi_scan/main.lua
  38. 76 73
      lua/src/liolib.c
  39. 24 24
      lua/src/luat_bget.c
  40. 2 0
      luat/include/luat_libs.h
  41. 16 12
      luat/modules/luat_lib_gpio.c
  42. 4 3
      luat/modules/luat_ota.c
  43. 8 24
      script/turnkey/eink-calendar/main.lua

+ 64 - 0
.github/workflows/esp32c3-idf5.yml

@@ -0,0 +1,64 @@
+name: esp32c3-idf5
+
+on:
+  push:
+    paths:
+      - '.github/workflows/esp32c3-idf5.yml'
+      - 'lua/**'
+      - 'luat/**'
+      - 'components/**'
+  workflow_dispatch:
+  repository_dispatch:
+    types:
+      - webhook-esp32c3-idf5-action
+
+jobs:
+  build:
+    runs-on: ubuntu-20.04
+    steps:
+    - uses: actions/checkout@v1
+    - name: prepare software
+      run: |
+        sudo apt-get update
+        sudo apt-get install git gcc-multilib libc6 libgcc1 libstdc++5 libstdc++6 libsdl-dev p7zip-full python3 python3-pip libncurses5-dev -y
+        mkdir -p ~/esp
+        cd ~/esp
+        git clone --recursive https://github.com/espressif/esp-idf.git
+        cd ~/esp/esp-idf
+        git submodule update --init --recursive
+        ./install.sh esp32c3
+    - name: clone LuatOS-ESP32
+      run: |
+        sudo sh -c "curl https://raw.githubusercontent.com/kadwanev/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry"
+        cd ..
+        retry 'git clone --branch=master https://gitee.com/openLuat/luatos-soc-idf5'
+    - name: build
+      run: |
+        mkdir luatosfw
+        cd ../luatos-soc-idf5/luatos
+        sed -i 's/E:\/\/code\/codeup\/LuatOS\//\/home\/runner\/work\/LuatOS\/LuatOS/g' CMakeLists.txt
+        . ~/esp/esp-idf/export.sh
+        idf.py set-target esp32c3
+        idf.py build
+        mv *.soc ../../LuatOS/luatosfw
+    - name: Upload artifact
+      uses: actions/upload-artifact@v1
+      with:
+        name: esp32c3
+        path: luatosfw
+    - name: report if failure
+      if: always()
+      env:
+        STATUS: ${{ job.status }}
+        MQTTADDR: ${{ secrets.MQTTADDR }}
+        MQTTPORT: ${{ secrets.MQTTPORT }}
+        MQTTTOPIC: ${{ secrets.MQTTTOPIC }}
+        DD_APPKEY: ${{ secrets.DD_APPKEY }}
+        DD_APPSECRET: ${{ secrets.DD_APPSECRET }}
+        DD_NOTIFY_LIST: ${{ secrets.DD_NOTIFY_LIST }}
+        DD_API_TOKEN: ${{ secrets.DD_API_TOKEN }}
+        DD_API_SEND: ${{ secrets.DD_API_SEND }}
+      run: |
+        sudo pip3 install paho_mqtt gitpython requests
+        cd tools
+        if [ "$STATUS" = "failure" ];then python3 ciNotify.py $MQTTADDR $MQTTPORT $MQTTTOPIC "https://github.com/openLuat/LuatOS/actions/runs/$GITHUB_RUN_ID" "LuatOS-ESP32-IDF5" "$DD_APPKEY" "$DD_APPSECRET" "$DD_NOTIFY_LIST" "$DD_API_TOKEN" "$DD_API_SEND"; fi

+ 3 - 2
README.md

@@ -6,9 +6,10 @@
 
 [![air101](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/air101.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air101/master)
 [![air105](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/air105.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air105/master)
-[![esp32c3](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/esp32c3.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/esp32c3/master)
+[![esp32c3](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/esp32c3-idf5.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/esp32c3-idf5/master)
 [![win32](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/win32.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/win32/master)
 [![linux](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/linux.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/linux/master)
+![Build Status](http://luat.papapoi.com:23380/api/badges/openLuat/LuatOS/status.svg)
 
 LuatOS : Powerful embedded Lua Engine for IoT devices, with many components and low memory requirements (16K RAM, 128K Flash)
 
@@ -16,7 +17,7 @@ LuatOS : Powerful embedded Lua Engine for IoT devices, with many components and
 
 ## 快速入门
 
-1. 使用或购买支持的开发板 - [Air101](https://item.taobao.com/item.htm?id=655145668811)/[Air103](https://item.taobao.com/item.htm?id=662164666516)/[Air105](https://item.taobao.com/item.htm?id=665811924219)/[ESP32C3](https://item.taobao.com/item.htm?id=666974425430)
+1. 使用或购买支持的开发板 - [Air101](https://luat.taobao.com)/[Air103](https://luat.taobao.com)/[Air105](luat.taobao.com)/[ESP32C3](luat.taobao.com)
 2. 掌握[刷机](https://wiki.luatos.com/boardGuide/flash.html)
 3. 尝试[各种demo](https://gitee.com/openLuat/LuatOS/tree/master/demo), 浏览[API](https://wiki.luatos.com/api/index.html), [30分钟入门lua语法(视频)](https://www.bilibili.com/video/BV1vf4y1L7Rb?spm_id_from=333.999.0.0)
 4. 愉快地写业务代码

+ 6 - 7
README_FULL.md

@@ -4,13 +4,12 @@
 [![fork](https://gitee.com/openLuat/LuatOS/badge/fork.svg?theme=gvp)](https://gitee.com/openLuat/LuatOS/members)
 [![license](https://img.shields.io/github/license/openLuat/LuatOS)](/LICENSE)
 
-[![air101](https://github.com/openLuat/LuatOS/actions/workflows/air101.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air101/master)
-[![air105](https://github.com/openLuat/LuatOS/actions/workflows/air105.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air105/master)
-[![esp32c3](https://github.com/openLuat/LuatOS/actions/workflows/esp32c3.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/esp32c3/master)
-[![air100st](https://github.com/openLuat/LuatOS/actions/workflows/air100st.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air100st/master)
-[![air640w](https://github.com/openLuat/LuatOS/actions/workflows/air640w.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air640w/master)
-[![win32](https://github.com/openLuat/LuatOS/actions/workflows/win32.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/win32/master)
-[![linux](https://github.com/openLuat/LuatOS/actions/workflows/linux.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/linux/master)
+[![air101](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/air101.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air101/master)
+[![air105](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/air105.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/air105/master)
+[![esp32c3](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/esp32c3-idf5.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/esp32c3-idf5/master)
+[![win32](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/win32.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/win32/master)
+[![linux](https://pg.air32.cn/openLuat/LuatOS/actions/workflows/linux.yml/badge.svg)](https://nightly.link/openLuat/LuatOS/workflows/linux/master)
+![Build Status](http://luat.papapoi.com:23380/api/badges/openLuat/LuatOS/status.svg)
 
 LuatOS-SoC是一款实时操作系统,用户编写Lua代码就可完成各种功能, 仅需极少的内存和Flash空间
 

+ 1 - 1
components/epaper/EPD_7in5bc.c

@@ -278,7 +278,7 @@ void EPD_7IN5BC_Display(const UBYTE *blackimage, const UBYTE *ryimage)
 
 void EPD_7IN5BC_DisplayHalfScreen(const UBYTE *blackimage, const UBYTE *ryimage)
 {
-    UBYTE Data_Black, Data_RY, Data;
+    UBYTE Data_Black, Data_RY, Data = 0;
     UDOUBLE i, j, Width, Height;
     Width = (EPD_7IN5BC_WIDTH % 8 == 0)? (EPD_7IN5BC_WIDTH / 8 ): (EPD_7IN5BC_WIDTH / 8 + 1);
     Height = EPD_7IN5BC_HEIGHT;

+ 29 - 13
components/lua-cjson/lua_cjson.c

@@ -56,6 +56,9 @@
 
 #define MIN_OPT_LEVEL 2
 
+#define LUAT_LOG_TAG "json"
+#include "luat_log.h"
+
 //#include <lrodefs.h>
 //#include <auxmods.h>
 
@@ -442,6 +445,8 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
      * If there are any excess pages, they won't be hit anyway.
      * This gains ~5% speedup. */
     strbuf_ensure_empty_length(json, len * 6 + 2);
+    if (json->is_err)
+        return;
 
     strbuf_append_char_unsafe(json, '\"');
     for (i = 0; i < len; i++) {
@@ -588,6 +593,8 @@ static void json_append_number(lua_State *l,
     }
 
     strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);
+    if (json->is_err)
+        return;
     if (lua_isinteger(l, lindex)) {
         len = snprintf_(strbuf_empty_ptr(json), FPCONV_G_FMT_BUFSIZE, "%ld", lua_tointeger(l, lindex));
     }
@@ -698,26 +705,31 @@ static int json_encode(lua_State *l)
     strbuf_t *encode_buf;
     char *json;
     int len;
+    int ret;
 
     luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
 
-    // if (!DEFAULT_ENCODE_KEEP_BUFFER) {
-        /* Use private buffer */
-        encode_buf = &local_encode_buf;
-        strbuf_init(encode_buf, 0);
-    // } else {
-    //     /* Reuse existing buffer */
-    //     encode_buf = &cfg->encode_buf;
-    //     strbuf_reset(encode_buf);
-    // }
+    
+    encode_buf = &local_encode_buf;
+    ret = strbuf_init(encode_buf, 0);
+    if (ret) {
+        LLOGE("json encode out of memory!!!");
+        return 0;
+    }
 
     json_append_data(l, 0, encode_buf);
-    json = strbuf_string(encode_buf, &len);
 
-    lua_pushlstring(l, json, len);
+    // check if err
+    if (local_encode_buf.is_err) {
+        LLOGE("json encode failed by memory less");
+        lua_pushnil(l);
+    }
+    else {
+        json = strbuf_string(encode_buf, &len);
+        lua_pushlstring(l, json, len);
+    }
 
-    // if (!cfg->encode_keep_buffer)
-        strbuf_free(encode_buf);
+    strbuf_free(encode_buf);
 
     return 1;
 }
@@ -1295,6 +1307,10 @@ static int json_decode(lua_State *l)
      * This means we no longer need to do length checks since the decoded
      * string must be smaller than the entire json string */
     json.tmp = strbuf_new(json_len);
+    if (json.tmp == NULL) {
+        LLOGE("json decode out of memory!");
+        return 0;
+    }
 
     json_next_token(&json, &token);
     json_process_value(l, &json, &token);

+ 32 - 121
components/lua-cjson/strbuf.c

@@ -42,13 +42,7 @@
 #define L_FREE  luat_heap_free
 #define L_REALLOC  luat_heap_realloc
 
-static void die(const char *fmt, ...)
-{
-    LLOGD("%s", fmt);
-    exit(-1);
-}
-
-void strbuf_init(strbuf_t *s, int len)
+int strbuf_init(strbuf_t *s, int len)
 {
     int size;
 
@@ -62,25 +56,32 @@ void strbuf_init(strbuf_t *s, int len)
     s->length = 0;
     s->increment = STRBUF_DEFAULT_INCREMENT;
     s->dynamic = 0;
-    s->reallocs = 0;
-    s->debug = 0;
+    s->is_err = 0;
+    // s->reallocs = 0;
+    // s->debug = 0;
 
     s->buf = (char *)L_MALLOC(size);
     if (!s->buf)
-        die("Out of memory");
+        return -1;
 
     strbuf_ensure_null(s);
+    return 0;
 }
 
 strbuf_t *strbuf_new(int len)
 {
     strbuf_t *s;
+    int ret = 0;
 
     s = (strbuf_t *)L_MALLOC(sizeof(strbuf_t));
     if (!s)
-        die("Out of memory");
+        return NULL;
 
-    strbuf_init(s, len);
+    ret = strbuf_init(s, len);
+    if (ret) {
+        L_FREE(s);
+        return NULL;
+    }
 
     /* Dynamic strbuf allocation / deallocation */
     s->dynamic = 1;
@@ -88,29 +89,11 @@ strbuf_t *strbuf_new(int len)
     return s;
 }
 
-void strbuf_set_increment(strbuf_t *s, int increment)
-{
-    /* Increment > 0:  Linear buffer growth rate
-     * Increment < -1: Exponential buffer growth rate */
-    if (increment == 0 || increment == -1)
-        die("BUG: Invalid string increment");
-
-    s->increment = increment;
-}
-
-static inline void debug_stats(strbuf_t *s)
-{
-    if (s->debug) {
-        fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
-                (long)s, s->reallocs, s->length, s->size);
-    }
-}
-
 /* If strbuf_t has not been dynamically allocated, strbuf_free() can
  * be called any number of times strbuf_init() */
 void strbuf_free(strbuf_t *s)
 {
-    debug_stats(s);
+    // debug_stats(s);
 
     if (s->buf) {
         L_FREE (s->buf);
@@ -120,30 +103,12 @@ void strbuf_free(strbuf_t *s)
         L_FREE (s);
 }
 
-char *strbuf_free_to_string(strbuf_t *s, int *len)
-{
-    char *buf;
-
-    debug_stats(s);
-
-    strbuf_ensure_null(s);
-
-    buf = s->buf;
-    if (len)
-        *len = s->length;
-
-    if (s->dynamic)
-        L_FREE (s);
-
-    return buf;
-}
-
 static int calculate_new_size(strbuf_t *s, int len)
 {
     int reqsize, newsize;
 
-    if (len <= 0)
-        die("BUG: Invalid strbuf length requested");
+    // if (len <= 0)
+    //     die("BUG: Invalid strbuf length requested");
 
     /* Ensure there is room for optional NULL termination */
     reqsize = len + 1;
@@ -153,16 +118,11 @@ static int calculate_new_size(strbuf_t *s, int len)
         return reqsize;
 
     newsize = s->size;
-    if (s->increment < 0) {
-        /* Exponential sizing */
-        while (newsize < reqsize)
-            newsize *= -s->increment;
-    } else {
-        /* Linear sizing */
-        newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
+    if (reqsize - s->size < 1023) {
+        reqsize = s->size + 1023;
     }
 
-    return newsize;
+    return reqsize + 1;
 }
 
 
@@ -171,24 +131,28 @@ static int calculate_new_size(strbuf_t *s, int len)
 void strbuf_resize(strbuf_t *s, int len)
 {
     int newsize;
+    void* ptr;
+
+    if (s->is_err)
+        return;
 
     newsize = calculate_new_size(s, len);
 
-    if (s->debug > 1) {
-        fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
-                (long)s, s->size, newsize);
+    ptr = (char *)L_REALLOC(s->buf, newsize);
+    if (ptr == NULL) {
+        s->is_err = 1;
+    }
+    else {
+        s->size = newsize;
+        s->buf = ptr;
     }
-
-    s->size = newsize;
-    s->buf = (char *)L_REALLOC(s->buf, s->size);
-    if (!s->buf)
-        die("Out of memory");
-    s->reallocs++;
 }
 
 void strbuf_append_string(strbuf_t *s, const char *str)
 {
     int space, i;
+    if (s->is_err)
+        return;
 
     space = strbuf_empty_length(s);
 
@@ -203,56 +167,3 @@ void strbuf_append_string(strbuf_t *s, const char *str)
         space--;
     }
 }
-
-/* strbuf_append_fmt() should only be used when an upper bound
- * is known for the output string. */
-void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
-{
-    va_list arg;
-    int fmt_len;
-
-    strbuf_ensure_empty_length(s, len);
-
-    va_start(arg, fmt);
-    fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
-    va_end(arg);
-
-    if (fmt_len < 0)
-        die("BUG: Unable to convert number");  /* This should never happen.. */
-
-    s->length += fmt_len;
-}
-
-/* strbuf_append_fmt_retry() can be used when the there is no known
- * upper bound for the output string. */
-void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
-{
-    va_list arg;
-    int fmt_len, try;
-    int empty_len;
-
-    /* If the first attempt to append fails, resize the buffer appropriately
-     * and try again */
-    for (try = 0; ; try++) {
-        va_start(arg, fmt);
-        /* Append the new formatted string */
-        /* fmt_len is the length of the string required, excluding the
-         * trailing NULL */
-        empty_len = strbuf_empty_length(s);
-        /* Add 1 since there is also space to store the terminating NULL. */
-        fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
-        va_end(arg);
-
-        if (fmt_len <= empty_len)
-            break;  /* SUCCESS */
-        if (try > 0)
-            die("BUG: length of formatted string changed");
-
-        strbuf_resize(s, s->length + fmt_len);
-    }
-
-    s->length += fmt_len;
-}
-
-/* vi:ai et sw=4 ts=4:
- */

+ 9 - 3
components/lua-cjson/strbuf.h

@@ -39,8 +39,9 @@ typedef struct {
     int length;
     int increment;
     int dynamic;
-    int reallocs;
-    int debug;
+    int is_err;
+    // int reallocs;
+    // int debug;
 } strbuf_t;
 
 #ifndef STRBUF_DEFAULT_SIZE
@@ -52,7 +53,7 @@ typedef struct {
 
 /* Initialise */
 extern strbuf_t *strbuf_new(int len);
-extern void strbuf_init(strbuf_t *s, int len);
+extern int strbuf_init(strbuf_t *s, int len);
 extern void strbuf_set_increment(strbuf_t *s, int increment);
 
 /* Release */
@@ -118,29 +119,34 @@ static inline int strbuf_length(strbuf_t *s)
 static inline void strbuf_append_char(strbuf_t *s, const char c)
 {
     strbuf_ensure_empty_length(s, 1);
+    if (s->is_err) return;
     s->buf[s->length++] = c;
 }
 
 static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
 {
+    if (s->is_err) return;
     s->buf[s->length++] = c;
 }
 
 static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
 {
     strbuf_ensure_empty_length(s, len);
+    if (s->is_err) return;
     memcpy(s->buf + s->length, c, len);
     s->length += len;
 }
 
 static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
 {
+    if (s->is_err) return;
     memcpy(s->buf + s->length, c, len);
     s->length += len;
 }
 
 static inline void strbuf_ensure_null(strbuf_t *s)
 {
+    if (s->is_err) return;
     s->buf[s->length] = 0;
 }
 

+ 13 - 13
components/lvgl/binding/luat_lv_fs.c

@@ -12,19 +12,19 @@ static bool luat_lv_fs_ready(struct _lv_fs_drv_t * drv);
 
 static lv_fs_res_t luat_lv_fs_open(struct _lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
 static lv_fs_res_t luat_lv_fs_close(struct _lv_fs_drv_t * drv, void * file_p);
-static lv_fs_res_t luat_lv_fs_remove(struct _lv_fs_drv_t * drv, const char * fn);
+// static lv_fs_res_t luat_lv_fs_remove(struct _lv_fs_drv_t * drv, const char * fn);
 static lv_fs_res_t luat_lv_fs_read(struct _lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
-static lv_fs_res_t luat_lv_fs_write(struct _lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
+// static lv_fs_res_t luat_lv_fs_write(struct _lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
 static lv_fs_res_t luat_lv_fs_seek(struct _lv_fs_drv_t * drv, void * file_p, uint32_t pos);
 static lv_fs_res_t luat_lv_fs_tell(struct _lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
-static lv_fs_res_t luat_lv_fs_trunc(struct _lv_fs_drv_t * drv, void * file_p);
+// static lv_fs_res_t luat_lv_fs_trunc(struct _lv_fs_drv_t * drv, void * file_p);
 static lv_fs_res_t luat_lv_fs_size(struct _lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
-static lv_fs_res_t luat_lv_fs_rename(struct _lv_fs_drv_t * drv, const char * oldname, const char * newname);
-static lv_fs_res_t luat_lv_fs_free_space(struct _lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
+// static lv_fs_res_t luat_lv_fs_rename(struct _lv_fs_drv_t * drv, const char * oldname, const char * newname);
+// static lv_fs_res_t luat_lv_fs_free_space(struct _lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
 
-static lv_fs_res_t luat_lv_fs_dir_open(struct _lv_fs_drv_t * drv, void * rddir_p, const char * path);
-static lv_fs_res_t luat_lv_fs_dir_read(struct _lv_fs_drv_t * drv, void * rddir_p, char * fn);
-static lv_fs_res_t luat_lv_fs_dir_close(struct _lv_fs_drv_t * drv, void * rddir_p);
+// static lv_fs_res_t luat_lv_fs_dir_open(struct _lv_fs_drv_t * drv, void * rddir_p, const char * path);
+// static lv_fs_res_t luat_lv_fs_dir_read(struct _lv_fs_drv_t * drv, void * rddir_p, char * fn);
+// static lv_fs_res_t luat_lv_fs_dir_close(struct _lv_fs_drv_t * drv, void * rddir_p);
 
 void luat_lv_fs_init(void) {
     lv_fs_drv_t fs_drv = {
@@ -34,7 +34,7 @@ void luat_lv_fs_init(void) {
         .ready_cb = luat_lv_fs_ready,
         .open_cb = luat_lv_fs_open,
         .close_cb = luat_lv_fs_close,
-        .remove_cb = luat_lv_fs_remove,
+        .remove_cb = NULL,
         .read_cb = luat_lv_fs_read,
         .write_cb = NULL,
         .seek_cb = luat_lv_fs_seek,
@@ -85,10 +85,10 @@ static lv_fs_res_t luat_lv_fs_close(struct _lv_fs_drv_t * drv, void * file_p) {
     return LV_FS_RES_NOT_EX;
 }
 
-static lv_fs_res_t luat_lv_fs_remove(struct _lv_fs_drv_t * drv, const char * fn) {
-    luat_fs_remove(fn);
-    return LV_FS_RES_OK;
-}
+// static lv_fs_res_t luat_lv_fs_remove(struct _lv_fs_drv_t * drv, const char * fn) {
+//     luat_fs_remove(fn);
+//     return LV_FS_RES_OK;
+// }
 
 static lv_fs_res_t luat_lv_fs_read(struct _lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) {
     file_t* fp = file_p;

+ 0 - 80
components/minmea/luat_lib_libgnss.c

@@ -564,81 +564,6 @@ static int l_libgnss_get_gga(lua_State* L) {
     return 1;
 }
 
-
-//-----------------------------------------------------
-// For Air530Z
-//-----------------------------------------------------
-
-uint8_t air530z_uart_id = 2;
-
-/**
-设置gps串口id(For Air530Z)
-@api libgnss.air530z_setup(air530z_uart_id)
-@number air530z_uart_id 串口id 默认串口2
-@usage
-libgnss.air530z_setup(2)
- */
-static int l_libgnss_air530_setup(lua_State *L) {
-    air530z_uart_id = luaL_checkinteger(L, 1);
-    return 0;
-}
-
-/**
-保存配置信息(For Air530Z)
-@api libgnss.air530z_saveconf()
-@usage
-libgnss.air530z_saveconf()
- */
-static int l_libgnss_air530_saveconf(lua_State *L) {
-    luat_uart_write(air530z_uart_id, "$PCAS00*01\r\n", strlen("$PCAS00*01\r\n"));
-    return 0;
-}
-
-/**
-设置通讯波特率(For Air530Z)
-@api libgnss.air530z_setbandrate(bandrate)
-@number table 波特率
-@usage
-libgnss.air530z_setbandrate(115200)
- */
-static int l_libgnss_air530_setbandrate(lua_State *L) {
-    /*
-0=4800bps
-1=9600bps
-2=19200bps
-3=38400bps
-4=57600bps
-5=115200bps
-    */
-    int bandrate = luaL_checkinteger(L, 1);
-    switch (bandrate)
-    {
-    case 4800:
-        luat_uart_write(air530z_uart_id, "$PCAS01,0*1C\r\n", strlen("$PCAS01,0*1C\r\n"));
-        break;
-    case 9600:
-        luat_uart_write(air530z_uart_id, "$PCAS01,1*1D\r\n", strlen("$PCAS01,1*1D\r\n"));
-        break;
-    case 19200:
-        luat_uart_write(air530z_uart_id, "$PCAS01,2*1E\r\n", strlen("$PCAS01,2*1E\r\n"));
-        break;
-    case 38400:
-        luat_uart_write(air530z_uart_id, "$PCAS01,3*1F\r\n", strlen("$PCAS01,3*1F\r\n"));
-        break;
-    case 57600:
-        luat_uart_write(air530z_uart_id, "$PCAS01,4*18\r\n", strlen("$PCAS01,4*18\r\n"));
-        break;
-    case 115200:
-        luat_uart_write(air530z_uart_id, "$PCAS01,5*19\r\n", strlen("$PCAS01,5*19\r\n"));
-        break;
-    default:
-        LLOGD("fallback to default 9600");
-        luat_uart_write(air530z_uart_id, "$PCAS01,1*1D\r\n", strlen("$PCAS01,1*1D\r\n"));
-        break;
-    }
-    return 0;
-}
-
 #include "rotable2.h"
 static const rotable_Reg_t reg_libgnss[] =
 {
@@ -653,11 +578,6 @@ static const rotable_Reg_t reg_libgnss[] =
     { "getZda", ROREG_FUNC(l_libgnss_get_zda)},
     { "debug",  ROREG_FUNC(l_libgnss_debug)},
 
-    //-----------------------------------------
-    { "air530z_setup", ROREG_FUNC(l_libgnss_air530_setup)},
-    { "air530z_saveconf", ROREG_FUNC(l_libgnss_air530_saveconf)},
-    { "air530z_setbandrate", ROREG_FUNC(l_libgnss_air530_setbandrate)},
-
 	{ NULL,      ROREG_INT(0)}
 };
 

+ 60 - 0
components/network/httpsrv/inc/luat_httpsrv.h

@@ -0,0 +1,60 @@
+#include "luat_base.h"
+
+
+typedef struct luat_httpsrv_ctx
+{
+    uint16_t port;
+    uint16_t https;
+    char static_path[32];
+    int lua_ref_id;
+    int server_fd;
+    void* userdata;
+}luat_httpsrv_ctx_t;
+
+
+typedef struct http_code_str
+{
+    int code;
+    const char* msg;
+}http_code_str_t;
+
+static const http_code_str_t http_codes[] = {
+    {200, "OK"},
+    {302, "Found"},
+    {400, "Bad Request"},
+    {401, "Unauthorized"},
+    {403, "Forbidden"},
+    {404, "Not Found"},
+    {500, "Internal Server Error"},
+    {0, ""}
+};
+
+
+typedef struct ct_reg
+{
+    const char* suff;
+    const char* value;
+}ct_reg_t;
+
+static const ct_reg_t ct_regs[] = {
+    {"html",    "text/html; charset=utf-8"},
+    {"txt",     "text/txt; charset=utf-8"},
+    {"xml",     "text/xml; charset=utf-8"},
+    {"jpg",      "image/jpeg"},
+    {"png",     "image/png"},
+    {"gif",     "image/gif"},
+    {"svg",     "svg+xml"},
+    {"json",    "application/json; charset=utf-8"},
+    {"js",      "application/javascript; charset=utf-8"},
+    {"css",     "text/css"},
+    {"wav",     "audio/wave"},
+    {"ogg",     "audio/ogg"},
+    {"wav",     "audio/wave"},
+    {"webm",    "video/webm"},
+    {"mp4",     "video/mpeg4"},
+    {"bin",     "application/octet-stream"},
+};
+
+
+int luat_httpsrv_stop(int port);
+int luat_httpsrv_start(luat_httpsrv_ctx_t* ctx);

+ 87 - 0
components/network/httpsrv/src/luat_lib_httpsrv.c

@@ -0,0 +1,87 @@
+/*
+@module  httpsrv
+@summary http服务端
+@version 1.0
+@date    2022.010.15
+@demo network
+*/
+
+#include "luat_base.h"
+#include "luat_httpsrv.h"
+
+#define LUAT_LOG_TAG "httpsrv"
+#include "luat_log.h"
+
+/*
+启动并监听一个http端口
+@api httpsrv.start(port, func)
+@int 端口号
+@function 回调函数
+@return bool 成功返回true, 否则返回false
+@usage
+
+-- 监听80端口
+httpsrv.start(80, function(client, method, uri, headers, body)
+    -- method 是字符串, 例如 GET POST PUT DELETE
+    -- uri 也是字符串 例如 / /api/abc
+    -- headers table类型
+    -- body 字符串
+    log.info("httpsrv", method, uri, json.encode(headers), body)
+    if uri == "/led/1" then
+        LEDA(1)
+        return 200, {}, "ok"
+    elseif uri == "/led/0" then
+        LEDA(0)
+        return 200, {}, "ok"
+    end
+    -- 返回值的约定 code, headers, body
+    -- 若没有返回值, 则默认 404, {} ,""
+    return 404, {}, "Not Found" .. uri
+end)
+-- 关于静态文件
+-- 情况1: / , 映射为 /index.html
+-- 情况2: /abc.html , 先查找 /abc.html, 不存在的话查找 /abc.html.gz
+-- 若gz存在, 会自动以压缩文件进行响应, 绝大部分浏览器支持.
+-- 当前默认查找 /luadb/xxx 下的文件,暂不可配置
+*/
+static int l_httpsrv_start(lua_State *L) {
+    int port = luaL_checkinteger(L, 1);
+    if (!lua_isfunction(L, 2)) {
+        LLOGW("httpsrv need callback function!!!");
+        return 0;
+    }
+    lua_pushvalue(L, 2);
+    int lua_ref_id = luaL_ref(L, LUA_REGISTRYINDEX);
+    luat_httpsrv_ctx_t ctx = {
+        .port = port,
+        .lua_ref_id = lua_ref_id
+    };
+    int ret = luat_httpsrv_start(&ctx);
+    lua_pushboolean(L, ret == 0 ? 1 : 0);
+    return 1;
+}
+
+/*
+停止http服务
+@api httpsrv.stop(port)
+@int 端口号
+@return nil 当前无返回值
+*/
+static int l_httpsrv_stop(lua_State *L) {
+    int port = luaL_checkinteger(L, 1);
+    luat_httpsrv_stop(port);
+    return 0;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_httpsrv[] =
+{
+    {"start",        ROREG_FUNC(l_httpsrv_start) },
+    {"stop",         ROREG_FUNC(l_httpsrv_stop) },
+	{ NULL,          ROREG_INT(0) }
+};
+
+LUAMOD_API int luaopen_httpsrv( lua_State *L ) {
+    luat_newlib2(L, reg_httpsrv);
+    return 1;
+}

+ 34 - 0
components/nimble/inc/luat_nimble.h

@@ -0,0 +1,34 @@
+
+#ifndef LUAT_NUMBLE_H
+#define LUAT_NUMBLE_H
+#include "luat_base.h"
+#include "luat_msgbus.h"
+
+
+/** Bluetooth Adapter State */
+typedef enum
+{
+    BT_STATE_OFF,
+    BT_STATE_ON,
+    BT_STATE_CONNECTED,
+    BT_STATE_DISCONNECT,
+} bt_state_t;
+
+
+typedef enum
+{
+    BT_MODE_BLE_SERVER,
+    BT_MODE_BLE_CLIENT,
+    BT_MODE_BLE_BEACON,
+    BT_MODE_BLE_MESH,
+} bt_mode_t;
+
+int luat_nimble_trace_level(int level);
+
+int luat_nimble_init(uint8_t uart_idx, char* name, int mode);
+int luat_nimble_deinit();
+
+int luat_nimble_server_send(int id, char* data, size_t len);
+
+#endif
+

+ 179 - 0
components/nimble/src/luat_lib_nimble.c

@@ -0,0 +1,179 @@
+/*
+@module  nimble
+@summary 蓝牙BLE库(nimble版)
+@version 1.0
+@date    2022.10.21
+@demo    nimble
+@usage
+-- 本库当前支持Air101/Air103/ESP32/ESP32C3
+-- 理论上支持ESP32C2/ESP32S2/ESP32S3,但尚未测试
+
+-- 本库当前仅支持BLE Peripheral, 其他模式待添加
+sys.taskInit(function()
+    -- 初始化nimble, 因为当仅支持作为主机,也没有其他配置项
+    nimble.init("LuatOS-Wendal") -- 选取一个蓝牙设备名称
+    sys.wait(1000)
+
+    --local data = string.char(0x5A, 0xA5, 0x12, 0x34, 0x56)
+    local data = "1234567890"
+    while 1 do
+        sys.wait(5000)
+        -- Central端建立连接并订阅后, 可上报数据
+        nimble.send_msg(1, 0, data)
+    end
+end
+sys.subscribe("BLE_GATT_WRITE_CHR", function(info, data)
+    -- Central端建立连接后, 可往设备写入数据
+    log.info("ble", "Data Got", data:toHex())
+end)
+
+-- 配合微信小程序 "LuatOS蓝牙调试"
+-- 1. 若开发板无天线, 将手机尽量靠近芯片也能搜到
+-- 2. 该小程序是开源的, 每次write会自动分包
+-- https://gitee.com/openLuat/luatos-miniapps
+*/
+
+#include "luat_base.h"
+#include "luat_msgbus.h"
+#include "luat_malloc.h"
+#include "luat_spi.h"
+
+#include "luat_nimble.h"
+
+#define LUAT_LOG_TAG "nimble"
+#include "luat_log.h"
+
+static uint32_t nimble_mode = 0;
+
+/*
+初始化BLE上下文,开始对外广播/扫描
+@api nimble.init(name)
+@string 蓝牙设备名称,可选,建议填写
+@return bool 成功与否
+@usage
+-- 参考 demo/nimble
+*/
+static int l_nimble_init(lua_State* L) {
+    int rc = 0;
+    size_t len = 0;
+    const char* name = NULL;
+    if(lua_isstring(L, 1)) {
+        name = luaL_checklstring(L, 1, &len);
+    }
+    LLOGD("init name %s mode %d", name, nimble_mode);
+    rc = luat_nimble_init(0xFF, name, nimble_mode);
+    if (rc) {
+        lua_pushboolean(L, 0);
+        lua_pushinteger(L, rc);
+        return 2;
+    }
+    else {
+        lua_pushboolean(L, 1);
+        return 1;
+    }
+}
+
+/*
+关闭BLE上下文
+@api nimble.deinit()
+@return bool 成功与否
+@usage
+-- 仅部分设备支持,当前可能都不支持
+*/
+static int l_nimble_deinit(lua_State* L) {
+    int rc = 0;
+    rc = luat_nimble_deinit();
+    if (rc) {
+        lua_pushboolean(L, 0);
+        lua_pushinteger(L, rc);
+        return 2;
+    }
+    else {
+        lua_pushboolean(L, 1);
+        return 1;
+    }
+}
+
+static int l_nimble_debug(lua_State* L) {
+    int level = 0;
+    // if (lua_gettop(L) > 0)
+    //     level = luat_nimble_trace_level(luaL_checkinteger(L, 1));
+    // else
+    //     level = luat_nimble_trace_level(-1);
+    lua_pushinteger(L, level);
+    return 1;
+}
+
+static int l_nimble_server_init(lua_State* L) {
+    LLOGI("nimble.server_init is removed");
+    return 0;
+}
+
+
+static int l_nimble_server_deinit(lua_State* L) {
+    LLOGI("nimble.server_deinit is removed");
+    return 0;
+}
+
+/*
+发送信息
+@api nimble.send_msg(conn, handle, data)
+@int 连接id, 当前固定填1
+@int 处理id, 当前固定填0
+@string 数据字符串,可包含不可见字符
+@return bool 成功与否
+@usage
+-- 参考 demo/nimble
+*/
+static int l_nimble_send_msg(lua_State *L) {
+    int conn_id = luaL_checkinteger(L, 1);
+    int handle_id = luaL_checkinteger(L, 2);
+    size_t len = 0;
+    const char* data = luaL_checklstring(L, 3, &len);
+    int ret = 0;
+    if (len == 0) {
+        LLOGI("send emtry msg? ignored");
+    }
+    else {
+        ret = luat_nimble_server_send(0, data, len);
+    }
+
+    lua_pushboolean(L, ret == 0 ? 1 : 0);
+    // lua_pushinteger(L, ret);
+    return 1;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_nimble[] =
+{
+	{ "init",           ROREG_FUNC(l_nimble_init)},
+    { "deinit",         ROREG_FUNC(l_nimble_deinit)},
+    { "debug",          ROREG_FUNC(l_nimble_debug)},
+    { "server_init",    ROREG_FUNC(l_nimble_server_init)},
+    { "server_deinit",  ROREG_FUNC(l_nimble_server_deinit)},
+    { "send_msg",       ROREG_FUNC(l_nimble_send_msg)},
+
+    // 放一些常量
+    { "STATE_OFF",           ROREG_INT(BT_STATE_OFF)},
+    { "STATE_ON",            ROREG_INT(BT_STATE_ON)},
+    { "STATE_CONNECTED",     ROREG_INT(BT_STATE_CONNECTED)},
+    { "STATE_DISCONNECT",    ROREG_INT(BT_STATE_DISCONNECT)},
+
+    // 模式
+    { "MODE_BLE_SERVER",           ROREG_INT(BT_MODE_BLE_SERVER)},
+    { "MODE_BLE_CLIENT",           ROREG_INT(BT_MODE_BLE_CLIENT)},
+    { "MODE_BLE_BEACON",           ROREG_INT(BT_MODE_BLE_BEACON)},
+    { "MODE_BLE_MESH",             ROREG_INT(BT_MODE_BLE_MESH)},
+    { "SERVER",                    ROREG_INT(BT_MODE_BLE_SERVER)},
+    { "CLIENT",                    ROREG_INT(BT_MODE_BLE_CLIENT)},
+    { "BEACON",                    ROREG_INT(BT_MODE_BLE_BEACON)},
+    { "MESH",                      ROREG_INT(BT_MODE_BLE_MESH)},
+
+	{ NULL,             ROREG_INT(0)}
+};
+
+LUAMOD_API int luaopen_nimble( lua_State *L ) {
+    rotable2_newlib(L, reg_nimble);
+    return 1;
+}
+

+ 749 - 0
components/nimble/src/luat_nimble_mode_ble_server.c

@@ -0,0 +1,749 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "luat_base.h"
+#if (defined(AIR101) || defined(AIR103))
+#include "FreeRTOS.h"
+#else
+#include "freertos/FreeRTOS.h"
+#endif
+
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "host/util/util.h"
+#include "services/gap/ble_svc_gap.h"
+#include "services/gatt/ble_svc_gatt.h"
+
+#include "luat_msgbus.h"
+#include "luat_malloc.h"
+#include "luat_nimble.h"
+
+/* BLE */
+#include "nimble/nimble_port.h"
+#include "nimble/nimble_port_freertos.h"
+
+/* Heart-rate configuration */
+#define GATT_HRS_UUID                           0x180D
+#define GATT_HRS_MEASUREMENT_UUID               0x2A37
+#define GATT_HRS_BODY_SENSOR_LOC_UUID           0x2A38
+#define GATT_DEVICE_INFO_UUID                   0x180A
+#define GATT_MANUFACTURER_NAME_UUID             0x2A29
+#define GATT_MODEL_NUMBER_UUID                  0x2A24
+
+/** GATT server. */
+#define GATT_SVR_SVC_ALERT_UUID               0x1811
+#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID   0x2A47
+#define GATT_SVR_CHR_NEW_ALERT                0x2A46
+#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID   0x2A48
+#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID      0x2A45
+#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT        0x2A44
+
+// extern uint16_t hrs_hrm_handle;
+
+typedef void (*TaskFunction_t)( void * );
+
+struct ble_hs_cfg;
+struct ble_gatt_register_ctxt;
+
+static void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
+static int gatt_svr_init(void);
+
+static const char *manuf_name = "LuatOS";
+static const char *model_num = "BLE Demo";
+static uint16_t hrs_hrm_handle;
+static uint16_t g_ble_attr_indicate_handle;
+static uint16_t g_ble_attr_write_handle;
+static uint16_t g_ble_conn_handle;
+// extern uint16_t g_ble_state;
+
+#define WM_GATT_SVC_UUID      0xFFF0
+#define WM_GATT_INDICATE_UUID 0xFFF1
+#define WM_GATT_WRITE_UUID    0xFFF2
+#define WM_GATT_NOTIFY_UUID    0xFFF3
+
+
+#define LUAT_LOG_TAG "nimble"
+#include "luat_log.h"
+
+static char selfname[32];
+// extern uint16_t g_ble_conn_handle;
+static uint16_t g_ble_state;
+
+typedef struct ble_write_msg {
+    // uint16_t conn_handle,
+    // uint16_t attr_handle,
+    ble_uuid_t* uuid;
+    uint16_t len;
+    char buff[1];
+}ble_write_msg_t;
+
+static int
+gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
+                               struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static int
+gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static int
+gatt_svr_chr_access_func(uint16_t conn_handle, uint16_t attr_handle,
+                               struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        /* Service: Heart-rate */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = BLE_UUID16_DECLARE(GATT_HRS_UUID),
+        .characteristics = (struct ble_gatt_chr_def[])
+        { {
+#if 1
+                /* Characteristic: Heart-rate measurement */
+                .uuid = BLE_UUID16_DECLARE(GATT_HRS_MEASUREMENT_UUID),
+                .access_cb = gatt_svr_chr_access_heart_rate,
+                .val_handle = &hrs_hrm_handle,
+                .flags = BLE_GATT_CHR_F_NOTIFY,
+            }, {
+                /* Characteristic: Body sensor location */
+                .uuid = BLE_UUID16_DECLARE(GATT_HRS_BODY_SENSOR_LOC_UUID),
+                .access_cb = gatt_svr_chr_access_heart_rate,
+                .flags = BLE_GATT_CHR_F_READ,
+            }, {
+#endif
+                /* Characteristic: Body sensor location */
+                .uuid = BLE_UUID16_DECLARE(WM_GATT_WRITE_UUID),
+                .val_handle = &g_ble_attr_write_handle,
+                .access_cb = gatt_svr_chr_access_func,
+                .flags = BLE_GATT_CHR_F_WRITE,
+            }, {
+                /* Characteristic: Body sensor location */
+                .uuid = BLE_UUID16_DECLARE(WM_GATT_INDICATE_UUID),
+                .val_handle = &g_ble_attr_indicate_handle,
+                .access_cb = gatt_svr_chr_access_func,
+                .flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ,
+            }, {
+                0, /* No more characteristics in this service */
+            },
+        }
+    },
+#if 1
+    {
+        /* Service: Device Information */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
+        .characteristics = (struct ble_gatt_chr_def[])
+        { {
+                /* Characteristic: * Manufacturer name */
+                .uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
+                .access_cb = gatt_svr_chr_access_device_info,
+                .flags = BLE_GATT_CHR_F_READ,
+            }, {
+                /* Characteristic: Model number string */
+                .uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
+                .access_cb = gatt_svr_chr_access_device_info,
+                .flags = BLE_GATT_CHR_F_READ,
+            }, {
+                0, /* No more characteristics in this service */
+            },
+        }
+    },
+#endif
+    {
+        0, /* No more services */
+    },
+};
+
+static int
+gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
+                               struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    /* Sensor location, set to "Chest" */
+    static uint8_t body_sens_loc = 0x01;
+    uint16_t uuid;
+    int rc;
+
+    uuid = ble_uuid_u16(ctxt->chr->uuid);
+
+    if (uuid == GATT_HRS_BODY_SENSOR_LOC_UUID) {
+        rc = os_mbuf_append(ctxt->om, &body_sens_loc, sizeof(body_sens_loc));
+
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+static int
+gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    uint16_t uuid;
+    int rc;
+
+    uuid = ble_uuid_u16(ctxt->chr->uuid);
+
+    if (uuid == GATT_MODEL_NUMBER_UUID) {
+        rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    if (uuid == GATT_MANUFACTURER_NAME_UUID) {
+        rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+static void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
+{
+    char buf[BLE_UUID_STR_LEN];
+
+    switch (ctxt->op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        LLOGD("registered service %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
+                    ctxt->svc.handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        LLOGD("registering characteristic %s with "
+                    "def_handle=%d val_handle=%d\n",
+                    ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
+                    ctxt->chr.def_handle,
+                    ctxt->chr.val_handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        LLOGD("registering descriptor %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
+                    ctxt->dsc.handle);
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+}
+
+static int l_ble_chr_write_cb(lua_State* L, void* ptr) {
+    ble_write_msg_t* wmsg = (ble_write_msg_t*)ptr;
+    rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
+    lua_getglobal(L, "sys_pub");
+    if (lua_isfunction(L, -1)) {
+        lua_pushstring(L, "BLE_GATT_WRITE_CHR");
+        lua_newtable(L);
+        lua_pushlstring(L, wmsg->buff, wmsg->len);
+        lua_call(L, 3, 0);
+    }
+    luat_heap_free(wmsg);
+    return 0;
+}
+
+static int
+gatt_svr_chr_access_func(uint16_t conn_handle, uint16_t attr_handle,
+                               struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    int i = 0;
+    struct os_mbuf *om = ctxt->om;
+    ble_write_msg_t* wmsg;
+    rtos_msg_t msg = {0};
+    LLOGD("gatt_svr_chr_access_func %d %d %d", conn_handle, attr_handle, ctxt->op);
+    switch (ctxt->op) {
+        case BLE_GATT_ACCESS_OP_WRITE_CHR:
+              while(om) {
+                  wmsg = (ble_write_msg_t*)(luat_heap_malloc(sizeof(ble_write_msg_t) + om->om_len - 1));
+                  if (wmsg != NULL) {
+                      wmsg->len = om->om_len;
+                      msg.handler = l_ble_chr_write_cb;
+                      msg.ptr = wmsg;
+                      msg.arg1 = conn_handle;
+                      msg.arg2 = attr_handle;
+                      memcpy(wmsg->buff, om->om_data, om->om_len);
+                      luat_msgbus_put(&msg, 0);
+                  }
+                  om = SLIST_NEXT(om, om_next);
+              }
+              return 0;
+        case BLE_GATT_ACCESS_OP_READ_CHR:
+            return 0;
+        default:
+            assert(0);
+            return BLE_ATT_ERR_UNLIKELY;
+    }
+}
+
+static int gatt_svr_init(void)
+{
+    int rc;
+
+    // ble_svc_gap_init();
+    //ble_gatts_reset();
+    // ble_svc_gatt_init();
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+int luat_nimble_server_send(int id, char* data, size_t data_len) {
+    int rc;
+    struct os_mbuf *om;
+
+    if (g_ble_state != BT_STATE_CONNECTED) {
+        //LLOGI("Not connected yet");
+        return -1;
+    }
+
+    om = ble_hs_mbuf_from_flat((const void*)data, (uint16_t)data_len);
+    if (!om) {
+        LLOGE("ble_hs_mbuf_from_flat return NULL!!");
+        return BLE_HS_ENOMEM;
+    }
+    rc = ble_gattc_indicate_custom(g_ble_conn_handle,g_ble_attr_indicate_handle, om);
+    LLOGD("ble_gattc_indicate_custom ret %d", rc);
+    return 0;
+}
+
+
+
+
+// static const char *tag = "NimBLE_BLE_PRPH";
+static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
+#else
+static uint8_t own_addr_type;
+#endif
+
+void ble_store_config_init(void);
+
+/**
+ * Logs information about a connection to the console.
+ */
+
+#define ADDR_FMT "%02X%02X%02X%02X%02X%02X"
+#define ADDR_T(addr) addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]
+
+static void
+bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
+{
+    LLOGI("handle=%d our_ota_addr_type=%d our_ota_addr=" ADDR_FMT, desc->conn_handle, desc->our_ota_addr.type, ADDR_T(desc->our_ota_addr.val));
+    LLOGI(" our_id_addr_type=%d our_id_addr=" ADDR_FMT, desc->our_id_addr.type, ADDR_T(desc->our_id_addr.val));
+    LLOGI(" peer_ota_addr_type=%d peer_ota_addr=" ADDR_FMT, desc->peer_ota_addr.type, ADDR_T(desc->peer_ota_addr.val));
+    LLOGI(" peer_id_addr_type=%d peer_id_addr=" ADDR_FMT, desc->peer_id_addr.type, ADDR_T(desc->peer_id_addr.val));
+    LLOGI(" conn_itvl=%d conn_latency=%d supervision_timeout=%d "
+                "encrypted=%d authenticated=%d bonded=%d\n",
+                desc->conn_itvl, desc->conn_latency,
+                desc->supervision_timeout,
+                desc->sec_state.encrypted,
+                desc->sec_state.authenticated,
+                desc->sec_state.bonded);
+}
+
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+/**
+ * Enables advertising with the following parameters:
+ *     o General discoverable mode.
+ *     o Undirected connectable mode.
+ */
+static void
+ext_bleprph_advertise(void)
+{
+    struct ble_gap_ext_adv_params params;
+    struct os_mbuf *data;
+    uint8_t instance = 1;
+    int rc;
+
+    /* use defaults for non-set params */
+    memset (&params, 0, sizeof(params));
+
+    /* enable connectable advertising */
+    params.connectable = 1;
+    params.scannable = 1;
+    params.legacy_pdu = 1;
+
+    /* advertise using random addr */
+    params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
+
+    params.primary_phy = BLE_HCI_LE_PHY_1M;
+    params.secondary_phy = BLE_HCI_LE_PHY_2M;
+    //params.tx_power = 127;
+    params.sid = 1;
+
+    params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
+    params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
+
+    /* configure instance 0 */
+    rc = ble_gap_ext_adv_configure(instance, &params, NULL,
+                                   bleprph_gap_event, NULL);
+    assert (rc == 0);
+
+    /* in this case only scan response is allowed */
+
+    /* get mbuf for scan rsp data */
+    data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
+    assert(data);
+
+    /* fill mbuf with scan rsp data */
+    rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
+    assert(rc == 0);
+
+    rc = ble_gap_ext_adv_set_data(instance, data);
+    assert (rc == 0);
+
+    /* start advertising */
+    rc = ble_gap_ext_adv_start(instance, 0, 0);
+    assert (rc == 0);
+}
+#else
+/**
+ * Enables advertising with the following parameters:
+ *     o General discoverable mode.
+ *     o Undirected connectable mode.
+ */
+static void
+bleprph_advertise(void)
+{
+    struct ble_gap_adv_params adv_params;
+    struct ble_hs_adv_fields fields;
+    const char *name;
+    int rc;
+
+    /**
+     *  Set the advertisement data included in our advertisements:
+     *     o Flags (indicates advertisement type and other general info).
+     *     o Advertising tx power.
+     *     o Device name.
+     *     o 16-bit service UUIDs (alert notifications).
+     */
+
+    memset(&fields, 0, sizeof fields);
+
+    /* Advertise two flags:
+     *     o Discoverability in forthcoming advertisement (general)
+     *     o BLE-only (BR/EDR unsupported).
+     */
+    fields.flags = BLE_HS_ADV_F_DISC_GEN |
+                   BLE_HS_ADV_F_BREDR_UNSUP;
+
+    /* Indicate that the TX power level field should be included; have the
+     * stack fill this value automatically.  This is done by assigning the
+     * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
+     */
+    fields.tx_pwr_lvl_is_present = 1;
+    fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
+
+    name = ble_svc_gap_device_name();
+    fields.name = (uint8_t *)name;
+    fields.name_len = strlen(name);
+    fields.name_is_complete = 1;
+
+    fields.uuids16 = (ble_uuid16_t[]) {
+        BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
+    };
+    fields.num_uuids16 = 1;
+    fields.uuids16_is_complete = 1;
+
+    rc = ble_gap_adv_set_fields(&fields);
+    if (rc != 0) {
+        LLOGE("error setting advertisement data; rc=%d\n", rc);
+        return;
+    }
+
+    /* Begin advertising. */
+    memset(&adv_params, 0, sizeof adv_params);
+    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+    rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
+                           &adv_params, bleprph_gap_event, NULL);
+    if (rc != 0) {
+        LLOGE("error enabling advertisement; rc=%d\n", rc);
+        return;
+    }
+}
+#endif
+
+/**
+ * The nimble host executes this callback when a GAP event occurs.  The
+ * application associates a GAP event callback with each connection that forms.
+ * bleprph uses the same callback for all connections.
+ *
+ * @param event                 The type of event being signalled.
+ * @param ctxt                  Various information pertaining to the event.
+ * @param arg                   Application-specified argument; unused by
+ *                                  bleprph.
+ *
+ * @return                      0 if the application successfully handled the
+ *                                  event; nonzero on failure.  The semantics
+ *                                  of the return code is specific to the
+ *                                  particular GAP event being signalled.
+ */
+static int
+bleprph_gap_event(struct ble_gap_event *event, void *arg)
+{
+    struct ble_gap_conn_desc desc;
+    int rc;
+
+    switch (event->type) {
+    case BLE_GAP_EVENT_CONNECT:
+        /* A new connection was established or a connection attempt failed. */
+        LLOGI("connection %s; status=%d ",
+                    event->connect.status == 0 ? "established" : "failed",
+                    event->connect.status);
+        if (event->connect.status == 0) {
+            g_ble_conn_handle = event->connect.conn_handle;
+            rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+            if (rc == 0)
+                bleprph_print_conn_desc(&desc);
+            g_ble_state = BT_STATE_CONNECTED;
+        }
+        else {
+            g_ble_state = BT_STATE_DISCONNECT;
+        }
+        // LLOGI("\n");
+
+        if (event->connect.status != 0) {
+            /* Connection failed; resume advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+            ext_bleprph_advertise();
+#else
+            bleprph_advertise();
+#endif
+        }
+        return 0;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        g_ble_state = BT_STATE_DISCONNECT;
+        LLOGI("disconnect; reason=%d ", event->disconnect.reason);
+        bleprph_print_conn_desc(&event->disconnect.conn);
+        // LLOGI("\n");
+
+        /* Connection terminated; resume advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+        ext_bleprph_advertise();
+#else
+        bleprph_advertise();
+#endif
+        return 0;
+
+    case BLE_GAP_EVENT_CONN_UPDATE:
+        /* The central has updated the connection parameters. */
+        LLOGI("connection updated; status=%d ", event->conn_update.status);
+        rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
+        if (rc == 0)
+            bleprph_print_conn_desc(&desc);
+        // LLOGI("\n");
+        return 0;
+
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        LLOGI("advertise complete; reason=%d", event->adv_complete.reason);
+#if !CONFIG_EXAMPLE_EXTENDED_ADV
+        bleprph_advertise();
+#endif
+        return 0;
+
+    case BLE_GAP_EVENT_ENC_CHANGE:
+        /* Encryption has been enabled or disabled for this connection. */
+        LLOGI("encryption change event; status=%d ",
+                    event->enc_change.status);
+        rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
+        if (rc == 0)
+            bleprph_print_conn_desc(&desc);
+        // LLOGI("\n");
+        return 0;
+
+    case BLE_GAP_EVENT_SUBSCRIBE:
+        LLOGI("subscribe event; conn_handle=%d attr_handle=%d "
+                    "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
+                    event->subscribe.conn_handle,
+                    event->subscribe.attr_handle,
+                    event->subscribe.reason,
+                    event->subscribe.prev_notify,
+                    event->subscribe.cur_notify,
+                    event->subscribe.prev_indicate,
+                    event->subscribe.cur_indicate);
+        return 0;
+
+    case BLE_GAP_EVENT_MTU:
+        LLOGI("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
+                    event->mtu.conn_handle,
+                    event->mtu.channel_id,
+                    event->mtu.value);
+        return 0;
+
+    case BLE_GAP_EVENT_REPEAT_PAIRING:
+        /* We already have a bond with the peer, but it is attempting to
+         * establish a new secure link.  This app sacrifices security for
+         * convenience: just throw away the old bond and accept the new link.
+         */
+
+        /* Delete the old bond. */
+        rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+        assert(rc == 0);
+        ble_store_util_delete_peer(&desc.peer_id_addr);
+
+        /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
+         * continue with the pairing operation.
+         */
+        return BLE_GAP_REPEAT_PAIRING_RETRY;
+
+    case BLE_GAP_EVENT_PASSKEY_ACTION:
+        LLOGI("PASSKEY_ACTION_EVENT started");
+#if 0
+        struct ble_sm_io pkey = {0};
+        int key = 0;
+
+        if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
+            pkey.action = event->passkey.params.action;
+            pkey.passkey = 123456; // This is the passkey to be entered on peer
+            // LLOGI("Enter passkey %d on the peer side", pkey.passkey);
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            LLOGI("ble_sm_inject_io BLE_SM_IOACT_DISP result: %d\n", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
+            LLOGI("Passkey on device's display: %d", event->passkey.params.numcmp);
+            LLOGI("Accept or reject the passkey through console in this format -> key Y or key N");
+            pkey.action = event->passkey.params.action;
+            // if (scli_receive_key(&key)) {
+            //     pkey.numcmp_accept = key;
+            // } else {
+            //     pkey.numcmp_accept = 0;
+            //     ESP_LOGE(tag, "Timeout! Rejecting the key");
+            // }
+            pkey.numcmp_accept = 1;
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            LLOGI("ble_sm_inject_io BLE_SM_IOACT_NUMCMP result: %d\n", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
+            static uint8_t tem_oob[16] = {0};
+            pkey.action = event->passkey.params.action;
+            for (int i = 0; i < 16; i++) {
+                pkey.oob[i] = tem_oob[i];
+            }
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            LLOGI("ble_sm_inject_io BLE_SM_IOACT_OOB result: %d\n", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
+            LLOGI("Passkey on device's display: %d", event->passkey.params.numcmp);
+            LLOGI("Enter the passkey through console in this format-> key 123456");
+            pkey.action = event->passkey.params.action;
+            // if (scli_receive_key(&key)) {
+            //     pkey.passkey = key;
+            // } else {
+            //     pkey.passkey = 0;
+            //     ESP_LOGE(tag, "Timeout! Passing 0 as the key");
+            // }
+            pkey.passkey = event->passkey.params.numcmp;
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            LLOGI("ble_sm_inject_io BLE_SM_IOACT_INPUT result: %d\n", rc);
+        }
+#endif
+        return 0;
+    }
+
+    return 0;
+}
+
+static void
+bleprph_on_reset(int reason)
+{
+    g_ble_state = BT_STATE_OFF;
+    LLOGE("Resetting state; reason=%d", reason);
+    //app_adapter_state_changed_callback(WM_BT_STATE_OFF);
+}
+
+
+static void
+bleprph_on_sync(void)
+{
+    int rc;
+
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+    /* Generate a non-resolvable private address. */
+    ble_app_set_addr();
+#endif
+
+    /* Make sure we have proper identity address set (public preferred) */
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+    rc = ble_hs_util_ensure_addr(1);
+#else
+    rc = ble_hs_util_ensure_addr(0);
+#endif
+    assert(rc == 0);
+
+    /* Figure out address to use while advertising (no privacy for now) */
+    rc = ble_hs_id_infer_auto(0, &own_addr_type);
+    if (rc != 0) {
+        LLOGE("error determining address type; rc=%d", rc);
+        return;
+    }
+
+    /* Printing ADDR */
+    uint8_t addr_val[6] = {0};
+    rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
+
+    LLOGI("Device Address: " ADDR_FMT, ADDR_T(addr_val));
+    ble_gatts_start();
+    //print_addr(addr_val);
+    // LLOGI("\n");
+    /* Begin advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+    ext_bleprph_advertise();
+#else
+    bleprph_advertise();
+#endif
+
+    if (g_ble_state == BT_STATE_OFF)
+        g_ble_state = BT_STATE_ON;
+}
+
+
+
+int luat_nimble_init_server(uint8_t uart_idx, char* name, int mode) {
+    int rc = 0;
+    nimble_port_init();
+
+    if (name == NULL || strlen(name) == 0) {
+        if (selfname[0] == 0) {
+            memcpy(selfname, "LuatOS", strlen("LuatOS") + 1);
+        }
+    }
+    else {
+        memcpy(selfname, name, strlen(name) + 1);
+    }
+
+    /* Set the default device name. */
+    if (strlen(selfname))
+        rc = ble_svc_gap_device_name_set((const char*)selfname);
+
+
+    /* Initialize the NimBLE host configuration. */
+    ble_hs_cfg.reset_cb = bleprph_on_reset;
+    ble_hs_cfg.sync_cb = bleprph_on_sync;
+    ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
+    ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+
+    ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
+    ble_hs_cfg.sm_sc = 0;
+
+
+    ble_svc_gap_init();
+    ble_svc_gatt_init();
+
+    rc = gatt_svr_init();
+    LLOGD("gatt_svr_init rc %d", rc);
+
+    /* XXX Need to have template for store */
+    ble_store_config_init();
+
+    return 0;
+}
+

+ 22 - 24
components/serialization/protobuf/luat_lib_protobuf.c

@@ -193,7 +193,7 @@ static void lpb_pushenchooktable(lua_State *L, lpb_State *LS)
 
 static void lpb_pushdechooktable(lua_State *L, lpb_State *LS)
 { LS->dec_hooks_index = lpb_reftable(L, LS->dec_hooks_index); }
-
+#if 0
 static int Lpb_delete(lua_State *L) {
     lpb_State *LS = (lpb_State*)luaL_testudata(L, 1, PB_STATE);
     if (LS != NULL) {
@@ -209,7 +209,7 @@ static int Lpb_delete(lua_State *L) {
     }
     return 0;
 }
-
+#endif
 LUALIB_API lpb_State *lpb_lstate(lua_State *L) {
     lpb_State *LS;
     if (lua53_rawgetp(L, LUA_REGISTRYINDEX, state_name) == LUA_TUSERDATA) {
@@ -230,7 +230,7 @@ LUALIB_API lpb_State *lpb_lstate(lua_State *L) {
     }
     return LS;
 }
-
+#if 0
 static int Lpb_state(lua_State *L) {
     int top = lua_gettop(L);
     lpb_lstate(L);
@@ -246,7 +246,7 @@ static int Lpb_state(lua_State *L) {
     }
     return 1;
 }
-
+#endif
 
 /* protobuf util routines */
 
@@ -257,7 +257,7 @@ static int typeerror(lua_State *L, int idx, const char *type) {
     lua_pushfstring(L, "%s expected, got %s", type, luaL_typename(L, idx));
     return luaL_argerror(L, idx, lua_tostring(L, -1));
 }
-
+#if 0
 static lua_Integer posrelat(lua_Integer pos, size_t len) {
     if (pos >= 0) return pos;
     else if (0u - (size_t)pos > len) return 0;
@@ -271,6 +271,7 @@ static lua_Integer rangerelat(lua_State *L, int idx, lua_Integer r[2], size_t le
     if (r[1] > (lua_Integer)len) r[1] = len;
     return r[0] <= r[1] ? r[1] - r[0] + 1 : 0;
 }
+#endif
 
 static int argcheck(lua_State *L, int cond, int idx, const char *fmt, ...) {
     if (!cond) {
@@ -364,14 +365,14 @@ static uint64_t lpb_tointegerx(lua_State *L, int idx, int *isint) {
     *isint = 1;
     return neg ? ~v + 1 : v;
 }
-
+#if 0
 static uint64_t lpb_checkinteger(lua_State *L, int idx) {
     int isint;
     uint64_t v = lpb_tointegerx(L, idx, &isint);
     if (!isint) typeerror(L, idx, "number/string");
     return v;
 }
-
+#endif
 static void lpb_pushinteger(lua_State *L, int64_t n, int mode) {
     if (mode != LPB_NUMBER && (n < INT_MIN || n > UINT_MAX)) {
         char buff[32], *p = buff + sizeof(buff) - 1;
@@ -537,7 +538,7 @@ static void lpb_readtype(lua_State *L, lpb_State *LS, int type, pb_Slice *s) {
 
 
 /* io routines */
-
+#if 0
 #ifdef _WIN32
 # include <io.h>
 # include <fcntl.h>
@@ -705,7 +706,6 @@ LUALIB_API int luaopen_pb_conv(lua_State *L) {
 
 
 /* protobuf encode routine */
-
 static int lpb_typefmt(int fmt) {
     switch (fmt) {
 #define X(name,type,fmt) case fmt: return PB_T##name;
@@ -898,7 +898,6 @@ LUALIB_API int luaopen_pb_buffer(lua_State *L) {
     return 1;
 }
 
-
 /* protobuf decode routine */
 
 #define LPB_INITSTACKLEN 2
@@ -1193,6 +1192,7 @@ LUALIB_API int luaopen_pb_slice(lua_State *L) {
     return 1;
 }
 
+#endif
 
 /* high level typeinfo/encode/decode routines */
 
@@ -1245,7 +1245,7 @@ static int Lpb_load(lua_State *L) {
     lua_pushinteger(L, pb_pos(s)+1);
     return 2;
 }
-
+#if 0
 static int Lpb_loadfile(lua_State *L) {
     lpb_State *LS = lpb_lstate(L);
     const char *filename = luaL_checkstring(L, 1);
@@ -1315,7 +1315,9 @@ static int Lpb_types(lua_State *L) {
     lua_pushnil(L);
     return 3;
 }
+#endif
 
+#if 0
 static int Lpb_fieldsiter(lua_State *L) {
     lpb_State *LS = lpb_lstate(L);
     const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1));
@@ -1357,7 +1359,7 @@ static int Lpb_enum(lua_State *L) {
         lpb_pushinteger(L, f->number, LS->int64_mode);
     return 1;
 }
-
+#endif
 static int lpb_pushdeffield(lua_State *L, lpb_State *LS, const pb_Field *f, int is_proto3) {
     int ret = 0;
     const pb_Type *type;
@@ -1436,7 +1438,6 @@ static void lpb_pushdefmeta(lua_State *L, lpb_State *LS, const pb_Type *t) {
     }
     lua_remove(L, -2);
 }
-
 static void lpb_cleardefmeta(lua_State *L, lpb_State *LS, const pb_Type *t) {
     lpb_pushdeftable(L, LS);
     lua_pushnil(L);
@@ -1444,6 +1445,7 @@ static void lpb_cleardefmeta(lua_State *L, lpb_State *LS, const pb_Type *t) {
     lua_pop(L, 1);
 }
 
+#if 0
 static int Lpb_defaults(lua_State *L) {
     lpb_State *LS = lpb_lstate(L);
     const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1));
@@ -1453,7 +1455,6 @@ static int Lpb_defaults(lua_State *L) {
     if (clear) lpb_cleardefmeta(L, LS, t);
     return 1;
 }
-
 static int Lpb_hook(lua_State *L) {
     lpb_State *LS = lpb_lstate(L);
     const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1));
@@ -1487,7 +1488,7 @@ static int Lpb_encode_hook(lua_State *L) {
     }
     return 1;
 }
-
+#endif
 /*
 清除已加载的二进制定义数据
 @api protobuf.clear()
@@ -1518,7 +1519,7 @@ static int Lpb_clear(lua_State *L) {
     lpb_cleardefmeta(L, LS, t);
     return 0;
 }
-
+#if 0
 static int Lpb_typefmt(lua_State *L) {
     pb_Slice s = lpb_checkslice(L, 1);
     const char *r = NULL;
@@ -1546,7 +1547,7 @@ static int Lpb_typefmt(lua_State *L) {
     lua_pushinteger(L, type);
     return 2;
 }
-
+#endif
 
 /* protobuf encode */
 
@@ -1748,7 +1749,7 @@ static int Lpb_encode(lua_State *L) {
     }
     return 1;
 }
-
+#if 0
 static int lpbE_pack(lpb_Env* e, const pb_Type* t, int idx) {
     unsigned i;
     lua_State* L = e->L;
@@ -1781,7 +1782,7 @@ static int Lpb_pack(lua_State* L) {
     }
     return 1;
 }
-
+#endif
 /* protobuf decode */
 
 #define lpb_withinput(e,ns,stmt) ((e)->s = (ns), (stmt), (e)->s = s)
@@ -1993,6 +1994,7 @@ static int Lpb_decode(lua_State *L) {
 }
 
 
+#if 0
 void lpb_pushunpackdef(lua_State* L, lpb_State* LS, const pb_Type* t, pb_Field** l, int top) {
     unsigned int i;
     int mode = LS->encode_mode;
@@ -2052,7 +2054,6 @@ static int lpbD_unpack(lpb_Env* e, const pb_Type* t) {
     if (decode_count != t->field_count) lpb_pushunpackdef(L, e->LS, t, list, top);
     return t->field_count;
 }
-
 static int Lpb_unpack(lua_State* L) {
     lpb_State* LS = lpb_lstate(L);
     const pb_Type* t = lpb_type(LS, lpb_checkslice(L, 1));
@@ -2064,7 +2065,6 @@ static int Lpb_unpack(lua_State* L) {
 }
 
 /* pb module interface */
-
 static int Lpb_option(lua_State *L) {
 #define OPTS(X) \
     X(0,  enum_as_name,         LS->enum_as_value = 0)               \
@@ -2104,8 +2104,6 @@ static int Lpb_option(lua_State *L) {
     return 0;
 #undef  OPTS
 }
-
-/*
 LUALIB_API int luaopen_pb(lua_State *L) {
     luaL_Reg libs[] = {
 #define ENTRY(name) { #name, Lpb_##name }
@@ -2146,7 +2144,6 @@ LUALIB_API int luaopen_pb(lua_State *L) {
     luaL_newlib(L, libs);
     return 1;
 }
-*/
 
 // static int Lpb_decode_unsafe(lua_State *L) {
 //     const char *data = (const char *)lua_touserdata(L, 2);
@@ -2192,6 +2189,7 @@ LUALIB_API int luaopen_pb(lua_State *L) {
 //     luaL_newlib(L, libs);
 //     return 1;
 // }
+#endif
 
 #include "luat_base.h"
 #include "rotable2.h"

+ 21 - 18
components/serialization/protobuf/pb.h

@@ -38,13 +38,16 @@
 # define PB_API extern
 #endif
 
-
-
-// #include "luat_base.h"
 #include "stdint.h"
 #include <stddef.h>
 #include <limits.h>
 
+void* luat_heap_malloc(size_t len);
+void  luat_heap_free(void* ptr);
+
+#define os_malloc luat_heap_malloc
+#define os_free luat_heap_free
+
 PB_NS_BEGIN
 
 
@@ -656,7 +659,7 @@ PB_API void pb_initbuffer(pb_Buffer *b)
 { memset(b, 0, sizeof(pb_Buffer)); }
 
 PB_API void pb_resetbuffer(pb_Buffer *b)
-{ if (pb_onheap(b)) free(b->u.h.buff); pb_initbuffer(b); }
+{ if (pb_onheap(b)) os_free(b->u.h.buff); pb_initbuffer(b); }
 
 static int pb_write32(char *buff, uint32_t n) {
     int p, c = 0;
@@ -790,7 +793,7 @@ PB_API void pb_freepool(pb_Pool *pool) {
     void *page = pool->pages;
     while (page) {
         void *next = *(void**)((char*)page + PB_POOLSIZE - sizeof(void*));
-        free(page);
+        os_free(page);
         page = next;
     }
     pb_initpool(pool, pool->obj_size);
@@ -800,7 +803,7 @@ PB_API void *pb_poolalloc(pb_Pool *pool) {
     void *obj = pool->freed;
     if (obj == NULL) {
         size_t objsize = pool->obj_size, offset;
-        void *newpage = malloc(PB_POOLSIZE);
+        void *newpage = os_malloc(PB_POOLSIZE);
         if (newpage == NULL) return NULL;
         offset = ((PB_POOLSIZE - sizeof(void*)) / objsize - 1) * objsize;
         for (; offset > 0; offset -= objsize) {
@@ -828,7 +831,7 @@ PB_API void pb_inittable(pb_Table *t, size_t entrysize)
 { memset(t, 0, sizeof(pb_Table)), t->entry_size = (unsigned)entrysize; }
 
 PB_API void pb_freetable(pb_Table *t)
-{ free(t->hash); pb_inittable(t, t->entry_size); }
+{ os_free(t->hash); pb_inittable(t, t->entry_size); }
 
 static pb_Entry *pbT_hash(const pb_Table *t, pb_Key key) {
     size_t h = ((size_t)key*2654435761U)&(t->size-1);
@@ -876,7 +879,7 @@ PB_API size_t pb_resizetable(pb_Table *t, size_t size) {
     if (newsize < size) return 0;
     nt.size     = newsize;
     nt.lastfree = nt.entry_size * newsize;
-    nt.hash     = (pb_Entry*)malloc(nt.lastfree);
+    nt.hash     = (pb_Entry*)os_malloc(nt.lastfree);
     if (nt.hash == NULL) return 0;
     memset(nt.hash, 0, nt.lastfree);
     for (i = 0; i < rawsize; i += t->entry_size) {
@@ -885,7 +888,7 @@ PB_API size_t pb_resizetable(pb_Table *t, size_t size) {
         if (nt.entry_size > sizeof(pb_Entry))
             memcpy(newe+1, olde+1, nt.entry_size - sizeof(pb_Entry));
     }
-    free(t->hash);
+    os_free(t->hash);
     *t = nt;
     return newsize;
 }
@@ -944,11 +947,11 @@ static void pbN_free(pb_State *S) {
         pb_NameEntry *ne = nt->hash[i];
         while (ne != NULL) {
             pb_NameEntry *next = ne->next;
-            free(ne);
+            os_free(ne);
             ne = next;
         }
     }
-    free(nt->hash);
+    os_free(nt->hash);
     pbN_init(S);
 }
 
@@ -968,7 +971,7 @@ static size_t pbN_resize(pb_State *S, size_t size) {
     while (newsize < PB_MAX_HASHSIZE/sizeof(pb_NameEntry*) && newsize < size)
         newsize <<= 1;
     if (newsize < size) return 0;
-    hash = (pb_NameEntry**)malloc(newsize * sizeof(pb_NameEntry*));
+    hash = (pb_NameEntry**)os_malloc(newsize * sizeof(pb_NameEntry*));
     if (hash == NULL) return 0;
     memset(hash, 0, newsize * sizeof(pb_NameEntry*));
     for (i = 0; i < nt->size; ++i) {
@@ -980,7 +983,7 @@ static size_t pbN_resize(pb_State *S, size_t size) {
             entry = next;
         }
     }
-    free(nt->hash);
+    os_free(nt->hash);
     nt->hash = hash;
     nt->size = newsize;
     return newsize;
@@ -992,7 +995,7 @@ static pb_NameEntry *pbN_newname(pb_State *S, pb_Slice s, unsigned hash) {
     size_t len = pb_len(s);
     if (nt->count >= nt->size && !pbN_resize(S, nt->size * 2)) return NULL;
     list = &nt->hash[hash & (nt->size - 1)];
-    newobj = (pb_NameEntry*)malloc(sizeof(pb_NameEntry) + len + 1);
+    newobj = (pb_NameEntry*)os_malloc(sizeof(pb_NameEntry) + len + 1);
     if (newobj == NULL) return NULL;
     newobj->next     = *list;
     newobj->length   = (unsigned)len;
@@ -1014,7 +1017,7 @@ static void pbN_delname(pb_State *S, pb_NameEntry *name) {
         else {
             *list = (*list)->next;
             --nt->count;
-            free(name);
+            os_free(name);
             break;
         }
     }
@@ -1140,7 +1143,7 @@ PB_API pb_Field** pb_sortfield(pb_Type* t) {
         int index = 0;
         unsigned int i = 0;
         const pb_Field* f = NULL;
-        pb_Field** list = malloc(sizeof(pb_Field*) * t->field_count);
+        pb_Field** list = os_malloc(sizeof(pb_Field*) * t->field_count);
 
         assert(list);
         while (pb_nextfield(t, &f)) {
@@ -1228,7 +1231,7 @@ PB_API pb_Type *pb_newtype(pb_State *S, pb_Name *tname) {
 
 PB_API void pb_delsort(pb_Type *t) {
     if (t->field_sort) {
-        free(t->field_sort);
+        os_free(t->field_sort);
         t->field_sort = NULL;
     }
 }
@@ -1318,7 +1321,7 @@ typedef struct pb_ArrayHeader {
 } pb_ArrayHeader;
 
 #define pbL_rawh(A)   ((pb_ArrayHeader*)(A) - 1)
-#define pbL_delete(A) ((A) ? (void)free(pbL_rawh(A)) : (void)0)
+#define pbL_delete(A) ((A) ? (void)os_free(pbL_rawh(A)) : (void)0)
 #define pbL_count(A)  ((A) ? pbL_rawh(A)->count    : 0)
 #define pbL_add(A)    (pbL_grow((void**)&(A),sizeof(*(A)))==PB_OK ?\
                        &(A)[pbL_rawh(A)->count++] : NULL)

+ 59 - 28
components/u8g2/luat_lib_u8g2.c

@@ -33,6 +33,16 @@ static uint8_t spi_res;
 static uint8_t spi_dc;
 static uint8_t spi_cs;
 
+static uint8_t * buff_ptr = NULL;
+
+static const char* mode_strs[] = {
+    "i2c_sw",
+    "i2c_hw",
+    "spi_sw_3pin",
+    "spi_sw_4pin",
+    "spi_hw_4pin"
+};
+
 /*
 u8g2显示屏初始化
 @api u8g2.begin(conf)
@@ -64,13 +74,15 @@ static int l_u8g2_begin(lua_State *L) {
     conf.pinType = 2; // I2C 硬件(或者是个假硬件)
     conf.ptr = u8g2;
     conf.direction = U8G2_R0;
+    char mode[8] = {0};
+    size_t mode_len = 0;
     if (lua_istable(L, 1)) {
         // 参数解析
         lua_pushliteral(L, "ic");
         lua_gettable(L, 1);
         if (lua_isstring(L, -1)) {
             conf.cname = (char*)luaL_checkstring(L, -1);
-            LLOGD("using ic: %s",conf.cname);
+            //LLOGD("using ic: %s",conf.cname);
         }
         lua_pop(L, 1);
 
@@ -102,31 +114,29 @@ static int l_u8g2_begin(lua_State *L) {
 
         lua_pushliteral(L, "mode");
         lua_gettable(L, 1);
-        if (lua_isstring(L, -1)) {
-            const char* mode = luaL_checkstring(L, -1);
-            LLOGD("mode = [%s]", mode);
-            if (strcmp("i2c_sw", mode) == 0) {
-                LLOGD("using i2c_sw");
-                conf.pinType = 1;
-            }
-            else if (strcmp("i2c_hw", mode) == 0) {
-                LLOGD("using i2c_hw");
-                conf.pinType = 2;
-            }
-            else if (strcmp("spi_sw_3pin", mode) == 0) {
-                LLOGD("using spi_sw_3pin");
-                conf.pinType = 3;
-            }
-            else if (strcmp("spi_sw_4pin", mode) == 0) {
-                LLOGD("using spi_sw_4pin");
-                conf.pinType = 4;
-            }
-            else if (strcmp("spi_hw_4pin", mode) == 0) {
-                LLOGD("using spi_hw_4pin");
-                conf.pinType = 5;
-            }
+        if (!lua_isstring(L, -1)) {
+            LLOGE("need mode!!!");
+            return 0;
+        }
+        const char* tmp = luaL_checklstring(L, -1, &mode_len);
+        if (mode_len < 1 || mode_len > 7) {
+            LLOGE("mode string too short or too long!!");
+            return 0;
         }
+        memcpy(mode, tmp, strlen(tmp));
         lua_pop(L, 1);
+        conf.pinType = 255;
+        for (size_t i = 0; i < sizeof(mode_strs) / sizeof(const char*); i++)
+        {
+            if (strcmp(mode_strs[i], tmp) == 0) {
+                conf.pinType = i + 1;
+                break;
+            }
+        }
+        if (conf.pinType == 255) {
+            LLOGE("no such mode [%s]", tmp);
+            return 0;
+        }
 
         lua_pushliteral(L, "i2c_scl");
         lua_gettable(L, 1);
@@ -185,14 +195,14 @@ static int l_u8g2_begin(lua_State *L) {
         lua_pop(L, 1);
 
     }
-    LLOGD("pinType=%d", conf.pinType);
+    LLOGD("driver %s mode %s", conf.cname, mode);
     if (luat_u8g2_setup(&conf)) {
         u8g2 = NULL;
         LLOGW("disp init fail");
         lua_pushinteger(L, 4);
         return 1; // 初始化失败
     }
-
+    LLOGD("setup done");
     u8g2_lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
     u8g2_SetFont(u8g2, u8g2_font_ncenB08_tr); // 设置默认字体
     lua_pushinteger(L, 1);
@@ -214,6 +224,12 @@ static int l_u8g2_close(lua_State *L) {
         }
         u8g2_lua_ref = 0;
     }
+    // buff也得释放掉
+    if (buff_ptr != NULL) {
+        luat_heap_free(buff_ptr);
+        buff_ptr = NULL;
+    }
+    lua_gc(L, LUA_GCCOLLECT, 0);
     lua_gc(L, LUA_GCCOLLECT, 0);
     u8g2 = NULL;
     return 0;
@@ -929,6 +945,7 @@ static const luat_u8g2_dev_reg_t devregs[] = {
     {.name="sh1106",  .w=128, .h=64, .spi_i2c=1, .devcb=u8g2_Setup_sh1106_128x64_noname_f},        // sh1106 128x64,SPI
     {.name="sh1107",  .w=64, .h=128, .spi_i2c=0, .devcb=u8g2_Setup_ssd1306_i2c_128x64_noname_f},       // sh1107 64x128
     {.name="st7567",  .w=128, .h=64, .spi_i2c=1, .devcb=u8g2_Setup_st7567_jlx12864_f},                 // st7567 128x64
+    {.name="uc1701",  .w=128, .h=64, .spi_i2c=1, .devcb=u8g2_Setup_uc1701_mini12864_f},                // uc1701
     {.name=NULL} // 结尾用,必须加.
 };
 
@@ -968,6 +985,10 @@ int luat_u8g2_setup_default(luat_u8g2_conf_t *conf) {
             return -1;
         }
         devreg->devcb(u8g2, conf->direction, u8x8_byte_sw_i2c, u8x8_luat_gpio_and_delay_default);
+        #ifdef U8G2_USE_DYNAMIC_ALLOC
+        buff_ptr = (uint8_t *)luat_heap_malloc(u8g2_GetBufferSize(u8g2));
+        u8g2_SetBufferPtr(u8g2, buff_ptr);
+        #endif
         u8g2->u8x8.pins[U8X8_PIN_I2C_CLOCK] = i2c_scl;
         u8g2->u8x8.pins[U8X8_PIN_I2C_DATA] = i2c_sda;
         u8g2_InitDisplay(u8g2);
@@ -980,7 +1001,11 @@ int luat_u8g2_setup_default(luat_u8g2_conf_t *conf) {
             return -1;
         }
         devreg->devcb(u8g2, conf->direction, u8x8_luat_byte_hw_i2c_default, u8x8_luat_gpio_and_delay_default);
-        LLOGD("setup disp i2c.hw");
+        #ifdef U8G2_USE_DYNAMIC_ALLOC
+        buff_ptr = (uint8_t *)luat_heap_malloc(u8g2_GetBufferSize(u8g2));
+        u8g2_SetBufferPtr(u8g2, buff_ptr);
+        #endif
+        //LLOGD("setup disp i2c.hw");
         u8g2_InitDisplay(u8g2);
         u8g2_SetPowerSave(u8g2, 0);
         return 0;
@@ -991,6 +1016,10 @@ int luat_u8g2_setup_default(luat_u8g2_conf_t *conf) {
             return -1;
         }
         devreg->devcb(u8g2, conf->direction, u8x8_luat_byte_4wire_hw_spi_default, u8x8_luat_gpio_and_delay_default);
+        #ifdef U8G2_USE_DYNAMIC_ALLOC
+        buff_ptr = (uint8_t *)luat_heap_malloc(u8g2_GetBufferSize(u8g2));
+        u8g2_SetBufferPtr(u8g2, buff_ptr);
+        #endif
         LLOGD("setup disp spi.hw  spi_id=%d spi_dc=%d spi_cs=%d spi_res=%d",spi_id,spi_dc,spi_cs,spi_res);
         u8x8_SetPin(u8g2_GetU8x8(u8g2), U8X8_PIN_CS, spi_cs);
         u8x8_SetPin(u8g2_GetU8x8(u8g2), U8X8_PIN_DC, spi_dc);
@@ -999,7 +1028,9 @@ int luat_u8g2_setup_default(luat_u8g2_conf_t *conf) {
         u8g2_SetPowerSave(u8g2, 0);
         return 0;
     }
-    LLOGI("no such u8g2 mode!!");
+    else {
+        LLOGI("no such u8g2 mode!!");
+    }
     return -1;
 }
 

+ 2 - 2
components/u8g2/u8g2.h

@@ -84,12 +84,12 @@
   Before using any display functions, the dynamic buffer *must* be assigned to the u8g2 struct using the u8g2_SetBufferPtr function.
   When using dynamic allocation, the stack size must be increased by u8g2_GetBufferSize bytes.
  */
-//#define U8G2_USE_DYNAMIC_ALLOC
+#define U8G2_USE_DYNAMIC_ALLOC
 
 /*
   U8G2 uses the same static array
  */
-#define U8G2_USE_ONE_STATIC_BUFF
+// #define U8G2_USE_ONE_STATIC_BUFF
 
 /* U8g2 feature selection, see also https://github.com/olikraus/u8g2/wiki/u8g2optimization */
 

+ 211 - 0
components/wlan/luat_lib_wlan.c

@@ -0,0 +1,211 @@
+#include "luat_base.h"
+#include "luat_wlan.h"
+
+#define LUAT_LOG_TAG "wlan"
+#include "luat_log.h"
+
+static int l_wlan_init(lua_State* L){
+    luat_wlan_init(NULL);
+    return 0;
+}
+
+static int l_wlan_mode(lua_State* L){
+    int mode = LUAT_WLAN_MODE_STA;
+    if (lua_isinteger(L, 1)) {
+        mode = lua_tointeger(L, 1);
+    }
+    else if (lua_isinteger(L, 2)) {
+        mode = lua_tointeger(L, 2);
+    }
+
+    if (mode <= LUAT_WLAN_MODE_NULL || mode >= LUAT_WLAN_MODE_MAX) {
+        mode = LUAT_WLAN_MODE_STA;
+    }
+
+    // switch (mode)
+    // {
+    // case LUAT_WLAN_MODE_NULL:
+    //     LLOGD("wlan mode NULL");
+    //     break;
+    // case LUAT_WLAN_MODE_STA:
+    //     LLOGD("wlan mode STATION");
+    //     break;
+    // case LUAT_WLAN_MODE_AP:
+    //     LLOGD("wlan mode AP");
+    //     break;
+    // case LUAT_WLAN_MODE_APSTA:
+    //     LLOGD("wlan mode AP-STATION");
+    //     break;
+    
+    // default:
+    //     break;
+    // }
+    luat_wlan_config_t conf = {
+        .mode = mode
+    };
+    luat_wlan_mode(&conf);
+    return 0;
+}
+
+static int l_wlan_ready(lua_State* L){
+    lua_pushboolean(L, luat_wlan_ready());
+    return 1;
+}
+
+static int l_wlan_connect(lua_State* L){
+    const char* ssid = luaL_optstring(L, 1, "");
+    const char* password = luaL_optstring(L, 2, "");
+    luat_wlan_conninfo_t info = {0};
+    info.auto_reconnection = 1;
+    memcpy(info.ssid, ssid, strlen(ssid));
+    memcpy(info.password, password, strlen(password));
+
+    luat_wlan_connect(&info);
+    return 0;
+}
+
+static int l_wlan_disconnect(lua_State* L){
+    luat_wlan_disconnect();
+    return 0;
+}
+
+static int l_wlan_scan(lua_State* L){
+    luat_wlan_scan();
+    return 0;
+}
+
+static int l_wlan_scan_result(lua_State* L) {
+    int ap_limit = luaL_optinteger(L, 1, 20);
+    if (ap_limit > 32)
+        ap_limit = 32;
+    else if (ap_limit < 8)
+        ap_limit = 8;
+    lua_newtable(L);
+    luat_wlan_scan_result_t *results = luat_heap_malloc(sizeof(luat_wlan_scan_result_t) * ap_limit);
+    if (results == NULL) {
+        LLOGE("out of memory when malloc scan result");
+        return 1;
+    }
+    memset(results, 0, sizeof(luat_wlan_scan_result_t) * ap_limit);
+    int len = luat_wlan_scan_get_result(results, ap_limit);
+    for (size_t i = 0; i < len; i++)
+    {
+        lua_newtable(L);
+
+        lua_pushstring(L, (const char *)results[i].ssid);
+        lua_setfield(L, -2, "ssid");
+
+        // lua_pushfstring(L, "%02X%02X%02X%02X%02X%02X", results[i].bssid[0], 
+        //                                                results[i].bssid[1], 
+        //                                                results[i].bssid[2], 
+        //                                                results[i].bssid[3], 
+        //                                                results[i].bssid[4], 
+        //                                                results[i].bssid[5]);
+        lua_pushlstring(L, (const char *)results[i].bssid, 6);
+        lua_setfield(L, -2, "bssid");
+
+        lua_pushinteger(L, results[i].ch);
+        lua_setfield(L, -2, "channel");
+
+        lua_pushinteger(L, results[i].rssi);
+        lua_setfield(L, -2, "rssi");
+
+        lua_seti(L, -2, i + 1);
+    }
+    luat_heap_free(results);
+    return 1;
+}
+
+static int l_wlan_smartconfig(lua_State *L) {
+    int tp = luaL_optinteger(L, 1, LUAT_SC_TYPE_ESPTOUCH);
+    if (tp == LUAT_SC_TYPE_STOP) {
+        luat_wlan_smartconfig_stop();
+        return 0;
+    }
+    else {
+        int ret = luat_wlan_smartconfig_start(tp);
+        lua_pushboolean(L, ret == 0 ? 1 : 0);
+        return 1;
+    }
+}
+
+// 获取mac
+static int l_wlan_get_mac(lua_State* L){
+    char tmp[6] = {0};
+    char tmpbuff[16] = {0};
+    luat_wlan_get_mac(luaL_optinteger(L, 1, 0), tmp);
+    sprintf_(tmpbuff, "%02X%02X%02X%02X%02X%02X", tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]);
+    lua_pushstring(L, tmpbuff);
+    return 1;
+}
+
+// 启动AP
+static int l_wlan_ap_start(lua_State *L) {
+    size_t ssid_len = 0;
+    size_t password_len = 0;
+    luat_wlan_apinfo_t apinfo = {0};
+    const char* ssid = luaL_checklstring(L, 1, &ssid_len);
+    const char* password = luaL_optlstring(L, 2, "", &password_len);
+    if (ssid_len < 1) {
+        LLOGE("ssid MUST NOT EMTRY");
+        return 0;
+    }
+    if (ssid_len > 32) {
+        LLOGE("ssid too long [%s]", ssid);
+        return 0;
+    }
+    if (password_len > 63) {
+        LLOGE("password too long [%s]", password);
+        return 0;
+    }
+
+    memcpy(apinfo.ssid, ssid, ssid_len);
+    memcpy(apinfo.password, password, password_len);
+
+    int ret = luat_wlan_ap_start(&apinfo);
+    LLOGD("apstart ret %d", ret);
+    lua_pushboolean(L, ret == 0 ? 1 : 0);
+    return 1;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_wlan[] =
+{
+    { "init",               ROREG_FUNC(l_wlan_init)},
+    { "mode",               ROREG_FUNC(l_wlan_mode)},
+    { "setMode",            ROREG_FUNC(l_wlan_mode)},
+    // { "setMode",           ROREG_FUNC(l_wlan_set_mode)},
+    // { "getMode",           ROREG_FUNC(l_wlan_get_mode)},
+    { "ready",              ROREG_FUNC(l_wlan_ready)},
+    { "connect",            ROREG_FUNC(l_wlan_connect)},
+    { "disconnect",         ROREG_FUNC(l_wlan_disconnect)},
+    { "scan",               ROREG_FUNC(l_wlan_scan)},
+    { "scanResult",         ROREG_FUNC(l_wlan_scan_result)},
+
+    // 配网相关
+    { "smartconfig",         ROREG_FUNC(l_wlan_smartconfig)},
+
+    { "getMac",              ROREG_FUNC(l_wlan_get_mac)},
+
+    // AP相关
+    { "createAP",            ROREG_FUNC(l_wlan_ap_start)},
+
+    // 常数
+    {"NONE",                ROREG_INT(LUAT_WLAN_MODE_NULL)},
+    {"STATION",             ROREG_INT(LUAT_WLAN_MODE_STA)},
+    {"AP",                  ROREG_INT(LUAT_WLAN_MODE_AP)},
+    {"STATIONAP",           ROREG_INT(LUAT_WLAN_MODE_APSTA)},
+
+    // smartconfig 配网
+    {"STOP",                ROREG_INT(0)},
+    {"ESPTOUCH",            ROREG_INT(LUAT_SC_TYPE_ESPTOUCH)},
+    {"AIRKISS",             ROREG_INT(LUAT_SC_TYPE_AIRKISS)},
+    {"ESPTOUCH_AIRKISS",    ROREG_INT(LUAT_SC_TYPE_ESPTOUCH_AIRKISS)},
+    {"ESPTOUCH_V2",         ROREG_INT(LUAT_SC_TYPE_ESPTOUCH_V2)},
+	{ NULL,                 ROREG_INT(0)}
+};
+
+LUAMOD_API int luaopen_wlan( lua_State *L ) {
+    luat_newlib2(L, reg_wlan);
+    return 1;
+}

+ 71 - 0
components/wlan/luat_wlan.h

@@ -0,0 +1,71 @@
+#include "luat_base.h"
+#include "luat_msgbus.h"
+#include "luat_malloc.h"
+
+typedef struct luat_wlan_config
+{
+    uint32_t mode;
+}luat_wlan_config_t;
+
+typedef struct luat_wlan_conninfo
+{
+    char ssid[36];
+    char password[64];
+    char bssid[8];
+    uint32_t authmode;
+    uint32_t auto_reconnection;
+    uint32_t auto_reconnection_delay_sec;
+}luat_wlan_conninfo_t;
+
+typedef struct luat_wlan_apinfo
+{
+    char ssid[36];
+    char password[64];
+}luat_wlan_apinfo_t;
+
+enum LUAT_WLAN_MODE {
+    LUAT_WLAN_MODE_NULL,
+    LUAT_WLAN_MODE_STA,
+    LUAT_WLAN_MODE_AP,
+    LUAT_WLAN_MODE_APSTA,
+    LUAT_WLAN_MODE_MAX
+};
+
+typedef struct luat_wlan_scan_result
+{
+    char ssid[33];
+    char bssid[6];
+    int16_t rssi;
+    int8_t ch;
+}luat_wlan_scan_result_t;
+
+
+
+int luat_wlan_init(luat_wlan_config_t *conf);
+int luat_wlan_mode(luat_wlan_config_t *conf);
+int luat_wlan_ready(void);
+int luat_wlan_connect(luat_wlan_conninfo_t* info);
+int luat_wlan_disconnect(void);
+int luat_wlan_scan(void);
+int luat_wlan_scan_get_result(luat_wlan_scan_result_t *results, int ap_limit);
+
+// 配网相关
+// --- smartconfig 配网
+enum LUAT_WLAN_SC_TYPE {
+    LUAT_SC_TYPE_STOP = 0,
+    LUAT_SC_TYPE_ESPTOUCH,
+    LUAT_SC_TYPE_AIRKISS,
+    LUAT_SC_TYPE_ESPTOUCH_AIRKISS,
+    LUAT_SC_TYPE_ESPTOUCH_V2
+};
+
+int luat_wlan_smartconfig_start(int tp);
+int luat_wlan_smartconfig_stop(void);
+
+// 数据类
+int luat_wlan_get_mac(int id, char* mac);
+int luat_wlan_set_mac(int id, char* mac);
+
+// AP类
+int luat_wlan_ap_start(luat_wlan_apinfo_t *apinfo);
+

+ 7 - 0
demo/camera/Air105/README.md

@@ -0,0 +1,7 @@
+# Air105摄像头的实例合集
+
+* capture - 捕捉图片并存入sd卡
+* raw_mode - 将摄像头数据通过w5500的udp协议发送到局域网,很慢
+* scanner - 演示扫码
+* synthesis - 综合演示, 扫码, 拍照, 存图
+* video - USB视频流, 可到5~10fps. 论图像质量,依然比不上某宝15块钱的USB摄像头

+ 0 - 336
demo/camera/Air105/capture_usb/GC032A_InitReg.txt

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

+ 3 - 0
demo/camera/Air105/capture_usb/README.md

@@ -0,0 +1,3 @@
+# 本demo已废弃
+
+请使用 video 示例

+ 0 - 110
demo/camera/Air105/capture_usb/main.lua

@@ -1,110 +0,0 @@
---[[
-
-特别提醒: 本demo已经有更好的替代品: video, 请使用新版video demo, 效果比本demo好很多.
-
-这是Air105+摄像头, 通过USB传输JPG到上位机显示图片的示例, 速率2fps, 色彩空间 RGB565, 不要期望太高
-本demo不需要lcd屏,但lcd的代码暂不可省略
-
-本demo需要V0006, 20220331之后编译的固件版本, 老版本不可用
-
-测试流程:
-1. 先选取最新固件, 配合本demo的main.lua及GC032A_InitReg.txt, 两个文件都需要下载到设备
-2. 断开USB, 将拨动开关切换到另一端, 切勿带电操作!!!
-3. 重新插入USB
-4. 打开上位机, 选择正确的COM口, 然后开始读取
-
--- USB驱动下载 https://doc.openluat.com/wiki/21?wiki_page_id=2070
--- USB驱动与 合宙Cat.1的USB驱动是一致的
-
-上位机下载: https://gitee.com/openLuat/luatos-soc-air105/attach_files
-上位机源码: https://gitee.com/openLuat/luatos-soc-air105 C#写的, 就能用, 勿生产
-
-
-]]
-
-PROJECT = "usbcamera"
-VERSION = "1.0.0"
-
-sys = require("sys")
-
-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("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))
-
---GC032A输出rgb图像初始化命令
-local GC032A_InitReg =
-{
-	zbar_scan = 0,--是否为扫码
-    draw_lcd = 0,--是否向lcd输出
-    i2c_id = 0,
-	i2c_addr = 0x21,
-    pwm_id = 5;
-    pwm_period  = 12*1000*1000,
-    pwm_pulse = 0,
-	sensor_width = 640,
-	sensor_height = 480,
-    color_bit = 16,
-	init_cmd ="/luadb/GC032A_InitReg.txt"--此方法将初始化指令写在外部文件,支持使用 # 进行注释
-}
-
-local uartid = uart.VUART_0 -- 根据实际设备选取不同的uartid
---初始化
-local result = uart.setup(
-    uartid,--串口id
-    115200,--波特率
-    8,--数据位
-    1--停止位
-)
-
-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引脚
-
-camera_rst(0)
-
--- 拍照, 自然就是RGB输出了
-local camera_id = camera.init(GC032A_InitReg)--屏幕输出rgb图像
-
-log.info("摄像头启动")
-camera.start(camera_id)--开始指定的camera
-log.info("摄像头启动完成")
-
-usbapp.start(0)
-
-camera.on(0, "scanned", function()
-    sys.publish("scanned")
-end)
-
-sys.taskInit(function()
-
-    while 1 do
-            -- 稍微等待一下
-            sys.wait(100)
-            log.debug("摄像头捕获图像")
-            -- 删除老的图片,避免重复显示
-            os.remove("/temp.jpg")
-            camera.capture(camera_id, "/temp.jpg", 1)
-            sys.waitUntil("scanned", 1000)
-            local f = io.open("/temp.jpg", "r")
-            local data
-            if f then -- 若文件存在, 必然能打开并读取, 否则肯定拍照失败了
-                data = f:read("*a")
-                log.info("fs", #data)
-                f:close()
-
-                -- 请使用上位机读取
-                uart.write(uart.VUART_0, "Air105 USB JPG " .. tostring(#data) .. "\r\n")
-                uart.write(uart.VUART_0, data)
-            end
-    end
-
-end)
-
--- 用户代码已结束---------------------------------------------
--- 结尾总是这一句
-sys.run()
--- sys.run()之后后面不要加任何语句!!!!!

+ 13 - 0
demo/camera/Air105/scanner/main.lua

@@ -21,6 +21,19 @@ BL           (PE09) --开发板上的U3_TX
 提示:
 1. 只使用SPI的时钟线(SCK)和数据输出线(MOSI), 其他均为GPIO脚
 2. 数据输入(MISO)和片选(CS), 虽然是SPI, 但已复用为GPIO, 并非固定,是可以自由修改成其他脚
+
+-- USB驱动下载 https://doc.openluat.com/wiki/21?wiki_page_id=2070
+-- USB驱动与 合宙Cat.1的USB驱动是一致的
+
+扫码解码会输出日志, 也会输出到USB HID.
+
+若需要通过USB HID查看
+1. 要安装USB驱动
+2. 刷好脚本, 务必把txt也下载下去,总共3个文件.
+3. 断电, 拨动切换开关, 重新连接电脑
+4. 打开记事本, 光标处于输入状态
+5. 移动摄像头进行扫码, 结果会输出到记事本, 每行一次
+
 ]]
 
 if wdt then

+ 23 - 24
demo/camera/Air105/video/camera_test.lua

@@ -2,16 +2,16 @@
 --编译好的工具:https://gitee.com/openLuat/luatos-soc-air105/attach_files
 local GC032A_InitReg =
 {
-	zbar_scan = 0,--是否为扫码
-    draw_lcd = 0,--是否向lcd输出
+	zbar_scan = 0,--是否为扫码, 扫码模式会显示灰度图像!!!
+    draw_lcd = 0,--是否向lcd输出, 若没有接lcd显示屏就不用设置为1
     i2c_id = 0,
 	i2c_addr = 0x21,
     pwm_id = 5;
-    pwm_period  = 24*1000*1000,
+    pwm_period  = 24*1000*1000, -- 摄像头的时钟线的波特率
     pwm_pulse = 0,
-	sensor_width = 640,
+	sensor_width = 640, -- GC032A摄像头的实际分辨率是30w,但内存不足,实际显示居中的1/4图像
 	sensor_height = 480,
-    color_bit = 16,
+    color_bit = 16, -- 颜色空间是 RGB565
 	init_cmd = "/luadb/GC032A_InitReg.txt"--此方法将初始化指令写在外部文件,支持使用 # 进行注释
 
 }
@@ -20,6 +20,24 @@ 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)
+    uart.setup(
+        uart.VUART_0,-- USB虚拟串口id
+        115200,--波特率
+        8,--数据位
+        1--停止位
+    )
+	-- 拍照, 自然就是RGB输出了
+	local camera_id = camera.init(GC032A_InitReg)--屏幕输出rgb图像
+
+	log.info("摄像头启动")
+    camera.video(camera_id, 320, 240, uart.VUART_0)
+	log.info("摄像头启动完成")
+end)
+
+-- 以下是扫码的回调, 仅当zbar_scan=1时会有回调
 camera.on(0, "scanned", function(id, str)
     if type(str) == 'string' then
         log.info("扫码结果", str)
@@ -38,22 +56,3 @@ camera.on(0, "scanned", function(id, str)
         log.error("摄像头没有数据")
     end
 end)
-
-sys.taskInit(function()
-	camera_rst(0)
-    uart.setup(
-        uart.VUART_0,--串口id
-        115200,--波特率
-        8,--数据位
-        1--停止位
-    )
-	-- 拍照, 自然就是RGB输出了
-	local camera_id = camera.init(GC032A_InitReg)--屏幕输出rgb图像
-
-	log.info("摄像头启动")
-    camera.video(camera_id, 320, 240, uart.VUART_0)
-	log.info("摄像头启动完成")
-    while 1 do
-    	sys.wait(10000)
-    end
-end)

+ 27 - 3
demo/camera/Air105/video/main.lua

@@ -1,14 +1,38 @@
 
 -- LuaTools需要PROJECT和VERSION这两个信息
 PROJECT = "camera_video"
-VERSION = "1.1"
-PRODUCT_KEY = "s1uUnY6KA06ifIjcutm5oNbG3MZf5aUv" --换成自己的
+VERSION = "1.0.0"
+
+--[[
+这是Air105+摄像头, 通过USB传输到上位机显示图像的示例, 速率5~10fps, 不要期望太高
+本demo不需要lcd屏,但lcd的代码暂不可省略
+
+本demo需要最新固件
+
+测试流程:
+1. 先选取最新固件, 配合本demo的3个文件,3个文件都需要下载到设备,包括txt文件!!!
+2. 查看日志, 若提示摄像头无数据, 检查摄像头连线,并检查是否已经下载txt文件.
+3. 断开USB, 将拨动开关切换到另一端, 切勿带电操作!!!
+4. 重新插入USB
+5. 打开上位机, 选择正确的COM口, 然后开始读取
+
+-- USB驱动下载 https://doc.openluat.com/wiki/21?wiki_page_id=2070
+-- USB驱动与 合宙Cat.1的USB驱动是一致的
+
+上位机下载: https://gitee.com/openLuat/luatos-soc-air105/attach_files
+上位机源码: https://gitee.com/openLuat/luatos-soc-air105 C#写的, 就能用, 勿生产
+
+]]
+
+
 -- sys库是标配
 _G.sys = require("sys")
 _G.sysplus = require("sysplus")
+
 log.style(1)
 require "camera_test"
+
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后后面不要加任何语句!!!!!
+-- sys.run()之后后面不要加任何语句!!!!!

+ 14 - 4
demo/crypto/main.lua

@@ -49,15 +49,23 @@ sys.taskInit(function()
 
     -- DES-ECB 加解密
     local data1 = crypto.cipher_encrypt("DES-ECB", "PKCS7", "abcdefg", "12345678")
-    print(data1:toHex())
-    local data2 = crypto.cipher_decrypt("DES-ECB", "PKCS7", data1, "12345678")
-    print(data2)
+    if data1 then -- DES-ECB 在某些平台不支持的
+        print(data1:toHex())
+        local data2 = crypto.cipher_decrypt("DES-ECB", "PKCS7", data1, "12345678")
+        print(data2)
+    end
 
     -- 打印所有支持的cipher
     if crypto.cipher_list then
         log.info("cipher", "list", json.encode(crypto.cipher_list()))
     end
 
+    for i=1, 10 do
+        sys.wait(100)
+        log.info("crypto", "真随机数",string.unpack("I",crypto.trng(4)))
+        log.info("crypto", "伪随机数",math.random())
+    end
+
     -- totp的密钥
     local secret = "VK54ZXPO74ISEM2E"
     --写死时间戳用来测试
@@ -66,9 +74,11 @@ sys.taskInit(function()
     for i=1,600,30 do
         local r = crypto.totp(secret,ts+i)
         local time = os.date("*t",ts+i + 8*3600)--东八区
-        log.info("totp",r,time.hour,time.min,time.sec)
+        log.info("totp", string.format("%06d" ,r),time.hour,time.min,time.sec)
     end
 
+    log.info("crypto", "ALL Done")
+    sys.wait(100000)
 end)
 
 -- 用户代码已结束---------------------------------------------

+ 58 - 0
demo/nimble/esp32c3/main.lua

@@ -0,0 +1,58 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "nimbledemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+
+-- --添加硬狗防止程序卡死
+-- if wdt then
+--     wdt.init(15000)--初始化watchdog设置为15s
+--     sys.timerLoopStart(wdt.feed, 10000)--10s喂一次狗
+-- end
+
+-- 监听BLE主适配的状态变化
+-- 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)
+
+-- 监听GATT服务器的WRITE_CHR, 收到Write数据时会回调该函数
+sys.subscribe("BLE_GATT_WRITE_CHR", function(info, data)
+    -- info 是个table, 但当前没有数据
+    -- data 是BLE收到的数据
+    log.info("ble", "data got!!", data:toHex())
+end)
+
+-- TODO 支持传数据(read)和推送数据(notify)
+
+-- 配合微信小程序 "LuatOS蓝牙调试"
+-- 1. 若开发板无天线, 将手机尽量靠近芯片也能搜到
+-- 2. 该小程序是开源的, 每次write会自动分包
+-- https://gitee.com/openLuat/luatos-miniapps
+
+sys.taskInit(function()
+    sys.wait(1000)
+    -- nimble.debug(6)
+    -- 默认模式是BLE server, 无pin码验证
+    nimble.init("LuatOS-" .. wlan.getMac()) -- 蓝牙名称可修改
+
+    -- 下面是周期性发送数据, nimble.send_msg可在任意代码中调用, 不依赖task
+    while 1 do
+        sys.wait(3000)
+        nimble.send_msg(1, 0, string.char(0x5A, 0xA5, 0x12, 0x34, 0x56))
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 27 - 0
demo/wlan/esp32c3/ap_get_start/index.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+    <header>
+        <meta charset="utf-8"/>
+        <title>Http Server Get-Start</title>
+        <!-- fetch api-->
+        <script type="text/javascript">
+            function led(key) {
+                fetch("/led/" + key)
+            }
+        </script>
+    </header>
+    <body>
+        <h2>点击按钮, led灯会亮起或熄灭</h2>
+        <div>
+            <div>
+                <button onclick="led(1)">LED亮</button>
+            </div>
+            <div>
+                <button onclick="led(0)">LED灭</button>
+            </div>
+        </div>
+        <div>
+            <h4>Power by <a href="https://wiki.luatos.com">LuatOS</a></h4>
+        </div>
+    </body>
+</html>

+ 45 - 0
demo/wlan/esp32c3/ap_get_start/main.lua

@@ -0,0 +1,45 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "wifidemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+require("sysplus")
+
+
+-- function meminfo()
+--     log.info("lua", rtos.meminfo())
+--     log.info("sys", rtos.meminfo("sys"))
+-- end
+
+-- 初始化LED灯, 开发板上左右2个led分别是gpio12/gpio13
+local LEDA= gpio.setup(12, 0, gpio.PULLUP)
+local LEDB= gpio.setup(13, 0, gpio.PULLUP)
+
+sys.taskInit(function()
+    sys.wait(1000)
+    wlan.init()
+    sys.wait(300)
+    -- AP的ssid和password
+    wlan.createAP("luatos", "12341234")
+
+    sys.wait(1000)
+    httpsrv.start(80, function(fd, method, uri, headers, body)
+        log.info("httpsrv", method, uri, json.encode(headers), body)
+        -- meminfo()
+        if uri == "/led/1" then
+            LEDA(1)
+            return 200, {}, "ok"
+        elseif uri == "/led/0" then
+            LEDA(0)
+            return 200, {}, "ok"
+        end
+        return 404, {}, "Not Found" .. uri
+    end)
+    log.info("web", "pls open url http://192.168.4.1/")
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 43 - 0
demo/wlan/esp32c3/hello_world/main.lua

@@ -0,0 +1,43 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "wifidemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+require("sysplus")
+
+-- sys.subscribe("WLAN_READY", function ()
+--     print("!!! wlan ready event !!!")
+-- end)
+
+-- sys.taskInit(function()
+--     while 1 do
+--         sys.wait(5000)
+--         log.info("lua", rtos.meminfo())
+--         log.info("sys", rtos.meminfo("sys"))
+--     end
+
+-- end)
+
+sys.taskInit(function()
+    sys.wait(1000)
+    wlan.init()
+    wlan.connect("uiot", "1234567890")
+    log.info("wlan", "wait for IP_READY")
+    sys.waitUntil("IP_READY", 30000)
+    if wlan.ready() then
+        log.info("wlan", "ready !!")
+        sys.wait(100)
+        -- local url = "http://ip.nutz.cn/json"
+        local url = "http://nutzam.com/1.txt"
+        local code, headers, body = http2.request("GET", url).wait()
+        log.info("http", code, json.encode(headers), #body)
+    else
+        print("wlan NOT ready!!!!")
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 27 - 0
demo/wlan/esp32c3/httpsrv/index.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+    <header>
+        <meta charset="utf-8"/>
+        <title>Http Server Get-Start</title>
+        <!-- fetch api-->
+        <script type="text/javascript">
+            function led(key) {
+                fetch("/led/" + key)
+            }
+        </script>
+    </header>
+    <body>
+        <h2>点击按钮, led灯会亮起或熄灭</h2>
+        <div>
+            <div>
+                <button onclick="led(1)">LED亮</button>
+            </div>
+            <div>
+                <button onclick="led(0)">LED灭</button>
+            </div>
+        </div>
+        <div>
+            <h4>Power by <a href="https://wiki.luatos.com">LuatOS</a></h4>
+        </div>
+    </body>
+</html>

+ 55 - 0
demo/wlan/esp32c3/httpsrv/main.lua

@@ -0,0 +1,55 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "wifidemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+require("sysplus")
+
+
+-- function meminfo()
+--     log.info("lua", rtos.meminfo())
+--     log.info("sys", rtos.meminfo("sys"))
+-- end
+
+-- 初始化LED灯, 开发板上左右2个led分别是gpio12/gpio13
+local LEDA= gpio.setup(12, 0, gpio.PULLUP)
+local LEDB= gpio.setup(13, 0, gpio.PULLUP)
+
+sys.taskInit(function()
+    sys.wait(1000)
+    wlan.init()
+    -- 修改成自己的ssid和password
+    wlan.connect("myssid", "mypassword")
+    -- wlan.connect("uiot", "")
+    log.info("wlan", "wait for IP_READY")
+    
+    while not wlan.ready() do
+        local ret, ip = sys.waitUntil("IP_READY", 30000)
+        -- wlan连上之后, 这里会打印ip地址
+        log.info("ip", ret, ip)
+        if ip then
+            _G.wlan_ip = ip
+        end
+    end
+    log.info("wlan", "ready !!", wlan.getMac())
+    sys.wait(1000)
+    httpsrv.start(80, function(fd, method, uri, headers, body)
+        log.info("httpsrv", method, uri, json.encode(headers), body)
+        -- meminfo()
+        if uri == "/led/1" then
+            LEDA(1)
+            return 200, {}, "ok"
+        elseif uri == "/led/0" then
+            LEDA(0)
+            return 200, {}, "ok"
+        end
+        return 404, {}, "Not Found" .. uri
+    end)
+    log.info("web", "pls open url http://" .. _G.wlan_ip .. "/")
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 76 - 0
demo/wlan/esp32c3/iotda/main.lua

@@ -0,0 +1,76 @@
+PROJECT = "gpiodemo"
+VERSION = "1.0.0"
+
+-- 一定要添加sys.lua !!!!
+local sys = require "sys"
+require("sysplus")
+log.info("main", "iotda demo")
+
+
+local device_id     = ""    --改为你自己的设备id
+local device_secret = ""    --改为你自己的设备密钥
+
+local mqttc = nil
+
+sys.taskInit(function()
+    log.info("wlan", "wlan_init:", wlan.init())
+    wlan.setMode(wlan.STATION)
+    wlan.connect("CMCC_EDU", "88995500", 1)
+    local result, data = sys.waitUntil("IP_READY")
+    log.info("wlan", "IP_READY", result, data)
+    
+    local client_id,user_name,password = iotauth.iotda(device_id,device_secret)
+    log.info("iotda",client_id,user_name,password)
+    
+    mqttc = mqtt.create(nil,"a16203e7a0.iot-mqtts.cn-north-4.myhuaweicloud.com", 1883)
+
+    mqttc:auth(client_id,user_name,password)
+    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("/luatos/123456")
+        elseif event == "recv" then
+            log.info("mqtt", "downlink", "topic", data, "payload", payload)
+        elseif event == "sent" then
+            log.info("mqtt", "sent", "pkgid", data)
+        end
+    end)
+
+    mqttc:connect()
+    sys.wait(10000)
+    mqttc:subscribe("/luatos/123456")
+	sys.waitUntil("mqtt_conack")
+    while true do
+        -- mqttc自动处理重连
+        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.taskInit(function()
+	local topic = "/luatos/123456"
+	local payload = "123"
+	local qos = 1
+    local result, data = sys.waitUntil("IP_READY")
+    while true do
+        sys.wait(5000)
+        if mqttc:ready() then
+            local pkgid = mqttc:publish(topic, payload, qos)
+        end
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 127 - 0
demo/wlan/esp32c3/smartconfig_esptouch/main.lua

@@ -0,0 +1,127 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "wifidemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要 V100x系列固件, 不兼容V000x系列
+https://gitee.com/openLuat/LuatOS/releases
+]]
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+require("sysplus")
+
+sys.subscribe("IP_READY", function(ip)
+    log.info("wlan", "ip ready", ip)
+    -- 联网成功, 可以发起http, mqtt, 等请求了
+end)
+
+fdb.kvdb_init()
+
+-- 把BOOT键, 即GPIO9, 作为清除配网信息的按钮
+BTN_BOOT = 9
+gpio.debounce(BTN_BOOT, 1000)
+gpio.setup(BTN_BOOT, function()
+    log.info("gpio", "boot button pressed")
+    sys.publish("BTN_BOOT")
+end)
+
+sys.taskInit(function()
+    sys.wait(500) -- 这里等500ms只是方便看日志,非必须
+    wlan.init() -- 初始化wifi协议栈
+
+    -- 获取上次保存的配网信息, 如果存在就直接联网, 不需要配网了
+    -- 注意, fdb保存的数据是掉电存储的, 刷脚本/刷固件也不会清除
+    -- 如需完全清除配置信息, 可调用 fdb.clear() 全清
+    if fdb.kv_get("wlan_ssid") then
+       wlan.connect(fdb.kv_get("wlan_ssid"), fdb.kv_get("wlan_passwd"))
+       return -- 等联网就行了
+    end
+
+    -- 以下是smartconfig之 esptouch 配网
+    -- 配网APP请搜索 esptouch , 当前最新版2.3.0
+    -- 配网时选用 esptouch, 虽然esptouch V2也是支持的,但 esptouch兼容性比较好
+    -- ESP32C3仅支持2.4G的wifi, 5G wifi是不支持的
+    -- 配网时, 手机应靠近模块, 以便更快配网成功
+    while 1 do
+        -- 启动配网, 默认是esptouch模式
+        wlan.smartconfig()
+        local ret, ssid, passwd = sys.waitUntil("SC_RESULT", 180*1000) -- 等3分钟
+        if ret == false then
+            log.info("smartconfig", "timeout")
+            wlan.smartconfig(wlan.STOP)
+            sys.wait(3000) -- 再等3s重新配网, 或者直接reboot也行
+        else
+            -- 获取配网后, ssid和passwd会有值
+            log.info("smartconfig", ssid, passwd)
+            -- 值得注意的是, 存在ssid和passwd填错的情况, 这里按获取到IP来算成功
+            local ret = sys.waitUntil("IP_READY", 30000)
+            if ret then
+                -- 获取IP成功, 将配网信息存入fdb, 做持久化存储
+                log.info("fdb", "save ssid and passwd")
+                fdb.kv_set("wlan_ssid", ssid)
+                fdb.kv_set("wlan_passwd", passwd)
+                -- 等3秒再重启, 因为esptouch联网后会发生广播, 告知APP配网成功
+                log.info("wifi", "wait 3s to reboot")
+                sys.wait(3000)
+                -- 这里建议重启, 当然这也不是强制的
+                -- 重启后有配网信息, 所以就自动连接
+                rtos.reboot()
+            end
+        end
+    end
+end)
+
+
+-- 下面的task是演示通过按键清除配网信息
+-- 实现的效果是: 开机500ms后, 长按BOOT按钮3秒以上, 清除配网信息, 然后重启或者快速闪灯.
+sys.taskInit(function()
+    -- 开机后, 先等500ms
+    sys.wait(500)
+    -- 然后开始监听BTN按钮
+    while true do
+        local flag = true
+        while true do
+            -- 等待boot按钮按下
+            local ret = sys.waitUntil("BTN_BOOT", 3000)
+            --log.info("gpio", "BTN_BOOT", "wait", ret)
+            if ret then
+                break
+            end
+        end
+        log.info("wifi", "Got BOOT button pressed")
+        for i=1, 30 do
+            -- 要求持续3s的低电平, 若中途松开了,就无效咯
+            if gpio.get(BTN_BOOT) ~= 0 then
+                log.info("wifi", "BOOT button released, wait next press")
+                flag = false
+                break
+            end
+            sys.wait(100)
+        end
+
+        if flag then
+            -- 用户的确要请求配网信息, 那就清除吧
+            log.info("gpio", "boot pressed 3s, remove ssid/passwd")
+            fdb.kv_del("wlan_ssid")
+            fdb.kv_del("wlan_passwd")
+            -- fdb.clear() -- 这里还有一个方案是清除fdb里的全部数据,从业务上说相当于恢复出厂配置
+            log.info("gpio", "removed, wait for reboot")
+
+            -- 方案1, 直接重启, 重启后因为没有配网数据了, 就自动开始配网
+            -- rtos.reboot()
+
+            -- 方案2, 100ms闪灯, 让用户自行复位重启
+            gpio.setup(12, 0)
+            while 1 do
+                gpio.toggle(12)
+                sys.wait(100)
+            end
+        end
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 30 - 0
demo/wlan/esp32c3/wifi_scan/main.lua

@@ -0,0 +1,30 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "wifidemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+require("sysplus")
+
+-- wifi扫描成功后, 会有WLAN_SCAN_DONE消息, 读取即可
+sys.subscribe("WLAN_SCAN_DONE", function ()
+    local results = wlan.scanResult()
+    log.info("scan", "results", #results)
+    for k,v in pairs(results) do
+        log.info("scan", v["ssid"], v["rssi"], (v["bssid"]:toHex()))
+    end
+end)
+
+sys.taskInit(function()
+    sys.wait(1000)
+    wlan.init()
+    while 1 do
+        wlan.scan()
+        sys.wait(15000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 76 - 73
lua/src/liolib.c

@@ -234,12 +234,13 @@ static int f_close (lua_State *L) {
   return aux_close(L);
 }
 
-
-// static int io_close (lua_State *L) {
-//   if (lua_isnone(L, 1))  /* no argument? */
-//     lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */
-//   return f_close(L);
-// }
+#ifdef LUA_USE_WINDOWS
+static int io_close (lua_State *L) {
+  if (lua_isnone(L, 1))  /* no argument? */
+    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */
+  return f_close(L);
+}
+#endif
 
 
 static int f_gc (lua_State *L) {
@@ -267,13 +268,12 @@ static LStream *newfile (lua_State *L) {
   return p;
 }
 
-
-// static void opencheck (lua_State *L, const char *fname, const char *mode) {
-//   LStream *p = newfile(L);
-//   p->f = fopen(fname, mode);
-//   if (p->f == NULL)
-//     luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
-// }
+static void opencheck (lua_State *L, const char *fname, const char *mode) {
+  LStream *p = newfile(L);
+  p->f = fopen(fname, mode);
+  if (p->f == NULL)
+    luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
+}
 
 
 static int io_open (lua_State *L) {
@@ -322,51 +322,51 @@ static int io_popen (lua_State *L) {
   #endif
   return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
 }
-#endif
 
-// static int io_tmpfile (lua_State *L) {
-//   LStream *p = newfile(L);
-//   p->f = tmpfile();
-//   return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
-// }
+static int io_tmpfile (lua_State *L) {
+  LStream *p = newfile(L);
+  p->f = tmpfile();
+  return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
+}
 
 
-// static FILE *getiofile (lua_State *L, const char *findex) {
-//   LStream *p;
-//   lua_getfield(L, LUA_REGISTRYINDEX, findex);
-//   p = (LStream *)lua_touserdata(L, -1);
-//   if (isclosed(p))
-//     luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN);
-//   return p->f;
-// }
+static FILE *getiofile (lua_State *L, const char *findex) {
+  LStream *p;
+  lua_getfield(L, LUA_REGISTRYINDEX, findex);
+  p = (LStream *)lua_touserdata(L, -1);
+  if (isclosed(p))
+    luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN);
+  return p->f;
+}
 
 
-// static int g_iofile (lua_State *L, const char *f, const char *mode) {
-//   if (!lua_isnoneornil(L, 1)) {
-//     const char *filename = lua_tostring(L, 1);
-//     if (filename)
-//       opencheck(L, filename, mode);
-//     else {
-//       tofile(L);  /* check that it's a valid file handle */
-//       lua_pushvalue(L, 1);
-//     }
-//     lua_setfield(L, LUA_REGISTRYINDEX, f);
-//   }
-//   /* return current value */
-//   lua_getfield(L, LUA_REGISTRYINDEX, f);
-//   return 1;
-// }
+static int g_iofile (lua_State *L, const char *f, const char *mode) {
+  if (!lua_isnoneornil(L, 1)) {
+    const char *filename = lua_tostring(L, 1);
+    if (filename)
+      opencheck(L, filename, mode);
+    else {
+      tofile(L);  /* check that it's a valid file handle */
+      lua_pushvalue(L, 1);
+    }
+    lua_setfield(L, LUA_REGISTRYINDEX, f);
+  }
+  /* return current value */
+  lua_getfield(L, LUA_REGISTRYINDEX, f);
+  return 1;
+}
 
 
-// static int io_input (lua_State *L) {
-//   return g_iofile(L, IO_INPUT, "r");
-// }
+static int io_input (lua_State *L) {
+  return g_iofile(L, IO_INPUT, "r");
+}
 
 
-// static int io_output (lua_State *L) {
-//   return g_iofile(L, IO_OUTPUT, "w");
-// }
+static int io_output (lua_State *L) {
+  return g_iofile(L, IO_OUTPUT, "w");
+}
 
+#endif
 
 static int io_readline (lua_State *L);
 
@@ -393,12 +393,12 @@ static int f_lines (lua_State *L) {
   return 1;
 }
 
-static void opencheck (lua_State *L, const char *fname, const char *mode) {
-  LStream *p = newfile(L);
-  p->f = fopen(fname, mode);
-  if (p->f == NULL)
-    luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
-}
+// static void opencheck (lua_State *L, const char *fname, const char *mode) {
+//   LStream *p = newfile(L);
+//   p->f = fopen(fname, mode);
+//   if (p->f == NULL)
+//     luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
+// }
 
 static int io_lines (lua_State *L) {
   int toclose;
@@ -623,10 +623,11 @@ static int g_read (lua_State *L, FILE *f, int first) {
   return n - first;
 }
 
-
-// static int io_read (lua_State *L) {
-//   return g_read(L, getiofile(L, IO_INPUT), 1);
-// }
+#ifdef LUA_USE_WINDOWS
+static int io_read (lua_State *L) {
+  return g_read(L, getiofile(L, IO_INPUT), 1);
+}
+#endif
 
 
 static int f_read (lua_State *L) {
@@ -688,10 +689,11 @@ static int g_write (lua_State *L, FILE *f, int arg) {
   else return luaL_fileresult(L, status, NULL);
 }
 
-
-// static int io_write (lua_State *L) {
-//   return g_write(L, getiofile(L, IO_OUTPUT), 1);
-// }
+#ifdef LUA_USE_WINDOWS
+static int io_write (lua_State *L) {
+  return g_write(L, getiofile(L, IO_OUTPUT), 1);
+}
+#endif
 
 
 static int f_write (lua_State *L) {
@@ -731,10 +733,11 @@ static int f_setvbuf (lua_State *L) {
 }
 
 
-
-// static int io_flush (lua_State *L) {
-//   return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
-// }
+#ifdef LUA_USE_WINDOWS
+static int io_flush (lua_State *L) {
+  return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+}
+#endif
 
 
 static int f_flush (lua_State *L) {
@@ -903,18 +906,18 @@ static int io_lsmount (lua_State *L);
 */
 #include "rotable2.h"
 static const rotable_Reg_t iolib[] = {
-  // {"close", io_close,  0},
-  // {"flush", io_flush,  0},
-  // {"input", io_input,  0},
   {"open", ROREG_FUNC(io_open)},
-  // {"output", io_output,0},
 #ifdef LUA_USE_WINDOWS
   {"popen", ROREG_FUNC(io_popen)},
+  {"read", ROREG_FUNC(io_read)},
+  {"tmpfile", ROREG_FUNC(io_tmpfile)},
+  {"write", ROREG_FUNC(io_write)},
+  {"close", ROREG_FUNC(io_close)},
+  {"flush", ROREG_FUNC(io_flush)},
+  {"input", ROREG_FUNC(io_input)},
+  {"output", ROREG_FUNC(io_output)},
 #endif
-  // {"read", io_read,    0},
-  // {"tmpfile", io_tmpfile, 0},
   {"type", ROREG_FUNC(io_type)},
-  // {"write", io_write,  0},
   {"exists", ROREG_FUNC(io_exists)},
   {"fileSize", ROREG_FUNC(io_fileSize)},
   {"readFile", ROREG_FUNC(io_readFile)},

+ 24 - 24
lua/src/luat_bget.c

@@ -438,7 +438,7 @@ void luat_bget_init(luat_bget_t* bg) {
    bufsize, defined in a way that the compiler will accept. */
 
 #define ESent   ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2))
-#define assert(x)
+#define _assert_(x)
 /*  BGET  --  Allocate a buffer.  */
 
 void *luat_bget(luat_bget_t* bg, bufsize requested_size)
@@ -452,7 +452,7 @@ void *luat_bget(luat_bget_t* bg, bufsize requested_size)
 #ifdef BECtl
     int compactseq = 0;
 #endif
-    assert(size >= 0);
+    _assert_(size >= 0);
     if (!size)
     {
     	return NULL;
@@ -515,7 +515,7 @@ void *luat_bget(luat_bget_t* bg, bufsize requested_size)
 
                     ba = BH(((char *) b) + (b->bh.bsize - size));
                     bn = BH(((char *) ba) + size);
-                    assert(bn->prevfree == b->bh.bsize);
+                    _assert_(bn->prevfree == b->bh.bsize);
                     /* Subtract size from length of free block. */
                     b->bh.bsize -= size;
                     /* Link allocated buffer to the previous free buffer. */
@@ -539,13 +539,13 @@ void *luat_bget(luat_bget_t* bg, bufsize requested_size)
                     struct bhead *ba;
 
                     ba = BH(((char *) b) + b->bh.bsize);
-                    assert(ba->prevfree == b->bh.bsize);
+                    _assert_(ba->prevfree == b->bh.bsize);
 
                     /* The buffer isn't big enough to split.  Give  the  whole
                        shebang to the caller and remove it from the free list. */
 
-                    assert(b->ql.blink->ql.flink == b);
-                    assert(b->ql.flink->ql.blink == b);
+                    _assert_(b->ql.blink->ql.flink == b);
+                    _assert_(b->ql.flink->ql.blink == b);
                     b->ql.blink->ql.flink = b->ql.flink;
                     b->ql.flink->ql.blink = b->ql.blink;
 
@@ -597,7 +597,7 @@ void *luat_bgetz(luat_bget_t* bg, bufsize size)
         } else {
             rsize -= sizeof(struct bhead);
         }
-        assert(rsize >= size);
+        _assert_(rsize >= size);
         memset(buf, 0, (MemSize) rsize);
     }
     return ((void *) buf);
@@ -624,7 +624,7 @@ void *luat_bgetr(luat_bget_t* bg, void *buf, bufsize size)
     osize = -b->bsize;
 
     osize -= sizeof(struct bhead);
-    assert(osize > 0);
+    _assert_(osize > 0);
     V memcpy((char *) nbuf, (char *) buf, /* Copy the data */
              (MemSize) ((size < osize) ? size : osize));
     luat_brel(bg, buf);
@@ -641,7 +641,7 @@ void luat_brel(luat_bget_t* bg, void *buf)
 #ifdef BufStats
     bg->numrel++;                         /* Increment number of brel() calls */
 #endif
-    assert(buf != NULL);
+    _assert_(buf != NULL);
     if (!buf)
     {
     	return;
@@ -653,16 +653,16 @@ void luat_brel(luat_bget_t* bg, void *buf)
     if (b->bh.bsize >= 0) {
         bn = NULL;
     }
-    assert(b->bh.bsize < 0);
+    _assert_(b->bh.bsize < 0);
 
     /*  Back pointer in next buffer must be zero, indicating the
         same thing: */
 
-    assert(BH((char *) b - b->bh.bsize)->prevfree == 0);
+    _assert_(BH((char *) b - b->bh.bsize)->prevfree == 0);
 
 #ifdef BufStats
     bg->totalloc += b->bh.bsize;
-    assert(bg->totalloc >= 0);
+    _assert_(bg->totalloc >= 0);
 #endif
 
     /* If the back link is nonzero, the previous buffer is free.  */
@@ -678,7 +678,7 @@ void luat_brel(luat_bget_t* bg, void *buf)
         register bufsize size = b->bh.bsize;
 
         /* Make the previous buffer the one we're working on. */
-        assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree);
+        _assert_(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree);
         b = BFH(((char *) b) - b->bh.prevfree);
         b->bh.bsize -= size;
     } else {
@@ -686,8 +686,8 @@ void luat_brel(luat_bget_t* bg, void *buf)
         /* The previous buffer isn't allocated.  Insert this buffer
            on the free list as an isolated free block. */
 
-        assert(bg->freelist.ql.blink->ql.flink == &bg->freelist);
-        assert(bg->freelist.ql.flink->ql.blink == &bg->freelist);
+        _assert_(bg->freelist.ql.blink->ql.flink == &bg->freelist);
+        _assert_(bg->freelist.ql.flink->ql.blink == &bg->freelist);
         b->ql.flink = &bg->freelist;
         b->ql.blink = bg->freelist.ql.blink;
         bg->freelist.ql.blink = b;
@@ -706,9 +706,9 @@ void luat_brel(luat_bget_t* bg, void *buf)
         /* The buffer is free.  Remove it from the free list and add
            its size to that of our buffer. */
 
-        assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize);
-        assert(bn->ql.blink->ql.flink == bn);
-        assert(bn->ql.flink->ql.blink == bn);
+        _assert_(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize);
+        _assert_(bn->ql.blink->ql.flink == bn);
+        _assert_(bn->ql.flink->ql.blink == bn);
         bn->ql.blink->ql.flink = bn->ql.flink;
         bn->ql.flink->ql.blink = bn->ql.blink;
         b->bh.bsize += bn->bh.bsize;
@@ -726,7 +726,7 @@ void luat_brel(luat_bget_t* bg, void *buf)
     V memset(((char *) b) + sizeof(struct bfhead), 0x55,
             (MemSize) (b->bh.bsize - sizeof(struct bfhead)));
 #endif
-    assert(bn->bh.bsize < 0);
+    _assert_(bn->bh.bsize < 0);
 
     /* The next buffer is allocated.  Set the backpointer in it  to  point
        to this buffer; the previous free buffer in memory. */
@@ -749,7 +749,7 @@ void luat_bpool(luat_bget_t* bg, void *buf, bufsize len)
        it  had  better  not  be  (much) larger than the largest buffer
        whose size we can store in bhead.bsize. */
 
-    assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1));
+    _assert_(len - sizeof(struct bhead) <= -((bufsize) ESent + 1));
 
     /* Clear  the  backpointer at  the start of the block to indicate that
        there  is  no  free  block  prior  to  this   one.    That   blocks
@@ -759,8 +759,8 @@ void luat_bpool(luat_bget_t* bg, void *buf, bufsize len)
 
     /* Chain the new block to the free list. */
 
-    assert(bg->freelist.ql.blink->ql.flink == &bg->freelist);
-    assert(bg->freelist.ql.flink->ql.blink == &bg->freelist);
+    _assert_(bg->freelist.ql.blink->ql.flink == &bg->freelist);
+    _assert_(bg->freelist.ql.flink->ql.blink == &bg->freelist);
     b->ql.flink = &bg->freelist;
     b->ql.blink = bg->freelist.ql.blink;
     bg->freelist.ql.blink = b;
@@ -783,7 +783,7 @@ void luat_bpool(luat_bget_t* bg, void *buf, bufsize len)
     bn = BH(((char *) b) + len);
     bn->prevfree = (bufsize) len;
     /* Definition of ESent assumes two's complement! */
-    assert((~0) == -1);
+    _assert_((~0) == -1);
     bn->bsize = ESent;
 }
 
@@ -801,7 +801,7 @@ void luat_bstats(luat_bget_t* bg, bufsize *curalloc, bufsize *totfree, bufsize *
     *totfree = 0;
     *maxfree = -1;
     while (b != &bg->freelist) {
-        assert(b->bh.bsize > 0);
+        _assert_(b->bh.bsize > 0);
         *totfree += b->bh.bsize;
         if (b->bh.bsize > *maxfree) {
             *maxfree = b->bh.bsize;

+ 2 - 0
luat/include/luat_libs.h

@@ -131,4 +131,6 @@ LUAMOD_API int luaopen_mobile( lua_State *L );
 
 LUAMOD_API int luaopen_protobuf( lua_State *L );
 
+LUAMOD_API int luaopen_httpsrv( lua_State *L );
+
 #endif

+ 16 - 12
luat/modules/luat_lib_gpio.c

@@ -17,10 +17,14 @@
 #define LUAT_LOG_TAG "gpio"
 #include "luat_log.h"
 
+// 若bsp没有定义最大PIN编号, 那么默认给个128吧
+#ifndef LUAT_GPIO_PIN_MAX
+#define LUAT_GPIO_PIN_MAX (128)
+#endif
+
 static int l_gpio_set(lua_State *L);
 static int l_gpio_get(lua_State *L);
 static int l_gpio_close(lua_State *L);
-#define PIN_MAX (128)
 
 typedef struct gpio_ctx
 {
@@ -30,21 +34,21 @@ typedef struct gpio_ctx
 }gpio_ctx_t;
 
 // 保存中断回调的数组
-static gpio_ctx_t gpios[PIN_MAX];
+static gpio_ctx_t gpios[LUAT_GPIO_PIN_MAX];
 static uint8_t default_gpio_pull = Luat_GPIO_DEFAULT;
 
 
 // 记录GPIO电平,仅OUTPUT时可用
-static uint8_t gpio_out_levels[PIN_MAX / 8] = {0};
+static uint8_t gpio_out_levels[LUAT_GPIO_PIN_MAX / 8] = {0};
 
 static uint8_t gpio_bit_get(int pin) {
-    if (pin < 0 || pin >= PIN_MAX)
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
         return 0;
     return (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
 }
 
 static void gpio_bit_set(int pin, uint8_t value) {
-    if (pin < 0 || pin >= PIN_MAX)
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
         return;
     uint8_t val = (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
     if (val == value)
@@ -64,7 +68,7 @@ int luat_gpio_irq_default(int pin, void* args) {
         return 0;
     }
 
-    if (pin < PIN_MAX && gpios[pin].conf_tick > 0) {
+    if (pin < LUAT_GPIO_PIN_MAX && gpios[pin].conf_tick > 0) {
         uint32_t ticks = (uint32_t)luat_mcu_ticks();
         uint32_t diff = (ticks > gpios[pin].latest_tick) ? (ticks - gpios[pin].latest_tick) : (gpios[pin].latest_tick - ticks);
         if (diff >= gpios[pin].conf_tick) {
@@ -87,7 +91,7 @@ int l_gpio_handler(lua_State *L, void* ptr) {
     // 给 sys.publish方法发送数据
     rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
     int pin = msg->arg1;
-    if (pin < 0 || pin >= PIN_MAX)
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
         return 0;
     if (gpios[pin].lua_ref == 0)
         return 0;
@@ -216,7 +220,7 @@ gpio.close(17)
 */
 static int l_gpio_close(lua_State *L) {
     int pin = luaL_checkinteger(L, 1);
-    if (pin < 0 || pin >= PIN_MAX)
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
         return 0;
     luat_gpio_close(pin);
     if (gpios[pin].lua_ref) {
@@ -266,7 +270,7 @@ static int l_gpio_toggle(lua_State *L) {
         pin = lua_tointeger(L, lua_upvalueindex(1));
     else
         pin = luaL_checkinteger(L, 1);
-    if (pin < 0 || pin >= PIN_MAX) {
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX) {
         LLOGW("pin id out of range (0-127)");
         return 0;
     }
@@ -314,7 +318,7 @@ static int l_gpio_pulse(lua_State *L) {
         len = luaL_checkinteger(L, 3);
         delay = luaL_checkinteger(L, 4);
     }
-    if (pin < 0 || pin >= PIN_MAX) {
+    if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX) {
         LLOGD("pin id out of range (0-127)");
         return 0;
     }
@@ -338,7 +342,7 @@ gpio.debounce(7, 0)
 static int l_gpio_debounce(lua_State *L) {
     uint8_t pin = luaL_checkinteger(L, 1);
     uint16_t time = luaL_checkinteger(L, 2);
-    if (pin >= PIN_MAX) {
+    if (pin >= LUAT_GPIO_PIN_MAX) {
         LLOGW("MUST pin < 128");
         return 0;
     }
@@ -390,7 +394,7 @@ static const rotable_Reg_t reg_gpio[] =
 };
 
 LUAMOD_API int luaopen_gpio( lua_State *L ) {
-    memset(gpios, 0, sizeof(gpio_ctx_t) * PIN_MAX);
+    memset(gpios, 0, sizeof(gpio_ctx_t) * LUAT_GPIO_PIN_MAX);
     luat_newlib2(L, reg_gpio);
     return 1;
 }

+ 4 - 3
luat/modules/luat_ota.c

@@ -253,19 +253,20 @@ int luat_ota_checkfile(const char* path) {
 #ifdef LUAT_USE_OTA
 
 int luat_ota(uint32_t luadb_addr){
-    
+    FILE *fd_out = NULL;
+    FILE *fd_in = NULL;
 #ifdef LUAT_USE_ZLIB 
     extern int zlib_decompress(FILE *source, FILE *dest);
     //检测是否有压缩升级文件
     if(luat_fs_fexist(UPDATE_TGZ_PATH)){
         LLOGI("found update.tgz, decompress ...");
-        FILE *fd_in = luat_fs_fopen(UPDATE_TGZ_PATH, "r");
+        fd_in = luat_fs_fopen(UPDATE_TGZ_PATH, "r");
         if (fd_in == NULL){
             LLOGE("open the input file : %s error!", UPDATE_TGZ_PATH);
             goto _close_decompress;
         }
         luat_fs_remove(UPDATE_BIN_PATH);
-        FILE *fd_out = luat_fs_fopen(UPDATE_BIN_PATH, "w+");
+        fd_out = luat_fs_fopen(UPDATE_BIN_PATH, "w+");
         if (fd_out == NULL){
             LLOGE("open the output file : %s error!", UPDATE_BIN_PATH);
             goto _close_decompress;

+ 8 - 24
script/turnkey/eink-calendar/main.lua

@@ -5,6 +5,7 @@ VERSION = "1.0.0"
 --测试固件版本:LuatOS-SoC_V0003_ESP32C3[_USB].soc
 
 local sys = require "sys"
+require("sysplus")
 
 --需要自行填写的东西
 --wifi信息
@@ -29,30 +30,13 @@ local function connectWifi()
 end
 
 local function requestHttp()
-    local rd = {}
-    local httpc = esphttp.init(esphttp.GET, "http://apicn.luatos.org:23328/luatos-calendar/v1?mac=111&battery=10&location="..location.."&appid="..appid.."&appsecret="..appsecret)
-    if httpc then
-        local ok, err = esphttp.perform(httpc, true)
-        if ok then
-            while 1 do
-                local result, c, ret, data = sys.waitUntil("ESPHTTP_EVT", 20000)
-                --log.info("httpc", result, c, ret)
-                if c == httpc then
-                    if esphttp.is_done(httpc, ret) then
-                        break
-                    end
-                    if ret == esphttp.EVENT_ON_DATA and esphttp.status_code(httpc) == 200 then
-                        table.insert(rd,data)
-                    end
-                end
-            end
-        else
-            log.warn("esphttp", "bad perform", err)
-        end
-        esphttp.cleanup(httpc)
-        if ok then
-            return table.concat(rd)
-        end
+    local code, headers, body = http2.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