浏览代码

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

alienwalker 3 年之前
父节点
当前提交
afb4fe894a
共有 78 个文件被更改,包括 1336 次插入540 次删除
  1. 1 0
      components/camera/luat_lib_camera.c
  2. 1 0
      components/coremark/luat_lib_coremark.c
  3. 6 5
      components/eink/luat_lib_eink.c
  4. 1 0
      components/ethernet/w5500/luat_lib_w5500.c
  5. 2 1
      components/flashdb/src/luat_lib_fdb.c
  6. 2 1
      components/gtfont/luat_lib_gtfont.c
  7. 1 0
      components/io_queue/luat_lib_io_queue.c
  8. 16 15
      components/iotauth/luat_lib_iotauth.c
  9. 3 2
      components/lcd/luat_lib_lcd.c
  10. 1 0
      components/lora/luat_lib_lora.c
  11. 2 1
      components/lua-cjson/lua_cjson.c
  12. 1 0
      components/luatfonts/luat_lib_fonts.c
  13. 2 0
      components/lvgl/binding/luat_lib_lvgl_anim.c
  14. 1 0
      components/miniz/luat_lib_miniz.c
  15. 8 7
      components/minmea/luat_lib_libgnss.c
  16. 1 0
      components/mlx90640-library/luat_lib_mlx90640.c
  17. 1 0
      components/mobile/luat_lib_mobile.c
  18. 1 0
      components/multimedia/luat_lib_multimedia.c
  19. 1 0
      components/network/adapter/luat_lib_socket.c
  20. 1 0
      components/network/httpsrv/src/luat_lib_httpsrv.c
  21. 1 0
      components/network/libemqtt/luat_lib_mqtt.c
  22. 0 449
      components/network/libhttp/http_parser.h
  23. 20 12
      components/network/libhttp/luat_lib_http.c
  24. 414 0
      components/network/websocket/luat_lib_websocket.c
  25. 588 0
      components/network/websocket/luat_websocket.c
  26. 71 0
      components/network/websocket/luat_websocket.h
  27. 1 0
      components/nimble/src/luat_lib_nimble.c
  28. 1 0
      components/rsa/binding/luat_lib_rsa.c
  29. 1 0
      components/serialization/protobuf/luat_lib_protobuf.c
  30. 1 0
      components/sfd/luat_lib_sfd.c
  31. 1 0
      components/sfud/luat_lib_sfud.c
  32. 1 0
      components/statem/luat_lib_statem.c
  33. 1 0
      components/u8g2/luat_lib_disp.c
  34. 1 0
      components/u8g2/luat_lib_u8g2.c
  35. 1 0
      components/usbapp/luat_lib_usbapp.c
  36. 1 0
      components/wlan/luat_lib_wlan.c
  37. 1 0
      components/zlib/luat_lib_zlib.c
  38. 7 11
      demo/socket/Air105/http_demo.lua
  39. 14 14
      demo/socket/EC618/http_demo.lua
  40. 61 0
      demo/websocket/main.lua
  41. 1 1
      demo/wlan/esp32c3/hello_world/main.lua
  42. 4 3
      lua/src/liolib.c
  43. 1 0
      lua/src/lstrlib_exts.c
  44. 3 0
      luat/include/luat_libs.h
  45. 6 0
      luat/modules/luat_lib_adc.c
  46. 2 1
      luat/modules/luat_lib_crypto.c
  47. 1 0
      luat/modules/luat_lib_dac.c
  48. 1 0
      luat/modules/luat_lib_fota.c
  49. 1 0
      luat/modules/luat_lib_fs.c
  50. 1 0
      luat/modules/luat_lib_gpio.c
  51. 1 0
      luat/modules/luat_lib_i2c.c
  52. 1 0
      luat/modules/luat_lib_i2s.c
  53. 1 0
      luat/modules/luat_lib_ir.c
  54. 4 3
      luat/modules/luat_lib_keyboard.c
  55. 1 0
      luat/modules/luat_lib_lcdseg.c
  56. 3 2
      luat/modules/luat_lib_libcoap.c
  57. 1 0
      luat/modules/luat_lib_log.c
  58. 4 3
      luat/modules/luat_lib_lpmem.c
  59. 1 0
      luat/modules/luat_lib_mcu.c
  60. 1 0
      luat/modules/luat_lib_otp.c
  61. 1 0
      luat/modules/luat_lib_pack.c
  62. 1 0
      luat/modules/luat_lib_pm.c
  63. 1 0
      luat/modules/luat_lib_pwm.c
  64. 1 0
      luat/modules/luat_lib_rtc.c
  65. 1 0
      luat/modules/luat_lib_rtos.c
  66. 1 0
      luat/modules/luat_lib_sdio.c
  67. 1 0
      luat/modules/luat_lib_sensor.c
  68. 1 0
      luat/modules/luat_lib_spi.c
  69. 1 0
      luat/modules/luat_lib_sys_doc.c
  70. 1 0
      luat/modules/luat_lib_timer.c
  71. 1 0
      luat/modules/luat_lib_touchkey.c
  72. 1 0
      luat/modules/luat_lib_uart.c
  73. 1 0
      luat/modules/luat_lib_wdt.c
  74. 1 0
      luat/modules/luat_lib_zbuff.c
  75. 2 2
      script/turnkey/EinkBook/Scripts/main.lua
  76. 3 3
      script/turnkey/eink-calendar/main.lua
  77. 6 1
      tools/api_get.py
  78. 32 3
      tools/make_doc_file.py

+ 1 - 0
components/camera/luat_lib_camera.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2022.01.11
 @demo camera
+@tag LUAT_USE_CAMERA
 */
 #include "luat_base.h"
 #include "luat_camera.h"

+ 1 - 0
components/coremark/luat_lib_coremark.c

@@ -3,6 +3,7 @@
 @summary 跑分
 @version 1.0
 @date    2022.01.11
+@tag LUAT_USE_COREMARK
 */
 #include "luat_base.h"
 

+ 6 - 5
components/eink/luat_lib_eink.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2020.11.14
 @demo eink
+@tag LUAT_USE_EINK
 */
 #include "luat_base.h"
 #include "luat_log.h"
@@ -500,7 +501,7 @@ static int l_eink_print(lua_State *L)
     int y           = luaL_checkinteger(L, 2);
     const char *str = luaL_checklstring(L, 3, &len);
 
-    
+
     if (check_init() == 0) {
       return 0;
     }
@@ -553,7 +554,7 @@ static int l_eink_show(lua_State *L)
     /* Display the frame_buffer */
     //EPD_SetFrameMemory(&epd, frame_buffer, x, y, Paint_GetWidth(&ctxs[ctx_index]->paint), Paint_GetHeight(&ctxs[ctx_index]->paint));
     //EPD_DisplayFrame(&epd);
-    
+
     if (check_init() == 0) {
       return 0;
     }
@@ -641,7 +642,7 @@ static int l_eink_rect(lua_State *L)
     int y2      = luaL_checkinteger(L, 4);
     int colored = luaL_optinteger(L, 5, 0);
     int fill    = luaL_optinteger(L, 6, 0);
-  
+
     if (check_init() == 0) {
       return 0;
     }
