Wendal Chen 4 лет назад
Родитель
Сommit
4d2ee5a631

+ 112 - 0
bsp/emulator/CMakeLists.txt

@@ -0,0 +1,112 @@
+
+
+# CMake 最低版本号要求
+cmake_minimum_required (VERSION 3.5)
+
+set(CMAKE_BUILD_TYPE "Debug")
+set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
+set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
+set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=luatos.map")
+
+set(TOPROOT "../..")
+
+# 项目信息
+project (luatos)
+
+# 一定一定要先添加本地的头文件
+include_directories(./include)
+
+include_directories(${TOPROOT}/lua/include
+                    ${TOPROOT}/luat/include
+                    )
+
+include_directories(${TOPROOT}/luat/packages/lfs
+                    ${TOPROOT}/components/cjson
+)
+
+aux_source_directory(./port PORT_SRCS)
+aux_source_directory(./remotem REMOTEM_SRCS)
+aux_source_directory(${TOPROOT}/lua/src LUA_SRCS)
+aux_source_directory(${TOPROOT}/luat/packages/lua-cjson CJSON_SRCS)
+aux_source_directory(${TOPROOT}/components/cjson CJSON2_SRCS)
+
+# add_library(freertos10 ${PORT_SRCS} ${RTOS_SRCS} ${RTOS_PORT_SRCS} ${MM_SRCS} ${MM2_SRCS})
+add_library(lua ${LUA_SRCS})
+add_library(luatos_msys ${PORT_SRCS} ${REMOTEM_SRCS})
+add_library(cjson ${CJSON_SRCS} ${CJSON2_SRCS})
+add_library(luat ${TOPROOT}/luat/modules/luat_main.c
+                 ${TOPROOT}/luat/modules/luat_base.c
+                 ${TOPROOT}/luat/modules/luat_ota.c
+                 ${TOPROOT}/luat/modules/luat_luat_bin.c
+                 ${TOPROOT}/luat/modules/luat_lib_rtos.c
+                 ${TOPROOT}/luat/modules/luat_lib_timer.c
+                 ${TOPROOT}/luat/modules/luat_lib_log.c
+                 ${TOPROOT}/luat/modules/luat_lib_gpio.c
+                 ${TOPROOT}/luat/modules/luat_lib_spi.c
+                 ${TOPROOT}/luat/modules/luat_lib_pack.c
+                 ${TOPROOT}/luat/modules/luat_lib_zbuff.c
+                 ${TOPROOT}/luat/modules/luat_lib_mqttcore.c
+                 ${TOPROOT}/luat/modules/luat_lib_libcoap.c
+                 ${TOPROOT}/luat/modules/luat_lib_crypto.c
+                 ${TOPROOT}/luat/modules/luat_lib_vmx.c
+                 ${TOPROOT}/components/sfd/luat_lib_sfd.c
+                 ${TOPROOT}/components/sfd/luat_sfd_mem.c
+                 ${TOPROOT}/components/sfd/luat_sfd_w25q.c
+                 ${TOPROOT}/components/luf/luat_lib_luf.c
+                 ${TOPROOT}/components/luf/luat_luf_dump.c
+                 ${TOPROOT}/components/luf/luat_luf_undump.c
+                 ${TOPROOT}/components/luf/luat_luf_cmp.c
+                 ${TOPROOT}/luat/modules/crc.c
+                 ${TOPROOT}/luat/vfs/luat_vfs.c
+                 ${TOPROOT}/luat/vfs/luat_fs_luadb.c
+                 ${TOPROOT}/luat/vfs/luat_fs_posix.c
+                 ${TOPROOT}/luat/vfs/luat_fs_lfs2.c
+                 ${TOPROOT}/luat/vfs/luat_fs_onefile.c
+                 ${TOPROOT}/luat/vfs/luat_luadb_inline.c
+                 ${TOPROOT}/luat/vfs/luat_luadb_inline_sys.c
+                 ${TOPROOT}/luat/vfs/luat_inline_sys.c
+                 ${TOPROOT}/luat/packages/lfs/lfs_sfd.c
+                 ${TOPROOT}/luat/packages/lfs/lfs_util.c
+                 ${TOPROOT}/luat/packages/lfs/lfs.c
+                 ${TOPROOT}/luat/packages/lfs/luat_lib_lfs2.c
+               #   ${LCD_SRCS}
+            )
+
+include_directories(${TOPROOT}/luat/packages/fatfs)
+add_library(fatfs   ${TOPROOT}/luat/packages/fatfs/ff.c
+                    ${TOPROOT}/luat/packages/fatfs/ffsystem.c
+                    ${TOPROOT}/luat/packages/fatfs/ffunicode.c
+                    ${TOPROOT}/luat/packages/fatfs/diskio_impl.c
+                    ${TOPROOT}/luat/packages/fatfs/diskio_ramdisk.c
+                    ${TOPROOT}/luat/packages/fatfs/diskio_spitf.c
+                    ${TOPROOT}/luat/vfs/luat_fs_fatfs.c
+                    ${TOPROOT}/luat/packages/fatfs/luat_lib_fatfs.c)
+
+#-----------------------
+# mbedtls
+include_directories(${TOPROOT}/components/mbedtls/include)
+add_subdirectory(${TOPROOT}/components/mbedtls mbedtls.out)
+#-----------------------
+
+#-----------------------
+# lvgl
+include_directories(${TOPROOT}/components/lvgl)
+include_directories(${TOPROOT}/components/lvgl/src)
+add_subdirectory(${TOPROOT}/components/lvgl lvgl.out)
+
+
+#-----------------------
+# paho_mqtt_c
+include_directories(${TOPROOT}/components/network/paho.mqtt.c/src)
+add_subdirectory(${TOPROOT}/components/network/paho.mqtt.c paho_mqtt_c.out)
+#-----------------------
+
+
+
+
+# 指定生成目标
+add_executable(luatos src/main_emulator.c src/lua.c)
+target_link_libraries(luat lua luatos_msys  winmm cjson
+                      mbedtls fatfs lvgl paho-mqtt3a-static)
+target_link_libraries(luatos  lua luatos_msys  winmm cjson
+                      mbedtls fatfs lvgl luat paho-mqtt3a-static)

+ 20 - 0
bsp/emulator/README.md

@@ -0,0 +1,20 @@
+# LuatOS模拟器
+
+本BSP处于开发阶段
+
+## BSP目标
+
+1. 可模拟LuatOS-SoC执行, 
+2. 支持平台无关库的实现
+3. 支持部分外设的驱动
+4. 支持显示,但不限于当前进程,支持远程显示
+5. 可观测的,具有统计数据
+
+## 关于远程显示与控制
+
+协议文本位于 remotem 目录, 当前处于讨论稿
+
+1. 基于平台无关的json协议
+2. 兼顾soc和air固件的显示和控制需求
+3. 兼顾性能与扩展性, 对大数据量的传送可协商额外的通信渠道,例如共享内存,socket直连等等
+

+ 77 - 0
bsp/emulator/include/luat_conf_bsp.h

@@ -0,0 +1,77 @@
+
+#ifndef LUAT_CONF_BSP
+#define LUAT_CONF_BSP
+
+#define LUAT_BSP_VERSION "V0007"
+#define LUAT_USE_CMDLINE_ARGS 1
+
+#define LUAT_WIN32_REMOTE_MODE 1
+
+#define LUA_USE_VFS_FILENAME_OFFSET 1
+
+#define LUAT_USE_FS_VFS 1
+
+#define LUAT_USE_VFS_INLINE_LIB 1
+
+// #define LUAT_MEMORY_OPT_G_FUNCS 1
+
+#define LUAT_USE_LOG_ASYNC_THREAD 0
+
+#define LUAT_FORCE_WIN32 1
+#define LUAT_EMULATOR_MODE 1
+
+#define LV_COLOR_16_SWAP 1
+#define LV_COLOR_DEPTH 16
+
+#define LUAT_USE_LVGL 1
+#define LV_MEM_CUSTOM 1
+#define LUAT_LV_DEBUG 0
+#define LUAT_USE_LVGL_INDEV 1
+
+#define LUAT_USE_LVGL_ARC   //圆弧 无依赖
+#define LUAT_USE_LVGL_BAR   //进度条 无依赖
+#define LUAT_USE_LVGL_BTN   //按钮 依赖容器CONT
+#define LUAT_USE_LVGL_BTNMATRIX   //按钮矩阵 无依赖
+#define LUAT_USE_LVGL_CALENDAR   //日历 无依赖
+#define LUAT_USE_LVGL_CANVAS   //画布 依赖图片IMG
+#define LUAT_USE_LVGL_CHECKBOX   //复选框 依赖按钮BTN 标签LABEL
+#define LUAT_USE_LVGL_CHART   //图表 无依赖
+#define LUAT_USE_LVGL_CONT   //容器 无依赖
+#define LUAT_USE_LVGL_CPICKER   //颜色选择器 无依赖
+#define LUAT_USE_LVGL_DROPDOWN   //下拉列表 依赖页面PAGE 标签LABEL
+#define LUAT_USE_LVGL_GAUGE   //仪表 依赖进度条BAR 仪表(弧形刻度)LINEMETER
+#define LUAT_USE_LVGL_IMG   //图片 依赖标签LABEL
+#define LUAT_USE_LVGL_IMGBTN   //图片按钮 依赖按钮BTN
+#define LUAT_USE_LVGL_KEYBOARD   //键盘 依赖图片按钮IMGBTN
+#define LUAT_USE_LVGL_LABEL   //标签 无依赖
+#define LUAT_USE_LVGL_LED   //LED 无依赖
+#define LUAT_USE_LVGL_LINE   //线 无依赖
+#define LUAT_USE_LVGL_LIST   //列表 依赖页面PAGE 按钮BTN 标签LABEL
+#define LUAT_USE_LVGL_LINEMETER   //仪表(弧形刻度) 无依赖
+#define LUAT_USE_LVGL_OBJMASK   //对象蒙版 无依赖
+#define LUAT_USE_LVGL_MSGBOX   //消息框 依赖图片按钮IMGBTN 标签LABEL
+#define LUAT_USE_LVGL_PAGE   //页面 依赖容器CONT
+#define LUAT_USE_LVGL_SPINNER   //旋转器 依赖圆弧ARC 动画ANIM
+#define LUAT_USE_LVGL_ROLLER   //滚筒 无依赖
+#define LUAT_USE_LVGL_SLIDER   //滑杆 依赖进度条BAR
+#define LUAT_USE_LVGL_SPINBOX   //数字调整框 无依赖
+#define LUAT_USE_LVGL_SWITCH   //开关 依赖滑杆SLIDER
+#define LUAT_USE_LVGL_TEXTAREA   //文本框 依赖标签LABEL 页面PAGE
+#define LUAT_USE_LVGL_TABLE   //表格 依赖标签LABEL
+#define LUAT_USE_LVGL_TABVIEW   //页签 依赖页面PAGE 图片按钮IMGBTN
+#define LUAT_USE_LVGL_TILEVIEW   //平铺视图 依赖页面PAGE
+#define LUAT_USE_LVGL_WIN   //窗口 依赖容器CONT 按钮BTN 标签LABEL 图片IMG 页面PAGE
+
+
+#define LV_FONT_OPPOSANS_M_8
+#define LV_FONT_OPPOSANS_M_10
+#define LV_FONT_OPPOSANS_M_12
+#define LV_FONT_OPPOSANS_M_14
+#define LV_FONT_OPPOSANS_M_16
+#define LV_FONT_OPPOSANS_M_18
+#define LV_FONT_OPPOSANS_M_20
+#define LV_FONT_OPPOSANS_M_22
+#define USE_LVGL_SIMSUN_42
+#define USE_LVGL_SIMSUN_48
+
+#endif

+ 52 - 0
bsp/emulator/include/luat_remotem.h

