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

add: 添加独立的bsp/linux,基本功能ok,但GUI还有问题

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

+ 129 - 0
bsp/linux/CMakeLists.txt

@@ -0,0 +1,129 @@
+
+
+# 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} -O2 -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
+                    ${TOPROOT}/components/freertos/include
+                    )
+
+include_directories(
+/usr/include/gtk-3.0 
+/usr/include/at-spi2-atk/2.0 
+/usr/include/at-spi-2.0 
+/usr/include/dbus-1.0 
+/usr/lib/arm-linux-gnueabihf/dbus-1.0/include 
+/usr/include/gtk-3.0 
+/usr/include/gio-unix-2.0 
+/usr/include/cairo 
+/usr/include/pango-1.0 
+/usr/include/harfbuzz 
+/usr/include/pango-1.0 
+/usr/include/fribidi 
+/usr/include/atk-1.0 
+/usr/include/cairo 
+/usr/include/pixman-1 
+/usr/include/freetype2 
+/usr/include/libpng16 
+/usr/include/gdk-pixbuf-2.0 
+/usr/include/libmount 
+/usr/include/blkid 
+/usr/include/uuid 
+/usr/include/glib-2.0 
+/usr/lib/arm-linux-gnueabihf/glib-2.0/include
+)
+
+include_directories(${TOPROOT}/components/freertos/portable/ThirdParty/GCC/Posix)
+include_directories(${TOPROOT}/components/freertos/portable/ThirdParty/GCC/Posix/utils)
+aux_source_directory(${TOPROOT}/components/freertos/portable/ThirdParty/GCC/Posix MM_SRCS)
+aux_source_directory(${TOPROOT}/components/freertos/portable/ThirdParty/GCC/Posix/utils MM2_SRCS)
+
+include_directories(${TOPROOT}/luat/packages/lfs)
+include_directories(${TOPROOT}/components/lcd)
+
+aux_source_directory(./port PORT_SRCS)
+aux_source_directory(${TOPROOT}/lua/src LUA_SRCS)
+#aux_source_directory(${TOPROOT}/luat/freertos FTOS_T_SRCS)
+aux_source_directory(${TOPROOT}/components/freertos RTOS_SRCS)
+aux_source_directory(${TOPROOT}/components/freertos/port RTOS_PORT_SRCS)
+aux_source_directory(${TOPROOT}/luat/packages/lua-cjson CJSON_SRCS)
+
+aux_source_directory(${TOPROOT}/components/lcd LCD_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})
+add_library(cjson ${CJSON_SRCS})
+add_library(luat ${TOPROOT}/luat/modules/luat_main.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}/components/sfd/luat_lib_sfd.c
+                 ${TOPROOT}/components/sfd/luat_sfd_mem.c
+                 ${TOPROOT}/components/sfd/luat_sfd_w25q.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_luadb_inline.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)
+add_subdirectory(${TOPROOT}/components/lvgl lvgl.out)
+#-----------------------
+
+
+
+add_executable(luatos src/main.c)
+target_link_libraries(luat freertos10 pthread fatfs lvgl)
+target_link_libraries(luatos freertos10 lua luatos_msys fatfs luat pthread cjson mbedtls lvgl m
+gtk-3 gdk-3 pangocairo-1.0 pango-1.0 atk-1.0 cairo-gobject cairo gdk_pixbuf-2.0 gio-2.0 gobject-2.0 glib-2.0
+)
+

+ 45 - 0
bsp/linux/README.md

@@ -0,0 +1,45 @@
+
+# LuatOS@Linux
+
+* 底层rtos FreeRTOSv202012.00
+* 编译工具cmake/make/gcc
+* 文件系统,posix原生文件系统,以工作目录为基点
+* 默认luavm和rtos内存分配均为 1MByte
+
+## 简易编译说明
+
+```sh
+cd bsp/linux
+mkdir build
+cd build
+cmake ..
+make
+```
+
+编译完成后, 会在build目录生成 `luatos`
+
+## 简单用法
+
+```sh
+./luatos
+```
+
+```lua
+local sys = require "sys"
+
+log.info("sys", "from win32")
+
+sys.taskInit(function ()
+    while true do
+        log.info("hi", os.date())
+        log.info("sys", rtos.meminfo("sys"))
+        log.info("lua", rtos.meminfo("lua"))
+        sys.wait(1000)
+    end
+end)
+
+sys.run()
+```
+
+
+

+ 162 - 0
bsp/linux/include/FreeRTOSConfig.h