@@ -1056,13 +1057,13 @@ static int l_eink_drawXbm(lua_State *L){
     const char* data = luaL_checklstring(L, 5, &len);
     if (h < 1) return 0; // 行数必须大于0
     if (len*8/h < w) return 0; // 起码要填满一行
-    if (len != h*w/8)return 0;
+    if (len < h*w/8) return 0;
 
     if (check_init() == 0) {
       return 0;
     }
 
-    uint8_t blen;
+    uint8_t blen = 0;
     blen = w;
     blen += 7;
     blen >>= 3;

+ 1 - 0
components/ethernet/w5500/luat_lib_w5500.c

@@ -3,6 +3,7 @@
 @summary w5500以太网驱动
 @version 1.0
 @date    2022.04.11
+@tag LUAT_USE_W5500
 */
 
 #include "luat_base.h"

+ 2 - 1
components/flashdb/src/luat_lib_fdb.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.11.03
 @demo fdb
+@tag LUAT_USE_FDB
 */
 
 #include "luat_base.h"
@@ -212,7 +213,7 @@ static int l_fdb_kv_get(lua_State *L) {
     blob.buf = buff.b;
     blob.size = buff.size;
     size_t read_len = fdb_kv_get_blob(kvdb, key, &blob);
-    
+
     lua_Integer *intVal;
     // lua_Number *numVal;
 

+ 2 - 1
components/gtfont/luat_lib_gtfont.c

@@ -3,6 +3,7 @@
 @summary gtfont高通字库模块
 @version 1.0
 @date    2021.11.11
+@tag LUAT_USE_GTFONT
 */
 
 #include "luat_base.h"
@@ -23,7 +24,7 @@ void gtfont_draw_w(unsigned char *pBits,unsigned int x,unsigned int y,unsigned i
 	unsigned int i,j,k,n;
 	unsigned char temp;
 	n = 0;
-	
+
 	for( i = 0;i < high; i++){
 		for( j = 0;j < ((widt+7)>> 3);j++){
 			temp = pBits[n++];

+ 1 - 0
components/io_queue/luat_lib_io_queue.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2022.03.13
 @demo io_queue
+@tag LUAT_USE_IO_QUEUE
 */
 #include "luat_base.h"
 #include "luat_multimedia.h"

+ 16 - 15
components/iotauth/luat_lib_iotauth.c

@@ -5,6 +5,7 @@
 @version core V0007
 @date    2022.08.06
 @demo iotauth
+@tag LUAT_USE_IOTAUTH
 */
 #include "luat_base.h"
 #include "luat_crypto.h"
@@ -87,9 +88,9 @@ static void aliyun_token(const char* product_key,const char* device_name,const c
 /*
 阿里云物联网平台三元组生成
 @api iotauth.aliyun(product_key, device_name,device_secret,method,cur_timestamp)
-@string product_key 
-@string device_name 
-@string device_secret 
+@string product_key
+@string device_name
+@string device_secret
 @string method 加密方式,"hmacmd5" "hmacsha1" "hmacsha256" 可选,默认"hmacsha256"
 @number cur_timestamp 可选
 @return string mqtt三元组 client_id
@@ -209,9 +210,9 @@ static void onenet_token(const char* product_id,const char* device_name,const ch
 /*
 中国移动物联网平台三元组生成
 @api iotauth.onenet(produt_id, device_name,key,method,cur_timestamp,version)
-@string produt_id 
-@string device_name 
-@string key 
+@string produt_id
+@string device_name
+@string key
 @string method 加密方式,"md5" "sha1" "sha256" 可选,默认"md5"
 @number cur_timestamp 可选
 @string version 可选 默认"2018-10-31"
@@ -253,8 +254,8 @@ static void iotda_token(const char* device_id,const char* device_secret,long lon
 /*
 华为物联网平台三元组生成
 @api iotauth.iotda(device_id,device_secret,ins_timestamp,cur_timestamp)
-@string device_id 
-@string device_secret 
+@string device_id
+@string device_secret
 @number ins_timestamp 是否校验时间戳 1:校验 0:不校验
 @number cur_timestamp 可选
 @return string mqtt三元组 client_id
@@ -335,9 +336,9 @@ static void qcloud_token(const char* product_id,const char* device_name,const ch
 /*
 腾讯联网平台三元组生成
 @api iotauth.qcloud(product_id, device_name,device_secret,method,cur_timestamp,sdk_appid)
-@string product_id 
-@string device_name 
-@string device_secret 
+@string product_id
+@string device_name
+@string device_secret
 @string method 加密方式,"sha1" "sha256" 可选,默认"sha256"
 @number cur_timestamp 可选
 @string sdk_appid 可选 默认为"12010126"
@@ -383,7 +384,7 @@ static void tuya_token(const char* device_id,const char* device_secret,long long
 涂鸦联网平台三元组生成
 @api iotauth.tuya(device_id,device_secret,cur_timestamp)
 @string device_id
-@string device_secret 
+@string device_secret
 @number cur_timestamp 可选
 @return string mqtt三元组 client_id
 @return string mqtt三元组 user_name
@@ -432,9 +433,9 @@ static void baidu_token(const char* iot_core_id,const char* device_key,const cha
 /*
 百度物联网平台三元组生成
 @api iotauth.baidu(iot_core_id, device_key,device_secret,method,cur_timestamp)
-@string iot_core_id 
-@string device_key 
-@string device_secret 
+@string iot_core_id
+@string device_key
+@string device_secret
 @string method 加密方式,"MD5" "SHA256" 可选,默认"MD5"
 @number cur_timestamp 可选
 @return string mqtt三元组 client_id

+ 3 - 2
components/lcd/luat_lib_lcd.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.06.16
 @demo lcd
+@tag LUAT_USE_LCD
 */
 #include "luat_base.h"
 #include "luat_lcd.h"
@@ -1590,7 +1591,7 @@ static const int l_lcd_draw_utf8(lua_State *L) {
             luat_lcd_draw(default_conf, draw_x, y, draw_x + desc.char_w - 1, y + font->line_height - 1, buff);
           //}
           //else {
-          // 
+          //
           //}
         }
     }
@@ -1598,7 +1599,7 @@ static const int l_lcd_draw_utf8(lua_State *L) {
       luat_heap_free(buff);
 
     lcd_auto_flush(default_conf);
-    lua_pushinteger(L, draw_x + desc.char_w);  
+    lua_pushinteger(L, draw_x + desc.char_w);
     return 1;
 }
 #endif

+ 1 - 0
components/lora/luat_lib_lora.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.06.24
 @demo lora
+@tag LUAT_USE_LORA
 */
 
 #include "luat_base.h"

+ 2 - 1
components/lua-cjson/lua_cjson.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2020.02.18
 @demo json
+@tag LUAT_USE_CJSON
 */
 /* Lua CJSON - JSON support for Lua
  *
@@ -709,7 +710,7 @@ static int json_encode(lua_State *l)
 
     luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
 
-    
+
     encode_buf = &local_encode_buf;
     ret = strbuf_init(encode_buf, 0);
     if (ret) {

+ 1 - 0
components/luatfonts/luat_lib_fonts.c

@@ -3,6 +3,7 @@
 @summary 字体库
 @version 1.0
 @date    2022.07.11
+@tag LUAT_USE_FONTS
 */
 
 #include "luat_base.h"

+ 2 - 0
components/lvgl/binding/luat_lib_lvgl_anim.c

@@ -3,6 +3,8 @@
 @summary LVGL图像库
 @version 1.0
 @date    2021.06.01
+@demo lvgl
+@tag LUAT_USE_LVGL
 */
 
 #include "luat_base.h"

+ 1 - 0
components/miniz/luat_lib_miniz.c

@@ -3,6 +3,7 @@
 @summary 简易zlib压缩
 @version 1.0
 @date    2022.8.11
+@tag LUAT_USE_MINIZ
 @usage
 -- 准备好数据
 local bigdata = "123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw"

+ 8 - 7
components/minmea/luat_lib_libgnss.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2020.07.03
 @demo libgnss
+@tag LUAT_USE_LIBGNSS
 */
 #include "luat_base.h"
 #include "luat_msgbus.h"
@@ -41,7 +42,7 @@ static int luat_libgnss_init(lua_State *L) {
             LLOGW("out of memory for libgnss data parse");
             return 0;
         }
-        gnsstmp = luat_heap_malloc(sizeof(luat_libgnss_t)); 
+        gnsstmp = luat_heap_malloc(sizeof(luat_libgnss_t));
         if (gnsstmp == NULL) {
             luat_heap_free(gnss);
             LLOGW("out of memory for libgnss data parse");
@@ -62,7 +63,7 @@ static int parse_nmea(const char* line, lua_State *L) {
     if (gnss == NULL && luat_libgnss_init(L)) {
         return 0;
     }
-    
+
     switch (minmea_sentence_id(line, false)) {
         case MINMEA_SENTENCE_RMC: {
             if (minmea_parse_rmc(&(gnsstmp->frame_rmc), line)) {
@@ -206,7 +207,7 @@ static int l_libgnss_parse(lua_State *L) {
             prev = i;
         }
     }
-    
+
     return 0;
 }
 
@@ -265,7 +266,7 @@ static int l_libgnss_get_rmc(lua_State *L) {
     lua_createtable(L, 0, 12);
 
     if (gnss != NULL) {
-        
+
         lua_pushliteral(L, "valid");
         lua_pushboolean(L, gnss->frame_rmc.valid);
         lua_settable(L, -3);
@@ -346,7 +347,7 @@ static int l_libgnss_get_gsv(lua_State *L) {
                 if (gnss->frame_gsv[i].sats[j].snr) {
                     lua_pushinteger(L, count++);
                     lua_createtable(L, 0, 3);
-                    
+
                     lua_pushliteral(L, "snr");
                     lua_pushinteger(L, gnss->frame_gsv[i].sats[j].snr);
                     lua_settable(L, -3);
@@ -412,7 +413,7 @@ static int l_libgnss_get_gsa(lua_State *L) {
             lua_settable(L, -3);
         }
     }
-    
+
     lua_settable(L, -3);
 
     return 1;
@@ -519,7 +520,7 @@ static int l_libgnss_debug(lua_State *L) {
     {
         gnss->debug = 0;
     }
-    
+
     return 0;
 }
 

+ 1 - 0
components/mlx90640-library/luat_lib_mlx90640.c

@@ -4,6 +4,7 @@
 @summary 红外测温(MLX90640)
 @version 1.0
 @date    2022.1.20
+@tag LUAT_USE_MLX90640
 */
 
 #include "luat_base.h"

+ 1 - 0
components/mobile/luat_lib_mobile.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2022.8.9
 @demo    mobile
+@tag LUAT_USE_MOBILE
 @usage
 -- 简单演示
 

+ 1 - 0
components/multimedia/luat_lib_multimedia.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2022.03.11
 @demo multimedia
+@tag LUAT_USE_MEDIA
 */
 #include "luat_base.h"
 #include "luat_multimedia.h"

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

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.11.13
 @demo socket
+@tag LUAT_USE_NETWORK
 */
 #include "luat_base.h"
 #include "luat_malloc.h"

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

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.010.15
 @demo wlan
+@tag LUAT_USE_HTTPSRV
 */
 
 #include "luat_base.h"

+ 1 - 0
components/network/libemqtt/luat_lib_mqtt.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.08.25
 @demo socket
+@tag LUAT_USE_MQTT
 */
 
 #include "luat_base.h"

+ 0 - 449
components/network/libhttp/http_parser.h

@@ -1,449 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef http_parser_h
-#define http_parser_h
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Also update SONAME in the Makefile whenever you change these. */
-#define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 9
-#define HTTP_PARSER_VERSION_PATCH 4
-
-#include <stddef.h>
-#if defined(_WIN32) && !defined(__MINGW32__) && \
-  (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
-#include <BaseTsd.h>
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#elif (defined(__sun) || defined(__sun__)) && defined(__SunOS_5_9)
-#include <sys/inttypes.h>
-#else
-#include <stdint.h>
-#endif
-
-/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
- * faster
- */
-#ifndef HTTP_PARSER_STRICT
-# define HTTP_PARSER_STRICT 1
-#endif
-
-/* Maximium header size allowed. If the macro is not defined
- * before including this header then the default is used. To
- * change the maximum header size, define the macro in the build
- * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
- * the effective limit on the size of the header, define the macro
- * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
- */
-#ifndef HTTP_MAX_HEADER_SIZE
-# define HTTP_MAX_HEADER_SIZE (80*1024)
-#endif
-
-typedef struct http_parser http_parser;
-typedef struct http_parser_settings http_parser_settings;
-
-
-/* Callbacks should return non-zero to indicate an error. The parser will
- * then halt execution.
- *
- * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
- * returning '1' from on_headers_complete will tell the parser that it
- * should not expect a body. This is used when receiving a response to a
- * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
- * chunked' headers that indicate the presence of a body.
- *
- * Returning `2` from on_headers_complete will tell parser that it should not
- * expect neither a body nor any futher responses on this connection. This is
- * useful for handling responses to a CONNECT request which may not contain
- * `Upgrade` or `Connection: upgrade` headers.
- *
- * http_data_cb does not return data chunks. It will be called arbitrarily
- * many times for each string. E.G. you might get 10 callbacks for "on_url"
- * each providing just a few characters more data.
- */
-typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
-typedef int (*http_cb) (http_parser*);
-
-
-/* Status Codes */
-#define HTTP_STATUS_MAP(XX)                                                 \
-  XX(100, CONTINUE,                        Continue)                        \
-  XX(101, SWITCHING_PROTOCOLS,             Switching Protocols)             \
-  XX(102, PROCESSING,                      Processing)                      \
-  XX(200, OK,                              OK)                              \
-  XX(201, CREATED,                         Created)                         \
-  XX(202, ACCEPTED,                        Accepted)                        \
-  XX(203, NON_AUTHORITATIVE_INFORMATION,   Non-Authoritative Information)   \
-  XX(204, NO_CONTENT,                      No Content)                      \
-  XX(205, RESET_CONTENT,                   Reset Content)                   \
-  XX(206, PARTIAL_CONTENT,                 Partial Content)                 \
-  XX(207, MULTI_STATUS,                    Multi-Status)                    \
-  XX(208, ALREADY_REPORTED,                Already Reported)                \
-  XX(226, IM_USED,                         IM Used)                         \
-  XX(300, MULTIPLE_CHOICES,                Multiple Choices)                \
-  XX(301, MOVED_PERMANENTLY,               Moved Permanently)               \
-  XX(302, FOUND,                           Found)                           \
-  XX(303, SEE_OTHER,                       See Other)                       \
-  XX(304, NOT_MODIFIED,                    Not Modified)                    \
-  XX(305, USE_PROXY,                       Use Proxy)                       \
-  XX(307, TEMPORARY_REDIRECT,              Temporary Redirect)              \
-  XX(308, PERMANENT_REDIRECT,              Permanent Redirect)              \
-  XX(400, BAD_REQUEST,                     Bad Request)                     \
-  XX(401, UNAUTHORIZED,                    Unauthorized)                    \
-  XX(402, PAYMENT_REQUIRED,                Payment Required)                \
-  XX(403, FORBIDDEN,                       Forbidden)                       \
-  XX(404, NOT_FOUND,                       Not Found)                       \
-  XX(405, METHOD_NOT_ALLOWED,              Method Not Allowed)              \
-  XX(406, NOT_ACCEPTABLE,                  Not Acceptable)                  \
-  XX(407, PROXY_AUTHENTICATION_REQUIRED,   Proxy Authentication Required)   \
-  XX(408, REQUEST_TIMEOUT,                 Request Timeout)                 \
-  XX(409, CONFLICT,                        Conflict)                        \
-  XX(410, GONE,                            Gone)                            \
-  XX(411, LENGTH_REQUIRED,                 Length Required)                 \
-  XX(412, PRECONDITION_FAILED,             Precondition Failed)             \
-  XX(413, PAYLOAD_TOO_LARGE,               Payload Too Large)               \
-  XX(414, URI_TOO_LONG,                    URI Too Long)                    \
-  XX(415, UNSUPPORTED_MEDIA_TYPE,          Unsupported Media Type)          \
-  XX(416, RANGE_NOT_SATISFIABLE,           Range Not Satisfiable)           \
-  XX(417, EXPECTATION_FAILED,              Expectation Failed)              \
-  XX(421, MISDIRECTED_REQUEST,             Misdirected Request)             \
-  XX(422, UNPROCESSABLE_ENTITY,            Unprocessable Entity)            \
-  XX(423, LOCKED,                          Locked)                          \
-  XX(424, FAILED_DEPENDENCY,               Failed Dependency)               \
-  XX(426, UPGRADE_REQUIRED,                Upgrade Required)                \
-  XX(428, PRECONDITION_REQUIRED,           Precondition Required)           \
-  XX(429, TOO_MANY_REQUESTS,               Too Many Requests)               \
-  XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
-  XX(451, UNAVAILABLE_FOR_LEGAL_REASONS,   Unavailable For Legal Reasons)   \
-  XX(500, INTERNAL_SERVER_ERROR,           Internal Server Error)           \
-  XX(501, NOT_IMPLEMENTED,                 Not Implemented)                 \
-  XX(502, BAD_GATEWAY,                     Bad Gateway)                     \
-  XX(503, SERVICE_UNAVAILABLE,             Service Unavailable)             \
-  XX(504, GATEWAY_TIMEOUT,                 Gateway Timeout)                 \
-  XX(505, HTTP_VERSION_NOT_SUPPORTED,      HTTP Version Not Supported)      \
-  XX(506, VARIANT_ALSO_NEGOTIATES,         Variant Also Negotiates)         \
-  XX(507, INSUFFICIENT_STORAGE,            Insufficient Storage)            \
-  XX(508, LOOP_DETECTED,                   Loop Detected)                   \
-  XX(510, NOT_EXTENDED,                    Not Extended)                    \
-  XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
-
-enum http_status
-  {
-#define XX(num, name, string) HTTP_STATUS_##name = num,
-  HTTP_STATUS_MAP(XX)
-#undef XX
-  };
-
-
-/* Request Methods */
-#define HTTP_METHOD_MAP(XX)         \
-  XX(0,  DELETE,      DELETE)       \
-  XX(1,  GET,         GET)          \
-  XX(2,  HEAD,        HEAD)         \
-  XX(3,  POST,        POST)         \
-  XX(4,  PUT,         PUT)          \
-  /* pathological */                \
-  XX(5,  CONNECT,     CONNECT)      \
-  XX(6,  OPTIONS,     OPTIONS)      \
-  XX(7,  TRACE,       TRACE)        \
-  /* WebDAV */                      \
-  XX(8,  COPY,        COPY)         \
-  XX(9,  LOCK,        LOCK)         \
-  XX(10, MKCOL,       MKCOL)        \
-  XX(11, MOVE,        MOVE)         \
-  XX(12, PROPFIND,    PROPFIND)     \
-  XX(13, PROPPATCH,   PROPPATCH)    \
-  XX(14, SEARCH,      SEARCH)       \
-  XX(15, UNLOCK,      UNLOCK)       \
-  XX(16, BIND,        BIND)         \
-  XX(17, REBIND,      REBIND)       \
-  XX(18, UNBIND,      UNBIND)       \
-  XX(19, ACL,         ACL)          \
-  /* subversion */                  \
-  XX(20, REPORT,      REPORT)       \
-  XX(21, MKACTIVITY,  MKACTIVITY)   \
-  XX(22, CHECKOUT,    CHECKOUT)     \
-  XX(23, MERGE,       MERGE)        \
-  /* upnp */                        \
-  XX(24, MSEARCH,     M-SEARCH)     \
-  XX(25, NOTIFY,      NOTIFY)       \
-  XX(26, SUBSCRIBE,   SUBSCRIBE)    \
-  XX(27, UNSUBSCRIBE, UNSUBSCRIBE)  \
-  /* RFC-5789 */                    \
-  XX(28, PATCH,       PATCH)        \
-  XX(29, PURGE,       PURGE)        \
-  /* CalDAV */                      \
-  XX(30, MKCALENDAR,  MKCALENDAR)   \
-  /* RFC-2068, section 19.6.1.2 */  \
-  XX(31, LINK,        LINK)         \
-  XX(32, UNLINK,      UNLINK)       \
-  /* icecast */                     \
-  XX(33, SOURCE,      SOURCE)       \
-
-enum http_method
-  {
-#define XX(num, name, string) HTTP_##name = num,
-  HTTP_METHOD_MAP(XX)
-#undef XX
-  };
-
-
-enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
-
-
-/* Flag values for http_parser.flags field */
-enum flags
-  { F_CHUNKED               = 1 << 0
-  , F_CONNECTION_KEEP_ALIVE = 1 << 1
-  , F_CONNECTION_CLOSE      = 1 << 2
-  , F_CONNECTION_UPGRADE    = 1 << 3
-  , F_TRAILING              = 1 << 4
-  , F_UPGRADE               = 1 << 5
-  , F_SKIPBODY              = 1 << 6
-  , F_CONTENTLENGTH         = 1 << 7
-  };
-
-
-/* Map for errno-related constants
- *
- * The provided argument should be a macro that takes 2 arguments.
- */
-#define HTTP_ERRNO_MAP(XX)                                           \
-  /* No error */                                                     \
-  XX(OK, "success")                                                  \
-                                                                     \
-  /* Callback-related errors */                                      \
-  XX(CB_message_begin, "the on_message_begin callback failed")       \
-  XX(CB_url, "the on_url callback failed")                           \
-  XX(CB_header_field, "the on_header_field callback failed")         \
-  XX(CB_header_value, "the on_header_value callback failed")         \
-  XX(CB_headers_complete, "the on_headers_complete callback failed") \
-  XX(CB_body, "the on_body callback failed")                         \
-  XX(CB_message_complete, "the on_message_complete callback failed") \
-  XX(CB_status, "the on_status callback failed")                     \
-  XX(CB_chunk_header, "the on_chunk_header callback failed")         \
-  XX(CB_chunk_complete, "the on_chunk_complete callback failed")     \
-                                                                     \
-  /* Parsing-related errors */                                       \
-  XX(INVALID_EOF_STATE, "stream ended at an unexpected time")        \
-  XX(HEADER_OVERFLOW,                                                \
-     "too many header bytes seen; overflow detected")                \
-  XX(CLOSED_CONNECTION,                                              \
-     "data received after completed connection: close message")      \
-  XX(INVALID_VERSION, "invalid HTTP version")                        \
-  XX(INVALID_STATUS, "invalid HTTP status code")                     \
-  XX(INVALID_METHOD, "invalid HTTP method")                          \
-  XX(INVALID_URL, "invalid URL")                                     \
-  XX(INVALID_HOST, "invalid host")                                   \
-  XX(INVALID_PORT, "invalid port")                                   \
-  XX(INVALID_PATH, "invalid path")                                   \
-  XX(INVALID_QUERY_STRING, "invalid query string")                   \
-  XX(INVALID_FRAGMENT, "invalid fragment")                           \
-  XX(LF_EXPECTED, "LF character expected")                           \
-  XX(INVALID_HEADER_TOKEN, "invalid character in header")            \
-  XX(INVALID_CONTENT_LENGTH,                                         \
-     "invalid character in content-length header")                   \
-  XX(UNEXPECTED_CONTENT_LENGTH,                                      \
-     "unexpected content-length header")                             \
-  XX(INVALID_CHUNK_SIZE,                                             \
-     "invalid character in chunk size header")                       \
-  XX(INVALID_CONSTANT, "invalid constant string")                    \
-  XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
-  XX(STRICT, "strict mode assertion failed")                         \
-  XX(PAUSED, "parser is paused")                                     \
-  XX(UNKNOWN, "an unknown error occurred")                           \
-  XX(INVALID_TRANSFER_ENCODING,                                      \
-     "request has invalid transfer-encoding")                        \
-
-
-/* Define HPE_* values for each errno value above */
-#define HTTP_ERRNO_GEN(n, s) HPE_##n,
-enum http_errno {
-  HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
-};
-#undef HTTP_ERRNO_GEN
-
-
-/* Get an http_errno value from an http_parser */
-#define HTTP_PARSER_ERRNO(p)            ((enum http_errno) (p)->http_errno)
-
-
-struct http_parser {
-  /** PRIVATE **/
-  unsigned int type : 2;         /* enum http_parser_type */
-  unsigned int flags : 8;       /* F_* values from 'flags' enum; semi-public */
-  unsigned int state : 7;        /* enum state from http_parser.c */
-  unsigned int header_state : 7; /* enum header_state from http_parser.c */
-  unsigned int index : 5;        /* index into current matcher */
-  unsigned int uses_transfer_encoding : 1; /* Transfer-Encoding header is present */
-  unsigned int allow_chunked_length : 1; /* Allow headers with both
-                                          * `Content-Length` and
-                                          * `Transfer-Encoding: chunked` set */
-  unsigned int lenient_http_headers : 1;
-
-  uint32_t nread;          /* # bytes read in various scenarios */
-  uint64_t content_length; /* # bytes in body. `(uint64_t) -1` (all bits one)
-                            * if no Content-Length header.
-                            */
-
-  /** READ-ONLY **/
-  unsigned short http_major;
-  unsigned short http_minor;
-  unsigned int status_code : 16; /* responses only */
-  unsigned int method : 8;       /* requests only */
-  unsigned int http_errno : 7;
-
-  /* 1 = Upgrade header was present and the parser has exited because of that.
-   * 0 = No upgrade header present.
-   * Should be checked when http_parser_execute() returns in addition to
-   * error checking.
-   */
-  unsigned int upgrade : 1;
-
-  /** PUBLIC **/
-  void *data; /* A pointer to get hook to the "connection" or "socket" object */
-};
-
-
-struct http_parser_settings {
-  http_cb      on_message_begin;
-  http_data_cb on_url;
-  http_data_cb on_status;
-  http_data_cb on_header_field;
-  http_data_cb on_header_value;
-  http_cb      on_headers_complete;
-  http_data_cb on_body;
-  http_cb      on_message_complete;
-  /* When on_chunk_header is called, the current chunk length is stored
-   * in parser->content_length.
-   */
-  http_cb      on_chunk_header;
-  http_cb      on_chunk_complete;
-};
-
-
-enum http_parser_url_fields
-  { UF_SCHEMA           = 0
-  , UF_HOST             = 1
-  , UF_PORT             = 2
-  , UF_PATH             = 3
-  , UF_QUERY            = 4
-  , UF_FRAGMENT         = 5
-  , UF_USERINFO         = 6
-  , UF_MAX              = 7
-  };
-
-
-/* Result structure for http_parser_parse_url().
- *
- * Callers should index into field_data[] with UF_* values iff field_set
- * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
- * because we probably have padding left over), we convert any port to
- * a uint16_t.
- */
-struct http_parser_url {
-  uint16_t field_set;           /* Bitmask of (1 << UF_*) values */
-  uint16_t port;                /* Converted UF_PORT string */
-
-  struct {
-    uint16_t off;               /* Offset into buffer in which field starts */
-    uint16_t len;               /* Length of run in buffer */
-  } field_data[UF_MAX];
-};
-
-
-/* Returns the library version. Bits 16-23 contain the major version number,
- * bits 8-15 the minor version number and bits 0-7 the patch level.
- * Usage example:
- *
- *   unsigned long version = http_parser_version();
- *   unsigned major = (version >> 16) & 255;
- *   unsigned minor = (version >> 8) & 255;
- *   unsigned patch = version & 255;
- *   printf("http_parser v%u.%u.%u\n", major, minor, patch);
- */
-unsigned long http_parser_version(void);
-
-void http_parser_init(http_parser *parser, enum http_parser_type type);
-
-
-/* Initialize http_parser_settings members to 0
- */
-void http_parser_settings_init(http_parser_settings *settings);
-
-
-/* Executes the parser. Returns number of parsed bytes. Sets
- * `parser->http_errno` on error. */
-size_t http_parser_execute(http_parser *parser,
-                           const http_parser_settings *settings,
-                           const char *data,
-                           size_t len);
-
-
-/* If http_should_keep_alive() in the on_headers_complete or
- * on_message_complete callback returns 0, then this should be
- * the last message on the connection.
- * If you are the server, respond with the "Connection: close" header.
- * If you are the client, close the connection.
- */
-int http_should_keep_alive(const http_parser *parser);
-
-/* Returns a string version of the HTTP method. */
-const char *http_method_str(enum http_method m);
-
-/* Returns a string version of the HTTP status code. */
-const char *http_status_str(enum http_status s);
-
-/* Return a string name of the given error */
-const char *http_errno_name(enum http_errno err);
-
-/* Return a string description of the given error */
-const char *http_errno_description(enum http_errno err);
-
-/* Initialize all http_parser_url members to 0 */
-void http_parser_url_init(struct http_parser_url *u);
-
-/* Parse a URL; return nonzero on failure */
-int http_parser_parse_url(const char *buf, size_t buflen,
-                          int is_connect,
-                          struct http_parser_url *u);
-
-/* Pause or un-pause the parser; a nonzero value pauses */
-void http_parser_pause(http_parser *parser, int paused);
-
-/* Checks if this is the final chunk of the body. */
-int http_body_is_final(const http_parser *parser);
-
-/* Change the maximum header size provided at compile time. */
-void http_parser_set_max_header_size(uint32_t size);
-
-#ifdef __cplusplus
-}
-#endif
-#endif

+ 20 - 12
components/network/libhttp/luat_lib_http.c

@@ -1,9 +1,10 @@
 /*
-@module  http2
-@summary http2客户端
+@module  http
+@summary http 客户端
 @version 1.0
 @date    2022.09.05
 @demo    socket
+@tag LUAT_USE_HTTP
 */
 
 #include "luat_base.h"
@@ -572,8 +573,8 @@ static int http_set_url(luat_http_ctrl_t *http_ctrl) {
 }
 
 /*
-http2客户端
-@api http2.request(method,url,headers,body,opts,ca_file)
+http客户端
+@api http.request(method,url,headers,body,opts,ca_file)
 @string 请求方法, 支持 GET/POST
 @string url地址
 @tabal  请求头 可选 例如{["Content-Type"] = "application/x-www-form-urlencoded"}
@@ -585,15 +586,15 @@ http2客户端
 @return string body
 @usage
 -- GET请求
-local code, headers, body = http2.request("GET","http://site0.cn/api/httptest/simple/time").wait()
-log.info("http2.get", code, headers, body)
+local code, headers, body = http.request("GET","http://site0.cn/api/httptest/simple/time").wait()
+log.info("http.get", code, headers, body)
 -- POST请求
-local code, headers, body = http2.request("POST","http://httpbin.com/post", {}, "abc=123").wait()
-log.info("http2.post", code, headers, body)
+local code, headers, body = http.request("POST","http://httpbin.com/post", {}, "abc=123").wait()
+log.info("http.post", code, headers, body)
 
 -- GET请求,但下载到文件
-local code, headers, body = http2.request("GET","http://httpbin.com/", {}, "", {dst="/data.bin"}).wait()
-log.info("http2.get", code, headers, body)
+local code, headers, body = http.request("GET","http://httpbin.com/", {}, "", {dst="/data.bin"}).wait()
+log.info("http.get", code, headers, body)
 */
 static int l_http_request(lua_State *L) {
 	size_t client_cert_len, client_key_len, client_password_len,len;
@@ -659,7 +660,7 @@ static int l_http_request(lua_State *L) {
 	}
 	network_init_ctrl(http_ctrl->netc, NULL, luat_lib_http_callback, http_ctrl);
 
-	
+
 	network_set_base_mode(http_ctrl->netc, 1, 10000, 0, 0, 0, 0);
 	network_set_local_port(http_ctrl->netc, 0);
 
@@ -772,8 +773,15 @@ LUAMOD_API int luaopen_http( lua_State *L ) {
     luat_newlib2(L, reg_http);
 #else
     luat_newlib2(L, reg_http_emtry);
-	LLOGE("reg_http2 require network enable!!");
+	LLOGE("reg_http require network enable!!");
 #endif
     return 1;
 }
 
+LUAMOD_API int luaopen_http2( lua_State *L ) {
+    lua_getglobal(L, "http");
+    if (lua_isuserdata(L, -1))
+        return 1;
+    luaopen_http(L);
+    return 1;
+}

+ 414 - 0
components/network/websocket/luat_lib_websocket.c

@@ -0,0 +1,414 @@
+/*
+@module  websocket
+@summary websocket客户端
+@version 1.0
+@date    2022.11.28
+@demo    websocket
+@usage
+local wsc = nil
+if websocket then
+    wsc = websocket.create(nil, "ws://nutz.cn/websocket")
+    wsc:autoreconn(true, 3000) -- 自动重连机制
+    wsc:on(function(wsc, event, data)
+        log.info("wsc", event, data)
+        if event == "conack" then
+            wsc:send((json.encode({action="login",device_id=device_id})))
+        end
+    end)
+    wsc:connect()
+    --sys.waitUntil("websocket_conack", 15000)
+    while true do
+        sys.wait(45000)
+        if wsc:ready() then
+        	wsc:send((json.encode({action="echo", msg=os.date()})))
+		end
+    end
+    wsc:close()
+    wsc = nil
+end
+*/
+
+#include "luat_base.h"
+
+#include "luat_network_adapter.h"
+#include "luat_rtos.h"
+#include "luat_zbuff.h"
+#include "luat_malloc.h"
+#include "luat_websocket.h"
+
+#define LUAT_LOG_TAG "websocket"
+#include "luat_log.h"
+
+#define LUAT_WEBSOCKET_CTRL_TYPE "WS*"
+
+static luat_websocket_ctrl_t *get_websocket_ctrl(lua_State *L)
+{
+	if (luaL_testudata(L, 1, LUAT_WEBSOCKET_CTRL_TYPE))
+	{
+		return ((luat_websocket_ctrl_t *)luaL_checkudata(L, 1, LUAT_WEBSOCKET_CTRL_TYPE));
+	}
+	else
+	{
+		return ((luat_websocket_ctrl_t *)lua_touserdata(L, 1));
+	}
+}
+
+static int32_t l_websocket_callback(lua_State *L, void *ptr)
+{
+	rtos_msg_t *msg = (rtos_msg_t *)lua_topointer(L, -1);
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)msg->ptr;
+	luat_websocket_pkg_t pkg = {0};
+	// size_t payload_size = 0;
+	switch (msg->arg1)
+	{
+	case WEBSOCKET_MSG_TIMER_PING:
+	{
+		luat_websocket_ping(websocket_ctrl);
+		break;
+	}
+	case WEBSOCKET_MSG_PUBLISH:
+	{
+		if (websocket_ctrl->websocket_cb)
+		{
+			lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb);
+			if (lua_isfunction(L, -1))
+			{
+				lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
+				lua_pushstring(L, "recv");
+				luat_websocket_payload((char *)msg->arg2, &pkg, 64 * 1024);
+				lua_pushlstring(L, pkg.payload, pkg.plen);
+				lua_pushinteger(L, pkg.FIN);
+				lua_pushinteger(L, pkg.OPT_CODE);
+				lua_call(L, 5, 0);
+			}
+		}
+		luat_heap_free((char *)msg->arg2);
+		break;
+	}
+	case WEBSOCKET_MSG_CONNACK:
+	{
+		if (websocket_ctrl->websocket_cb)
+		{
+			lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb);
+			if (lua_isfunction(L, -1))
+			{
+				lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
+				lua_pushstring(L, "conack");
+				lua_call(L, 2, 0);
+			}
+			lua_getglobal(L, "sys_pub");
+			if (lua_isfunction(L, -1))
+			{
+				lua_pushstring(L, "WEBSOCKET_CONNACK");
+				lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
+				lua_call(L, 2, 0);
+			}
+		}
+		break;
+	}
+	case WEBSOCKET_MSG_RELEASE:
+	{
+		if (websocket_ctrl->websocket_ref)
+		{
+			luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
+			websocket_ctrl->websocket_ref = 0;
+		}
+		break;
+	}
+	default:
+	{
+		LLOGD("l_websocket_callback error arg1:%d", msg->arg1);
+		break;
+	}
+	}
+	// lua_pushinteger(L, 0);
+	return 0;
+}
+
+int l_luat_websocket_msg_cb(luat_websocket_ctrl_t *ctrl, int arg1, int arg2)
+{
+	rtos_msg_t msg = {
+		.handler = l_websocket_callback,
+		.ptr = ctrl,
+		.arg1 = arg1,
+		.arg2 = arg2,
+	};
+	luat_msgbus_put(&msg, 0);
+	return 0;
+}
+
+/*
+配置是否打开debug信息
+@api wsc:debug(onoff)
+@boolean 是否打开debug开关
+@return nil 无返回值
+@usage wsc:debug(true)
+*/
+static int l_websocket_set_debug(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	if (lua_isboolean(L, 2))
+	{
+		websocket_ctrl->netc->is_debug = lua_toboolean(L, 2);
+	}
+	return 0;
+}
+
+/*
+websocket客户端创建
+@api websocket.create(adapter, url)
+@int 适配器序号, 只能是network.ETH0,network.STA,network.AP,如果不填,会选择最后一个注册的适配器
+@string 连接字符串,参考usage
+@return userdata 若成功会返回websocket客户端实例,否则返回nil
+@usage
+-- 普通TCP链接
+wsc = websocket.create(nil,"ws://air32.cn/abc")
+-- 加密TCP链接
+wsc = websocket.create(nil,"wss://air32.cn/abc")
+*/
+static int l_websocket_create(lua_State *L)
+{
+	int ret = 0;
+	int adapter_index = luaL_optinteger(L, 1, network_get_last_register_adapter());
+	if (adapter_index < 0 || adapter_index >= NW_ADAPTER_QTY)
+	{
+		return 0;
+	}
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)lua_newuserdata(L, sizeof(luat_websocket_ctrl_t));
+	if (!websocket_ctrl)
+	{
+		LLOGE("out of memory when malloc websocket_ctrl");
+		return 0;
+	}
+
+	ret = luat_websocket_init(websocket_ctrl, adapter_index);
+	if (ret)
+	{
+		LLOGE("websocket init FAID ret %d", ret);
+		return 0;
+	}
+
+	luat_websocket_connopts_t opts = {0};
+
+	// 连接参数相关
+	const char *ip;
+	size_t ip_len = 0;
+#ifdef LUAT_USE_LWIP
+	websocket_ctrl->ip_addr.type = 0xff;
+#else
+	websocket_ctrl->ip_addr.is_ipv6 = 0xff;
+#endif
+	opts.url = luaL_checklstring(L, 2, &ip_len);
+
+	ret = luat_websocket_set_connopts(websocket_ctrl, luaL_checklstring(L, 2, &ip_len));
+
+	// TODO 判断ret, 如果初始化失败, 应该终止
+
+	luaL_setmetatable(L, LUAT_WEBSOCKET_CTRL_TYPE);
+	lua_pushvalue(L, -1);
+	websocket_ctrl->websocket_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+	return 1;
+}
+
+/*
+注册websocket回调
+@api wsc:on(cb)
+@function cb websocket回调,参数包括websocket_client, event, data, payload
+@return nil 无返回值
+@usage
+wsc:on(function(websocket_client, event, data, payload)
+	-- 用户自定义代码
+	log.info("websocket", "event", event, websocket_client, data, payload)
+end)
+*/
+static int l_websocket_on(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	if (websocket_ctrl->websocket_cb != 0)
+	{
+		luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb);
+		websocket_ctrl->websocket_cb = 0;
+	}
+	if (lua_isfunction(L, 2))
+	{
+		lua_pushvalue(L, 2);
+		websocket_ctrl->websocket_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+	}
+	return 0;
+}
+
+/*
+连接服务器
+@api wsc:connect()
+@return boolean 发起成功返回true, 否则返回false
+@usage
+-- 开始建立连接
+wsc:connect()
+-- 本函数仅代表发起成功, 后续仍需根据ready函数判断websocket是否连接正常
+*/
+static int l_websocket_connect(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	int ret = luat_websocket_connect(websocket_ctrl);
+	if (ret)
+	{
+		LLOGE("socket connect ret=%d\n", ret);
+		luat_websocket_close_socket(websocket_ctrl);
+		lua_pushboolean(L, 0);
+		return 1;
+	}
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+/*
+自动重连
+@api wsc:autoreconn(reconnect, reconnect_time)
+@bool 是否自动重连
+@int 自动重连周期 单位ms 默认3000ms
+@usage
+wsc:autoreconn(true)
+*/
+static int l_websocket_autoreconn(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	if (lua_isboolean(L, 2))
+	{
+		websocket_ctrl->reconnect = lua_toboolean(L, 2);
+	}
+	websocket_ctrl->reconnect_time = luaL_optinteger(L, 3, 3000);
+	return 0;
+}
+
+/*
+发布消息
+@api wsc:send(data, fin, opt)
+@string 待发送的数据,必填
+@int 是否为最后一帧,默认1
+@int 操作码, 默认为字符串帧
+@return int 消息id, 当qos为1或2时会有效值. 若底层返回是否, 会返回nil
+@usage
+wsc:publish("/luatos/123456", "123")
+*/
+static int l_websocket_send(lua_State *L)
+{
+	uint32_t payload_len = 0;
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	const char *payload = NULL;
+	luat_zbuff_t *buff = NULL;
+	int ret = 0;
+	if (lua_isstring(L, 2))
+	{
+		payload = luaL_checklstring(L, 2, &payload_len);
+	}
+	else if (luaL_testudata(L, 2, LUAT_ZBUFF_TYPE))
+	{
+		buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
+		payload = buff->addr;
+		payload_len = buff->used;
+	}
+	else
+	{
+		LLOGD("only support string or zbuff");
+		return 0;
+	}
+	luat_websocket_pkg_t pkg = {
+		.FIN = 1,
+		.OPT_CODE = 0x01,
+		.plen = payload_len,
+		.payload = payload};
+	ret = luat_websocket_send_frame(websocket_ctrl, &pkg);
+	return 0;
+}
+
+/*
+websocket客户端关闭(关闭后资源释放无法再使用)
+@api wsc:close()
+@usage
+wsc:close()
+*/
+static int l_websocket_close(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	// websocket_disconnect(&(websocket_ctrl->broker));
+	luat_websocket_close_socket(websocket_ctrl);
+	if (websocket_ctrl->websocket_cb != 0)
+	{
+		luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb);
+		websocket_ctrl->websocket_cb = 0;
+	}
+	luat_websocket_release_socket(websocket_ctrl);
+	return 0;
+}
+
+/*
+websocket客户端是否就绪
+@api wsc:ready()
+@return bool 客户端是否就绪
+@usage
+local error = wsc:ready()
+*/
+static int l_websocket_ready(lua_State *L)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
+	lua_pushboolean(L, websocket_ctrl->websocket_state > 0 ? 1 : 0);
+	return 1;
+}
+
+static int _websocket_struct_newindex(lua_State *L);
+
+void luat_websocket_struct_init(lua_State *L)
+{
+	luaL_newmetatable(L, LUAT_WEBSOCKET_CTRL_TYPE);
+	lua_pushcfunction(L, _websocket_struct_newindex);
+	lua_setfield(L, -2, "__index");
+	lua_pop(L, 1);
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_websocket[] =
+	{
+		{"create", ROREG_FUNC(l_websocket_create)},
+		{"on", ROREG_FUNC(l_websocket_on)},
+		{"connect", ROREG_FUNC(l_websocket_connect)},
+		{"autoreconn", ROREG_FUNC(l_websocket_autoreconn)},
+		{"send", ROREG_FUNC(l_websocket_send)},
+		{"close", ROREG_FUNC(l_websocket_close)},
+		{"ready", ROREG_FUNC(l_websocket_ready)},
+
+		{NULL, ROREG_INT(0)}};
+
+static int _websocket_struct_newindex(lua_State *L)
+{
+	rotable_Reg_t *reg = reg_websocket;
+	const char *key = luaL_checkstring(L, 2);
+	while (1)
+	{
+		if (reg->name == NULL)
+			return 0;
+		if (!strcmp(reg->name, key))
+		{
+			lua_pushcfunction(L, reg->value.value.func);
+			return 1;
+		}
+		reg++;
+	}
+	// return 0;
+}
+static const rotable_Reg_t reg_websocket_emtry[] =
+	{
+		{NULL, ROREG_INT(0)}};
+
+LUAMOD_API int luaopen_websocket(lua_State *L)
+{
+
+#ifdef LUAT_USE_NETWORK
+	luat_newlib2(L, reg_websocket);
+	luat_websocket_struct_init(L);
+	return 1;
+#else
+	LLOGE("websocket require network enable!!");
+	luat_newlib2(L, reg_websocket_emtry);
+	return 1;
+#endif
+}

+ 588 - 0
components/network/websocket/luat_websocket.c

@@ -0,0 +1,588 @@
+#include "luat_base.h"
+
+#include "luat_network_adapter.h"
+#include "luat_rtos.h"
+#include "luat_zbuff.h"
+#include "luat_malloc.h"
+#include "luat_websocket.h"
+// #include "http_parser.h"
+
+#define LUAT_LOG_TAG "websocket"
+#include "luat_log.h"
+
+#define WEBSOCKET_DEBUG 1
+#if WEBSOCKET_DEBUG == 0
+#undef LLOGD
+#define LLOGD(...)
+#endif
+
+#if WEBSOCKET_DEBUG
+static void print_pkg(const char *tag, char *buff, luat_websocket_pkg_t *pkg)
+{
+	if (pkg == NULL)
+	{
+		LLOGD("pkg is NULL");
+		return;
+	}
+	LLOGD("%s pkg %02X%02X", tag, buff[0], buff[1]);
+	LLOGD("%s pkg FIN %d R %d OPT %d MARK %d PLEN %d", tag, pkg->FIN, pkg->R, pkg->OPT_CODE, pkg->mark, pkg->plen);
+}
+#else
+#define print_pkg(...)
+#endif
+
+int luat_websocket_payload(char *buf, luat_websocket_pkg_t *pkg, size_t limit)
+{
+	uint32_t pkg_len = 0;
+	// 先处理FIN
+	if (buf[0] && (1 << 7))
+	{
+		pkg->FIN = 1;
+	}
+	// 处理操作码
+	pkg->OPT_CODE = buf[0] & 0xF;
+	// 然后处理plen
+	pkg->plen = buf[1] & 0x7F;
+
+	print_pkg("downlink", buf, pkg);
+	// websocket的payload长度支持3种情况:
+	// 0字节(小于126,放在头部)
+	// 2个字节 126 ~ 0xFFFF
+	// 6个字节 0x1000 ~ 0xFFFFFFFF, 不打算支持.
+	if (pkg->plen == 126)
+	{
+		if (limit < 4)
+		{
+			// 还缺1个字节,等吧
+			LLOGD("wait more data offset %d", limit);
+			return NULL;
+		}
+		pkg->plen = (buf[2] & 0xFF) << 8;
+		pkg->plen += (buf[3] & 0xFF);
+		pkg_len = 4 + pkg->plen;
+		pkg->payload = buf + 4;
+	}
+	else if (pkg->plen == 127)
+	{
+		// 后续还要8个字节,但这个包也太大了吧!!!
+		LLOGE("websocket payload is too large!!!");
+		return -1;
+	}
+	else
+	{
+		pkg_len = 2 + pkg->plen;
+		pkg->payload = buf + 2;
+	}
+
+	LLOGD("payload %04X pkg %04X", pkg->plen, pkg_len);
+	if (limit < pkg_len)
+	{
+		LLOGD("wait more data offset %d", limit);
+		return 0;
+	}
+
+	return 0;
+}
+
+int luat_websocket_send_packet(void *socket_info, const void *buf, unsigned int count)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)socket_info;
+	uint32_t tx_len = 0;
+	int ret = network_tx(websocket_ctrl->netc, buf, count, 0, NULL, 0, &tx_len, 0);
+	if (ret < 0)
+	{
+		LLOGI("network_tx %d , close socket", ret);
+		luat_websocket_close_socket(websocket_ctrl);
+		return 0;
+	}
+	return count;
+}
+
+void luat_websocket_ping(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	luat_websocket_pkg_t pkg = {
+		.FIN = 1,
+		.OPT_CODE = WebSocket_OP_PING,
+		.plen = 0};
+	luat_websocket_send_frame(websocket_ctrl, &pkg);
+}
+
+void luat_websocket_pong(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	luat_websocket_pkg_t pkg = {
+		.FIN = 1,
+		.OPT_CODE = WebSocket_OP_PONG,
+		.plen = 0};
+	luat_websocket_send_frame(websocket_ctrl, &pkg);
+}
+
+LUAT_RT_RET_TYPE luat_websocket_timer_callback(LUAT_RT_CB_PARAM)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)param;
+	l_luat_websocket_msg_cb(websocket_ctrl, WEBSOCKET_MSG_TIMER_PING, 0);
+}
+
+static void reconnect_timer_cb(LUAT_RT_CB_PARAM)
+{
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)param;
+	int ret = luat_websocket_connect(websocket_ctrl);
+	if (ret)
+	{
+		LLOGI("reconnect init socket ret=%d\n", ret);
+		luat_websocket_close_socket(websocket_ctrl);
+	}
+}
+
+int luat_websocket_init(luat_websocket_ctrl_t *websocket_ctrl, int adapter_index)
+{
+	memset(websocket_ctrl, 0, sizeof(luat_websocket_ctrl_t));
+	websocket_ctrl->adapter_index = adapter_index;
+	websocket_ctrl->netc = network_alloc_ctrl(adapter_index);
+	if (!websocket_ctrl->netc)
+	{
+		LLOGW("network_alloc_ctrl fail");
+		return -1;
+	}
+	network_init_ctrl(websocket_ctrl->netc, NULL, luat_websocket_callback, websocket_ctrl);
+
+	websocket_ctrl->websocket_state = 0;
+	websocket_ctrl->netc->is_debug = 0;
+	websocket_ctrl->keepalive = 240;
+	network_set_base_mode(websocket_ctrl->netc, 1, 10000, 0, 0, 0, 0);
+	network_set_local_port(websocket_ctrl->netc, 0);
+	websocket_ctrl->ping_timer = luat_create_rtos_timer(luat_websocket_timer_callback, websocket_ctrl, NULL);
+	return 0;
+}
+
+int luat_websocket_set_connopts(luat_websocket_ctrl_t *websocket_ctrl, const char *url)
+{
+	int is_tls = 0;
+	const char *tmp = url;
+	LLOGD("url %s", url);
+
+	websocket_ctrl->host[0] = 0;
+	char port_tmp[6] = {0};
+	uint16_t port = 0;
+
+	if (!memcmp(tmp, "wss://", strlen("wss://")))
+	{
+		// LLOGD("using WSS");
+		is_tls = 1;
+		tmp += strlen("wss://");
+	}
+	else if (!memcmp(tmp, "ws://", strlen("ws://")))
+	{
+		// LLOGD("using ws");
+		is_tls = 0;
+		tmp += strlen("ws://");
+	}
+
+	// LLOGD("tmp %s", tmp);
+
+	for (size_t i = 0; i < strlen(tmp); i++)
+	{
+		if (tmp[i] == '/')
+		{
+			for (size_t j = 0; j < i; j++)
+			{
+				if (tmp[j] == ':')
+				{
+					memcpy(websocket_ctrl->host, tmp, j - 1);
+					websocket_ctrl->host[j - 1] = 0;
+					memcpy(port_tmp, tmp + j, i - j);
+					port = atoi(port_tmp);
+					// LLOGD("found custom host %s port %d", websocket_ctrl->host, port);
+					break;
+				}
+			}
+			// 没有自定义host
+			if (websocket_ctrl->host[0] == 0)
+			{
+				memcpy(websocket_ctrl->host, tmp, i);
+				websocket_ctrl->host[i] = 0;
+				// LLOGD("found custom host %s", websocket_ctrl->host);
+			}
+			memcpy(websocket_ctrl->uri, tmp + i, strlen(tmp) - i);
+			websocket_ctrl->uri[strlen(tmp) - i] = 0;
+			// LLOGD("found uri %s", websocket_ctrl->uri);
+			break;
+		}
+	}
+	if (port == 0 && is_tls)
+	{
+		port = 443;
+	}
+	else
+	{
+		port = 80;
+	}
+
+	if (websocket_ctrl->uri[0] == 0)
+	{
+		websocket_ctrl->uri[0] = '/';
+		websocket_ctrl->uri[1] = 0x00;
+	}
+
+	// LLOGD("host %s port %d uri %s", host, port, uri);
+	// memcpy(websocket_ctrl->host, host, strlen(host) + 1);
+	websocket_ctrl->remote_port = port;
+	// memcpy(websocket_ctrl->uri, uri, strlen(uri) + 1);
+	LLOGD("host %s port %d uri %s", websocket_ctrl->host, port, websocket_ctrl->uri);
+
+	if (is_tls)
+	{
+		network_init_tls(websocket_ctrl->netc, 0);
+	}
+	else
+	{
+		network_deinit_tls(websocket_ctrl->netc);
+	}
+	return 0;
+}
+
+static void websocket_reconnect(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	if (websocket_ctrl->reconnect)
+	{
+		LLOGI("reconnect after %dms", websocket_ctrl->reconnect_time);
+		websocket_ctrl->buffer_offset = 0;
+		websocket_ctrl->reconnect_timer = luat_create_rtos_timer(reconnect_timer_cb, websocket_ctrl, NULL);
+		luat_start_rtos_timer(websocket_ctrl->reconnect_timer, websocket_ctrl->reconnect_time, 0);
+	}
+}
+
+void luat_websocket_close_socket(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	LLOGI("websocket closing socket");
+	if (websocket_ctrl->netc)
+	{
+		network_force_close_socket(websocket_ctrl->netc);
+	}
+	luat_stop_rtos_timer(websocket_ctrl->ping_timer);
+	websocket_ctrl->websocket_state = 0;
+	websocket_reconnect(websocket_ctrl);
+}
+
+void luat_websocket_release_socket(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	l_luat_websocket_msg_cb(websocket_ctrl, WEBSOCKET_MSG_RELEASE, 0);
+	if (websocket_ctrl->netc)
+	{
+		network_release_ctrl(websocket_ctrl->netc);
+		websocket_ctrl->netc = NULL;
+	}
+}
+
+static int websocket_connect(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	LLOGD("request host %s port %d uri %s", websocket_ctrl->host, websocket_ctrl->remote_port, websocket_ctrl->uri);
+	// 借用pkg_buff
+	int ret = snprintf_(websocket_ctrl->pkg_buff,
+						WEBSOCKET_RECV_BUF_LEN_MAX,
+						"GET %s HTTP/1.1\r\n"
+						"Host: %s\r\n"
+						"Upgrade: websocket\r\n"
+						"Connection: Upgrade\r\n"
+						"Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==\r\n"
+						"Sec-WebSocket-Version: 13\r\n"
+						"\r\n",
+						websocket_ctrl->uri, websocket_ctrl->host);
+	// LLOGD("Request %s", websocket_ctrl->pkg_buff);
+	return luat_websocket_send_packet(websocket_ctrl, websocket_ctrl->pkg_buff, ret);
+}
+
+int luat_websocket_send_frame(luat_websocket_ctrl_t *websocket_ctrl, luat_websocket_pkg_t *pkg)
+{
+	char *dst = luat_heap_malloc(pkg->plen + 6);
+	memset(dst, 0, pkg->plen + 6);
+	size_t offset = 0;
+	// first byte, FIN and OPTCODE
+	dst[0] = pkg->FIN << 7;
+	dst[0] |= pkg->OPT_CODE & 0xF;
+	if (pkg->plen < 126)
+	{
+		dst[1] = pkg->plen;
+		offset = 2;
+	}
+	else if (pkg->plen < 0xFFFF)
+	{
+		dst[1] = 126;
+		dst[2] = pkg->plen >> 8;
+		dst[4] = pkg->plen & 0xFF;
+		offset = 4;
+	}
+	dst[1] |= 1 << 7;
+
+	print_pkg("uplink", dst, pkg);
+
+	// 添加mark, TODO 改成随机?
+	char mark[] = {0, 1, 2, 3};
+	memcpy(dst + offset, mark, 4);
+	offset += 4;
+
+	if (pkg->plen > 0)
+	{
+		for (size_t i = 0; i < pkg->plen; i++)
+		{
+			dst[offset + i] = pkg->payload[i] ^ (mark[i % 4]);
+		}
+	}
+
+	luat_websocket_send_packet(websocket_ctrl, dst, offset + pkg->plen);
+	return 0;
+}
+
+static int websocket_parse(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	char *buf = websocket_ctrl->pkg_buff;
+	LLOGD("websocket_parse offset %d %d", websocket_ctrl->buffer_offset, websocket_ctrl->websocket_state);
+	if (websocket_ctrl->websocket_state == 0)
+	{
+		if (websocket_ctrl->buffer_offset < strlen("HTTP/1.1 101"))
+		{ // 最起码得等5个字符
+			LLOGD("wait more data offset %d", websocket_ctrl->buffer_offset);
+			return 0;
+		}
+		// 前3个字符肯定是101, 否则必然是不合法的
+		if (memcmp("HTTP/1.1 101", buf, strlen("HTTP/1.1 101")))
+		{
+			buf[websocket_ctrl->buffer_offset] = 0;
+			LLOGD("server not support websocket? resp code %s", buf);
+			return -1;
+		}
+		// 然后找\r\n\r\n
+		for (size_t i = 4; i < websocket_ctrl->buffer_offset; i++)
+		{
+			if (!memcmp("\r\n\r\n", buf + i, 4))
+			{
+				// LLOGD("Found \\r\\n\\r\\n");
+				//  找到了!! 但貌似完全不用处理呢
+				websocket_ctrl->buffer_offset = 0;
+				LLOGD("ready!!");
+				websocket_ctrl->websocket_state = 1;
+				luat_stop_rtos_timer(websocket_ctrl->ping_timer);
+				luat_start_rtos_timer(websocket_ctrl->ping_timer, 30000, 1);
+				l_luat_websocket_msg_cb(websocket_ctrl, WEBSOCKET_MSG_CONNACK, 0);
+				return 1;
+			}
+		}
+		// LLOGD("Not Found \\r\\n\\r\\n %s", buf);
+		return 0;
+	}
+
+	if (websocket_ctrl->buffer_offset < 2)
+	{
+		LLOGD("wait more data offset %d", websocket_ctrl->buffer_offset);
+		return 0;
+	}
+	// 判断数据长度, 前几个字节能判断出够不够读出websocket的头
+
+	luat_websocket_pkg_t pkg = {0};
+	luat_websocket_payload(buf, &pkg, websocket_ctrl->buffer_offset);
+
+	switch (pkg.OPT_CODE)
+	{
+	case 0x01: // 文本帧
+		break;
+	case 0x02: // 二进制帧
+		break;
+	case 0x08:
+		// 主动断开? 我擦
+		LLOGD("server say CLOSE");
+		return -1;
+	case 0x09:
+		// ping->pong
+		luat_websocket_pong(websocket_ctrl);
+		break;
+	case 0x0A:
+		break;
+
+	default:
+		LLOGE("unkown optcode %0x2X", pkg.OPT_CODE);
+		return -1;
+	}
+
+	size_t pkg_len = pkg.plen >= 126 ? pkg.plen + 4 : pkg.plen + 2;
+
+	if (pkg.OPT_CODE <= 0x02)
+	{
+		char *buff = luat_heap_malloc(pkg_len);
+		if (buff == NULL)
+		{
+			LLOGE("out of memory when malloc websocket buff");
+			return -1;
+		}
+		memcpy(buff, buf, pkg_len);
+		l_luat_websocket_msg_cb(websocket_ctrl, WEBSOCKET_MSG_PUBLISH, buff);
+	}
+
+	// 处理完成后, 如果还有数据, 移动数据, 继续处理
+	websocket_ctrl->buffer_offset -= pkg_len;
+	if (websocket_ctrl->buffer_offset > 0)
+	{
+		memmove(websocket_ctrl->pkg_buff, websocket_ctrl->pkg_buff + pkg_len, websocket_ctrl->buffer_offset);
+		return 1;
+	}
+	return 0;
+}
+
+int luat_websocket_read_packet(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	// LLOGD("luat_websocket_read_packet websocket_ctrl->buffer_offset:%d",websocket_ctrl->buffer_offset);
+	int ret = -1;
+	uint8_t *read_buff = NULL;
+	uint32_t total_len = 0;
+	uint32_t rx_len = 0;
+	int result = network_rx(websocket_ctrl->netc, NULL, 0, 0, NULL, NULL, &total_len);
+	if (total_len > 0xFFF)
+	{
+		LLOGE("too many data wait for recv %d", total_len);
+		luat_websocket_close_socket(websocket_ctrl);
+		return -1;
+	}
+	if (total_len == 0)
+	{
+		LLOGW("rx event but NO data wait for recv");
+		return 0;
+	}
+	if (WEBSOCKET_RECV_BUF_LEN_MAX - websocket_ctrl->buffer_offset <= 0)
+	{
+		LLOGE("buff is FULL, websocket packet too big");
+		luat_websocket_close_socket(websocket_ctrl);
+		return -1;
+	}
+#define MAX_READ (1024)
+	int recv_want = 0;
+
+	while (WEBSOCKET_RECV_BUF_LEN_MAX - websocket_ctrl->buffer_offset > 0)
+	{
+		if (MAX_READ > (WEBSOCKET_RECV_BUF_LEN_MAX - websocket_ctrl->buffer_offset))
+		{
+			recv_want = WEBSOCKET_RECV_BUF_LEN_MAX - websocket_ctrl->buffer_offset;
+		}
+		else
+		{
+			recv_want = MAX_READ;
+		}
+		// 从网络接收数据
+		result = network_rx(websocket_ctrl->netc, websocket_ctrl->pkg_buff + websocket_ctrl->buffer_offset, recv_want, 0, NULL, NULL, &rx_len);
+		if (rx_len == 0 || result != 0)
+		{
+			LLOGD("rx_len %d result %d", rx_len, result);
+			break;
+		}
+		// 收到数据了, 传给处理函数继续处理
+		// 数据的长度变更, 触发传递
+		websocket_ctrl->buffer_offset += rx_len;
+		LLOGD("data recv %d offset %d", rx_len, websocket_ctrl->buffer_offset);
+	further:
+		result = websocket_parse(websocket_ctrl);
+		if (result == 0)
+		{
+			// OK
+		}
+		else if (result == 1)
+		{
+			if (websocket_ctrl->buffer_offset > 0)
+				goto further;
+			else
+			{
+				continue;
+			}
+		}
+		else
+		{
+			LLOGW("websocket_parse ret %d, closing socket", result);
+			luat_websocket_close_socket(websocket_ctrl);
+			break;
+		}
+	}
+	return 0;
+}
+
+static const char *event2str(uint32_t id)
+{
+	switch (id)
+	{
+	case EV_NW_RESULT_LINK:
+		return "EV_NW_RESULT_LINK";
+	case EV_NW_RESULT_CONNECT:
+		return "EV_NW_RESULT_CONNECT";
+	case EV_NW_RESULT_EVENT:
+		return "EV_NW_RESULT_EVENT";
+	case EV_NW_RESULT_TX:
+		return "EV_NW_RESULT_TX";
+	case EV_NW_RESULT_CLOSE:
+		return "EV_NW_RESULT_CLOSE";
+	default:
+		return "UNKOWN";
+	}
+}
+
+int32_t luat_websocket_callback(void *data, void *param)
+{
+	OS_EVENT *event = (OS_EVENT *)data;
+	luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)param;
+	int ret = 0;
+	// LLOGD("LINK %d ON_LINE %d EVENT %d TX_OK %d CLOSED %d",EV_NW_RESULT_LINK & 0x0fffffff,EV_NW_RESULT_CONNECT & 0x0fffffff,EV_NW_RESULT_EVENT & 0x0fffffff,EV_NW_RESULT_TX & 0x0fffffff,EV_NW_RESULT_CLOSE & 0x0fffffff);
+	LLOGD("network websocket cb %8X %s %8X", event->ID & 0x0ffffffff, event2str(event->ID & 0x0ffffffff), event->Param1);
+	if (event->ID == EV_NW_RESULT_LINK)
+	{
+		return 0; // 这里应该直接返回, 不能往下调用network_wait_event
+	}
+	else if (event->ID == EV_NW_RESULT_CONNECT)
+	{
+		ret = websocket_connect(websocket_ctrl);
+	}
+	else if (event->ID == EV_NW_RESULT_EVENT)
+	{
+		if (event->Param1 == 0)
+		{
+			ret = luat_websocket_read_packet(websocket_ctrl);
+			// LLOGD("luat_websocket_read_packet ret:%d",ret);
+			luat_stop_rtos_timer(websocket_ctrl->ping_timer);
+			luat_start_rtos_timer(websocket_ctrl->ping_timer, websocket_ctrl->keepalive * 1000 * 0.75, 1);
+		}
+	}
+	else if (event->ID == EV_NW_RESULT_TX)
+	{
+		luat_stop_rtos_timer(websocket_ctrl->ping_timer);
+		luat_start_rtos_timer(websocket_ctrl->ping_timer, websocket_ctrl->keepalive * 1000 * 0.75, 1);
+	}
+	else if (event->ID == EV_NW_RESULT_CLOSE)
+	{
+	}
+	if (event->Param1)
+	{
+		LLOGW("websocket_callback param1 %d, closing socket", event->Param1);
+		luat_websocket_close_socket(websocket_ctrl);
+	}
+	ret = network_wait_event(websocket_ctrl->netc, NULL, 0, NULL);
+	if (ret < 0)
+	{
+		LLOGW("network_wait_event ret %d, closing socket", ret);
+		luat_websocket_close_socket(websocket_ctrl);
+		return -1;
+	}
+	return 0;
+}
+
+int luat_websocket_connect(luat_websocket_ctrl_t *websocket_ctrl)
+{
+	int ret = 0;
+	const char *hostname = websocket_ctrl->host;
+	uint16_t port = websocket_ctrl->remote_port;
+	LLOGD("host %s port %d", hostname, port);
+#ifdef LUAT_USE_LWIP
+	ret = network_connect(websocket_ctrl->netc, hostname, strlen(hostname), (0xff == websocket_ctrl->ip_addr.type) ? NULL : &(websocket_ctrl->ip_addr), port, 0) < 0;
+#else
+	ret = network_connect(websocket_ctrl->netc, hostname, strlen(hostname), (0xff == websocket_ctrl->ip_addr.is_ipv6) ? NULL : &(websocket_ctrl->ip_addr), port, 0) < 0;
+#endif
+	LLOGD("network_connect ret %d", ret);
+	if (ret < 0)
+	{
+		network_close(websocket_ctrl->netc, 0);
+		return -1;
+	}
+	return 0;
+}

+ 71 - 0
components/network/websocket/luat_websocket.h

@@ -0,0 +1,71 @@
+#ifndef LUAT_WEBSOCKET_H
+#define LUAT_WEBSOCKET_H
+
+enum
+{
+	WEBSOCKET_MSG_RELEASE = 0,
+	WEBSOCKET_MSG_PUBLISH = 1,
+	WEBSOCKET_MSG_TIMER_PING = 2,
+	WEBSOCKET_MSG_CONNACK = 3,
+};
+
+#define WEBSOCKET_RECV_BUF_LEN_MAX 4096
+
+typedef struct
+{
+	// http_parser parser;// websocket broker
+	network_ctrl_t *netc;	// websocket netc
+	luat_ip_addr_t ip_addr; // websocket ip
+	char host[192]; // websocket host
+	char uri[256];
+	uint8_t is_tls;
+	uint16_t remote_port; // 远程端口号
+	uint16_t buffer_offset; // 用于标识pkg_buff当前有多少数据
+	uint8_t pkg_buff[WEBSOCKET_RECV_BUF_LEN_MAX + 4];
+	int websocket_cb;		 // websocket lua回调函数
+	uint32_t keepalive;		 // 心跳时长 单位s
+	uint8_t adapter_index;	 // 适配器索引号, 似乎并没有什么用
+	uint8_t websocket_state; // websocket状态
+	uint8_t reconnect;		 // websocket是否重连
+	uint32_t reconnect_time; // websocket重连时间 单位ms
+	void *reconnect_timer;	 // websocket重连定时器
+	void *ping_timer;		 // websocket_ping定时器
+	int websocket_ref;		 // 强制引用自身避免被GC
+} luat_websocket_ctrl_t;
+
+typedef struct luat_websocket_connopts
+{
+	const char *url;
+	uint16_t is_tls;
+} luat_websocket_connopts_t;
+
+typedef struct luat_websocket_pkg
+{
+	uint8_t FIN;
+	uint8_t OPT_CODE;
+	uint8_t R;
+	uint8_t mark;
+	uint16_t plen; // 最多支持64k
+	char *payload;
+} luat_websocket_pkg_t;
+
+#define WebSocket_OP_CONTINUE 0x0 /* 0000 - continue frame */
+#define WebSocket_OP_TEXT 0x1	  /* 0001 - text frame */
+#define WebSocket_OP_BINARY 0x2	  /* 0010 - binary frame */
+#define WebSocket_OP_CLOSE 0x8	  /* 1000 - close frame */
+#define WebSocket_OP_PING 0x9	  /* 1001 - ping frame */
+#define WebSocket_OP_PONG 0xA	  /* 1010 - pong frame */
+
+int luat_websocket_connect(luat_websocket_ctrl_t *websocket_ctrl);
+int l_luat_websocket_msg_cb(luat_websocket_ctrl_t *ctrl, int arg1, int arg2);
+int32_t luat_websocket_callback(void *data, void *param);
+int luat_websocket_send_packet(void *socket_info, const void *buf, unsigned int count);
+void luat_websocket_close_socket(luat_websocket_ctrl_t *websocket_ctrl);
+void luat_websocket_release_socket(luat_websocket_ctrl_t *websocket_ctrl);
+void luat_websocket_ping(luat_websocket_ctrl_t *websocket_ctrl);
+int luat_websocket_init(luat_websocket_ctrl_t *websocket_ctrl, int adapter_index);
+int luat_websocket_set_connopts(luat_websocket_ctrl_t *websocket_ctrl, const char *url);
+int luat_websocket_payload(char *buff, luat_websocket_pkg_t *pkg, size_t limit);
+int luat_websocket_send_frame(luat_websocket_ctrl_t *websocket_ctrl, luat_websocket_pkg_t *pkg);
+
+#endif

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

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.10.21
 @demo    nimble
+@tag LUAT_USE_NIMBLE
 @usage
 -- 本库当前支持Air101/Air103/ESP32/ESP32C3
 -- 理论上支持ESP32C2/ESP32S2/ESP32S3,但尚未测试

+ 1 - 0
components/rsa/binding/luat_lib_rsa.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.11.03
 @demo    rsa
+@tag LUAT_USE_RSA
 @usage
 -- 请在电脑上生成私钥和公钥, 当前最高支持4096bit, 一般来说2048bit就够用了
 -- openssl genrsa -out privkey.pem 2048

+ 1 - 0
components/serialization/protobuf/luat_lib_protobuf.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.09.08
 @demo protobuf
+@tag LUAT_USE_PROTOBUF
 @usage
 
 -- 加载 pb 文件, 这个是从pbtxt 转换得到的

+ 1 - 0
components/sfd/luat_lib_sfd.c

@@ -3,6 +3,7 @@
 @summary SPI FLASH操作库
 @version 1.0
 @date    2021.05.18
+@tag LUAT_USE_SFD
 */
 #include "luat_base.h"
 #include "luat_spi.h"

+ 1 - 0
components/sfud/luat_lib_sfud.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2021.09.23
 @demo sfud
+@tag LUAT_USE_SFUD
 */
 
 #include "luat_base.h"

+ 1 - 0
components/statem/luat_lib_statem.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.09.26
 @demo statem
+@tag LUAT_USE_STATEM
 */
 
 #include "luat_base.h"

+ 1 - 0
components/u8g2/luat_lib_disp.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2020.03.30
 @demo u8g2
+@tag LUAT_USE_DISP
 */
 #include "luat_base.h"
 #include "luat_malloc.h"

+ 1 - 0
components/u8g2/luat_lib_u8g2.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.01.25
 @demo u8g2
+@tag LUAT_USE_U8G2
 */
 #include "luat_base.h"
 #include "luat_malloc.h"

+ 1 - 0
components/usbapp/luat_lib_usbapp.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2022.01.17
 @demo usb_hid
+@tag LUAT_USE_USB
 */
 #include "luat_base.h"
 #include "luat_msgbus.h"

+ 1 - 0
components/wlan/luat_lib_wlan.c

@@ -6,6 +6,7 @@
 @version 1.0
 @date    2022.09.30
 @demo wlan
+@tag LUAT_USE_WLAN
 */
 
 #include "luat_base.h"

+ 1 - 0
components/zlib/luat_lib_zlib.c

@@ -3,6 +3,7 @@
 @summary zlib压缩/解压缩
 @version 1.0
 @date    2022.01.06
+@tag LUAT_USE_ZLIB
 */
 
 #include "luat_base.h"

+ 7 - 11
demo/socket/Air105/http_demo.lua

@@ -1,35 +1,31 @@
 
---[[
-这个demo未完成, 暂不可用
-TODO http2库完成后删除这段注释
-]]
 local function testTask()
 
     -- GET request, task内的同步操作
-    local code, headers, body = http2.request("GET","http://site0.cn/api/httptest/simple/time").wait()
-    log.info("http2.get", code, headers, body)
+    local code, headers, body = http.request("GET","http://site0.cn/api/httptest/simple/time").wait()
+    log.info("http.get", code, headers, body)
 
     -- POST request
     local req_headers = {}
     req_headers["Content-Type"] = "application/json"
     local body = json.encode({name="LuatOS"})
-    local code, headers, body = http2.request("POST","http://site0.cn/api/httptest/simple/date", 
+    local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date", 
             req_headers,
             body -- POST请求所需要的body, string, zbuff, file均可
     ).wait()
-    log.info("http2.post", code, headers, body)
+    log.info("http.post", code, headers, body)
 
     -- POST and download, task内的同步操作
     local opts = {}                 -- 额外的配置项
     opts["dst"] = "/data.bin"       -- 下载路径,可选
     opts["timeout"] = 30            -- 超时时长,单位秒,可选
     opts["adapter"] = socket.ETH0  -- 使用哪个网卡,可选
-    local code, headers, body = http2.request("POST","http://site0.cn/api/httptest/simple/date", 
+    local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date", 
             {}, -- 请求所添加的 headers, 可以是nil
             "", 
             opts
     ).wait()
-    log.info("http2.post", code, headers, body) -- 只返回code和headers
+    log.info("http.post", code, headers, body) -- 只返回code和headers
 
     local f = io.open("/data.bin", "rb")
     if f then
@@ -38,7 +34,7 @@ local function testTask()
     end
     
     -- GET request, 开个task让它自行执行去吧, 不管执行结果了
-    sys.taskInit(http2.request("GET","http://site0.cn/api/httptest/simple/time").wait)
+    sys.taskInit(http.request("GET","http://site0.cn/api/httptest/simple/time").wait)
 end
 
 function httpDemo()

+ 14 - 14
demo/socket/EC618/http_demo.lua

@@ -2,7 +2,7 @@ local libnet = require "libnet"
 
 
 -- local function downloadFile(code, headers, body)
---     log.info("http2.get", code, json.encode(headers), body)
+--     log.info("http.get", code, json.encode(headers), body)
 --     local r = io.writeFile("/data.txt", body)
 --     if r then
 --         log.info("文件写入成功")
@@ -18,12 +18,12 @@ sys.taskInit(function ()
     log.info("------下载文件------")
     local path = "/data.txt"
     -- GET请求,但下载到文件
-    http2.request(
+    http.request(
         "GET",
         "http://cdn.openluat-luatcommunity.openluat.com/attachment/20220825134126812_text.txt").cb
         (
             function (code, headers, body)
-                log.info("http2.get", code, json.encode(headers), body)
+                log.info("http.get", code, json.encode(headers), body)
                 local r = io.writeFile("/data.txt", body)
                 if r then
                     log.info("文件写入成功")
@@ -48,12 +48,12 @@ sys.taskInit(function ()
     -- opts["adapter"] = ""  -- 使用哪个网卡,可选
     -- local req_headers = {}
     -- req_headers["Content-Type"] = "application/json"
-    -- local code, headers, body = http2.request("POST","http://site0.cn/api/httptest/simple/date", 
+    -- local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date", 
     --         json.encode(req_headers), -- 请求所添加的 headers, 可以是nil
     --         "",
     --         opts
     -- ).wait()
-    -- log.info("http2.post", code, headers, body) -- 只返回code和headers
+    -- log.info("http.post", code, headers, body) -- 只返回code和headers
 end)
 
 -- [[
@@ -66,7 +66,7 @@ sys.taskInit(
 
         -- GET请求
         log.info("------GET请求------")
-        local code, headers, body = http2.request("GET","https://www.baidu.com/").wait()
+        local code, headers, body = http.request("GET","https://www.baidu.com/").wait()
         log.info("http.get", code, json.encode(headers), body)
         sys.wait(2000)
 
@@ -75,7 +75,7 @@ sys.taskInit(
         local req_headers = {}
         req_headers["Content-Type"] = "application/json"
         local body = json.encode({name="LuatOS"})
-        http2.request("POST","http://site0.cn/api/httptest/simple/date", 
+        http.request("POST","http://site0.cn/api/httptest/simple/date", 
             req_headers,
             body -- POST请求所需要的body, string, zbuff, file均可
         ).cb(function(code, headers, body)
@@ -94,24 +94,24 @@ sys.taskInit(
 --         -- while 1 do
 --             log.info("mem.lua", rtos.meminfo())
 --             log.info("mem.sys", rtos.meminfo("sys"))
---             local code, headers, body = http2.request("GET","https://www.baidu.com/").wait()
---             log.info("http2.get", code, json.encode(headers), body)
+--             local code, headers, body = http.request("GET","https://www.baidu.com/").wait()
+--             log.info("http.get", code, json.encode(headers), body)
 
---             -- -- local code, headers, body = http2.request("GET","http://site0.cn/api/httptest/simple/time").wait()
---             -- -- log.info("http2.get", code, json.encode(headers), body)
+--             -- -- local code, headers, body = http.request("GET","http://site0.cn/api/httptest/simple/time").wait()
+--             -- -- log.info("http.get", code, json.encode(headers), body)
 --             -- sys.wait(2000)
 
 --             -- -- POST request
 --             -- local req_headers = {}
 --             -- req_headers["Content-Type"] = "application/json"
 --             -- local body = json.encode({name="LuatOS"})
---             -- local code, headers, body = http2.request("POST","http://site0.cn/api/httptest/simple/date", 
+--             -- local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date", 
 --             --         req_headers,
 --             --         body -- POST请求所需要的body, string, zbuff, file均可
 --             -- ).cb(function (code, headers, body)
---             --     log.info("http2.post", code, headers, body)
+--             --     log.info("http.post", code, headers, body)
 --             -- end)
---             -- log.info("http2.post1", code, headers, body)
+--             -- log.info("http.post1", code, headers, body)
 --         -- end
 --     end
 -- )

+ 61 - 0
demo/websocket/main.lua

@@ -0,0 +1,61 @@
+
+PROJECT = "airtun"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+-- _G.sysplus = require("sysplus")
+
+local wsc = nil
+
+sys.taskInit(function()
+    if rtos.bsp():startsWith("ESP32") then
+        local ssid = "uiot123"
+        local password = "12348888"
+        log.info("wifi", ssid, password)
+        -- TODO 改成esptouch配网
+        LED = gpio.setup(12, 0, gpio.PULLUP)
+        wlan.init()
+        wlan.setMode(wlan.STATION)
+        wlan.connect(ssid, password, 1)
+        local result, data = sys.waitUntil("IP_READY", 30000)
+        log.info("wlan", "IP_READY", result, data)
+        device_id = wlan.getMac()
+    elseif rtos.bsp() == "AIR105" then
+        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
+        w5500.config() --默认是DHCP模式
+        w5500.bind(socket.ETH0)
+        LED = gpio.setup(62, 0, gpio.PULLUP)
+        sys.wait(1000)
+        -- TODO 获取mac地址作为device_id
+    elseif rtos.bsp() == "EC618" then
+        --mobile.simid(2)
+        LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+        sys.waitUntil("IP_READY", 30000)
+    end
+
+    wsc = websocket.create(nil, "ws://nutz.cn/websocket")
+    wsc:autoreconn(true, 3000) -- 自动重连机制
+    wsc:on(function(wsc, event, data, fin, optcode)
+        log.info("wsc", event, data, fid, optcode)
+        if event == "conack" then
+            wsc:send((json.encode({action="login",device_id=device_id})))
+        end
+    end)
+    wsc:connect()
+    --sys.waitUntil("websocket_conack", 15000)
+    while true do
+        sys.wait(45000)
+        -- wsc:send("{\"room\":\"topic:okfd7qcob2iujp1br83nn7lcg5\",\"action\":\"join\"}")
+        wsc:send((json.encode({action="echo", msg=os.date()})))
+    end
+    wsc:close()
+    wsc = nil
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 1 - 1
demo/wlan/esp32c3/hello_world/main.lua

@@ -30,7 +30,7 @@ sys.taskInit(function()
         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()
+        local code, headers, body = http.request("GET", url).wait()
         log.info("http", code, json.encode(headers), #body)
     else
         print("wlan NOT ready!!!!")

+ 4 - 3
lua/src/liolib.c

@@ -3,6 +3,7 @@
 @summary io操作(扩展)
 @version 1.0
 @date    2020.07.03
+@tag LUAT_CONF_BSP
 */
 
 #define liolib_c
@@ -755,7 +756,7 @@ static int f_flush (lua_State *L) {
 @string 文件路径
 @return bool 存在返回true,否则返回false
 @usage
-log.info("io", "file exists", io.exists("/boottime")) 
+log.info("io", "file exists", io.exists("/boottime"))
  */
 static int io_exists (lua_State *L) {
   const char *filename = luaL_checkstring(L, 1);
@@ -781,7 +782,7 @@ static int io_fileSize (lua_State *L) {
   const char *filename = luaL_checkstring(L, 1);
   FILE* f = fopen(filename, "rb");
   if(f == NULL) {
-    lua_pushinteger(L, 0); 
+    lua_pushinteger(L, 0);
   }
   else {
     fseek(f, 0, SEEK_END);
@@ -1115,7 +1116,7 @@ static int io_lsdir (lua_State *L) {
   else if (ret > 0) {
     lua_pushboolean(L, 1);
     lua_createtable(L, ret, 0);
-    
+
     for (size_t i = 0; i < ret; i++)
     {
       lua_createtable(L, 0, 2);

+ 1 - 0
lua/src/lstrlib_exts.c

@@ -1,6 +1,7 @@
 /*
 @module  string
 @summary 字符串操作函数
+@tag LUAT_CONF_BSP
 */
 #include "luat_base.h"
 #include "luat_malloc.h"

+ 3 - 0
luat/include/luat_libs.h

@@ -51,6 +51,7 @@ LUAMOD_API int luaopen_sfud( lua_State *L );
 LUAMOD_API int luaopen_mqtt( lua_State *L );
 /** http库*/
 LUAMOD_API int luaopen_http( lua_State *L );
+LUAMOD_API int luaopen_http2( lua_State *L );
 /** pack库*/
 LUAMOD_API int luaopen_pack( lua_State *L );
 /** mqttcore库*/
@@ -134,4 +135,6 @@ LUAMOD_API int luaopen_protobuf( lua_State *L );
 LUAMOD_API int luaopen_httpsrv( lua_State *L );
 LUAMOD_API int luaopen_rsa( lua_State *L );
 
+LUAMOD_API int luaopen_websocket( lua_State *L );
+
 #endif

+ 6 - 0
luat/modules/luat_lib_adc.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2020.07.03
 @demo adc
+@tag LUAT_USE_ADC
 */
 #include "luat_base.h"
 #include "luat_adc.h"
@@ -128,6 +129,11 @@ static const rotable_Reg_t reg_adc[] =
 	{ "ADC_RANGE_3_6",   ROREG_INT(1)},
 	//@const ADC_RANGE_1_8 number air105的ADC分压电阻关闭,范围0~1.88V
 	{ "ADC_RANGE_1_8",   ROREG_INT(0)},
+
+    //@const CH_CPU number CPU内部温度的通道id
+    { "CH_CPU",          ROREG_INT(10)},
+    //@const CH_VBAT number VBAT供电电压的通道id
+    { "CH_VBAT",         ROREG_INT(11)},
 	{ NULL,              ROREG_INT(0) }
 };
 

+ 2 - 1
luat/modules/luat_lib_crypto.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2020.07.03
 @demo crypto
+@tag LUAT_USE_CRYPTO
 */
 #include "luat_base.h"
 #include "luat_crypto.h"
@@ -288,7 +289,7 @@ int l_crypto_cipher_decrypt(lua_State *L) {
 local crc = crypto.crc16("")
  */
 static int l_crypto_crc16(lua_State *L)
-{   
+{
     size_t inputlen;
     const unsigned char *inputData;
     const char  *inputmethod = (const char*)luaL_checkstring(L, 1);

+ 1 - 0
luat/modules/luat_lib_dac.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.12.03
 @demo multimedia
+@tag LUAT_USE_DAC
 */
 
 #include "luat_base.h"

+ 1 - 0
luat/modules/luat_lib_fota.c

@@ -5,6 +5,7 @@
 @version core V0007
 @date    2022.05.26
 @demo ota
+@tag LUAT_USE_FOTA
 */
 #include "luat_base.h"
 #include "luat_fota.h"

+ 1 - 0
luat/modules/luat_lib_fs.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.03.30
 @demo fs
+@tag LUAT_USE_FS
 */
 #include "luat_base.h"
 #include "luat_fs.h"

+ 1 - 0
luat/modules/luat_lib_gpio.c

@@ -7,6 +7,7 @@
 @date    2020.03.30
 @demo gpio
 @video https://www.bilibili.com/video/BV1hr4y1p7dt
+@tag LUAT_USE_GPIO
 */
 #include "luat_base.h"
 #include "luat_gpio.h"

+ 1 - 0
luat/modules/luat_lib_i2c.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2020.03.30
 @demo i2c
+@tag LUAT_USE_I2C
 */
 #include "luat_base.h"
 #include "luat_log.h"

+ 1 - 0
luat/modules/luat_lib_i2s.c

@@ -3,6 +3,7 @@
 @summary 数字音频
 @version core V0007
 @date    2022.05.26
+@tag LUAT_USE_I2S
 */
 #include "luat_base.h"
 #include "luat_malloc.h"

+ 1 - 0
luat/modules/luat_lib_ir.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2021.10.26
 @demo ir
+@tag LUAT_USE_IR
 */
 #include "luat_base.h"
 #include "luat_gpio.h"

+ 4 - 3
luat/modules/luat_lib_keyboard.c

@@ -1,10 +1,11 @@
 
 /*
 @module  keyboard
-@summary 键盘矩阵(当前仅air105支持)
+@summary 键盘矩阵
 @version 1.0
 @date    2021.11.24
 @demo keyboard
+@tag LUAT_USE_KEYBOARD
 */
 
 #include "luat_base.h"
@@ -84,7 +85,7 @@ static int l_keyboard_init(lua_State *L) {
     conf.debounce = luaL_optinteger(L, 4, 1);
     conf.cb = l_keyboard_irq_cb;
     int ret = luat_keyboard_init(&conf);
-    
+
     lua_pushboolean(L, ret == 0 ? 1 : 0);
     return 1;
 }
@@ -97,7 +98,7 @@ static int l_keyboard_deinit(lua_State *L) {
     conf.debounce = luaL_optinteger(L, 4, 1);
 
     int ret = luat_keyboard_deinit(&conf);
-    
+
     lua_pushboolean(L, ret == 0 ? 1 : 0);
     return 1;
 }

+ 1 - 0
luat/modules/luat_lib_lcdseg.c

@@ -3,6 +3,7 @@
 @summary 段式lcd
 @version 1.0
 @date    2021.10.22
+@tag LUAT_USE_LCDSEG
 */
 
 #include "luat_base.h"

+ 3 - 2
luat/modules/luat_lib_libcoap.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2020.06.30
 @demo libcoap
+@tag LUAT_USE_COAP
 */
 #include "luat_base.h"
 #include "luat_timer.h"
@@ -220,7 +221,7 @@ static int l_libcoap_parse(lua_State* L) {
             else if (opt_header->opt_len == 13) {
                 opt_header->opt_len += (unsigned int)(*(ptr+1));
             }
-            
+
             ptr += opt_header->opt_len + 1;
             idx += opt_header->opt_len + 1;
             _coap->optSize += opt_header->opt_len + 1;
@@ -228,7 +229,7 @@ static int l_libcoap_parse(lua_State* L) {
         LLOGD("opt size=%d", _coap->optSize);
         memcpy(_coap->opt, ptr - _coap->optSize, _coap->optSize);
     }
-    
+
 
     // 分析一下data
     if (idx < len) {

+ 1 - 0
luat/modules/luat_lib_log.c

@@ -4,6 +4,7 @@
 @summary 日志库
 @version 1.0
 @date    2020.03.30
+@tag LUAT_CONF_BSP
 */
 #include "luat_base.h"
 #include "luat_sys.h"

+ 4 - 3
luat/modules/luat_lib_lpmem.c

@@ -4,6 +4,7 @@
 @summary 操作低功耗不掉电内存块
 @version V0002
 @date    2020.07.10
+@tag LUAT_USE_LPMEM
 */
 
 #include "luat_base.h"
@@ -18,7 +19,7 @@
 @int 内存偏移量
 @int 读取大小,单位字节
 @return string 读取成功返回字符串,否则返回nil
-@usage  
+@usage
 -- 读取1kb的内存
 local data = lpmem.read(0, 1024)
 */
@@ -43,7 +44,7 @@ static int l_lpmem_read(lua_State *L) {
 @int 内存偏移量
 @string 待写入的数据
 @return boolean 成功返回true,否则返回false
-@usage  
+@usage
 -- 往偏移量为512字节的位置, 写入数据
 lpmem.write(512, data)
 */
@@ -66,7 +67,7 @@ static int l_lpmem_write(lua_State *L) {
 获取内存块的总大小
 @api    lpmem.size()
 @return int 内存块的大小
-@usage  
+@usage
 lpmem.size()
 */
 static int l_lpmem_size(lua_State *L) {

+ 1 - 0
luat/modules/luat_lib_mcu.c

@@ -4,6 +4,7 @@
 @summary 封装mcu一些特殊操作
 @version core V0007
 @date    2021.08.18
+@tag LUAT_USE_MCU
 */
 #include "luat_base.h"
 #include "luat_mcu.h"

+ 1 - 0
luat/modules/luat_lib_otp.c

@@ -4,6 +4,7 @@
 @summary OTP操作库
 @version 1.0
 @date    2021.12.08
+@tag LUAT_USE_OTP
 */
 #include "luat_base.h"
 #include "luat_otp.h"

+ 1 - 0
luat/modules/luat_lib_pack.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2021.12.20
 @video https://www.bilibili.com/video/BV1Sr4y1n7bP
+@tag LUAT_USE_PACK
 */
 
 #define	OP_ZSTRING	      'z'		/* zero-terminated string */

+ 1 - 0
luat/modules/luat_lib_pm.c

@@ -5,6 +5,7 @@
 @version 1.0
 @date    2020.07.02
 @demo pm
+@tag LUAT_USE_PM
 */
 #include "lua.h"
 #include "lauxlib.h"

+ 1 - 0
luat/modules/luat_lib_pwm.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2020.07.03
 @demo pwm
+@tag LUAT_USE_PWM
 */
 #include "luat_base.h"
 #include "luat_pwm.h"

+ 1 - 0
luat/modules/luat_lib_rtc.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2021.08.31
 @demo rtc
+@tag LUAT_USE_RTC
 */
 #include "luat_base.h"
 #include "luat_rtc.h"

+ 1 - 0
luat/modules/luat_lib_rtos.c

@@ -3,6 +3,7 @@
 @summary RTOS底层操作库
 @version 1.0
 @date    2020.03.30
+@tag LUAT_CONF_BSP
 */
 #include "luat_base.h"
 #include "luat_sys.h"

+ 1 - 0
luat/modules/luat_lib_sdio.c

@@ -4,6 +4,7 @@
 @summary sdio
 @version 1.0
 @date    2021.09.02
+@tag LUAT_USE_SDIO
 */
 #include "luat_base.h"
 #include "luat_sdio.h"

+ 1 - 0
luat/modules/luat_lib_sensor.c

@@ -4,6 +4,7 @@
 @summary 传感器操作库
 @version 1.0
 @date    2020.03.30
+@tag LUAT_USE_SENSOR
 */
 #include "luat_base.h"
 #include "luat_timer.h"

+ 1 - 0
luat/modules/luat_lib_spi.c

@@ -5,6 +5,7 @@
 @date    2020.04.23
 @demo spi
 @video https://www.bilibili.com/video/BV1VY411M7YH
+@tag LUAT_USE_SPI
 */
 #include "luat_base.h"
 #include "luat_log.h"

+ 1 - 0
luat/modules/luat_lib_sys_doc.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2019.11.23
 @video https://www.bilibili.com/video/BV1194y1o7q2
+@tag LUAT_CONF_BSP
 */
 
 /*

+ 1 - 0
luat/modules/luat_lib_timer.c

@@ -3,6 +3,7 @@
 @summary 操作底层定时器
 @version 1.0
 @date    2020.03.30
+@tag LUAT_USE_TIMER
 */
 #include "luat_base.h"
 #include "luat_log.h"

+ 1 - 0
luat/modules/luat_lib_touchkey.c

@@ -3,6 +3,7 @@
 @summary 触摸按键
 @version 1.0
 @date    2022.01.15
+@tag LUAT_USE_TOUCHKEY
 */
 #include "luat_base.h"
 #include "luat_touchkey.h"

+ 1 - 0
luat/modules/luat_lib_uart.c

@@ -5,6 +5,7 @@
 @date    2020.03.30
 @demo uart
 @video https://www.bilibili.com/video/BV1er4y1p75y
+@tag LUAT_USE_UART
 */
 #include "luat_base.h"
 #include "luat_uart.h"

+ 1 - 0
luat/modules/luat_lib_wdt.c

@@ -4,6 +4,7 @@
 @version 1.0
 @date    2021.08.06
 @demo wdt
+@tag LUAT_USE_WDT
 */
 #include "luat_base.h"
 #include "luat_wdt.h"

+ 1 - 0
luat/modules/luat_lib_zbuff.c

@@ -4,6 +4,7 @@
 @version 0.1
 @date    2021.03.31
 @video https://www.bilibili.com/video/BV1gr4y1V7HN
+@tag LUAT_USE_ZBUFF
 */
 #include "luat_base.h"
 #include "luat_zbuff.h"

+ 2 - 2
script/turnkey/EinkBook/Scripts/main.lua

@@ -150,7 +150,7 @@ function showBook(bookName, bookUrl, page)
     sys.taskInit(function()
         waitHttpTask = true
         for i = 1, 3 do
-            local code, headers, data = http2.request("GET",bookUrl .. "/" .. page).wait()
+            local code, headers, data = http.request("GET",bookUrl .. "/" .. page).wait()
             log.info("SHOWBOOK", code)
             if code ~= 200 then
                 log.error("SHOWBOOK", "获取图书内容失败 ", data)
@@ -317,7 +317,7 @@ sys.taskInit(function()
         end
     end
     for i = 1, 5 do
-        local code, headers, data = http2.request("GET", serverAdress .. "getBooks").wait()
+        local code, headers, data = http.request("GET", serverAdress .. "getBooks").wait()
         log.info("SHOWBOOK", code)
         if code ~= 200 then
             log.error(tag, "获取图书列表失败 ", data)

+ 3 - 3
script/turnkey/eink-calendar/main.lua

@@ -9,11 +9,11 @@ require("sysplus")
 
 --需要自行填写的东西
 --wifi信息
-local wifiName,wifiPassword = "wifi","password"
+local wifiName,wifiPassword = "Xiaomi_AX6000","Air123456"
 --地区id,请前往https://api.luatos.org/luatos-calendar/v1/check-city/ 查询自己所在位置的id
 local location = "101020100"
 --天气接口信息,需要自己申请,具体参数请参考https://api.luatos.org/ 页面上的描述
-local appid,appsecret = "appid(要改)","appsecret(要改)"
+local appid,appsecret = "27548549","3wdKWuRZ"
 
 local function connectWifi()
     log.info("wlan", "wlan_init:", wlan.init())
@@ -30,7 +30,7 @@ local function connectWifi()
 end
 
 local function requestHttp()
-    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()
+    local code, headers, body = http.request("GET","http://apicn.luatos.org:23328/luatos-calendar/v1?mac=111&battery=10&location="..location.."&appid="..appid.."&appsecret="..appsecret).wait()
     if code == 200 then
         return body
     else

+ 6 - 1
tools/api_get.py

@@ -110,6 +110,7 @@ def get_modules(file_list, start="/*", end="*/"):
             module["usage"] = ""
             module["demo"] = ""
             module["video"] = ""
+            module["tag"] = ""
             module["api"] = []
             module["const"] = []
         else:
@@ -117,7 +118,7 @@ def get_modules(file_list, start="/*", end="*/"):
 
         for mstep in range(len(modules)-1,-1,-1):
             if modules[mstep]["module"] == module["module"]:
-                module["api"] = modules[mstep]["api"]
+                module = modules[mstep]
                 del modules[mstep]
                 module["url"] = ""
 
@@ -138,6 +139,10 @@ def get_modules(file_list, start="/*", end="*/"):
                     module["video"] = re.search(" *@video * (.+) *",lines[line_now],re.I).group(1)
                     line_now+=1
                     continue
+                if re.search(" *@tag *.+",lines[line_now],re.I):
+                    module["tag"] = re.search(" *@tag * (.+) *",lines[line_now],re.I).group(1)
+                    line_now+=1
+                    continue
                 if re.search(" *@usage *",lines[line_now],re.I):
                     line_now+=1
                     while lines[line_now].find(end) < 0:

+ 32 - 3
tools/make_doc_file.py

@@ -1,5 +1,29 @@
 import shutil
 import os
+import requests
+
+#bsp.h文件列表
+bsp_header_list = [
+{"name":"Air101/Air103","url":"https://gitee.com/openLuat/luatos-soc-air101/raw/master/app/port/luat_conf_bsp.h"},
+{"name":"Air105","url":"https://gitee.com/openLuat/luatos-soc-air105/raw/master/application/include/luat_conf_bsp.h"},
+{"name":"ESP32C3","url":"https://gitee.com/openLuat/luatos-soc-idf5/raw/master/luatos/include/luat_conf_bsp.h"},
+{"name":"Air780","url":"https://gitee.com/openLuat/luatos-soc-2022/raw/master/project/luatos/inc/luat_conf_bsp.h"},
+]
+print("getting bsp.h files...")
+for bsp in bsp_header_list:
+    print("getting "+bsp["name"]+"...")
+    bsp["url"] = requests.get(bsp["url"]).text
+    print("done "+ str(len(bsp["url"])) + " bytes")
+
+def get_tags(tag):
+    r = ["{bdg-success}`已适配`"]
+    for bsp in bsp_header_list:
+        if bsp["url"].find(" "+tag+" ") >= 0 or bsp["url"].find(" "+tag+"\r") >= 0 or bsp["url"].find(" "+tag+"\n") >= 0:
+            r.append("{bdg-primary}`" + bsp["name"] + "`")
+    if len(r) > 1:
+        return " ".join(r)
+    else:
+        return "{bdg-secondary}`适配状态未知`"
 
 def make(path,modules,index_text):
     try:
@@ -14,13 +38,18 @@ def make(path,modules,index_text):
     for module in modules:
         mdoc = open(path+module["module"]+".md", "a+",encoding='utf-8')
         mdoc.write("# "+module["module"]+" - "+module["summary"]+"\n\n")
+
+        if len(module["tag"]) > 0:
+            mdoc.write(get_tags(module["tag"]))
+            mdoc.write("\n\n")
+
         if len(module["url"]) > 0:
-            mdoc.write("> 本页文档由[这个文件]("+module["url"]+")自动生成。如有错误,请提交issue或帮忙修改后pr,谢谢!\n\n")
+            mdoc.write("```{note}\n本页文档由[这个文件]("+module["url"]+")自动生成。如有错误,请提交issue或帮忙修改后pr,谢谢!\n```\n\n")
 
         if len(module["demo"]) > 0:
-            mdoc.write("> 本库有专属demo,[点此链接查看"+module["module"]+"的demo例子]("+module["demo"]+")\n")
+            mdoc.write("```{tip}\n本库有专属demo,[点此链接查看"+module["module"]+"的demo例子]("+module["demo"]+")\n```\n")
         if len(module["video"]) > 0:
-            mdoc.write("> 本库还有视频教程,[点此链接查看]("+module["video"]+")\n\n")
+            mdoc.write("```{tip}\n本库还有视频教程,[点此链接查看]("+module["video"]+")\n```\n\n")
         else:
             mdoc.write("\n")