@@ -0,0 +1,52 @@
+#include "luat_base.h"
+#include "cJSON.h"
+
+
+
+typedef void (*luat_remotem_uplink_cb)(char* buff, size_t len);
+typedef void (*luat_remotem_typeopt)(cJSON* top, cJSON* data);
+
+
+typedef struct luat_remotem_ctx
+{
+    char bsp[32];
+    char self_id[64];
+    char session_id[64];
+    int wait;
+    struct
+    {
+        char host[64];
+        int  port;
+        char user[128];
+        char password[128];
+        char protocol[8];
+        char topic_uplink[192];
+        char topic_downlink[192];
+    } mqtt;
+    
+}luat_remotem_ctx_t;
+
+void luat_remotem_init(int argc, char** argv);
+
+
+void luat_remotem_putbuff(char* buff, size_t len);
+void luat_remotem_set_uplink(luat_remotem_uplink_cb uplink);
+cJSON* luat_remotem_json_init(cJSON* top);
+int luat_remotem_ready(void);
+int luat_remotem_up(cJSON* top);
+// from string ext
+void luat_str_tohex(char* str, size_t len, char* buff);
+
+
+void luat_remotem_typeopt_init(cJSON* top, cJSON* data);
+void luat_remotem_typeopt_log(cJSON* top, cJSON* data);
+void luat_remotem_typeopt_gpio(cJSON* top, cJSON* data);
+void luat_remotem_typeopt_uart(cJSON* top, cJSON* data);
+void luat_remotem_typeopt_indev(cJSON* top, cJSON* data);
+void luat_remotem_typeopt_ping(cJSON* top, cJSON* data);
+
+typedef struct type_opt
+{
+    const char* name;
+    luat_remotem_typeopt typeopt;
+}type_opt_t;

+ 99 - 0
bsp/emulator/port/luat_base_emulator.c

@@ -0,0 +1,99 @@
+#include "luat_base.h"
+#include "luat_msgbus.h"
+#include "luat_fs.h"
+#include "luat_timer.h"
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifdef LUAT_USE_LVGL
+#include "lvgl.h"
+void luat_lv_fs_init(void);
+void lv_bmp_init(void);
+void lv_png_init(void);
+void lv_split_jpeg_init(void);
+#endif
+
+LUAMOD_API int luaopen_win32( lua_State *L );
+int luaopen_lfs(lua_State * L);
+int luaopen_rs232_core(lua_State * L);
+
+static const luaL_Reg loadedlibs[] = {
+  {"_G", luaopen_base}, // _G
+  {LUA_LOADLIBNAME, luaopen_package}, // require
+  {LUA_COLIBNAME, luaopen_coroutine}, // coroutine协程库
+  {LUA_TABLIBNAME, luaopen_table},    // table库,操作table类型的数据结构
+  {LUA_IOLIBNAME, luaopen_io},        // io库,操作文件
+  {LUA_OSLIBNAME, luaopen_os},        // os库,已精简
+  {LUA_STRLIBNAME, luaopen_string},   // string库,字符串操作
+  {LUA_MATHLIBNAME, luaopen_math},    // math 数值计算
+  {LUA_UTF8LIBNAME, luaopen_utf8},
+  {LUA_DBLIBNAME, luaopen_debug},     // debug库,已精简
+#if defined(LUA_COMPAT_BITLIB)
+  {LUA_BITLIBNAME, luaopen_bit32},    // 不太可能启用
+#endif
+  {"rtos", luaopen_rtos},             // rtos底层库, 核心功能是队列和定时器
+  {"log", luaopen_log},               // 日志库
+  {"timer", luaopen_timer},           // 延时库
+  {"pack", luaopen_pack},             // pack.pack/pack.unpack
+  {"json", luaopen_cjson},             // json
+  // {"win32", luaopen_win32},            // windows 32 tools
+  {"zbuff", luaopen_zbuff},            // 
+//   {"mqttcore", luaopen_mqttcore},      // 
+//   {"libcoap", luaopen_libcoap},        // 
+  {"crypto", luaopen_crypto},
+  // {"fatfs", luaopen_fatfs},
+  // {"sfd",   luaopen_sfd},
+  // {"lfs2",   luaopen_lfs2},
+  // {"gpio",   luaopen_gpio},
+  {"vmx",    luaopen_vmx},
+#ifdef LUAT_USE_LVGL
+  {"lvgl",   luaopen_lvgl},
+#endif
+  {NULL, NULL}
+};
+
+// 按不同的rtconfig加载不同的库函数
+void luat_openlibs(lua_State *L) {
+    // 初始化队列服务
+    luat_msgbus_init();
+    //print_list_mem("done>luat_msgbus_init");
+    // 加载系统库
+    const luaL_Reg *lib;
+    /* "require" functions from 'loadedlibs' and set results to global table */
+    for (lib = loadedlibs; lib->func; lib++) {
+        luaL_requiref(L, lib->name, lib->func, 1);
+        lua_pop(L, 1);  /* remove lib */
+        //extern void print_list_mem(const char* name);
+        //print_list_mem(lib->name);
+    }
+}
+
+void luat_os_reboot(int code) {
+    exit(code);
+}
+
+const char* luat_os_bsp(void) {
+    return "win32";
+}
+
+
+void vConfigureTimerForRunTimeStats( void ) {}
+
+/** 设备进入待机模式 */
+void luat_os_standy(int timeout) {
+    return; // nop
+}
+
+void luat_ota_reboot(int timeout_ms) {
+  if (timeout_ms > 0)
+    luat_timer_mdelay(timeout_ms);
+  exit(0);
+}
+
+#include <unistd.h>
+
+void luat_timer_us_delay(size_t us) {
+    if (us)
+        usleep(us);
+    return;
+}

+ 409 - 0
bsp/emulator/port/luat_crypto_emulator.c