@@ -0,0 +1,162 @@
+/*
+ * FreeRTOS V202012.00
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  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.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.  See
+ * http://www.freertos.org/a00110.html
+ *----------------------------------------------------------*/
+
+#define configUSE_PREEMPTION					1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION	0
+#define configUSE_IDLE_HOOK						1
+#define configUSE_TICK_HOOK						1
+#define configUSE_DAEMON_TASK_STARTUP_HOOK		1
+#define configTICK_RATE_HZ						( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */
+#define configMINIMAL_STACK_SIZE				( ( unsigned short ) 70 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */
+#define configTOTAL_HEAP_SIZE					( ( size_t ) ( 512 * 1024 ) )
+#define configMAX_TASK_NAME_LEN					( 12 )
+#define configUSE_TRACE_FACILITY				1
+#define configUSE_16_BIT_TICKS					0
+#define configIDLE_SHOULD_YIELD					1
+#define configUSE_MUTEXES						1
+#define configCHECK_FOR_STACK_OVERFLOW			0
+#define configUSE_RECURSIVE_MUTEXES				1
+#define configQUEUE_REGISTRY_SIZE				20
+#define configUSE_APPLICATION_TASK_TAG			1
+#define configUSE_COUNTING_SEMAPHORES			1
+#define configUSE_ALTERNATIVE_API				0
+#define configUSE_QUEUE_SETS					1
+#define configUSE_TASK_NOTIFICATIONS			1
+#define configSUPPORT_STATIC_ALLOCATION			1
+
+/* Software timer related configuration options.  The maximum possible task
+priority is configMAX_PRIORITIES - 1.  The priority of the timer task is
+deliberately set higher to ensure it is correctly capped back to
+configMAX_PRIORITIES - 1. */
+#define configUSE_TIMERS						1
+#define configTIMER_TASK_PRIORITY				( configMAX_PRIORITIES - 1 )
+#define configTIMER_QUEUE_LENGTH				20
+#define configTIMER_TASK_STACK_DEPTH			( configMINIMAL_STACK_SIZE * 2 )
+
+#define configMAX_PRIORITIES					( 7 )
+
+/* Run time stats gathering configuration options. */
+unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
+void vConfigureTimerForRunTimeStats( void );	/* Prototype of function that initialises the run time counter. */
+#define configGENERATE_RUN_TIME_STATS			0
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats()
+#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue()
+
+/* Co-routine related configuration options. */
+#define configUSE_CO_ROUTINES 					0
+#define configMAX_CO_ROUTINE_PRIORITIES			( 2 )
+
+/* This demo can use of one or more example stats formatting functions.  These
+format the raw data provided by the uxTaskGetSystemState() function in to human
+readable ASCII form.  See the notes in the implementation of vTaskList() within
+FreeRTOS/Source/tasks.c for limitations. */
+#define configUSE_STATS_FORMATTING_FUNCTIONS	0
+
+/* Enables the test whereby a stack larger than the total heap size is
+requested. */
+#define configSTACK_DEPTH_TYPE uint32_t
+
+/* Set the following definitions to 1 to include the API function, or zero
+to exclude the API function.  In most cases the linker will remove unused
+functions anyway. */
+#define INCLUDE_vTaskPrioritySet				1
+#define INCLUDE_uxTaskPriorityGet				1
+#define INCLUDE_vTaskDelete						1
+#define INCLUDE_vTaskCleanUpResources			0
+#define INCLUDE_vTaskSuspend					1
+#define INCLUDE_vTaskDelayUntil					1
+#define INCLUDE_vTaskDelay						1
+#define INCLUDE_uxTaskGetStackHighWaterMark		1
+#define INCLUDE_uxTaskGetStackHighWaterMark2	1
+#define INCLUDE_xTaskGetSchedulerState			1
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle	1
+#define INCLUDE_xTaskGetIdleTaskHandle			1
+#define INCLUDE_xTaskGetHandle					1
+#define INCLUDE_eTaskGetState					1
+#define INCLUDE_xSemaphoreGetMutexHolder		1
+#define INCLUDE_xTimerPendFunctionCall			1
+#define INCLUDE_xTaskAbortDelay					1
+
+#define projCOVERAGE_TEST                       0
+
+#define configINCLUDE_MESSAGE_BUFFER_AMP_DEMO	0
+#if ( configINCLUDE_MESSAGE_BUFFER_AMP_DEMO == 1 )
+	extern void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer );
+	#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
+#endif /* configINCLUDE_MESSAGE_BUFFER_AMP_DEMO */
+
+extern void vAssertCalled( unsigned long ulLine, const char * const pcFileName );
+
+/* projCOVERAGE_TEST should be defined on the command line so this file can be
+used with multiple project configurations.  If it is
+ */
+#ifndef projCOVERAGE_TEST
+	#error projCOVERAGE_TEST should be defined to 1 or 0 on the command line.
+#endif
+
+#if( projCOVERAGE_TEST == 1 )
+	/* Insert NOPs in empty decision paths to ensure both true and false paths
+	are being tested. */
+	#define mtCOVERAGE_TEST_MARKER() __asm volatile( "NOP" )
+
+	/* Ensure the tick count overflows during the coverage test. */
+	#define configINITIAL_TICK_COUNT 0xffffd800UL
+
+	/* Allows tests of trying to allocate more than the heap has free. */
+	#define configUSE_MALLOC_FAILED_HOOK			0
+
+	/* To test builds that remove the static qualifier for debug builds. */
+	#define portREMOVE_STATIC_QUALIFIER
+#else
+	/* It is a good idea to define configASSERT() while developing.  configASSERT()
+	uses the same semantics as the standard C assert() macro.  Don't define
+	configASSERT() when performing code coverage tests though, as it is not
+	intended to asserts() to fail, some some code is intended not to run if no
+	errors are present. */
+	#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ )
+
+	#define configUSE_MALLOC_FAILED_HOOK			1
+
+	/* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */
+	// #include "trcRecorder.h"
+#endif
+
+
+#endif /* FREERTOS_CONFIG_H */

+ 41 - 0
bsp/linux/include/luat_conf_bsp.h

@@ -0,0 +1,41 @@
+
+#ifndef LUAT_CONF_BSP
+#define LUAT_CONF_BSP
+
+#define LUAT_BSP_VERSION "V0001"
+
+// 启用64位虚拟机
+// #define LUAT_CONF_VM_64bit
+
+//#define LUAT_CONF_LUASTATE_NOT_STATIC
+
+#define LUAT_CONF_LAUX_BUFFSIZE 1024
+
+// #define LUA_COMPAT_BITLIB 1
+
+//#define LUAT_CONF_DISABLE_ROTABLE
+
+#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_USE_LVGL 1
+#define USE_GTK 1
+
+//#define LUAT_FORCE_WIN32 1
+
+#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_48
+
+#endif

+ 257 - 0
bsp/linux/port/luat_base_linux.c

@@ -0,0 +1,257 @@
+#include "luat_base.h"
+#include "luat_msgbus.h"
+#include "luat_fs.h"
+#include "luat_timer.h"
+#include <stdlib.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
+  {"zbuff", luaopen_zbuff},            // 
+#ifdef LUA_USE_WINDOWS
+  {"lfs", luaopen_lfs},                //
+#endif
+  {"crypto", luaopen_crypto},
+  {"fatfs", luaopen_fatfs},
+  {"sfd",   luaopen_sfd},
+  {"lfs2",   luaopen_lfs2},
+  {"gpio",   luaopen_gpio},
+#ifdef LUAT_USE_LVGL
+  {"lvgl",   luaopen_lvgl},
+  {"lcd",    luaopen_lcd},
+#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 */
+    }
+}
+
+void luat_os_reboot(int code) {
+    exit(code);
+}
+
+const char* luat_os_bsp(void) {
+    return "linux";
+}
+
+extern const struct luat_vfs_filesystem vfs_fs_posix;
+extern const struct luat_vfs_filesystem vfs_fs_luadb;
+
+#ifdef LUAT_USE_VFS_INLINE_LIB
+extern const char luadb_inline[];
+#endif
+
+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_luadb);
+
+	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_conf_t conf2 = {
+		.busname = (char*)luadb_inline,
+		.type = "luadb",
+		.filesystem = "luadb",
+		.mount_point = "/luadb/",
+	};
+	luat_fs_mount(&conf2);
+	#endif
+	#endif
+
+	#ifdef LUAT_USE_LVGL
+	luat_lv_fs_init();
+	lv_bmp_init();
+	lv_png_init();
+	lv_split_jpeg_init();
+	#endif
+	return 0;
+}
+
+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);
+}
+
+
+//--------------------------------------------------------------------------------
+// for freertos
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
+use a callback function to optionally provide the memory required by the idle
+and timer tasks.  This is the stack that will be used by the timer task.  It is
+declared here, as a global, so it can be checked by a test that is implemented
+in a different file. */
+StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
+
+/* Notes if the trace is running or not. */
+static BaseType_t xTraceRunning = pdTRUE;
+
+void vApplicationIdleHook( void )
+{
+#ifdef LUA_USE_WINDOWS
+    Sleep(1);
+#else
+    usleep(1000);
+#endif
+}
+
+void vAssertCalled( unsigned long ulLine, const char * const pcFileName ) {
+  printf( "ASSERT! Line %d, file %s\r\n", ulLine, pcFileName );
+  exit(255);
+}
+
+void vApplicationDaemonTaskStartupHook( void )
+{
+	/* This function will be called once only, when the daemon task starts to
+	execute	(sometimes called the timer task).  This is useful if the
+	application includes initialisation code that would benefit from executing
+	after the scheduler has been started. */
+}
+void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
+{
+	( void ) pcTaskName;
+	( void ) pxTask;
+
+	/* Run time stack overflow checking is performed if
+	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
+	function is called if a stack overflow is detected.  This function is
+	provided as an example only as stack overflow checking does not function
+	when running the FreeRTOS Windows port. */
+	vAssertCalled( __LINE__, __FILE__ );
+}
+
+/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
+implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
+used by the Idle task. */
+void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
+{
+/* If the buffers to be provided to the Idle task are declared inside this
+function then they must be declared static - otherwise they will be allocated on
+the stack and so not exists after this function exits. */
+static StaticTask_t xIdleTaskTCB;
+static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
+
+	/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
+	state will be stored. */
+	*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+	/* Pass out the array that will be used as the Idle task's stack. */
+	*ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+	/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+	Note that, as the array is necessarily of type StackType_t,
+	configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+/*-----------------------------------------------------------*/
+
+/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
+application must provide an implementation of vApplicationGetTimerTaskMemory()
+to provide the memory that is used by the Timer service task. */
+void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize )
+{
+/* If the buffers to be provided to the Timer task are declared inside this
+function then they must be declared static - otherwise they will be allocated on
+the stack and so not exists after this function exits. */
+static StaticTask_t xTimerTaskTCB;
+
+	/* Pass out a pointer to the StaticTask_t structure in which the Timer
+	task's state will be stored. */
+	*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
+
+	/* Pass out the array that will be used as the Timer task's stack. */
+	*ppxTimerTaskStackBuffer = uxTimerTaskStack;
+
+	/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
+	Note that, as the array is necessarily of type StackType_t,
+	configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+	*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+
+
+/*-----------------------------------------------------------*/
+
+void vApplicationMallocFailedHook( void )
+{
+	/* vApplicationMallocFailedHook() will only be called if
+	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
+	function that will get called if a call to pvPortMalloc() fails.
+	pvPortMalloc() is called internally by the kernel whenever a task, queue,
+	timer or semaphore is created.  It is also called by various parts of the
+	demo application.  If heap_1.c, heap_2.c or heap_4.c is being used, then the
+	size of the	heap available to pvPortMalloc() is defined by
+	configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize()
+	API function can be used to query the size of free heap space that remains
+	(although it does not provide information on how the remaining heap might be
+	fragmented).  See http://www.freertos.org/a00111.html for more
+	information. */
+	vAssertCalled( __LINE__, __FILE__ );
+}
+/*-----------------------------------------------------------*/
+
+
+void vApplicationTickHook( void ) {
+	#ifdef LUAT_USE_LVGL
+	lv_tick_inc(1);
+	#endif
+}
+
+

+ 409 - 0
bsp/linux/port/luat_crypto_linux.c

@@ -0,0 +1,409 @@
+
+#include "luat_base.h"
+#include "luat_crypto.h"
+
+
+
+#define LUAT_LOG_TAG "luat.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 "luat.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

+ 66 - 0
bsp/linux/port/luat_gpio_linux.c

@@ -0,0 +1,66 @@
+#include "luat_base.h"
+#include "luat_gpio.h"
+#include "luat_msgbus.h"
+
+// 模拟GPIO在win32下的实现
+
+#define LUAT_WIN32_GPIO_COUNT (32)
+
+typedef struct gpio_state {
+    luat_gpio_t gpio;
+    uint8_t open;
+    uint8_t state;
+}gpio_state_t;
+
+gpio_state_t win32gpios[LUAT_WIN32_GPIO_COUNT] = {0};
+
+int luat_gpio_setup(luat_gpio_t* gpio) {
+    if (gpio->pin < 0 || gpio->pin >= LUAT_WIN32_GPIO_COUNT) {
+        return -1;
+    }
+    memcpy(&win32gpios[gpio->pin], gpio, sizeof(luat_gpio_t));
+    win32gpios[gpio->pin].open = 1;
+    if (gpio->mode == Luat_GPIO_OUTPUT) {
+        win32gpios[gpio->pin].state = gpio->irq;
+    }
+    else {
+        win32gpios[gpio->pin].state = 0;
+    }
+    return 0;
+}
+
+int luat_gpio_set(int pin, int level) {
+    if (pin < 0 || pin >= LUAT_WIN32_GPIO_COUNT) {
+        return -1;
+    }
+    if (win32gpios[pin].open == 0) {
+        return -1;
+    }
+    
+    if (win32gpios[pin].state != level) {
+        win32gpios[pin].state = level;
+        rtos_msg_t msg = {0};
+        msg.ptr = NULL;
+        msg.arg1 = pin;
+        msg.arg2 = level;
+        msg.handler = l_gpio_handler;
+        luat_msgbus_put(&msg, 0);
+    };
+    return 0;
+}
+
+int luat_gpio_get(int pin) {
+    if (pin < 0 || pin >= LUAT_WIN32_GPIO_COUNT) {
+        return 0;
+    }
+    if (win32gpios[pin].open == 0) {
+        return 0;
+    }
+    return win32gpios[pin].state;
+}
+void luat_gpio_close(int pin) {
+    if (pin < 0 || pin >= LUAT_WIN32_GPIO_COUNT) {
+        return;
+    }
+    win32gpios[pin].open = 0;
+}

+ 114 - 0
bsp/linux/port/luat_log_linux.c

@@ -0,0 +1,114 @@
+
+#include "luat_base.h"
+#include "luat_log.h"
+#include "luat_uart.h"
+#include "luat_malloc.h"
+#include "printf.h"
+
+#include <stdio.h>
+
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+typedef struct log_msg {
+    char* buff;
+}log_msg_t;
+
+static QueueHandle_t xQueue = NULL;
+
+static uint8_t luat_log_uart_port = 0;
+static uint8_t luat_log_level_cur = LUAT_LOG_DEBUG;
+
+void luat_log_thread_task(void* args) {
+    log_msg_t msg = {0};
+    while (1) {
+        if (pdTRUE == xQueueReceive(xQueue, &msg, -1)) {
+            printf("%s", msg.buff);
+            luat_heap_free(msg.buff);  
+        };
+    }
+}
+
+void luat_log_init_win32(void) {
+    xQueue = xQueueCreate(1024, sizeof(void*));
+    xTaskCreate( luat_log_thread_task, "log", 1024*2, NULL, 23, NULL );
+}
+
+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) {
+    //luat_uart_write(luat_log_uart_port, s, l);
+#if LUAT_USE_LOG_ASYNC_THREAD
+    char* buff = luat_heap_malloc(l + 1);
+    if (buff == NULL)
+        return;
+    memcpy(buff, s, l);
+    buff[l] = 0x00;
+    log_msg_t msg = {
+        .buff = buff
+    };
+    xQueueSendFromISR(xQueue, &msg, NULL);
+#else
+    printf("%s", s);
+#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);
+    }
+}