@@ -0,0 +1,409 @@
+
+#include "luat_base.h"
+#include "luat_crypto.h"
+
+
+
+#define LUAT_LOG_TAG "crypto"
+#include "luat_log.h"
+
+#define PKG_USING_MBEDTLS
+
+#ifdef PKG_USING_MBEDTLS
+#include "mbedtls/cipher.h"
+#endif
+
+int l_crypto_cipher_xxx(lua_State *L, uint8_t flags) {
+    size_t cipher_size = 0;
+    size_t pad_size = 0;
+    size_t str_size = 0;
+    size_t key_size = 0;
+    size_t iv_size = 0;
+    const char* cipher = luaL_optlstring(L, 1, "AES-128-ECB", &cipher_size);
+    const char* pad = luaL_optlstring(L, 2, "PKCS7", &pad_size);
+    const char* str = luaL_checklstring(L, 3, &str_size);
+    const char* key = luaL_checklstring(L, 4, &key_size);
+    const char* iv = luaL_optlstring(L, 5, "", &iv_size);
+
+    int ret = 0;
+
+    unsigned char output[32] = {0};
+    size_t input_size = 0;
+    size_t output_size = 0;
+    size_t block_size = 0;
+    
+    luaL_Buffer buff;
+
+#ifdef PKG_USING_MBEDTLS
+    mbedtls_cipher_context_t ctx;
+    mbedtls_cipher_init(&ctx);
+
+
+
+    const mbedtls_cipher_info_t * _cipher = mbedtls_cipher_info_from_string(cipher);
+    if (_cipher == NULL) {
+        lua_pushstring(L, "bad cipher name");
+        lua_error(L);
+        return 0;
+    }
+
+
+	ret = mbedtls_cipher_setup(&ctx, _cipher);
+    if (ret) {
+        LLOGE("mbedtls_cipher_setup fail %ld", ret);
+        goto _exit;
+    }
+    ret = mbedtls_cipher_setkey(&ctx, key, key_size * 8, flags & 0x1);
+    if (ret) {
+        LLOGE("mbedtls_cipher_setkey fail %ld", ret);
+        goto _exit;
+    }
+    // TODO 设置padding mode
+    // mbedtls_cipher_set_padding_mode
+    if (iv_size) {
+        ret = mbedtls_cipher_set_iv(&ctx, iv, iv_size);
+        if (ret) {
+            LLOGE("mbedtls_cipher_set_iv fail %ld", ret);
+            goto _exit;
+        }
+    }
+
+    mbedtls_cipher_reset(&ctx);
+
+    //mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_PKCS7);
+
+    // 开始注入数据
+    luaL_buffinit(L, &buff);
+    block_size = mbedtls_cipher_get_block_size(&ctx);
+    for (size_t i = 0; i < str_size; i+=block_size) {
+        input_size = str_size - i;
+        if (input_size > block_size)
+            input_size = block_size;
+        ret = mbedtls_cipher_update(&ctx, str+i, input_size, output, &output_size);
+        if (ret) {
+            LLOGE("mbedtls_cipher_update fail %ld", ret);
+            goto _exit;
+        }
+        //else LLOGD("mbedtls_cipher_update, output size=%ld", output_size);
+        if (output_size > 0)
+            luaL_addlstring(&buff, output, output_size);
+        output_size = 0;
+    }
+    ret = mbedtls_cipher_finish(&ctx, output, &output_size);
+    if (ret) {
+        LLOGE("mbedtls_cipher_finish fail %ld", ret);
+        goto _exit;
+    }
+    //else LLOGD("mbedtls_cipher_finish, output size=%ld", output_size);
+    if (output_size > 0)
+        luaL_addlstring(&buff, output, output_size);
+
+_exit:
+    mbedtls_cipher_free(&ctx);
+    luaL_pushresult(&buff);
+    return 1;
+#else
+    return 0;
+#endif
+}
+
+
+#ifdef PKG_USING_MBEDTLS
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "mbedtls/sha1.h"
+#include "mbedtls/sha256.h"
+#ifdef MBEDTLS_SHA512_C
+#include "mbedtls/sha512.h"
+#endif
+#include "mbedtls/md5.h"
+
+#define LUAT_LOG_TAG "crypto"
+#include "luat_log.h"
+
+void luat_crypto_HmacSha1(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen);
+void luat_crypto_HmacSha256(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen);
+void luat_crypto_HmacSha512(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen);
+void luat_crypto_HmacMd5(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen);
+
+#ifndef LUAT_CRYPTO_MD5
+#define LUAT_CRYPTO_MD5
+int luat_crypto_md5_simple(const char* str, size_t str_size, void* out_ptr) {
+    mbedtls_md5_context ctx;
+    mbedtls_md5_init(&ctx);
+
+    mbedtls_md5_starts(&ctx);
+    mbedtls_md5_update(&ctx, (const unsigned char *)str, str_size);
+    mbedtls_md5_finish(&ctx, (unsigned char *)out_ptr);
+    mbedtls_md5_free(&ctx);
+    return 0;
+}
+#endif
+#ifndef LUAT_CRYPTO_SHA1
+#define LUAT_CRYPTO_SHA1
+int luat_crypto_sha1_simple(const char* str, size_t str_size, void* out_ptr) {
+    mbedtls_sha1_context ctx;
+    mbedtls_sha1_init(&ctx);
+
+    mbedtls_sha1_starts(&ctx);
+    mbedtls_sha1_update(&ctx, (const unsigned char *)str, str_size);
+    mbedtls_sha1_finish(&ctx, (unsigned char *)out_ptr);
+    mbedtls_sha1_free(&ctx);
+    return 0;
+}
+#endif
+
+int luat_crypto_sha256_simple(const char* str, size_t str_size, void* out_ptr) {
+    mbedtls_sha256_context ctx;
+    mbedtls_sha256_init(&ctx);
+
+    mbedtls_sha256_starts(&ctx, 0);
+    mbedtls_sha256_update(&ctx, (const unsigned char *)str, str_size);
+    mbedtls_sha256_finish(&ctx, (unsigned char *)out_ptr);
+    mbedtls_sha256_free(&ctx);
+    return 0;
+}
+#ifdef MBEDTLS_SHA512_C
+int luat_crypto_sha512_simple(const char* str, size_t str_size, void* out_ptr) {
+    mbedtls_sha512_context ctx;
+    mbedtls_sha512_init(&ctx);
+
+    mbedtls_sha512_starts(&ctx, 0);
+    mbedtls_sha512_update(&ctx, (const unsigned char *)str, str_size);
+    mbedtls_sha512_finish(&ctx, (unsigned char *)out_ptr);
+    mbedtls_sha512_free(&ctx);
+    return 0;
+}
+#endif
+
+#ifndef LUAT_CRYPTO_MD5
+#define LUAT_CRYPTO_MD5
+int luat_crypto_hmac_md5_simple(const char* str, size_t str_size, const char* mac, size_t mac_size, void* out_ptr) {
+    luat_crypto_HmacMd5((const unsigned char *)str, str_size, (unsigned char *)out_ptr, (const unsigned char *)mac, mac_size);
+    return 0;
+}
+#endif
+#ifndef LUAT_CRYPTO_SHA1
+#define LUAT_CRYPTO_SHA1
+int luat_crypto_hmac_sha1_simple(const char* str, size_t str_size, const char* mac, size_t mac_size, void* out_ptr) {
+    luat_crypto_HmacSha1((const unsigned char *)str, str_size, (unsigned char *)out_ptr, (const unsigned char *)mac, mac_size);
+    return 0;
+}
+#endif
+
+int luat_crypto_hmac_sha256_simple(const char* str, size_t str_size, const char* mac, size_t mac_size, void* out_ptr) {
+    luat_crypto_HmacSha256((const unsigned char *)str, str_size, (unsigned char *)out_ptr, (const unsigned char *)mac, mac_size);
+    return 0;
+}
+#ifdef MBEDTLS_SHA512_C
+int luat_crypto_hmac_sha512_simple(const char* str, size_t str_size, const char* mac, size_t mac_size, void* out_ptr) {
+    luat_crypto_HmacSha512((const unsigned char *)str, str_size, (unsigned char *)out_ptr, (const unsigned char *)mac, mac_size);
+    return 0;
+}
+#endif
+
+
+///----------------------------
+
+#define ALI_SHA1_KEY_IOPAD_SIZE (64)
+#define ALI_SHA1_DIGEST_SIZE    (20)
+
+#define ALI_SHA256_KEY_IOPAD_SIZE   (64)
+#define ALI_SHA256_DIGEST_SIZE      (32)
+
+#define ALI_SHA512_KEY_IOPAD_SIZE   (128)
+#define ALI_SHA512_DIGEST_SIZE      (64)
+
+#define ALI_MD5_KEY_IOPAD_SIZE  (64)
+#define ALI_MD5_DIGEST_SIZE     (16)
+
+// char atHb2Hex(unsigned char hb)
+// {
+//     hb = hb&0xF;
+//     return (char)(hb<10 ? '0'+hb : hb-10+'a');
+// }
+
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void luat_crypto_HmacSha1(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen)
+{
+    int i;
+    mbedtls_sha1_context ctx;
+    unsigned char k_ipad[ALI_SHA1_KEY_IOPAD_SIZE] = {0};
+    unsigned char k_opad[ALI_SHA1_KEY_IOPAD_SIZE] = {0};
+    unsigned char tempbuf[ALI_SHA1_DIGEST_SIZE];
+
+    memset(k_ipad, 0x36, ALI_SHA1_KEY_IOPAD_SIZE);
+    memset(k_opad, 0x5C, ALI_SHA1_KEY_IOPAD_SIZE);
+
+    for(i=0; i<keylen; i++)
+    {
+        if(i>=ALI_SHA1_KEY_IOPAD_SIZE)
+        {
+            break;
+        }
+        k_ipad[i] ^=key[i];
+        k_opad[i] ^=key[i];
+    }
+    mbedtls_sha1_init(&ctx);
+
+    mbedtls_sha1_starts(&ctx);
+    mbedtls_sha1_update(&ctx, k_ipad, ALI_SHA1_KEY_IOPAD_SIZE);
+    mbedtls_sha1_update(&ctx, input, ilen);
+    mbedtls_sha1_finish(&ctx, tempbuf);
+
+    mbedtls_sha1_starts(&ctx);
+    mbedtls_sha1_update(&ctx, k_opad, ALI_SHA1_KEY_IOPAD_SIZE);
+    mbedtls_sha1_update(&ctx, tempbuf, ALI_SHA1_DIGEST_SIZE);
+    mbedtls_sha1_finish(&ctx, tempbuf);
+
+    // for(i=0; i<ALI_SHA1_DIGEST_SIZE; ++i)
+    // {
+    //     output[i*2] = atHb2Hex(tempbuf[i]>>4);
+    //     output[i*2+1] = atHb2Hex(tempbuf[i]);
+    // }
+    memcpy(output, tempbuf, ALI_SHA1_DIGEST_SIZE);
+
+    mbedtls_sha1_free(&ctx);
+}
+/*
+ * output = SHA-256( input buffer )
+ */
+void luat_crypto_HmacSha256(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen)
+{
+    int i;
+    mbedtls_sha256_context ctx;
+    unsigned char k_ipad[ALI_SHA256_KEY_IOPAD_SIZE] = {0};
+    unsigned char k_opad[ALI_SHA256_KEY_IOPAD_SIZE] = {0};
+
+    memset(k_ipad, 0x36, 64);
+    memset(k_opad, 0x5C, 64);
+
+    if ((NULL == input) || (NULL == key) || (NULL == output)) {
+        return;
+    }
+
+    if (keylen > ALI_SHA256_KEY_IOPAD_SIZE) {
+        return;
+    }
+
+    for(i=0; i<keylen; i++)
+    {
+        if(i>=ALI_SHA256_KEY_IOPAD_SIZE)
+        {
+            break;
+        }
+        k_ipad[i] ^=key[i];
+        k_opad[i] ^=key[i];
+    }
+    mbedtls_sha256_init(&ctx);
+
+    mbedtls_sha256_starts(&ctx, 0);
+    mbedtls_sha256_update(&ctx, k_ipad, ALI_SHA256_KEY_IOPAD_SIZE);
+    mbedtls_sha256_update(&ctx, input, ilen);
+    mbedtls_sha256_finish(&ctx, output);
+
+    mbedtls_sha256_starts(&ctx, 0);
+    mbedtls_sha256_update(&ctx, k_opad, ALI_SHA256_KEY_IOPAD_SIZE);
+    mbedtls_sha256_update(&ctx, output, ALI_SHA256_DIGEST_SIZE);
+    mbedtls_sha256_finish(&ctx, output);
+
+    mbedtls_sha256_free(&ctx);
+}
+#ifdef MBEDTLS_SHA512_C
+/*
+ * output = SHA-512( input buffer )
+ */
+void luat_crypto_HmacSha512(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen)
+{
+    int i;
+    mbedtls_sha512_context ctx;
+    unsigned char k_ipad[ALI_SHA512_KEY_IOPAD_SIZE] = {0};
+    unsigned char k_opad[ALI_SHA512_KEY_IOPAD_SIZE] = {0};
+
+    memset(k_ipad, 0x36, ALI_SHA512_KEY_IOPAD_SIZE);
+    memset(k_opad, 0x5C, ALI_SHA512_KEY_IOPAD_SIZE);
+
+    if ((NULL == input) || (NULL == key) || (NULL == output)) {
+        return;
+    }
+
+    if (keylen > ALI_SHA512_KEY_IOPAD_SIZE) {
+        return;
+    }
+
+    for(i=0; i<keylen; i++)
+    {
+        if(i>=ALI_SHA512_KEY_IOPAD_SIZE)
+        {
+            break;
+        }
+        k_ipad[i] ^=key[i];
+        k_opad[i] ^=key[i];
+    }
+    mbedtls_sha512_init(&ctx);
+
+    mbedtls_sha512_starts(&ctx, 0);
+    mbedtls_sha512_update(&ctx, k_ipad, ALI_SHA512_KEY_IOPAD_SIZE);
+    mbedtls_sha512_update(&ctx, input, ilen);
+    mbedtls_sha512_finish(&ctx, output);
+
+    mbedtls_sha512_starts(&ctx, 0);
+    mbedtls_sha512_update(&ctx, k_opad, ALI_SHA512_KEY_IOPAD_SIZE);
+    mbedtls_sha512_update(&ctx, output, ALI_SHA512_DIGEST_SIZE);
+    mbedtls_sha512_finish(&ctx, output);
+
+    mbedtls_sha512_free(&ctx);
+}
+#endif
+/*
+ * output = MD-5( input buffer )
+ */
+void luat_crypto_HmacMd5(const unsigned char *input, int ilen, unsigned char *output,const unsigned char *key, int keylen)
+{
+    int i;
+    mbedtls_md5_context ctx;
+    unsigned char k_ipad[ALI_MD5_KEY_IOPAD_SIZE] = {0};
+    unsigned char k_opad[ALI_MD5_KEY_IOPAD_SIZE] = {0};
+    unsigned char tempbuf[ALI_MD5_DIGEST_SIZE];
+
+    memset(k_ipad, 0x36, ALI_MD5_KEY_IOPAD_SIZE);
+    memset(k_opad, 0x5C, ALI_MD5_KEY_IOPAD_SIZE);
+
+    for(i=0; i<keylen; i++)
+    {
+        if(i>=ALI_MD5_KEY_IOPAD_SIZE)
+        {
+            break;
+        }
+        k_ipad[i] ^=key[i];
+        k_opad[i] ^=key[i];
+    }
+    mbedtls_md5_init(&ctx);
+
+    mbedtls_md5_starts(&ctx);
+    mbedtls_md5_update(&ctx, k_ipad, ALI_MD5_KEY_IOPAD_SIZE);
+    mbedtls_md5_update(&ctx, input, ilen);
+    mbedtls_md5_finish(&ctx, tempbuf);
+
+    mbedtls_md5_starts(&ctx);
+    mbedtls_md5_update(&ctx, k_opad, ALI_MD5_KEY_IOPAD_SIZE);
+    mbedtls_md5_update(&ctx, tempbuf, ALI_MD5_DIGEST_SIZE);
+    mbedtls_md5_finish(&ctx, tempbuf);
+
+    // for(i=0; i<ALI_MD5_DIGEST_SIZE; ++i)
+    // {
+    //     output[i*2] = atHb2Hex(tempbuf[i]>>4);
+    //     output[i*2+1] = atHb2Hex(tempbuf[i]);
+    // }
+    memcpy(output, tempbuf, ALI_MD5_DIGEST_SIZE);
+    mbedtls_md5_free(&ctx);
+}
+#endif

+ 68 - 0
bsp/emulator/port/luat_fs_emulator.c

@@ -0,0 +1,68 @@
+#include "luat_base.h"
+#include "luat_fs.h"
+#include "luat_malloc.h"
+
+#ifdef LUAT_USE_LVGL
+#include "lvgl.h"
+void luat_lv_fs_init(void);
+void lv_bmp_init(void);
+void lv_png_init(void);
+void lv_split_jpeg_init(void);
+#endif
+
+extern const struct luat_vfs_filesystem vfs_fs_posix;
+extern const struct luat_vfs_filesystem vfs_fs_onefile;
+
+// #ifdef LUAT_USE_VFS_INLINE_LIB
+extern const char luat_inline_sys[];
+extern const uint32_t luat_inline_sys_size;
+// #endif
+
+typedef struct luat_fs_onefile
+{
+    char* ptr;
+    uint32_t  size;
+    uint32_t  offset;
+}luat_fs_onefile_t;
+
+int luat_fs_init(void) {
+	#ifdef LUAT_USE_FS_VFS
+	// vfs进行必要的初始化
+	luat_vfs_init(NULL);
+	// 注册vfs for posix 实现
+	luat_vfs_reg(&vfs_fs_posix);
+	luat_vfs_reg(&vfs_fs_onefile);
+
+	luat_fs_conf_t conf = {
+		.busname = "",
+		.type = "posix",
+		.filesystem = "posix",
+		.mount_point = "", // window环境下, 需要支持任意路径的读取,不能强制要求必须是/
+	};
+	luat_fs_mount(&conf);
+	// #ifdef LUAT_USE_VFS_INLINE_LIB
+    luat_fs_onefile_t* fd = luat_heap_malloc(sizeof(luat_fs_onefile_t));
+    fd->ptr = luat_inline_sys;
+    fd->size = luat_inline_sys_size;
+	luat_fs_conf_t conf2 = {
+		.busname = (char*)fd,
+		.type = "onefile",
+		.filesystem = "onefile",
+		.mount_point = "/luadb/sys.luac",
+	};
+	luat_fs_mount(&conf2);
+
+	// FILE* fd2 = luat_fs_fopen("/luadb/sys.lua", "rb");
+	// char buff[1024];
+	// luat_fs_fread(buff, 1, 1024, fd2);
+	// #endif
+	#endif
+
+	#ifdef LUAT_USE_LVGL
+	luat_lv_fs_init();
+	lv_bmp_init();
+	lv_png_init();
+	lv_split_jpeg_init();
+	#endif
+	return 0;
+}

+ 102 - 0
bsp/emulator/port/luat_log_emulator.c

@@ -0,0 +1,102 @@
+
+#include "luat_base.h"
+#include "luat_log.h"
+#include "luat_uart.h"
+#include "luat_malloc.h"
+#include "printf.h"
+
+#include <stdio.h>
+
+#include "luat_remotem.h"
+#include "cJSON.h"
+
+static uint8_t luat_log_uart_port = 0;
+static uint8_t luat_log_level_cur = LUAT_LOG_DEBUG;
+
+void luat_log_init_emulator(void) {
+    
+}
+
+void luat_log_set_uart_port(int port) {
+    luat_log_uart_port = port;
+}
+
+void luat_print(const char* _str) {
+    luat_nprint((char*)_str, strlen(_str));
+}
+
+void luat_nprint(char *s, size_t l) {
+    if (luat_remotem_ready()) {
+        cJSON* top = cJSON_CreateObject();
+        cJSON* data = luat_remotem_json_init(top);
+
+        cJSON_AddStringToObject(top, "type", "log");
+        cJSON_AddStringToObject(data, "type", "hex");
+        char* buff = luat_heap_malloc(l * 2 + 1);
+        luat_str_tohex(s, l, buff);
+        buff[l*2] = 0x00;
+        cJSON_AddStringToObject(data, "value", buff);
+
+        luat_remotem_up(top);
+        cJSON_Delete(top);
+        luat_heap_free(buff);
+    }
+    char buff[4*1024];
+    memcpy(buff, s, l);
+    buff[l] = 0;
+    printf("%s", buff);
+// #endif
+}
+
+void luat_log_set_level(int level) {
+    luat_log_level_cur = level;
+}
+int luat_log_get_level() {
+    return luat_log_level_cur;
+}
+#define LOGLOG_SIZE 1024
+void luat_log_log(int level, const char* tag, const char* _fmt, ...) {
+    if (luat_log_level_cur > level) return;
+    char buff[LOGLOG_SIZE] = {0};
+    char *tmp = (char *)buff;
+    switch (level)
+        {
+        case LUAT_LOG_DEBUG:
+            buff[0] = 'D';
+            break;
+        case LUAT_LOG_INFO:
+            buff[0] = 'I';
+            break;
+        case LUAT_LOG_WARN:
+            buff[0] = 'W';
+            break;
+        case LUAT_LOG_ERROR:
+            buff[0] = 'E';
+            break;
+        default:
+            buff[0] = '?';
+            break;
+        }
+    buff[1] = '/';
+    tmp += 2;
+    memcpy(tmp, tag, strlen(tag));
+    buff[2+strlen(tag)] = ' ';
+    tmp += strlen(tag) + 1;
+
+    va_list args;
+    va_start(args, _fmt);
+    size_t len = vsnprintf_(tmp, LOGLOG_SIZE, _fmt, args);
+    va_end(args);
+    if (len > 0) {
+        len = strlen(buff);
+        // if (len > LOGLOG_SIZE - 2)
+        //     len = LOGLOG_SIZE - 2;
+        // buff[len] = '\r';
+        // buff[len+1] = '\n';
+        // luat_nprint(buff, len+2);
+        if (len > LOGLOG_SIZE - 1)
+            len = LOGLOG_SIZE - 1;
+        buff[len] = '\n';
+        luat_nprint(buff, len+1);
+    }
+}

+ 116 - 0
bsp/emulator/port/luat_lvgl_emulator.c

@@ -0,0 +1,116 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#include "lv_conf.h"
+#include "lvgl.h"
+
+#define LUAT_LOG_TAG "win32"
+#include "luat_log.h"
+
+#include "luat_remotem.h"
+#include "windows.h"
+#include "luat_msgbus.h"
+
+typedef struct luat_lv {
+    lv_disp_t* disp;
+    lv_disp_buf_t disp_buf;
+    int buff_ref;
+    int buff2_ref;
+}luat_lv_t;
+
+static luat_lv_t LV = {0};
+
+static char* rbuff;
+
+#ifdef LUAT_USE_LVGL
+
+#include "lvgl.h"
+static int luat_lvg_handler(lua_State* L, void* ptr) {
+    lv_tick_inc(25);
+    lv_task_handler();
+    return 0;
+}
+
+static void CALLBACK _lvgl_handler(HWND hwnd,       
+    UINT message,     
+    UINT idTimer,     
+    DWORD dwTime) {
+    rtos_msg_t msg = {0};
+    msg.handler = luat_lvg_handler;
+    luat_msgbus_put(&msg, 0);
+}
+#endif
+
+void luat_lv_disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
+    //-----
+    //LLOGD("disp_flush (%d, %d, %d, %d)", area->x1, area->y1, area->x2, area->y2);
+    if (luat_remotem_ready()) {
+        cJSON* top = cJSON_CreateObject();
+        cJSON* data = luat_remotem_json_init(top);
+        //luat_heap_malloc(sizeof(lv_color16_t) * (area->x2 - area->x1) * (area->y2 - area->y1) * 2);
+        cJSON_AddStringToObject(top, "type", "display");
+        cJSON_AddStringToObject(data, "opt", "zone_update");
+        cJSON_AddStringToObject(data, "type", "hex");
+        //char* buff = luat_heap_malloc(l * 2 + 1);
+        size_t len = (area->x2 - area->x1) * (area->y2 - area->y1);
+        luat_str_tohex((char*)color_p, len, rbuff);
+        rbuff[len * 2] = 0x00;
+
+        cJSON* _rbuff = cJSON_AddObjectToObject(data, "rbuff");
+        cJSON_AddStringToObject(_rbuff, "type", "hex");
+        cJSON_AddStringToObject(_rbuff, "value", rbuff);
+
+        cJSON* _area = cJSON_AddObjectToObject(data, "area");
+        cJSON_AddNumberToObject(_area, "x1", area->x1);
+        cJSON_AddNumberToObject(_area, "x2", area->x2);
+        cJSON_AddNumberToObject(_area, "y1", area->y1);
+        cJSON_AddNumberToObject(_area, "y2", area->y2);
+
+        luat_remotem_up(top);
+        cJSON_Delete(top);
+    }
+
+    lv_disp_flush_ready(disp_drv);
+}
+
+void win32_lvgl_remote_init(int w, int h) {
+    if (rbuff != NULL) {
+        LLOGE("lvgl was init completed!!");
+        return;
+    }
+    size_t fbuff_size = w * 10;
+    LLOGD("w %d h %d buff %d", w, h, fbuff_size);
+    lv_color_t* fbuffer = luat_heap_malloc(fbuff_size * sizeof(lv_color_t));
+
+    lv_disp_buf_init(&LV.disp_buf, fbuffer, NULL, fbuff_size);
+
+    lv_disp_drv_t my_disp_drv;
+    lv_disp_drv_init(&my_disp_drv);
+
+    my_disp_drv.flush_cb = luat_lv_disp_flush;
+
+    my_disp_drv.hor_res = w;
+    my_disp_drv.ver_res = h;
+    my_disp_drv.buffer = &LV.disp_buf;
+    //LLOGD(">>%s %d", __func__, __LINE__);
+    LV.disp = lv_disp_drv_register(&my_disp_drv);
+
+    rbuff = luat_heap_malloc(sizeof(lv_color_t) * w * h *2 + 4);
+
+    // send message to mqtt
+    {
+        cJSON* top = cJSON_CreateObject();
+        cJSON* data = luat_remotem_json_init(top);
+        cJSON_AddStringToObject(top, "type", "display");
+        cJSON_AddStringToObject(data, "opt", "init");
+        cJSON_AddNumberToObject(data, "w", w);
+        cJSON_AddNumberToObject(data, "h", h);
+        cJSON_AddStringToObject(data, "colorspace", "rgb565");
+        cJSON_AddBoolToObject(data, "colorswap", true);
+
+        luat_remotem_up(top);
+        cJSON_Delete(top);
+    }
+    
+    SetTimer(NULL, 0, 25, _lvgl_handler);
+}

+ 95 - 0
bsp/emulator/port/luat_malloc_emulator.c

@@ -0,0 +1,95 @@
+
+// 这个文件包含 系统heap和lua heap的默认实现
+
+
+#include <stdlib.h>
+#include <string.h>//add for memset
+#include "bget.h"
+#include "luat_malloc.h"
+
+#define LUAT_LOG_TAG "heap"
+#include "luat_log.h"
+
+//------------------------------------------------
+//  管理系统内存
+
+void* luat_heap_malloc(size_t len) {
+    return malloc(len);
+}
+
+void luat_heap_free(void* ptr) {
+    free(ptr);
+}
+
+void* luat_heap_realloc(void* ptr, size_t len) {
+    return realloc(ptr, len);
+}
+
+void* luat_heap_calloc(size_t count, size_t _size) {
+    void *ptr = luat_heap_malloc(count * _size);
+    if (ptr) {
+        memset(ptr, 0, _size);
+    }
+    return ptr;
+}
+//------------------------------------------------
+
+//------------------------------------------------
+// ---------- 管理 LuaVM所使用的内存----------------
+void* luat_heap_alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
+    if (0) {
+        if (ptr) {
+            if (nsize) {
+                // 缩放内存块
+                LLOGD("realloc %p from %d to %d", ptr, osize, nsize);
+            }
+            else {
+                // 释放内存块
+                LLOGD("free %p ", ptr);
+                brel(ptr);
+                return NULL;
+            }
+        }
+        else {
+            // 申请内存块
+            ptr = bget(nsize);
+            LLOGD("malloc %p type=%d size=%d", ptr, osize, nsize);
+            return ptr;
+        }
+    }
+
+    if (nsize)
+    {
+    	void* ptmp = bgetr(ptr, nsize);
+    	if(ptmp == NULL && osize >= nsize)
+    	{
+    		return ptr;
+    	}
+        return ptmp;
+    }
+    brel(ptr);
+    return NULL;
+}
+
+void luat_meminfo_luavm(size_t *total, size_t *used, size_t *max_used) {
+	long curalloc, totfree, maxfree;
+	unsigned long nget, nrel;
+	bstats(&curalloc, &totfree, &maxfree, &nget, &nrel);
+	*used = curalloc;
+	*max_used = bstatsmaxget();
+    *total = curalloc + totfree;
+}
+
+// #include "FreeRTOS.h"
+// #include "task.h"
+
+void luat_meminfo_sys(size_t *total, size_t *used, size_t *max_used) {
+	*used = 1;
+	*max_used = 1;
+    *total = 2;
+    	// *used = configTOTAL_HEAP_SIZE - xPortGetFreeHeapSize();
+	// *max_used = configTOTAL_HEAP_SIZE - xPortGetMinimumEverFreeHeapSize();
+    // *total = configTOTAL_HEAP_SIZE;
+}
+
+//-----------------------------------------------------------------------------

+ 68 - 0
bsp/emulator/port/luat_msgbus_emulator.c