+ 92 - 0
bsp/linux/port/luat_malloc_linux.c

@@ -0,0 +1,92 @@
+
+// 这个文件包含 系统heap和lua heap的默认实现
+
+
+#include <stdlib.h>
+#include <string.h>//add for memset
+#include "bget.h"
+#include "luat_malloc.h"
+
+#define LUAT_LOG_TAG "luat.vmheap"
+#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 = configTOTAL_HEAP_SIZE - xPortGetFreeHeapSize();
+	*max_used = configTOTAL_HEAP_SIZE - xPortGetMinimumEverFreeHeapSize();
+    *total = configTOTAL_HEAP_SIZE;
+}
+
+//-----------------------------------------------------------------------------

+ 43 - 0
bsp/linux/port/luat_msgbus_freertos.c

@@ -0,0 +1,43 @@
+
+#include "luat_msgbus.h"
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+#define QUEUE_LENGTH 0xFF
+#define ITEM_SIZE sizeof(rtos_msg_t)
+
+static StaticQueue_t xStaticQueue = {0};
+static QueueHandle_t xQueue = {0};
+
+#if configSUPPORT_STATIC_ALLOCATION
+static uint8_t ucQueueStorageArea[ QUEUE_LENGTH * ITEM_SIZE ];
+#endif
+
+void luat_msgbus_init(void) {
+    if (!xQueue) {
+        #if configSUPPORT_STATIC_ALLOCATION
+        xQueue = xQueueCreateStatic( QUEUE_LENGTH,
+                                 ITEM_SIZE,
+                                 ucQueueStorageArea,
+                                 &xStaticQueue );
+        #else
+        xQueue = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);
+        #endif
+    }
+}
+uint32_t luat_msgbus_put(rtos_msg_t* msg, size_t timeout) {
+    if (xQueue == NULL)
+        return 1;
+    return xQueueSendFromISR(xQueue, msg, NULL) == pdTRUE ? 0 : 1;
+}
+uint32_t luat_msgbus_get(rtos_msg_t* msg, size_t timeout) {
+    if (xQueue == NULL)
+        return 1;
+    return xQueueReceive(xQueue, msg, timeout) == pdTRUE ? 0 : 1; // 要不要除portTICK_RATE_MS呢?
+}
+uint32_t luat_msgbus_freesize(void) {
+    if (xQueue == NULL)
+        return 1;
+    return 1;
+}