@@ -0,0 +1,68 @@
+/**
+ * @file luat_msgbus_emulator.c
+ * @author wendal (wendal1985@gamil.com)
+ * @brief 基于win32的ThreadMessage机制实现的msgbus
+ * @version 0.1
+ * @date 2022-03-27
+ * 
+ * @copyright Copyright (c) 2022 OpenLuat & AirM2M
+ * 
+ */
+#include "luat_base.h"
+#include "luat_msgbus.h"
+#include "luat_timer.h"
+#include "luat_malloc.h"
+
+#include "windows.h"
+
+#define LUAT_LOG_TAG "msgbus"
+#include "luat_log.h"
+
+static DWORD luat_main_thread_id;
+
+void luat_msgbus_init(void) {
+    luat_main_thread_id = GetCurrentThreadId();
+    // LLOGD("main thread id %d", luat_main_thread_id);
+}
+uint32_t luat_msgbus_put(rtos_msg_t* msg, size_t timeout) {
+    rtos_msg_t* tmp = luat_heap_malloc(sizeof(rtos_msg_t));
+    memcpy(tmp, msg, sizeof(rtos_msg_t));
+    PostThreadMessageA(luat_main_thread_id, WM_COMMAND, (WPARAM)tmp, 0);
+    return 0;
+}
+uint32_t luat_msgbus_get(rtos_msg_t* rtmsg, size_t timeout) {
+    MSG msg;
+    rtos_msg_t* tmp;
+    WINBOOL ret = FALSE;
+    if ((ret = GetMessageA(&msg,NULL,0,0)) != 0)
+    {
+    //   LLOGD("msg type %d", msg.message);
+      if(msg.message==WM_TIMER)
+      {
+        //   LLOGD("WM_TIMER %d", msg.message);
+          DispatchMessage(&msg);
+      }
+      else if (msg.message == WM_COMMAND) {
+        //   LLOGD("WM_COMMAND %d", msg.message);
+          tmp = (rtos_msg_t*)msg.wParam;
+        //   LLOGD("WM_COMMAND %p", tmp);
+          if (tmp != NULL) {
+            memcpy(rtmsg, tmp, sizeof(rtos_msg_t));
+            luat_heap_free(tmp);
+            return 0;
+          }
+      }
+      else {
+          DispatchMessage(&msg);
+      }                      
+    }
+    else {
+        // LLOGD("GetMessageA ret %d", ret);
+        exit(1);
+    }
+    return 1;
+}
+
+// uint32_t luat_msgbus_freesize(void) {
+//     return 1;
+// }

+ 103 - 0
bsp/emulator/port/luat_timer_emulator.c