+ 63 - 0
bsp/linux/port/luat_spi_linux.c

@@ -0,0 +1,63 @@
+
+#include "luat_base.h"
+#include "luat_gpio.h"
+#include "luat_msgbus.h"
+#include "luat_spi.h"
+
+// 模拟SPI在win32下的实现
+// TODO 当需要返回数据时, 调用lua方法获取需要返回的数据
+
+#define LUAT_WIN32_SPI_COUNT (3)
+
+typedef struct win32spi {
+    luat_spi_t spi;
+    uint8_t open;
+}win32spi_t;
+
+win32spi_t win32spis[LUAT_WIN32_SPI_COUNT] = {0};
+
+int luat_spi_setup(luat_spi_t* spi) {
+    if (spi->id < 0 || spi->id >= LUAT_WIN32_SPI_COUNT) {
+        return -1;
+    }
+    memcpy(&win32spis[spi->id].spi, spi, sizeof(luat_spi_t));
+    win32spis[spi->id].open = 1;
+    return 0;
+}
+//关闭SPI,成功返回0
+int luat_spi_close(int spi_id) {
+    if (spi_id < 0 || spi_id >= LUAT_WIN32_SPI_COUNT) {
+        return -1;
+    }
+    win32spis[spi_id].open = 0;
+    return 0;
+}
+//收发SPI数据,返回接收字节数
+int luat_spi_transfer(int spi_id, const char* send_buf, char* recv_buf, size_t length) {
+    if (spi_id < 0 || spi_id >= LUAT_WIN32_SPI_COUNT) {
+        return -1;
+    }
+    if (win32spis[spi_id].open == 0)
+        return -1;
+    memset(recv_buf, 0, length);
+    return length;
+}
+//收SPI数据,返回接收字节数
+int luat_spi_recv(int spi_id, char* recv_buf, size_t length) {
+    if (spi_id < 0 || spi_id >= LUAT_WIN32_SPI_COUNT) {
+        return -1;
+    }
+    if (win32spis[spi_id].open == 0)
+        return -1;
+    memset(recv_buf, 0, length);
+    return length;
+}
+//发SPI数据,返回发送字节数
+int luat_spi_send(int spi_id, const char* send_buf, size_t length) {
+    if (spi_id < 0 || spi_id >= LUAT_WIN32_SPI_COUNT) {
+        return -1;
+    }
+    if (win32spis[spi_id].open == 0)
+        return -1;
+    return length;
+}

+ 98 - 0
bsp/linux/port/luat_timer_freertos.c

@@ -0,0 +1,98 @@
+
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_timer.h"
+#include "luat_msgbus.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+
+#define LUAT_LOG_TAG "luat.timer"
+#include "luat_log.h"
+
+#define FREERTOS_TIMER_COUNT 32
+static luat_timer_t* timers[FREERTOS_TIMER_COUNT] = {0};
+
+static void luat_timer_callback(TimerHandle_t xTimer) {
+    //LLOGD("timer callback");
+    rtos_msg_t msg;
+    luat_timer_t *timer = (luat_timer_t*) pvTimerGetTimerID(xTimer);
+    msg.handler = timer->func;
+    msg.ptr = timer;
+    msg.arg1 = 0;
+    msg.arg2 = 0;
+    int re = luat_msgbus_put(&msg, 0);
+    //LLOGD("timer msgbus re=%ld", re);
+}
+
+static int nextTimerSlot() {
+    for (size_t i = 0; i < FREERTOS_TIMER_COUNT; i++)
+    {
+        if (timers[i] == NULL) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int luat_timer_start(luat_timer_t* timer) {
+    TimerHandle_t os_timer;
+    int timerIndex;
+    //LLOGD(">>luat_timer_start timeout=%ld", timer->timeout);
+    timerIndex = nextTimerSlot();
+    //LLOGD("timer id=%ld", timerIndex);
+    if (timerIndex < 0) {
+        return 1; // too many timer!!
+    }
+    os_timer = xTimerCreate("luat_timer", timer->timeout / portTICK_RATE_MS, timer->repeat, timer, luat_timer_callback);
+    //LLOGD("timer id=%ld, osTimerNew=%p", timerIndex, os_timer);
+    if (!os_timer) {
+        return -1;
+    }
+    timers[timerIndex] = timer;
+    
+    timer->os_timer = os_timer;
+    int re = xTimerStart(os_timer, 0);
+    //LLOGD("timer id=%ld timeout=%ld start=%ld", timerIndex, timer->timeout, re);
+    if (re != pdPASS) {
+        xTimerDelete(os_timer, 0);
+        timers[timerIndex] = 0;
+    }
+    return re == pdPASS ? 0 : -1;
+}
+
+int luat_timer_stop(luat_timer_t* timer) {
+    if (!timer)
+        return 1;
+    for (size_t i = 0; i < FREERTOS_TIMER_COUNT; i++)
+    {
+        if (timers[i] == timer) {
+            timers[i] = NULL;
+            break;
+        }
+    }
+    xTimerStop((TimerHandle_t)timer->os_timer, 10);
+    xTimerDelete((TimerHandle_t)timer->os_timer, 10);
+    return 0;
+};
+
+luat_timer_t* luat_timer_get(size_t timer_id) {
+    for (size_t i = 0; i < FREERTOS_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) {
+        vTaskDelay(ms / portTICK_RATE_MS);
+    }
+    return 0;
+}
+
+

+ 98 - 0
bsp/linux/src/main.c

@@ -0,0 +1,98 @@
+
+#include <stdio.h>
+
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_msgbus.h"
+
+#include "bget.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#define LUAT_HEAP_SIZE (1024*1024)
+uint8_t luavm_heap[LUAT_HEAP_SIZE] = {0};
+
+void luat_log_init_win32(void);
+
+static void _luat_main(void* args) {
+    luat_main();
+}
+
+#ifdef LUAT_USE_LVGL
+
+#include "lvgl.h"
+#include "exts/lv_drivers/gtkdrv/gtkdrv.h"
+static int luat_lvg_handler(lua_State* L, void* ptr) {
+    lv_task_handler();
+    return 0;
+}
+
+static void _lvgl_handler(void* args) {
+    rtos_msg_t msg = {0};
+    msg.handler = luat_lvg_handler;
+    while (1) {
+        luat_msgbus_put(&msg, 0);
+        vTaskDelay(5);
+    };
+}
+#endif
+
+#ifdef LUAT_USE_LWIP
+int lwip_init_main(void);
+static void _lwip_init(void* arg) {
+    lwip_init_main();
+}
+#endif
+
+int win32_argc;
+char** win32_argv;
+
+// boot
+int main(int argc, char** argv) {
+    win32_argc = argc;
+    win32_argv = argv;
+    
+    bpool(luavm_heap, LUAT_HEAP_SIZE);
+
+    luat_log_init_win32();
+
+#ifdef LUAT_USE_LVGL
+    lv_init();
+
+    xTaskCreate( _lvgl_handler, "lvgl", 1024*2, NULL, 23, NULL );
+#endif
+
+#ifdef LUAT_USE_LWIP
+    xTaskCreate( _lwip_init, "lwip", 1024*2, NULL, 22, NULL );
+#endif
+
+    xTaskCreate( _luat_main, "luatos", 1024*16, NULL, 21, NULL );
+    vTaskStartScheduler();
+    return 0;
+}
+
+void lvgl_linux_init(void) {
+    gtkdrv_init();
+    static lv_disp_buf_t disp_buf1;
+    static lv_color_t buf1_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];
+    lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX);
+
+    /*Create a display*/
+    lv_disp_drv_t disp_drv;
+    lv_disp_drv_init(&disp_drv);
+    disp_drv.buffer = &disp_buf1;
+    disp_drv.flush_cb = gtkdrv_flush_cb;
+
+    lv_disp_drv_register(&disp_drv);
+
+//   lv_indev_drv_t indev_drv_mouse;
+//   lv_indev_drv_init(&indev_drv_mouse);
+//   indev_drv_mouse.type = LV_INDEV_TYPE_POINTER;
+
+//   lv_indev_drv_t indev_drv_kb;
+//   lv_indev_drv_init(&indev_drv_kb);
+//   indev_drv_kb.type = LV_INDEV_TYPE_KEYPAD;
+//   indev_drv_kb.read_cb = lv_keyboard_read_cb;
+//   lv_indev_drv_register(&indev_drv_kb);
+}

+ 4 - 4
components/lvgl/binding/luat_lib_lvgl7.c