@@ -0,0 +1,103 @@
+/**
+ * @file luat_timer_emulator.c
+ * @author wendal (wendal1985@gamil.com)
+ * @brief 基于win32的timer实现
+ * @version 0.1
+ * @date 2022-03-27
+ * 
+ * @copyright Copyright (c) 2022 OpenLuat & AirM2M
+ * 
+ */
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_timer.h"
+#include "luat_msgbus.h"
+
+#include "windows.h"
+#include <unistd.h>
+
+#define LUAT_LOG_TAG "timer"
+#include "luat_log.h"
+
+#define WIN32_TIMER_COUNT 64
+
+static luat_timer_t* timers[WIN32_TIMER_COUNT] = {0};
+
+void CALLBACK TimeProc( 
+    HWND hwnd,       
+    UINT message,     
+    UINT idTimer,     
+    DWORD dwTime) {
+    rtos_msg_t msg;
+    msg.arg1 = 0;
+    msg.arg2 = 0;
+
+    // LLOGD("timer callback");
+
+    for (size_t i = 0; i < WIN32_TIMER_COUNT; i++)
+    {
+        if (timers[i] && (UINT_PTR)(timers[i]->os_timer) == idTimer) {
+            msg.handler = timers[i]->func;
+            msg.ptr = timers[i];
+            luat_msgbus_put(&msg, 0);
+            // LLOGD("timer msgbus index=%ld", i);
+        }
+    }
+    
+}
+
+static int nextTimerSlot() {
+    for (size_t i = 0; i < WIN32_TIMER_COUNT; i++)
+    {
+        if (timers[i] == NULL) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int luat_timer_start(luat_timer_t* timer) {
+    int timerIndex;
+    //LLOGD(">>luat_timer_start timeout=%ld", timer->timeout);
+    timerIndex = nextTimerSlot();
+    if (timerIndex < 0) {
+        LLOGE("too many timers");
+        return 1; // too many timer!!
+    }
+    UINT_PTR timer_id = SetTimer(NULL, 0, timer->timeout,TimeProc);
+    timer->os_timer = (void*)timer_id;
+    timers[timerIndex] = timer;
+    return 0;
+}
+
+int luat_timer_stop(luat_timer_t* timer) {
+    for (size_t i = 0; i < WIN32_TIMER_COUNT; i++)
+    {
+        if (timers[i] && timers[i] == timer) {
+            timers[i] = NULL;
+            KillTimer(NULL, (UINT_PTR)timer->os_timer);
+        }
+    }
+    
+    return 0;
+};
+
+luat_timer_t* luat_timer_get(size_t timer_id) {
+    for (size_t i = 0; i < WIN32_TIMER_COUNT; i++)
+    {
+        if (timers[i] && timers[i]->id == timer_id) {
+            return timers[i];
+        }
+    }
+    return NULL;
+}
+
+
+int luat_timer_mdelay(size_t ms) {
+    if (ms > 0) {
+        usleep(ms * 1000);
+    }
+    return 0;
+}
+
+

+ 167 - 0
bsp/emulator/remotem/README.md

@@ -0,0 +1,167 @@
+# LuatOS 远程模拟器通信协议
+
+本协议用于`模拟器`与`可视化界面`之间的通信, 且该通信是双向的
+
+## 基本约束
+
+* 基于`json`结构进行数据传递
+* 属于应用层协议, 不受底层传输方式的限制, 当前倾向于使用`tcp-mqtt`作为传输层协议
+
+## 术语
+
+* `模拟器` 执行lua脚本的程序, 不限平台
+* `可视化界面` 本地程序,本地网页,或者网站网页等可视化界面
+* `上行` 模拟器 --> 可视化界面
+* `下行` 可视化界面 --> 模拟器
+
+## 基本格式
+
+```json
+{
+    "id" : "1234567890", // 消息id,对同一个session应该唯一
+    "session": "12345",  // 会话id
+    "version" : 1,       // 协议版本号, 当前为1
+    "role" : "client",   // 角色, client或server的其中一种
+    "type" : "init",     // 消息类型
+    "data" : {
+        // 取决于具体的命令, 往下的协议描述仅包含data部分
+    }
+}
+```
+
+## 初始化命令及响应 init
+
+鉴于模拟器与可视化界面之间的通信是异步的,两种的启动顺序未知,所以需要初始化命令序列
+
+初始化命令 
+
+```json
+{
+    "state" : "req",
+    "bsp"  : "air101",   // 需要模拟的设备类型
+}
+```
+
+响应初始化命令
+
+```json
+{
+    "state" : "resp",
+    "id"   : "AABBCCDD", // 注意, 这里必须是req对应的id号,确保对等
+    "bsp" : "air101",
+    "gpio" : {
+        // gpio的配置信息
+    },
+    "uart" : {
+        // uart的配置信息
+    }
+    // 其他配置
+}
+```
+
+## 日志 log
+
+这是上传模拟器自身的日志
+
+```json
+{
+    "time" : 12345678,
+    "level" : "debug",
+    "type" : "hex",
+    "value" : "AABBCCDDEEFF"
+}
+```
+
+## GPIO控制 gpio
+
+模式设置, 仅`上行`
+
+```json
+{
+    "pin" : 1,
+    "opt" : "setup",
+    "mode" : "input", // 支持 input/output/interrupt 
+    "value" : 1
+}
+```
+
+电平设置 `双向`
+
+```json
+{
+    "pin" : 1,
+    "opt" : "set",
+    "value" : 1
+}
+```
+
+中断触发, `下行`
+
+```json
+{
+    "pin" : 1,
+    "opt" : "interrupt",
+    "value" : "fall" // fall, rising
+}
+```
+
+## Uart读写 uart
+
+uart对双方来说, 都是"写", `双向`
+
+```json
+{
+    "id" : 1,
+    "opt" : "write",
+    "type" : "hex",
+    "value" : "AABBCC"
+}
+```
+
+## 显示 display
+
+显示初始化
+
+```json
+{
+    "opt" : "init",
+    "w" : 800,
+    "h" : 640,
+    "colorspace" : "rgb565",
+    "colorswap" : true
+}
+```
+
+更新显示内容
+
+```json
+{
+    "opt" : "zone_update",
+    "area" : {
+        "x1" : 123,
+        "y1" : 123,
+        "x2" : 456,
+        "y2" : 456,
+    },
+    "rbuff" : {
+        "type" : "hex",
+        "value" : "AABBCCDDEEFF"
+    }
+}
+```
+
+## 输入设备 indev
+
+当前仅支持位置输入, 对应单点触摸屏, 鼠标
+
+```json
+{
+    "opt" : "pointer",
+    "pointer" : {
+        "x" : 123,
+        "y" : 456,
+        "state" : 1 // 0 抬起, 1 按下
+    }
+}
+```
+

+ 221 - 0
bsp/emulator/remotem/luat_remotem_main.c

@@ -0,0 +1,221 @@
+#include "luat_base.h"
+
+#include "luat_msgbus.h"
+#include "luat_malloc.h"
+#include "luat_timer.h"
+
+#include "cJSON.h"
+
+#include "luat_remotem.h"
+#include "unistd.h"
+#include <getopt.h>
+#include "windows.h"
+
+#define debug_printf printf
+
+static luat_remotem_uplink_cb uplink;
+
+luat_remotem_ctx_t rctx = {
+    .bsp = "win32",
+    .wait = 1,
+    .mqtt = {
+        .host = "broker-cn.emqx.io",
+        .port = 1883,
+        .protocol = "tcp",
+        .topic_uplink = "",
+        .topic_downlink = "",
+    },
+    .self_id = "",
+    .session_id = "",
+};
+
+static const type_opt_t opts[] = {
+    {"init", luat_remotem_typeopt_init},
+    {"log", luat_remotem_typeopt_log},
+    // {"ping", luat_remotem_typeopt_ping},
+    // {"gpio", luat_remotem_typeopt_gpio},
+    // {"uart", luat_remotem_typeopt_uart},
+    {"indev", luat_remotem_typeopt_indev},
+    {NULL, NULL}
+};
+
+void luat_remotem_init(int argc, char** argv) {
+
+    // 解析命令行参数
+    int c;
+    int digit_optind = 0;
+    int aopt = 0, bopt = 0;
+    char *copt = 0, *dopt = 0;
+    static struct option long_options[] = {
+    /*   NAME           ARGUMENT           FLAG  SHORTNAME */
+        {"bsp",             required_argument, NULL, 0},
+        {"selfid",          required_argument, NULL, 0},
+        {"sessionid",       required_argument, NULL, 0},
+        {"mqtt.host",       required_argument, NULL, 0},
+        {"mqtt.port",       required_argument, NULL, 0},
+        {"mqtt.clientid",   required_argument, NULL, 0},
+        {"mqtt.user",       required_argument, NULL, 0},
+        {"mqtt.password",   required_argument, NULL, 0},
+        {"wait",            required_argument, NULL, 0},
+        {NULL,      0,                 NULL, 0}
+    };
+    int option_index = 0;
+    while ((c = getopt_long(argc, argv, "d",
+                long_options, &option_index)) != -1) {
+        int this_option_optind = optind ? optind : 1;
+        switch (c) {
+        case 0:
+            //printf ("option %s", long_options[option_index].name);
+            if (!strcmp("bsp", long_options[option_index].name)) {
+                strcpy(rctx.bsp, optarg);
+            }
+            else if (!strcmp("selfid", long_options[option_index].name)) {
+                strcpy(rctx.self_id, optarg);
+            }
+            else if (!strcmp("sessionid", long_options[option_index].name)) {
+                strcpy(rctx.session_id, optarg);
+            }
+            else if (!strcmp("wait", long_options[option_index].name)) {
+                rctx.wait = atoi(optarg);
+            }
+            else if (!strcmp("mqtt.host", long_options[option_index].name)) {
+                strcpy(rctx.mqtt.host, optarg);
+            }
+            else if (!strcmp("mqtt.port", long_options[option_index].name)) {
+                rctx.mqtt.port = atoi(optarg);
+            }
+            else if (!strcmp("mqtt.user", long_options[option_index].name)) {
+                strcpy(rctx.mqtt.user, optarg);
+            }
+            else if (!strcmp("mqtt.password", long_options[option_index].name)) {
+                strcpy(rctx.mqtt.password, optarg);
+            }
+            else if (!strcmp("mqtt.protocol", long_options[option_index].name)) {
+                strcpy(rctx.mqtt.protocol, optarg);
+            }
+            break;
+        case 'd':
+            break;
+        }
+    }
+
+    // 修正部分默认参数,确保值是合法的
+    HCRYPTPROV   hCryptProv = 0;
+    BYTE         pbData[16];
+    if (strlen(rctx.self_id) < 1) {
+        CryptGenRandom(hCryptProv, 8, pbData);
+        luat_str_tohex(pbData, 8, rctx.self_id);
+        rctx.self_id[16] = 0x00;
+    }
+    if (strlen(rctx.session_id) < 1) {
+        strcpy(rctx.session_id, rctx.self_id);
+    }
+
+    if (strlen(rctx.mqtt.topic_downlink) < 1) {
+        sprintf(rctx.mqtt.topic_downlink, "/sys/luatos/emulator/%s/down", rctx.self_id);
+    }
+    if (strlen(rctx.mqtt.topic_uplink) < 1) {
+        sprintf(rctx.mqtt.topic_uplink, "/sys/luatos/emulator/%s/up", rctx.self_id);
+    }
+
+#if 1
+    printf("bsp        %s\n", rctx.bsp);
+    // printf("self id    %s\n", rctx.self_id);
+    printf("session id %s\n", rctx.session_id);
+    printf("mqtt url %s://%s:%d\n", rctx.mqtt.protocol, rctx.mqtt.host, rctx.mqtt.port);
+    printf("mqtt uplink %s\n", rctx.mqtt.topic_uplink);
+    printf("mqtt downlink %s\n", rctx.mqtt.topic_downlink);
+#endif
+}
+
+void luat_remotem_set_uplink(luat_remotem_uplink_cb _uplink) {
+    uplink = _uplink;
+}
+
+int luat_remotem_ready(void) {
+    if (uplink == NULL) return 0;
+    return 1;
+}
+
+static void handle_json(cJSON* top);
+
+void luat_remotem_putbuff(char* buff, size_t len) {
+    cJSON* top = cJSON_ParseWithLength((const char*)buff, len);
+    if (top == NULL) {
+        debug_printf("bad JSON income!!!");
+        return;
+    }
+    handle_json(top);
+    cJSON_Delete(top);
+    return;
+}
+
+cJSON* luat_remotem_json_init(cJSON* top) {
+    cJSON_AddNumberToObject(top, "version", 1);
+    cJSON_AddStringToObject(top, "session", "123");
+    cJSON_AddStringToObject(top, "id",      "123");
+    cJSON_AddStringToObject(top, "role",    "client");
+    return cJSON_AddObjectToObject(top,     "data");
+}
+
+int luat_remotem_up(cJSON* top) {
+    if (uplink == NULL)
+        return -1;
+    char* json = cJSON_Print(top);
+    uplink(json, strlen(json));
+    cJSON_free(json);
+    return 0;
+}
+
+static void handle_json(cJSON* top) {
+    // 验证必要的顶层元素
+    cJSON* id       = cJSON_GetObjectItem(top, "id");
+    cJSON* type     = cJSON_GetObjectItem(top, "type");
+    cJSON* session  = cJSON_GetObjectItem(top, "session");
+    cJSON* version  = cJSON_GetObjectItem(top, "version");
+    cJSON* role     = cJSON_GetObjectItem(top, "role");
+    cJSON* data     = cJSON_GetObjectItem(top, "data");
+
+    // 逐一检查是否存在
+    if (id == NULL || id->type != cJSON_String) {
+        debug_printf("json miss id\n");
+        return;
+    }
+    if (type == NULL || type->type != cJSON_String) {
+        debug_printf("json miss type\n");
+        return;
+    }
+    if (session == NULL || session->type != cJSON_String) {
+        debug_printf("json miss session\n");
+        return;
+    }
+    if (version == NULL || version->type != cJSON_Number) {
+        debug_printf("json miss version\n");
+        return;
+    }
+    if (data == NULL) {
+        debug_printf("json miss data\n");
+        return;
+    }
+
+    // 对值进行校验
+    if (version->valueint != 1) {
+        debug_printf("bad version value\n");
+        return;
+    }
+
+    // 进行type进行分类处理
+    for (size_t i = 0; i < 256; i++)
+    {
+        if (opts[i].name == NULL) {
+            printf("unknow json type %s\n", type->valuestring);
+            break;
+        }
+        if (!strcmp(opts[i].name, type->valuestring)) {
+            opts[i].typeopt(top, data);
+            break;
+        }
+    }
+    
+}
+

+ 200 - 0
bsp/emulator/remotem/luat_remotem_mqtt.c

@@ -0,0 +1,200 @@
+/*
+通信层,基于MQTT
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "MQTTAsync.h"
+// #include "MQTTClient.h"
+#include "luat_remotem.h"
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+#if defined(_WRS_KERNEL)
+#include <OsWrapper.h>
+#endif
+
+// #define ADDRESS     "tcp://broker-cn.emqx.io:1883"
+// #define CLIENTID    "123TTTZZVVV"
+// #define SUB_TOPIC       "/sys/luatos/em/test/down"
+// #define PUB_TOPIC       "/sys/luatos/em/test/up"
+// #define PAYLOAD     "Hello World!"
+// #define QOS         1
+#define TIMEOUT     10000L
+
+// int finished = 0;
+
+static MQTTAsync client;
+static boolean mqtt_client_ready;
+static boolean mqtt_client_suback_ready;
+static MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
+static boolean mqtt_client_isconneting;
+
+void luat_remotem_putbuff(char* buff, size_t len);
+
+extern luat_remotem_ctx_t rctx;
+
+static void mqtt_uplink_cb(char* buff, size_t len) {
+	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
+	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
+	pubmsg.payload = buff;
+    pubmsg.payloadlen = len;
+    pubmsg.qos = 1;
+    pubmsg.retained = 0;
+    int rc = 0;
+    if ((rc = MQTTAsync_sendMessage(client, rctx.mqtt.topic_uplink, &pubmsg, NULL)) != MQTTASYNC_SUCCESS)
+    {
+    	printf("Failed to publish message, return code %d\n", rc);
+    	rc = EXIT_FAILURE;
+    }
+}
+
+void connlost(void *context, char *cause)
+{
+	MQTTAsync client = (MQTTAsync)context;
+	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
+	int rc;
+
+	printf("\nConnection lost\n");
+	printf("     cause: %s\n", cause);
+
+	Sleep(2000);
+
+	printf("Reconnecting\n");
+	conn_opts.keepAliveInterval = 20;
+	conn_opts.cleansession = 1;
+	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
+	{
+		printf("Failed to start connect, return code %d\n", rc);
+ 		// finished = 1;
+	}
+}
+
+void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
+{
+	printf("Disconnect failed\n");
+	// finished = 1;
+}
+
+void onDisconnect(void* context, MQTTAsync_successData* response)
+{
+	printf("Successful disconnection\n");
+	// finished = 1;
+}
+
+void onSendFailure(void* context, MQTTAsync_failureData* response)
+{
+	MQTTAsync client = (MQTTAsync)context;
+	MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
+	int rc;
+
+	printf("Message send failed token %d error code %d\n", response->token, response->code);
+	opts.onSuccess = onDisconnect;
+	opts.onFailure = onDisconnectFailure;
+	opts.context = client;
+	if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
+	{
+		printf("Failed to start disconnect, return code %d\n", rc);
+		exit(EXIT_FAILURE);
+	}
+}
+
+void onSend(void* context, MQTTAsync_successData* response)
+{
+	
+}
+
+
+void onConnectFailure(void* context, MQTTAsync_failureData* response)
+{
+	printf("Connect failed, rc %d\n", response ? response->code : 0);
+	// finished = 1;
+}
+
+void onSubscribe(void* context, MQTTAsync_successData* response)
+{
+	// printf("Subscribe succeeded\n");
+	// subscribed = 1;
+	mqtt_client_suback_ready = TRUE;
+}
+
+void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
+{
+	printf("Subscribe failed, rc %d\n", response->code);
+	// finished = 1;
+}
+
+void onConnect(void* context, MQTTAsync_successData* response)
+{
+	MQTTAsync client = (MQTTAsync)context;
+	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
+	int rc;
+
+	printf("mqtt connect ok\n");
+	opts.onSuccess = onSubscribe;
+	opts.onFailure = onSubscribeFailure;
+	opts.context = client;
+	rc = MQTTAsync_subscribe(client, rctx.mqtt.topic_downlink, 1, &opts);
+}
+
+int messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* m)
+{
+	luat_remotem_putbuff((char*)m->payload, m->payloadlen);
+	return 1;
+}
+
+int mqtt_main(void)
+{
+	mqtt_client_ready = FALSE;
+	int rc;
+	char mqtturl[512];
+	sprintf(mqtturl, "%s://%s:%d", rctx.mqtt.protocol, rctx.mqtt.host, rctx.mqtt.port);
+
+	if ((rc = MQTTAsync_create(&client, mqtturl, rctx.self_id, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTASYNC_SUCCESS)
+	{
+		printf("Failed to create client object, return code %d\n", rc);
+		exit(EXIT_FAILURE);
+	}
+
+	if ((rc = MQTTAsync_setCallbacks(client, NULL, connlost, messageArrived, NULL)) != MQTTASYNC_SUCCESS)
+	{
+		printf("Failed to set callback, return code %d\n", rc);
+		exit(EXIT_FAILURE);
+	}
+
+	conn_opts.keepAliveInterval = 20;
+	conn_opts.cleansession = 1;
+	conn_opts.onSuccess = onConnect;
+	conn_opts.onFailure = onConnectFailure;
+	conn_opts.context = client;
+
+	mqtt_client_ready = TRUE;
+	mqtt_client_suback_ready = FALSE;
+
+	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
+	{
+		printf("Failed to start connect, return code %d\n", rc);
+		exit(EXIT_FAILURE);
+	}
+
+	size_t wait_time = 15;
+	size_t wait_ms = 10;
+	for (size_t i = 0; i < wait_time * (1000 / wait_ms); i++)
+	{
+		if (mqtt_client_ready && MQTTAsync_isConnected(client) && mqtt_client_suback_ready) {
+			printf("mqtt link ready\n");
+			// 发送初始化命令
+			luat_remotem_set_uplink(mqtt_uplink_cb);
+			break;
+		}
+		Sleep(wait_ms);
+	}
+
+    return rc;
+}
+

+ 40 - 0
bsp/emulator/remotem/luat_remotem_typeopt_base.c

@@ -0,0 +1,40 @@
+/*
+处理基本的remotem命令
+*/
+#include "luat_base.h"
+#include "luat_remotem.h"
+#include "luat_malloc.h"
+
+extern void luat_str_fromhex(char* str, size_t len, char* buff);
+
+// 初始包, 主要是为了确认交互通畅
+void luat_remotem_typeopt_init(cJSON* top, cJSON* data) {
+    // nop yet
+}
+
+// 心跳包, 还没确定是否需要
+void luat_remotem_typeopt_ping(cJSON* top, cJSON* data) {
+    // nop yet
+}
+
+// 服务器下发的日志, 直接在输出
+void luat_remotem_typeopt_log(cJSON* top, cJSON* data) {
+    //printf("json log income\n");
+    cJSON* value = cJSON_GetObjectItem(data, "value");
+    if (value == NULL || value->type != cJSON_String) {
+        return;
+    }
+    size_t slen = strlen(value->valuestring) / 2;
+    //printf("json log len %d\n", slen);
+    char* buff = luat_heap_malloc(slen);
+    if (buff == NULL) {
+        return;
+    }
+    memset(buff, 0, slen);
+    luat_str_fromhex(value->valuestring, slen*2, buff);
+    for (size_t i = 0; i < slen; i++)
+    {
+        fputc(buff[i], stdout);
+    }
+
+}

+ 50 - 0
bsp/emulator/remotem/luat_remotem_typeopt_indev.c

@@ -0,0 +1,50 @@
+/*
+处理输入设备的remotem命令
+*/
+#include "luat_base.h"
+#include "luat_remotem.h"
+#include "luat_malloc.h"
+
+#include "lvgl.h"
+
+static lv_indev_data_t point_emulator_data = {0};
+
+extern void luat_str_fromhex(char* str, size_t len, char* buff);
+
+static bool point_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data) {
+    memcpy(data, drv->user_data, sizeof(lv_indev_data_t));
+    // if (((lv_indev_data_t*)drv->user_data)->state == LV_INDEV_STATE_PR){
+    //     ((lv_indev_data_t*)drv->user_data)->state == LV_INDEV_STATE_REL;
+    // }
+    return false;
+}
+
+// 输入设备, 模拟鼠标点击/触摸屏点击
+void luat_remotem_typeopt_indev(cJSON* top, cJSON* data) {
+    cJSON* opt = cJSON_GetObjectItem(data, "opt");
+    if (opt == NULL || opt->type != cJSON_String) {
+        return;
+    }
+    if (!strcmp("pointer", opt->valuestring)) {
+        cJSON* pointer = cJSON_GetObjectItem(data, "pointer");
+        if (pointer) {
+            cJSON* x = cJSON_GetObjectItem(pointer, "x");
+            cJSON* y = cJSON_GetObjectItem(pointer, "y");
+            cJSON* state = cJSON_GetObjectItem(pointer, "state");
+            if (x != NULL && y != NULL && state != NULL) {
+                point_emulator_data.point.x = x->valueint;
+                point_emulator_data.point.y = y->valueint;
+                point_emulator_data.state = state->valueint;
+            }
+        }
+    }
+}
+
+void luat_remotem_indev_init(void) {
+    lv_indev_drv_t indev_drv;
+    lv_indev_drv_init(&indev_drv);
+    indev_drv.user_data = &point_emulator_data;
+    memset(indev_drv.user_data, 0, sizeof(lv_indev_data_t));
+    indev_drv.read_cb = point_input_read;
+    lv_indev_drv_register(&indev_drv);
+}

+ 614 - 0
bsp/emulator/src/lua.c

@@ -0,0 +1,614 @@
+/*
+** $Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp $
+** Lua stand-alone interpreter
+** See Copyright Notice in lua.h
+*/
+
+#define lua_c
+
+#include "lprefix.h"
+
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+LUALIB_API void luat_openlibs (lua_State *L);
+
+#if !defined(LUA_PROMPT)
+#define LUA_PROMPT		"> "
+#define LUA_PROMPT2		">> "
+#endif
+
+#if !defined(LUA_PROGNAME)
+#define LUA_PROGNAME		"lua"
+#endif
+
+#if !defined(LUA_MAXINPUT)
+#define LUA_MAXINPUT		512
+#endif
+
+#if !defined(LUA_INIT_VAR)
+#define LUA_INIT_VAR		"LUA_INIT"
+#endif
+
+#define LUA_INITVARVERSION	LUA_INIT_VAR LUA_VERSUFFIX
+
+
+/*
+** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
+** is, whether we're running lua interactively).
+*/
+#if !defined(lua_stdin_is_tty)	/* { */
+
+#if defined(LUA_USE_POSIX)	/* { */
+
+#include <unistd.h>
+#define lua_stdin_is_tty()	isatty(0)
+
+#elif defined(LUA_USE_WINDOWS)	/* }{ */
+
+#include <io.h>
+#include <windows.h>
+
+#define lua_stdin_is_tty()	_isatty(_fileno(stdin))
+
+#else				/* }{ */
+
+/* ISO C definition */
+#define lua_stdin_is_tty()	1  /* assume stdin is a tty */
+
+#endif				/* } */
+
+#endif				/* } */
+
+
+/*
+** lua_readline defines how to show a prompt and then read a line from
+** the standard input.
+** lua_saveline defines how to "save" a read line in a "history".
+** lua_freeline defines how to free a line read by lua_readline.
+*/
+#if !defined(lua_readline)	/* { */
+
+#if defined(LUA_USE_READLINE)	/* { */
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
+#define lua_saveline(L,line)	((void)L, add_history(line))
+#define lua_freeline(L,b)	((void)L, free(b))
+
+#else				/* }{ */
+
+#define lua_readline(L,b,p) \
+        ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
+        fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
+#define lua_saveline(L,line)	{ (void)L; (void)line; }
+#define lua_freeline(L,b)	{ (void)L; (void)b; }
+
+#endif				/* } */
+
+#endif				/* } */
+
+
+
+
+static lua_State *globalL = NULL;
+
+static const char *progname = LUA_PROGNAME;
+
+
+/*
+** Hook set by signal function to stop the interpreter.
+*/
+static void lstop (lua_State *L, lua_Debug *ar) {
+  (void)ar;  /* unused arg. */
+  lua_sethook(L, NULL, 0, 0);  /* reset hook */
+  luaL_error(L, "interrupted!");
+}
+
+
+/*
+** Function to be called at a C signal. Because a C signal cannot
+** just change a Lua state (as there is no proper synchronization),
+** this function only sets a hook that, when called, will stop the
+** interpreter.
+*/
+static void laction (int i) {
+  signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
+  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+}
+
+
+static void print_usage (const char *badoption) {
+  lua_writestringerror("%s: ", progname);
+  if (badoption[1] == 'e' || badoption[1] == 'l')
+    lua_writestringerror("'%s' needs argument\n", badoption);
+  else
+    lua_writestringerror("unrecognized option '%s'\n", badoption);
+  lua_writestringerror(
+  "usage: %s [options] [script [args]]\n"
+  "Available options are:\n"
+  "  -e stat  execute string 'stat'\n"
+  "  -i       enter interactive mode after executing 'script'\n"
+  "  -l name  require library 'name' into global 'name'\n"
+  "  -v       show version information\n"
+  "  -E       ignore environment variables\n"
+  "  --       stop handling options\n"
+  "  -        stop handling options and execute stdin\n"
+  ,
+  progname);
+}
+
+
+/*
+** Prints an error message, adding the program name in front of it
+** (if present)
+*/
+static void l_message (const char *pname, const char *msg) {
+  if (pname) lua_writestringerror("%s: ", pname);
+  lua_writestringerror("%s\n", msg);
+}
+
+
+/*
+** Check whether 'status' is not OK and, if so, prints the error
+** message on the top of the stack. It assumes that the error object
+** is a string, as it was either generated by Lua or by 'msghandler'.
+*/
+static int report (lua_State *L, int status) {
+  if (status != LUA_OK) {
+    const char *msg = lua_tostring(L, -1);
+    l_message(progname, msg);
+    lua_pop(L, 1);  /* remove message */
+  }
+  return status;
+}
+
+
+/*
+** Message handler used to run all chunks
+*/
+static int msghandler (lua_State *L) {
+  const char *msg = lua_tostring(L, 1);
+  if (msg == NULL) {  /* is error object not a string? */
+    if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
+        lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
+      return 1;  /* that is the message */
+    else
+      msg = lua_pushfstring(L, "(error object is a %s value)",
+                               luaL_typename(L, 1));
+  }
+  luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
+  return 1;  /* return the traceback */
+}
+
+
+/*
+** Interface to 'lua_pcall', which sets appropriate message function
+** and C-signal handler. Used to run all chunks.
+*/
+static int docall (lua_State *L, int narg, int nres) {
+  int status;
+  int base = lua_gettop(L) - narg;  /* function index */
+  lua_pushcfunction(L, msghandler);  /* push message handler */
+  lua_insert(L, base);  /* put it under function and args */
+  globalL = L;  /* to be available to 'laction' */
+  signal(SIGINT, laction);  /* set C-signal handler */
+  status = lua_pcall(L, narg, nres, base);
+  signal(SIGINT, SIG_DFL); /* reset C-signal handler */
+  lua_remove(L, base);  /* remove message handler from the stack */
+  return status;
+}
+
+
+static void print_version (void) {
+  lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
+  lua_writeline();
+  lua_writestring("Enhance by LuatOS. call os.exit() for quit", strlen("Enhance by LuatOS. call os.exit() for quit"));
+  lua_writeline();
+}
+
+
+/*
+** Create the 'arg' table, which stores all arguments from the
+** command line ('argv'). It should be aligned so that, at index 0,
+** it has 'argv[script]', which is the script name. The arguments
+** to the script (everything after 'script') go to positive indices;
+** other arguments (before the script name) go to negative indices.
+** If there is no script name, assume interpreter's name as base.
+*/
+static void createargtable (lua_State *L, char **argv, int argc, int script) {
+  int i, narg;
+  if (script == argc) script = 0;  /* no script name? */
+  narg = argc - (script + 1);  /* number of positive indices */
+  lua_createtable(L, narg, script + 1);
+  for (i = 0; i < argc; i++) {
+    lua_pushstring(L, argv[i]);
+    lua_rawseti(L, -2, i - script);
+  }
+  lua_setglobal(L, "arg");
+}
+
+
+static int dochunk (lua_State *L, int status) {
+  if (status == LUA_OK) status = docall(L, 0, 0);
+  return report(L, status);
+}
+
+
+static int dofile (lua_State *L, const char *name) {
+  return dochunk(L, luaL_loadfile(L, name));
+}
+
+
+static int dostring (lua_State *L, const char *s, const char *name) {
+  return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
+}
+
+
+/*
+** Calls 'require(name)' and stores the result in a global variable
+** with the given name.
+*/
+static int dolibrary (lua_State *L, const char *name) {
+  int status;
+  lua_getglobal(L, "require");
+  lua_pushstring(L, name);
+  status = docall(L, 1, 1);  /* call 'require(name)' */
+  if (status == LUA_OK)
+    lua_setglobal(L, name);  /* global[name] = require return */
+  return report(L, status);
+}
+
+
+/*
+** Returns the string to be used as a prompt by the interpreter.
+*/
+static const char *get_prompt (lua_State *L, int firstline) {
+  const char *p;
+  lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
+  p = lua_tostring(L, -1);
+  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
+  return p;
+}
+
+/* mark in error messages for incomplete statements */
+#define EOFMARK		"<eof>"
+#define marklen		(sizeof(EOFMARK)/sizeof(char) - 1)
+
+
+/*
+** Check whether 'status' signals a syntax error and the error
+** message at the top of the stack ends with the above mark for
+** incomplete statements.
+*/
+static int incomplete (lua_State *L, int status) {
+  if (status == LUA_ERRSYNTAX) {
+    size_t lmsg;
+    const char *msg = lua_tolstring(L, -1, &lmsg);
+    if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
+      lua_pop(L, 1);
+      return 1;
+    }
+  }
+  return 0;  /* else... */
+}
+
+
+/*
+** Prompt the user, read a line, and push it into the Lua stack.
+*/
+static int pushline (lua_State *L, int firstline) {
+  char buffer[LUA_MAXINPUT];
+  char *b = buffer;
+  size_t l;
+  const char *prmt = get_prompt(L, firstline);
+  int readstatus = lua_readline(L, b, prmt);
+  if (readstatus == 0)
+    return 0;  /* no input (prompt will be popped by caller) */
+  lua_pop(L, 1);  /* remove prompt */
+  l = strlen(b);
+  if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
+    b[--l] = '\0';  /* remove it */
+  if (firstline && b[0] == '=')  /* for compatibility with 5.2, ... */
+    lua_pushfstring(L, "return %s", b + 1);  /* change '=' to 'return' */
+  else
+    lua_pushlstring(L, b, l);
+  lua_freeline(L, b);
+  return 1;
+}
+
+
+/*
+** Try to compile line on the stack as 'return <line>;'; on return, stack
+** has either compiled chunk or original line (if compilation failed).
+*/
+static int addreturn (lua_State *L) {
+  const char *line = lua_tostring(L, -1);  /* original line */
+  const char *retline = lua_pushfstring(L, "return %s;", line);
+  int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
+  if (status == LUA_OK) {
+    lua_remove(L, -2);  /* remove modified line */
+    if (line[0] != '\0')  /* non empty? */
+      lua_saveline(L, line);  /* keep history */
+  }
+  else
+    lua_pop(L, 2);  /* pop result from 'luaL_loadbuffer' and modified line */
+  return status;
+}
+
+
+/*
+** Read multiple lines until a complete Lua statement
+*/
+static int multiline (lua_State *L) {
+  for (;;) {  /* repeat until gets a complete statement */
+    size_t len;
+    const char *line = lua_tolstring(L, 1, &len);  /* get what it has */
+    int status = luaL_loadbuffer(L, line, len, "=stdin");  /* try it */
+    if (!incomplete(L, status) || !pushline(L, 0)) {
+      lua_saveline(L, line);  /* keep history */
+      return status;  /* cannot or should not try to add continuation line */
+    }
+    lua_pushliteral(L, "\n");  /* add newline... */
+    lua_insert(L, -2);  /* ...between the two lines */
+    lua_concat(L, 3);  /* join them */
+  }
+}
+
+
+/*
+** Read a line and try to load (compile) it first as an expression (by
+** adding "return " in front of it) and second as a statement. Return
+** the final status of load/call with the resulting function (if any)
+** in the top of the stack.
+*/
+static int loadline (lua_State *L) {
+  int status;
+  lua_settop(L, 0);
+  if (!pushline(L, 1))
+    return -1;  /* no input */
+  if ((status = addreturn(L)) != LUA_OK)  /* 'return ...' did not work? */
+    status = multiline(L);  /* try as command, maybe with continuation lines */
+  lua_remove(L, 1);  /* remove line from the stack */
+  lua_assert(lua_gettop(L) == 1);
+  return status;
+}
+
+
+/*
+** Prints (calling the Lua 'print' function) any values on the stack
+*/
+static void l_print (lua_State *L) {
+  int n = lua_gettop(L);
+  if (n > 0) {  /* any result to be printed? */
+    luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
+    lua_getglobal(L, "print");
+    lua_insert(L, 1);
+    if (lua_pcall(L, n, 0, 0) != LUA_OK)
+      l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
+                                             lua_tostring(L, -1)));
+  }
+}
+
+
+/*
+** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and
+** print any results.
+*/
+static void doREPL (lua_State *L) {
+  int status;
+  const char *oldprogname = progname;
+  progname = NULL;  /* no 'progname' on errors in interactive mode */
+  while ((status = loadline(L)) != -1) {
+    if (status == LUA_OK)
+      status = docall(L, 0, LUA_MULTRET);
+    if (status == LUA_OK) l_print(L);
+    else report(L, status);
+  }
+  lua_settop(L, 0);  /* clear stack */
+  lua_writeline();
+  progname = oldprogname;
+}
+
+
+/*
+** Push on the stack the contents of table 'arg' from 1 to #arg
+*/
+static int pushargs (lua_State *L) {
+  int i, n;
+  if (lua_getglobal(L, "arg") != LUA_TTABLE)
+    luaL_error(L, "'arg' is not a table");
+  n = (int)luaL_len(L, -1);
+  luaL_checkstack(L, n + 3, "too many arguments to script");
+  for (i = 1; i <= n; i++)
+    lua_rawgeti(L, -i, i);
+  lua_remove(L, -i);  /* remove table from the stack */
+  return n;
+}
+
+
+static int handle_script (lua_State *L, char **argv) {
+  int status;
+  const char *fname = argv[0];
+  if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
+    fname = NULL;  /* stdin */
+  status = luaL_loadfile(L, fname);
+  if (status == LUA_OK) {
+    int n = pushargs(L);  /* push arguments to script */
+    status = docall(L, n, LUA_MULTRET);
+  }
+  return report(L, status);
+}
+
+
+
+/* bits of various argument indicators in 'args' */
+#define has_error	1	/* bad option */
+#define has_i		2	/* -i */
+#define has_v		4	/* -v */
+#define has_e		8	/* -e */
+#define has_E		16	/* -E */
+
+/*
+** Traverses all arguments from 'argv', returning a mask with those
+** needed before running any Lua code (or an error code if it finds
+** any invalid argument). 'first' returns the first not-handled argument
+** (either the script name or a bad argument in case of error).
+*/
+static int collectargs (char **argv, int *first) {
+  int args = 0;
+  int i;
+  for (i = 1; argv[i] != NULL; i++) {
+    *first = i;
+    if (argv[i][0] != '-')  /* not an option? */
+        return args;  /* stop handling options */
+    switch (argv[i][1]) {  /* else check option */
+      case '-':  /* '--' */
+        if (argv[i][2] != '\0')  /* extra characters after '--'? */
+          return has_error;  /* invalid option */
+        *first = i + 1;
+        return args;
+      case '\0':  /* '-' */
+        return args;  /* script "name" is '-' */
+      case 'E':
+        if (argv[i][2] != '\0')  /* extra characters after 1st? */
+          return has_error;  /* invalid option */
+        args |= has_E;
+        break;
+      case 'i':
+        args |= has_i;  /* (-i implies -v) *//* FALLTHROUGH */
+      case 'v':
+        if (argv[i][2] != '\0')  /* extra characters after 1st? */
+          return has_error;  /* invalid option */
+        args |= has_v;
+        break;
+      case 'e':
+        args |= has_e;  /* FALLTHROUGH */
+      case 'l':  /* both options need an argument */
+        if (argv[i][2] == '\0') {  /* no concatenated argument? */
+          i++;  /* try next 'argv' */
+          if (argv[i] == NULL || argv[i][0] == '-')
+            return has_error;  /* no next argument or it is another option */
+        }
+        break;
+      default:  /* invalid option */
+        return has_error;
+    }
+  }
+  *first = i;  /* no script name */
+  return args;
+}
+
+
+/*
+** Processes options 'e' and 'l', which involve running Lua code.
+** Returns 0 if some code raises an error.
+*/
+static int runargs (lua_State *L, char **argv, int n) {
+  int i;
+  for (i = 1; i < n; i++) {
+    int option = argv[i][1];
+    lua_assert(argv[i][0] == '-');  /* already checked */
+    if (option == 'e' || option == 'l') {
+      int status;
+      const char *extra = argv[i] + 2;  /* both options need an argument */
+      if (*extra == '\0') extra = argv[++i];
+      lua_assert(extra != NULL);
+      status = (option == 'e')
+               ? dostring(L, extra, "=(command line)")
+               : dolibrary(L, extra);
+      if (status != LUA_OK) return 0;
+    }
+  }
+  return 1;
+}
+
+
+
+static int handle_luainit (lua_State *L) {
+  const char *name = "=" LUA_INITVARVERSION;
+  const char *init = getenv(name + 1);
+  if (init == NULL) {
+    name = "=" LUA_INIT_VAR;
+    init = getenv(name + 1);  /* try alternative name */
+  }
+  if (init == NULL) return LUA_OK;
+  else if (init[0] == '@')
+    return dofile(L, init+1);
+  else
+    return dostring(L, init, name);
+}
+
+
+/*
+** Main body of stand-alone interpreter (to be called in protected mode).
+** Reads the options and handles them all.
+*/
+static int pmain (lua_State *L) {
+  int argc = (int)lua_tointeger(L, 1);
+  char **argv = (char **)lua_touserdata(L, 2);
+  int script;
+  int args = collectargs(argv, &script);
+  luaL_checkversion(L);  /* check that interpreter has correct version */
+  if (argv[0] && argv[0][0]) progname = argv[0];
+  if (args == has_error) {  /* bad arg? */
+    print_usage(argv[script]);  /* 'script' has index of bad arg. */
+    return 0;
+  }
+  if (args & has_v)  /* option '-v'? */
+    print_version();
+  if (args & has_E) {  /* option '-E'? */
+    lua_pushboolean(L, 1);  /* signal for libraries to ignore env. vars. */
+    lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+  }
+  luat_openlibs(L);  /* open standard libraries */
+  createargtable(L, argv, argc, script);  /* create table 'arg' */
+  if (!(args & has_E)) {  /* no option '-E'? */
+    if (handle_luainit(L) != LUA_OK)  /* run LUA_INIT */
+      return 0;  /* error running LUA_INIT */
+  }
+  if (!runargs(L, argv, script))  /* execute arguments -e and -l */
+    return 0;  /* something failed */
+  if (script < argc &&  /* execute main script (if there is one) */
+      handle_script(L, argv + script) != LUA_OK)
+    return 0;
+  if (args & has_i)  /* -i option? */
+    doREPL(L);  /* do read-eval-print loop */
+  else if (script == argc && !(args & (has_e | has_v))) {  /* no arguments? */
+    if (lua_stdin_is_tty()) {  /* running in interactive mode? */
+      print_version();
+      doREPL(L);  /* do read-eval-print loop */
+    }
+    else dofile(L, NULL);  /* executes stdin as a file */
+  }
+  lua_pushboolean(L, 1);  /* signal no errors */
+  return 1;
+}
+
+void* luat_heap_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
+
+int lua_main (int argc, char **argv) {
+  int status, result;
+  lua_State *L = lua_newstate(luat_heap_alloc, NULL);;  /* create state */
+  if (L == NULL) {
+    l_message(argv[0], "cannot create state: not enough memory");
+    return EXIT_FAILURE;
+  }
+  lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */
+  lua_pushinteger(L, argc);  /* 1st argument */
+  lua_pushlightuserdata(L, argv); /* 2nd argument */
+  status = lua_pcall(L, 2, 1, 0);  /* do the call */
+  result = lua_toboolean(L, -1);  /* get result */
+  report(L, status);
+  lua_close(L);
+  return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 73 - 0
bsp/emulator/src/main_emulator.c

@@ -0,0 +1,73 @@
+
+#include <stdio.h>
+
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_msgbus.h"
+#include "luat_fs.h"
+
+#include "bget.h"
+
+#define LUAT_LOG_TAG "main"
+#include "luat_log.h"
+
+// #include "FreeRTOS.h"
+// #include "task.h"
+#include "windows.h"
+#include <unistd.h>
+#include "luat_remotem.h"
+
+#ifdef LUAT_USE_LVGL
+#include "lvgl.h"
+#endif
+
+#define LUAT_HEAP_SIZE (1024*1024)
+uint8_t luavm_heap[LUAT_HEAP_SIZE] = {0};
+
+int cmdline_argc;
+char** cmdline_argv;
+
+int lua_main (int argc, char **argv);
+
+void luat_log_init_win32(void);
+
+static void _luat_main(void* args) {
+    //luat_main();
+    luat_fs_init();
+    lua_main(cmdline_argc, cmdline_argv);
+    exit(0);
+}
+
+
+BOOL WINAPI consoleHandler(DWORD signal) {
+    if (signal == CTRL_C_EVENT) {
+        printf("Ctrl-C handled\n"); // do cleanup
+        exit(1);
+    }
+    return TRUE;
+}
+
+// boot
+int main(int argc, char** argv) {
+    cmdline_argc = argc;
+    cmdline_argv = argv;
+
+    luat_remotem_init(argc, argv);
+
+    SetConsoleCtrlHandler(consoleHandler, TRUE);
+    bpool(luavm_heap, LUAT_HEAP_SIZE);
+
+    luat_msgbus_init();
+
+#ifdef LUAT_USE_LVGL
+    lv_init();
+#endif
+
+    extern int mqtt_main(void);
+    mqtt_main();
+
+    // xTaskCreate( _luat_main, "luatos", 1024*16, NULL, 21, NULL );
+    // vTaskStartScheduler();
+    luat_main();
+    return 0;
+}