@@ -40,6 +40,10 @@ int luat_lv_init(lua_State *L) {
     windrv_init();
     lua_pushboolean(L, 1);
     return 1;
+    #elif defined(LUA_USE_LINUX)
+    lvgl_linux_init();
+    lua_pushboolean(L, 1);
+    return 1;
     #else
     conf = luat_lcd_get_default();
     lv_color_t *fbuffer = NULL;
@@ -48,11 +52,7 @@ int luat_lv_init(lua_State *L) {
     int w = luaL_optinteger(L, 1, conf->w);
     int h = luaL_optinteger(L, 2, conf->h);
 
-    #ifdef LUA_USE_WINDOWS
-    fbuff_size = w * h;
-    #else
     fbuff_size = w * h / 10;
-    #endif
 
     LLOGD("w %d h %d buff %d", w, h, fbuff_size);
 

+ 323 - 0
components/lvgl/exts/lv_drivers/gtkdrv/gtkdrv.c

@@ -0,0 +1,323 @@
+/**
+ * @file gtk.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "gtkdrv.h"
+
+#if USE_GTK
+#define _DEFAULT_SOURCE /* needed for usleep() */
+#include <stdlib.h>
+#include <unistd.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+static void gtkdrv_handler(void * p);
+static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
+    gpointer user_data);
+static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
+    gpointer user_data);
+static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
+    gpointer user_data);
+static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
+    gpointer user_data);
+static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
+    gpointer user_data);
+
+static void quit_handler(void);
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+static GtkWidget    *window;
+static GtkWidget    *event_box;
+
+static GtkWidget    *output_image;
+static GdkPixbuf    *pixbuf;
+
+static unsigned char run_gtk;
+
+static lv_coord_t mouse_x;
+static lv_coord_t mouse_y;
+static lv_indev_state_t mouse_btn = LV_INDEV_STATE_REL;
+static lv_key_t last_key;
+static lv_indev_state_t last_key_state;
+
+static uint8_t fb[LV_HOR_RES_MAX * LV_VER_RES_MAX * 3];
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void gtkdrv_init(void)
+{
+    // Init GTK
+    gtk_init(NULL, NULL);
+
+    /* Or just set up the widgets in code */
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_default_size(GTK_WINDOW(window), LV_HOR_RES_MAX, LV_VER_RES_MAX);
+    gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
+    output_image = gtk_image_new();
+    event_box = gtk_event_box_new (); // Use event_box around image, otherwise mouse position output in broadway is offset
+    gtk_container_add(GTK_CONTAINER (event_box), output_image);
+    gtk_container_add(GTK_CONTAINER (window), event_box);
+
+    gtk_widget_add_events(event_box, GDK_BUTTON_PRESS_MASK);
+    gtk_widget_add_events(event_box, GDK_SCROLL_MASK);
+    gtk_widget_add_events(event_box, GDK_POINTER_MOTION_MASK);
+    gtk_widget_add_events(window, GDK_KEY_PRESS_MASK);
+
+    g_signal_connect(window, "destroy", G_CALLBACK(quit_handler), NULL);
+    g_signal_connect(event_box, "button-press-event", G_CALLBACK(mouse_pressed), NULL);
+    g_signal_connect(event_box, "button-release-event", G_CALLBACK(mouse_released), NULL);
+    g_signal_connect(event_box, "motion-notify-event", G_CALLBACK(mouse_motion), NULL);
+    g_signal_connect(window, "key_press_event", G_CALLBACK(keyboard_press), NULL);
+    g_signal_connect(window, "key_release_event", G_CALLBACK(keyboard_release), NULL);
+
+
+    gtk_widget_show_all(window);
+
+    pixbuf = gdk_pixbuf_new_from_data((guchar*)fb, GDK_COLORSPACE_RGB, false, 8, LV_HOR_RES_MAX, LV_VER_RES_MAX, LV_HOR_RES_MAX * 3, NULL, NULL);
+    if (pixbuf == NULL)
+    {
+        fprintf(stderr, "Creating pixbuf failed\n");
+        return;
+    }
+
+    pthread_t thread;
+    pthread_create(&thread, NULL, gtkdrv_handler, NULL);
+}
+
+
+/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
+uint32_t gtkdrv_tick_get(void)
+{
+    static uint64_t start_ms = 0;
+    if(start_ms == 0) {
+        struct timeval tv_start;
+        gettimeofday(&tv_start, NULL);
+        start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
+    }
+
+    struct timeval tv_now;
+    gettimeofday(&tv_now, NULL);
+    uint64_t now_ms;
+    now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
+
+    uint32_t time_ms = now_ms - start_ms;
+
+    return time_ms;
+}
+
+
+/**
+ * Flush a buffer to the marked area
+ * @param drv pointer to driver where this function belongs
+ * @param area an area where to copy `color_p`
+ * @param color_p an array of pixel to copy to the `area` part of the screen
+ */
+void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
+{
+    lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res;
+    lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res;
+
+
+    /*Return if the area is out the screen*/
+    if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
+
+        lv_disp_flush_ready(disp_drv);
+        return;
+    }
+
+    int32_t y;
+    int32_t x;
+    int32_t p;
+    for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
+        p = (y * disp_drv->hor_res + area->x1) * 3;
+        for(x = area->x1; x <= area->x2 && x < disp_drv->hor_res; x++) {
+            fb[p] = color_p->ch.red;
+            fb[p + 1] = color_p->ch.green;
+            fb[p + 2] = color_p->ch.blue;
+
+            p += 3;
+            color_p ++;
+        }
+    }
+
+    /*IMPORTANT! It must be called to tell the system the flush is ready*/
+    lv_disp_flush_ready(disp_drv);
+}
+
+
+void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
+{
+    data->point.x = mouse_x;
+    data->point.y = mouse_y;
+    data->state = mouse_btn;
+}
+
+
+void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
+{
+    data->key = last_key;
+    data->state = last_key_state;
+}
+
+
+
+
+/**********************
+ *   STATIC FUNCTIONS
+ **********************/
+
+static void gtkdrv_handler(void * p)
+{
+    while(1) {
+        gtk_image_set_from_pixbuf(GTK_IMAGE(output_image), pixbuf); // Test code
+
+        /* Real code should: call gdk_pixbuf_new_from_data () with pointer to frame buffer
+        generated by LVGL. See
+        https://developer.gnome.org/gdk-pixbuf/2.36/gdk-pixbuf-Image-Data-in-Memory.html
+        */
+
+        gtk_main_iteration_do(FALSE);
+        /* Explicitly calling each iteration of the GTK main loop allows LVGL to sync frame
+        buffer updates with GTK. It is perhaps also possible to just call gtk_main(), but not
+        sure how sync will work then
+        */
+        usleep(1*1000);
+    }
+}
+
+static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
+    gpointer user_data)
+{
+    mouse_btn = LV_INDEV_STATE_PR;
+    // Important, if this function returns TRUE the window cannot be moved around inside the browser
+    // when using broadway
+    return FALSE;
+}
+
+
+static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
+    gpointer user_data)
+{
+    mouse_btn = LV_INDEV_STATE_REL;
+    // Important, if this function returns TRUE the window cannot be moved around inside the browser
+    // when using broadway
+    return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
+    gpointer user_data)
+{
+    mouse_x = event->x;
+    mouse_y = event->y;
+    // Important, if this function returns TRUE the window cannot be moved around inside the browser
+    // when using broadway
+    return FALSE;
+}
+
+
+static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
+    gpointer user_data)
+{
+
+    uint32_t ascii_key = event->keyval;
+    /*Remap some key to LV_KEY_... to manage groups*/
+    switch(event->keyval) {
+        case GDK_KEY_rightarrow:
+        case GDK_KEY_Right:
+            ascii_key =  LV_KEY_RIGHT;
+            break;
+
+        case GDK_KEY_leftarrow:
+        case GDK_KEY_Left:
+            ascii_key =  LV_KEY_LEFT;
+            break;
+
+        case GDK_KEY_uparrow:
+        case GDK_KEY_Up:
+            ascii_key =  LV_KEY_UP;
+            break;
+
+        case GDK_KEY_downarrow:
+        case GDK_KEY_Down:
+            ascii_key =  LV_KEY_DOWN;
+            break;
+
+        case GDK_KEY_Escape:
+            ascii_key =  LV_KEY_ESC;
+            break;
+
+        case GDK_KEY_BackSpace:
+            ascii_key =  LV_KEY_BACKSPACE;
+            break;
+
+        case GDK_KEY_Delete:
+            ascii_key = LV_KEY_DEL;
+            break;
+
+        case GDK_KEY_Tab:
+            ascii_key = LV_KEY_NEXT;
+            break;
+
+        case GDK_KEY_KP_Enter:
+        case GDK_KEY_Return:
+        case '\r':
+            ascii_key = LV_KEY_ENTER;
+            break;
+
+        default:
+            break;
+
+    }
+
+     last_key = ascii_key;
+     last_key_state = LV_INDEV_STATE_PR;
+     // For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
+
+     return TRUE;
+}
+
+static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
+    gpointer user_data)
+{
+     last_key = 0;
+     last_key_state = LV_INDEV_STATE_REL;
+     // For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
+
+     return TRUE;
+}
+
+static void quit_handler(void)
+{
+    exit(0);
+    run_gtk = FALSE;
+}
+#endif /*USE_GTK*/
+

+ 49 - 0
components/lvgl/exts/lv_drivers/gtkdrv/gtkdrv.h

@@ -0,0 +1,49 @@
+/**
+ * @file gtkdrv
+ *
+ */
+
+#ifndef GTKDRV_H
+#define GTKDRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_drv_conf.h"
+
+#if USE_GTK
+
+#include "lvgl/lvgl.h"
+
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+void gtkdrv_init(void);
+uint32_t gtkdrv_tick_get(void);
+void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
+void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
+void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
+/**********************
+ *      MACROS
+ **********************/
+
+#endif /*USE_GTK*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* GTKDRV_H */

+ 5 - 0
luat/include/luat_msgbus.h

@@ -26,4 +26,9 @@ uint32_t luat_msgbus_put(rtos_msg_t* msg, size_t timeout);
 uint32_t luat_msgbus_get(rtos_msg_t* msg, size_t timeout);
 uint32_t luat_msgbus_freesize(void);
 
+#define luat_msgbug_put2(ABC1,ABC2,ABC3,ABC4,ABC5) {\
+    rtos_msg_t _msg = {.handler=ABC1,.ptr=ABC2,.arg1=ABC3,.arg2=ABC4};\
+    luat_msgbus_put(&_msg, ABC5);\
+}
+
 #endif