From f5e277c240b9211a1f047b88788f34f3dd5a97c2 Mon Sep 17 00:00:00 2001
From: ethan <ethan.tao@ewellix.com>
Date: Sat, 08 Apr 2023 18:33:01 +0800
Subject: [PATCH] first commit

---
 Device/src/Ems_config.h                                    |   27 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c        |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c      |    0 
 Driver/Src/gpio.c                                          |    0 
 MCU/stm32l4xx_it.c                                         |   21 
 APP/main.c                                                 |   14 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma_ex.h        |    0 
 MCU/stm32l4xx_hal_msp.c                                    |    0 
 Ems/common/Ems_def.h                                       |  107 +
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c           |    0 
 Ems/ems.h                                                  |   24 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma.h           |    0 
 MCU/STM32L4xx_HAL_Driver/LICENSE.txt                       |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c        |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio_ex.h       |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_can.h           |    0 
 MCU/STM32L4xx_HAL_Driver/License.md                        |    0 
 MCU/CMSIS/Include/cmsis_armclang_ltm.h                     |    0 
 MCU/CMSIS/Include/core_cm35p.h                             |    0 
 Device/inc/Hal_adc.h                                       |   14 
 Device/src/os_clock.c                                      |   19 
 Driver/Src/crc.c                                           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c        |    0 
 Ems/common/Ems_assert.h                                    |   29 
 Device/src/dev_pwm.c                                       |   84 
 Device/inc/as5601.h                                        |   94 
 MCU/CMSIS/Include/core_cm33.h                              |    0 
 Driver/Inc/dma.h                                           |    0 
 MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l443xx.h        |    0 
 Driver/Src/i2c.c                                           |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c_ex.h        |    0 
 MCU/stm32l4xx_it.h                                         |    1 
 MCU/CMSIS/LICENSE.txt                                      |    0 
 MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l4xx.h          |    0 
 Device/src/dev_pwm.h                                       |   47 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h           |    0 
 Driver/Src/can.c                                           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c           |    0 
 Driver/Inc/adc.h                                           |    2 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_cortex.h        |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ramfunc.h |    0 
 Driver/Inc/gpio.h                                          |    0 
 Driver/Src/drv_pwm.c                                       |  184 +
 MCU/CMSIS/Include/cmsis_compiler.h                         |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash.h         |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc_ex.h        |    0 
 MCU/CMSIS/Include/core_cm7.h                               |    0 
 Device/src/dev_time.c                                      |   43 
 Driver/Inc/crc.h                                           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c           |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc.h           |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim.h           |    0 
 Driver/Inc/main.h                                          |    0 
 Ems/common/Ems_export.c                                    |  242 ++
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c           |    0 
 MCU/CMSIS/Include/core_sc000.h                             |    0 
 MCU/CMSIS/Include/core_cm3.h                               |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr.h           |    0 
 Driver/Src/Hal_adc.c                                       |   87 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c        |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c           |    0 
 Ems/3rd/Shell/shell_ext.h                                  |   33 
 Driver/Inc/can.h                                           |    0 
 MCU/CMSIS/Device/ST/STM32L4xx/License.md                   |    0 
 Ems/3rd/Shell/shell_ext.c                                  |  447 ++++
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c        |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr_ex.h        |    0 
 Ems/3rd/Shell/shell_companion.c                            |   87 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio.h          |    0 
 MCU/CMSIS/Include/core_armv81mml.h                         |    0 
 Driver/Src/dma.c                                           |    0 
 Device/src/dev_list.h                                      |   21 
 MCU/CMSIS/Include/cmsis_armcc.h                            |    0 
 MCU/CMSIS/Include/mpu_armv8.h                              |    0 
 Device/src/dev_pin.c                                       |  121 +
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c               |    0 
 MCU/CMSIS/Include/core_cm23.h                              |    0 
 MCU/CMSIS/Include/cmsis_armclang.h                         |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c        |    0 
 MCU/CMSIS/Include/core_sc300.h                             |    0 
 MCU/system_stm32l4xx.c                                     |    0 
 MCU/CMSIS/Include/cmsis_iccarm.h                           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c          |    0 
 MCU/CMSIS/Include/core_cm0.h                               |    0 
 CAHB_L4_PH.ioc                                             |    9 
 MCU/CMSIS/Include/core_cm4.h                               |    0 
 Ems/3rd/Shell/shell_cmd_list.c                             |  103 +
 MCU/stm32l4xx_hal_conf.h                                   |    0 
 Device/inc/os_task.h                                       |    2 
 Ems/common/Ems_export.h                                    |  249 ++
 Device/inc/Hal_gpio.h                                      |   24 
 Device/src/dev_as5601.c                                    |   24 
 Driver/Inc/stm32l4xx_it.h                                  |    1 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c |    0 
 MCU/CMSIS/Include/core_armv8mbl.h                          |    0 
 Driver/Inc/tim.h                                           |    0 
 MCU/CMSIS/Device/ST/STM32L4xx/LICENSE.txt                  |    0 
 Device/inc/os_clock.h                                      |    9 
 Driver/Inc/stm32l4xx_hal_conf.h                            |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h            |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h               |    0 
 Device/src/bsp.h                                           |   25 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c        |    0 
 Ems/3rd/Shell/shell.h                                      |  477 ++++
 MCU/CMSIS/Include/cmsis_gcc.h                              |    0 
 MCU/CMSIS/Include/core_armv8mml.h                          |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h     |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c         |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim_ex.h        |    0 
 Device/src/bsp.c                                           |  105 +
 Device/src/dev_pin.h                                       |   61 
 Ems/3rd/Shell/shell.c                                      | 1972 ++++++++++++++++++++
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ex.h      |    0 
 Driver/Src/drv_gpio.c                                      |   86 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc_ex.h        |    0 
 Makefile                                                   |   13 
 Device/src/os_task.c                                       |    7 
 MCU/CMSIS/Include/mpu_armv7.h                              |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c        |    0 
 .mxproject                                                 |    6 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc_ex.h        |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_def.h           |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_exti.h          |    0 
 MCU/CMSIS/Include/core_cm1.h                               |    0 
 MCU/CMSIS/Include/tz_context.h                             |    0 
 Driver/Inc/i2c.h                                           |    0 
 MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc.h           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_can.c           |    0 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c           |    0 
 Driver/Src/clock.c                                         |   21 
 Device/src/ems_object.c                                    |  186 +
 MCU/CMSIS/Device/ST/STM32L4xx/Include/system_stm32l4xx.h   |    0 
 MCU/CMSIS/Include/core_cm0plus.h                           |    0 
 Driver/Src/adc.c                                           |    0 
 /dev/null                                                  |  111 -
 Device/src/ems_object.h                                    |   80 
 Ems/3rd/Shell/shell_cfg.h                                  |  183 +
 Driver/Inc/clock.h                                         |    7 
 Driver/Src/drv_pin.c                                       |  209 ++
 Ems/common/Ems_common.h                                    |   52 
 Driver/Src/tim.c                                           |    0 
 Ems/common/Ems_common.c                                    |   46 
 MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c          |    0 
 MCU/CMSIS/Include/cmsis_version.h                          |    0 
 146 files changed, 5,642 insertions(+), 174 deletions(-)

diff --git a/.mxproject b/.mxproject
index 6cd1355..8991315 100644
--- a/.mxproject
+++ b/.mxproject
@@ -5,7 +5,7 @@
 SourceFiles=;;
 
 [PreviousUsedMakefileFiles]
-SourceFiles=Core\Src\main.c;Core\Src\gpio.c;Core\Src\adc.c;Core\Src\can.c;Core\Src\crc.c;Core\Src\dma.c;Core\Src\i2c.c;Core\Src\tim.c;Core\Src\stm32l4xx_it.c;Core\Src\stm32l4xx_hal_msp.c;Core\Src\stm32l4xx_hal_timebase_tim.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ramfunc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_gpio.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_cortex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_exti.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_can.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim_ex.c;Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\system_stm32l4xx.c;Core\Src\system_stm32l4xx.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ramfunc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_gpio.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_cortex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_exti.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_can.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim_ex.c;Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\system_stm32l4xx.c;Core\Src\system_stm32l4xx.c;;;
+SourceFiles=Core\Src\main.c;Core\Src\gpio.c;Core\Src\adc.c;Core\Src\can.c;Core\Src\crc.c;Core\Src\dma.c;Core\Src\i2c.c;Core\Src\tim.c;Core\Src\stm32l4xx_it.c;Core\Src\stm32l4xx_hal_msp.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ramfunc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_gpio.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_cortex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_exti.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_can.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim_ex.c;Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\system_stm32l4xx.c;Core\Src\system_stm32l4xx.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_adc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_i2c_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_rcc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_flash_ramfunc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_gpio.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_dma_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_pwr_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_cortex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_exti.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_can.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_crc_ex.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim.c;Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal_tim_ex.c;Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\system_stm32l4xx.c;Core\Src\system_stm32l4xx.c;;;
 HeaderPath=Drivers\STM32L4xx_HAL_Driver\Inc;Drivers\STM32L4xx_HAL_Driver\Inc\Legacy;Drivers\CMSIS\Device\ST\STM32L4xx\Include;Drivers\CMSIS\Include;Core\Inc;
 CDefines=USE_HAL_DRIVER;STM32L443xx;USE_HAL_DRIVER;USE_HAL_DRIVER;
 
@@ -25,7 +25,7 @@
 HeaderFolderListSize=1
 HeaderPath#0=C:/Workspace/Software/CAHB_L4_PH/Core/Inc
 HeaderFiles=;
-SourceFileListSize=11
+SourceFileListSize=10
 SourceFiles#0=C:/Workspace/Software/CAHB_L4_PH/Core/Src/gpio.c
 SourceFiles#1=C:/Workspace/Software/CAHB_L4_PH/Core/Src/adc.c
 SourceFiles#2=C:/Workspace/Software/CAHB_L4_PH/Core/Src/can.c
@@ -35,8 +35,6 @@
 SourceFiles#6=C:/Workspace/Software/CAHB_L4_PH/Core/Src/tim.c
 SourceFiles#7=C:/Workspace/Software/CAHB_L4_PH/Core/Src/stm32l4xx_it.c
 SourceFiles#8=C:/Workspace/Software/CAHB_L4_PH/Core/Src/stm32l4xx_hal_msp.c
-SourceFiles#9=C:/Workspace/Software/CAHB_L4_PH/Core/Src/stm32l4xx_hal_timebase_tim.c
-SourceFiles#10=C:/Workspace/Software/CAHB_L4_PH/Core/Src/main.c
 SourceFolderListSize=1
 SourcePath#0=C:/Workspace/Software/CAHB_L4_PH/Core/Src
 SourceFiles=;
diff --git a/APP/main.c b/APP/main.c
index 2e1dd22..5ab694d 100644
--- a/APP/main.c
+++ b/APP/main.c
@@ -1,6 +1,16 @@
 #include "main.h"
 #include "os_task.h"
-
+#include "os_clock.h"
+#include "clock.h"
+#include "adc.h"
+#include "can.h"
+#include "crc.h"
+#include "dma.h"
+#include "i2c.h"
+#include "tim.h"
+#include "gpio.h"
+#include "Hal_gpio.h"
+#include "Hal_adc.h"
 static void GPIO_FunctionTestTask(void *p)
 {
     *p;
@@ -27,6 +37,8 @@
     MX_DMA_Init();
     MX_TIM15_Init();
 
+    Hal_ADCInit();
+
     OSTaskCreate(GPIO_FunctionTestTask, 1, 1, NULL);
 
     OSSchedule(&OS_GetTick);
diff --git a/CAHB_Hal/inc/os_clock.h b/CAHB_Hal/inc/os_clock.h
deleted file mode 100644
index e1919c8..0000000
--- a/CAHB_Hal/inc/os_clock.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef OS_CLOCK_H
-#define OS_CLOCK_H
-
-extern void Ostick_config(void);
-// void Ostick_ReInit(void);
-void HAL_IncTick(void);
-#endif
\ No newline at end of file
diff --git a/CAHB_Hal/src/os_clock.c b/CAHB_Hal/src/os_clock.c
deleted file mode 100644
index 810c3db..0000000
--- a/CAHB_Hal/src/os_clock.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "os_clock.h"
-#include "os_task.h"
-#include "stm32l4xx_hal.h"
-
-
-// void SysTick_Handler(void)
-// {
-//     OS_TickFlag = 1;
-// }
-
-// void Ostick_ReInit(void)
-// {
-    
-// }
-
-
-void HAL_IncTick(void)
-{
-//   uwTick += (uint32_t)uwTickFreq;
-OS_TickFlag = 1;
-
-}
diff --git a/CAHB_L4_PH.ioc b/CAHB_L4_PH.ioc
index 2a6bebb..1ff559b 100644
--- a/CAHB_L4_PH.ioc
+++ b/CAHB_L4_PH.ioc
@@ -109,7 +109,7 @@
 Mcu.Pin31=VP_ADC1_TempSens_Input
 Mcu.Pin32=VP_ADC1_Vbat_Input
 Mcu.Pin33=VP_CRC_VS_CRC
-Mcu.Pin34=VP_SYS_VS_tim6
+Mcu.Pin34=VP_SYS_VS_Systick
 Mcu.Pin35=VP_TIM1_VS_ClockSourceINT
 Mcu.Pin36=VP_TIM1_VS_ClockSourceITR
 Mcu.Pin37=VP_TIM1_VS_no_output4
@@ -136,9 +136,6 @@
 NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
 NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true
-NVIC.TIM6_DAC_IRQn=true\:15\:0\:false\:false\:true\:false\:true
-NVIC.TimeBase=TIM6_DAC_IRQn
-NVIC.TimeBaseIP=TIM6
 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
 PA0.GPIOParameters=GPIO_Label
 PA0.GPIO_Label=EXT_END
@@ -365,8 +362,8 @@
 VP_ADC1_Vbat_Input.Signal=ADC1_Vbat_Input
 VP_CRC_VS_CRC.Mode=CRC_Activate
 VP_CRC_VS_CRC.Signal=CRC_VS_CRC
-VP_SYS_VS_tim6.Mode=TIM6
-VP_SYS_VS_tim6.Signal=SYS_VS_tim6
+VP_SYS_VS_Systick.Mode=SysTick
+VP_SYS_VS_Systick.Signal=SYS_VS_Systick
 VP_TIM1_VS_ClockSourceINT.Mode=Internal
 VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
 VP_TIM1_VS_ClockSourceITR.Mode=TriggerSource_ITR3
diff --git a/Core/Src/stm32l4xx_hal_timebase_tim.c b/Core/Src/stm32l4xx_hal_timebase_tim.c
deleted file mode 100644
index ef21c4a..0000000
--- a/Core/Src/stm32l4xx_hal_timebase_tim.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* USER CODE BEGIN Header */
-/**
-  ******************************************************************************
-  * @file    stm32l4xx_hal_timebase_TIM.c
-  * @brief   HAL time base based on the hardware TIM.
-  ******************************************************************************
-  * @attention
-  *
-  * Copyright (c) 2022 STMicroelectronics.
-  * All rights reserved.
-  *
-  * This software is licensed under terms that can be found in the LICENSE file
-  * in the root directory of this software component.
-  * If no LICENSE file comes with this software, it is provided AS-IS.
-  *
-  ******************************************************************************
-  */
-/* USER CODE END Header */
-
-/* Includes ------------------------------------------------------------------*/
-#include "stm32l4xx_hal.h"
-#include "stm32l4xx_hal_tim.h"
-
-/* Private typedef -----------------------------------------------------------*/
-/* Private define ------------------------------------------------------------*/
-/* Private macro -------------------------------------------------------------*/
-/* Private variables ---------------------------------------------------------*/
-TIM_HandleTypeDef        htim6;
-/* Private function prototypes -----------------------------------------------*/
-/* Private functions ---------------------------------------------------------*/
-
-/**
-  * @brief  This function configures the TIM6 as a time base source.
-  *         The time source is configured  to have 1ms time base with a dedicated
-  *         Tick interrupt priority.
-  * @note   This function is called  automatically at the beginning of program after
-  *         reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
-  * @param  TickPriority: Tick interrupt priority.
-  * @retval HAL status
-  */
-HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
-{
-  RCC_ClkInitTypeDef    clkconfig;
-  uint32_t              uwTimclock = 0;
-  uint32_t              uwPrescalerValue = 0;
-  uint32_t              pFLatency;
-  /*Configure the TIM6 IRQ priority */
-  HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority ,0);
-
-  /* Enable the TIM6 global Interrupt */
-  HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
-
-  /* Enable TIM6 clock */
-  __HAL_RCC_TIM6_CLK_ENABLE();
-
-  /* Get clock configuration */
-  HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
-
-  /* Compute TIM6 clock */
-  uwTimclock = HAL_RCC_GetPCLK1Freq();
-  /* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
-  uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
-
-  /* Initialize TIM6 */
-  htim6.Instance = TIM6;
-
-  /* Initialize TIMx peripheral as follow:
-  + Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base.
-  + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
-  + ClockDivision = 0
-  + Counter direction = Up
-  */
-  htim6.Init.Period = (1000000U / 1000U) - 1U;
-  htim6.Init.Prescaler = uwPrescalerValue;
-  htim6.Init.ClockDivision = 0;
-  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
-
-  if(HAL_TIM_Base_Init(&htim6) == HAL_OK)
-  {
-    /* Start the TIM time Base generation in interrupt mode */
-    return HAL_TIM_Base_Start_IT(&htim6);
-  }
-
-  /* Return function status */
-  return HAL_ERROR;
-}
-
-/**
-  * @brief  Suspend Tick increment.
-  * @note   Disable the tick increment by disabling TIM6 update interrupt.
-  * @param  None
-  * @retval None
-  */
-void HAL_SuspendTick(void)
-{
-  /* Disable TIM6 update Interrupt */
-  __HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE);
-}
-
-/**
-  * @brief  Resume Tick increment.
-  * @note   Enable the tick increment by Enabling TIM6 update interrupt.
-  * @param  None
-  * @retval None
-  */
-void HAL_ResumeTick(void)
-{
-  /* Enable TIM6 Update interrupt */
-  __HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE);
-}
-
diff --git a/Device/inc/Hal_adc.h b/Device/inc/Hal_adc.h
new file mode 100644
index 0000000..1be9e1d
--- /dev/null
+++ b/Device/inc/Hal_adc.h
@@ -0,0 +1,14 @@
+#ifndef HAL_ADC_H
+#define HAL_ADC_H
+
+#define PCB_TEMPERATURE_CHANNEL (0)
+#define BUS_VOLTAGE_CHANNEL (1U)
+#define BUS_CURRENT_CHANNEL (2U)
+#define PHASE_CURRENT_CHANNEL (3U)
+#define MCU_TEMPERATURE_CHANNEL (4U)
+#define MCU_VOLTAGE_CHANNEL (5U)
+#define MAX_ADC_CHANNEL_NUM (6U)
+
+extern void Hal_ADCInit(void);
+extern uint16_t Hal_GetADCChannelValue(uint8_t channel);
+#endif /*end of file*/
diff --git a/Device/inc/Hal_gpio.h b/Device/inc/Hal_gpio.h
new file mode 100644
index 0000000..5c12756
--- /dev/null
+++ b/Device/inc/Hal_gpio.h
@@ -0,0 +1,24 @@
+#ifndef HAL_GPIO_H
+#define HAL_GPIO_H
+#include "stdint.h"
+
+
+
+extern void Hal_ExtendEndSetActive(void);
+extern void Hal_ExtendEndSetInactive(void);
+extern void Hal_RetractEndSetActive(void);
+extern void Hal_RetractEndSetInactive(void);
+extern void Hal_AlarmSetActive(void);
+extern void Hal_AlarmSetInactive(void);
+extern void Hal_SensorPowerEnable(void);
+extern void Hal_SensorPowerDisable(void);
+extern void Hal_MCU2PowerEnable(void);
+extern void Hal_MCU2PowerDisable(void);
+extern void Hal_CANEnable(void);
+extern void Hal_CANDisable(void);
+extern void Hal_HBridgeEnable(void);
+extern void Hal_HBridgeDisable(void);
+extern uint8_t Hal_GetExtendInLevel(void);
+extern uint8_t Hal_GetRetactInLevel(void);
+
+#endif
diff --git a/Device/inc/as5601.h b/Device/inc/as5601.h
new file mode 100644
index 0000000..165e432
--- /dev/null
+++ b/Device/inc/as5601.h
@@ -0,0 +1,94 @@
+#ifndef AS5601_H
+#define AS5061_H
+
+typedef struct AS5601_Magnet
+{
+    unsigned char magnet_status;
+    unsigned char AGC;
+    unsigned char MAGNITUDE_H4;
+    unsigned char MAGNITUDE_L8;
+} AS5601_Magnet_t;
+
+typedef struct AS5601
+{
+    unsigned char id;
+    unsigned char status;
+    AS5601_Magnet_t magnet;
+    unsigned short zero_pos;
+    unsigned short angle;
+    unsigned short raw_angle;
+} AS5601_t;
+
+typedef union AS5601_CONF
+{
+    unsigned short conf;
+    struct
+    {
+        unsigned char sf : 2;
+        unsigned char FTH : 3;
+        unsigned char WD : 1;
+        unsigned char reserved1 : 2;
+        unsigned char PM : 2;
+        unsigned char HYST : 2;
+        unsigned char reserved2 : 4;
+    } bit;
+} AS5601_CONF_t;
+
+typedef struct AS5601_Config
+{
+    unsigned short zero_pos;
+    AS5601_CONF_t CONF;
+    unsigned char ABN;
+    unsigned char PUSHTHR;
+} AS5601_Config_t;
+
+typedef enum AS5601PowerMode
+{
+    NOM = 0x0,
+    LPM1 = 1,
+    LPM2 = 2,
+    LPM3 = 3
+} AS5601PowerMode_t;
+
+typedef enum AS5601Hysteresis
+{
+    OFF = 0x0,
+    LSB1 = 0x1,
+    LSB2 = 0x2,
+    LSB3 = 0x3
+} AS5601Hysteresis_t;
+
+typedef enum AS5601SlowFilter
+{
+    SlowFilter_16x = 0x0,
+    SlowFilter_8x = 0x1,
+    SlowFilter_4x = 0x2,
+    SlowFilter_2x = 0x3
+} AS5601SlowFilter_t;
+
+typedef enum AS5601FastFilter
+{
+    FastFilter_slow = 0x0,
+    FastFilter_6LSB = 0x1,
+    FastFilter_7LSB = 0x2,
+    FastFilter_9LSB = 0x3,
+    FastFilter_18LSB = 0x4,
+    FastFilter_21LSB = 0x5,
+    FastFilter_24LSB = 0x6,
+    FastFilter_10LSB = 0x7
+} AS5601FastFilter_t;
+typedef enum AS5601ABN
+{
+    ABN_61Hz = 0x0,
+    ABN_122Hz = 0x1,
+    ABN_244Hz = 0x2,
+    ABN_488Hz = 0x3,
+    ABN_976Hz = 0x4,
+    ABN_1k9Hz = 0x5,
+    ABN_3k9Hz = 0x6,
+    ABN_7k8Hz = 0x7,
+    ABN_15k6Hz = 0x8
+} AS5601ABN_t;
+
+extern uint16_t Hal_GetHallSensorRawValue(uint8_t channel);
+#endif
diff --git a/Device/inc/os_clock.h b/Device/inc/os_clock.h
new file mode 100644
index 0000000..e3b83ac
--- /dev/null
+++ b/Device/inc/os_clock.h
@@ -0,0 +1,9 @@
+#ifndef OS_CLOCK_H
+#define OS_CLOCK_H
+extern volatile int OS_TickFlag;
+
+// void Ostick_ReInit(void);
+void os_SetTickFlag(void);
+int os_GetTickFlag(void);
+void os_ClearTickFlag(void);
+#endif
\ No newline at end of file
diff --git a/CAHB_Hal/inc/os_task.h b/Device/inc/os_task.h
similarity index 93%
rename from CAHB_Hal/inc/os_task.h
rename to Device/inc/os_task.h
index 5449660..cf65848 100644
--- a/CAHB_Hal/inc/os_task.h
+++ b/Device/inc/os_task.h
@@ -22,7 +22,7 @@
 	int OSTaskCreate(TASK_FUNC func, int tick, int work_tick, void *par);
 	void OSSchedule(GETTICK_t GetTick);
 	void OS_GetTick(void);
-	extern volatile int OS_TickFlag;
+
 	extern volatile int OS_Init_time_cnt;
 #ifdef __cplusplus
 }
diff --git a/Device/src/Ems_config.h b/Device/src/Ems_config.h
new file mode 100644
index 0000000..67d1293
--- /dev/null
+++ b/Device/src/Ems_config.h
@@ -0,0 +1,27 @@
+/**
+ * @file Ems_config.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_CONFIG_H
+#define EMS_CONFIG_H
+
+/* public config ------------------------------------------------------------ */
+/* CMSIS OS related -------------------------------------- */
+#define EMS_RTOS_CMSIS_OS_EN                   (0)
+#define EMS_RTOS_TICK_MS                       (1)
+
+/* QPC related ------------------------------------------- */
+#define EMS_QPC_EN                             (0)
+#define EMS_EVENT_DATA_SIZE                    (128)
+#define EMS_EVENT_POOL_SIZE                    (64)
+
+#endif /* EMS_CONFIG_H */
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/bsp.c b/Device/src/bsp.c
new file mode 100644
index 0000000..22b0f9b
--- /dev/null
+++ b/Device/src/bsp.c
@@ -0,0 +1,105 @@
+
+/**
+ * @file bsp.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#include "bsp.h"
+#include "stm32l4xx_hal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* private function prototype ----------------------------------------------- */
+static void _error_handler(void);
+static void _system_clock_config(void);
+
+/* includes ----------------------------------------------------------------- */
+/**
+  * @brief  BSP initialization.
+  * @retval None
+  */
+void bsp_init(void)
+{
+    HAL_Init();
+    SystemClock_Config();
+}
+
+/* private functions -------------------------------------------------------- */
+/**
+  * @brief System Clock Configuration
+  * @retval None
+  */
+void SystemClock_Config(void)
+{
+  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+  /** Configure the main internal regulator output voltage
+  */
+  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Initializes the RCC Oscillators according to the specified parameters
+  * in the RCC_OscInitTypeDef structure.
+  */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+  RCC_OscInitStruct.PLL.PLLM = 3;
+  RCC_OscInitStruct.PLL.PLLN = 32;
+  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
+  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
+  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;
+  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Initializes the CPU, AHB and APB buses clocks
+  */
+  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+
+  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
+  {
+    Error_Handler();
+  }
+}
+
+/* USER CODE BEGIN 4 */
+
+/* USER CODE END 4 */
+
+/**
+  * @brief  This function is executed in case of error occurrence.
+  * @retval None
+  */
+void Error_Handler(void)
+{
+  /* USER CODE BEGIN Error_Handler_Debug */
+  /* User can add his own implementation to report the HAL error return state */
+  __disable_irq();
+  while (1)
+  {
+  }
+  /* USER CODE END Error_Handler_Debug */
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/bsp.h b/Device/src/bsp.h
new file mode 100644
index 0000000..0396739
--- /dev/null
+++ b/Device/src/bsp.h
@@ -0,0 +1,25 @@
+/**
+ * @file bsp.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef BSP_H
+#define BSP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void bsp_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Device/src/dev_as5601.c b/Device/src/dev_as5601.c
new file mode 100644
index 0000000..9798084
--- /dev/null
+++ b/Device/src/dev_as5601.c
@@ -0,0 +1,24 @@
+#include "as5601.h"
+#include "i2c.h"
+#include "Hal_gpio.h"
+#include "stm32l4xx_hal_i2c"
+
+
+#define AS5601_ADDRESS  (0x6C) /**< in the as5601 datasheet the address (0x36) is expressed in 7 bit but needs to be left shifted by 1, giving 0x6C*/
+
+#define ZMCO_ADDR       (0x00)
+#define ZPOS_ADDR       (0x01)
+#define CONF_ADDR       (0x07)
+#define ABN_ADDR        (0x09)
+#define PUSHTHR_ADDR    (0x0A)
+#define RAWANGLE_ADDR   (0x0C)
+#define ANGLE_ADDR      (0x0E)
+#define STATUS_ADDR     (0x0B)
+#define AGC_ADDR        (0x1A)
+#define MAGNITUDE_ADDR  (0x1B)
+#define BURN_CMD        (0xFF)
+
+#define BURN_SETTING (0x40)
+#define BURN_ANGLE (0x80)
+
+extern uint16_t Hal_GetHallSensorRawValue(uint8_t channel);
\ No newline at end of file
diff --git a/Device/src/dev_list.h b/Device/src/dev_list.h
new file mode 100644
index 0000000..0605f46
--- /dev/null
+++ b/Device/src/dev_list.h
@@ -0,0 +1,21 @@
+/**
+ * @file dev_list.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+#ifndef __DEV_LIST_H__
+#define __DEV_LIST_H__
+
+#include "Ems_object.h"
+
+extern eio_object_t *led3;
+extern eio_object_t *led4;
+
+#endif /* __DEV_LIST_H__ */
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/dev_pin.c b/Device/src/dev_pin.c
new file mode 100644
index 0000000..67a7be9
--- /dev/null
+++ b/Device/src/dev_pin.c
@@ -0,0 +1,121 @@
+
+/**
+ * @file Ems_pin.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+#include <string.h>
+#include "dev_pin.h"
+#include "ems_assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EMS_TAG("EMS_PIN")
+
+static ems_ops_t _obj_ops =
+{
+    .open = NULL,
+    .close = NULL,
+    .read = NULL,
+    .write = NULL,
+};
+
+/**
+  * @brief  EMS pin initialization.
+  * @param  me      this pointer
+  * @param  name    pin's name.
+  * @param  mode    pin's mode.
+  * @retval None
+  */
+void ems_pin_register(ems_pin_t * const me,
+                        const char *name,
+                        const ems_pin_ops_t *ops,
+                        void *user_data)
+{
+    ems_assert(me != NULL);
+    ems_assert(name != NULL);
+    ems_assert(ops != NULL);
+
+    ems_obj_attr_t attr =
+    {
+        .user_data = user_data,
+        .standlone = true,
+        .type = EMS_OBJ_PIN,
+    };
+
+    ems_register(&me->super, name, &_obj_ops, &attr);
+
+    me->ops = ops;
+    me->ops->init(me);
+    me->status = me->ops->get_status(me);
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param mode 
+ */
+void ems_pin_set_mode(ems_object_t * const me, uint8_t mode)
+{
+    ems_assert(me != NULL);
+
+    ems_pin_t *pin = (ems_pin_t *)me;
+    if (pin->mode != mode)
+    {
+        pin->ops->set_mode(pin, mode);
+        pin->mode = mode;
+    }
+}
+
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @return true 
+ * @return false 
+ */
+bool ems_pin_get_status(ems_object_t * const me)
+{
+    ems_assert(me != NULL);
+    ems_pin_t *pin = (ems_pin_t *)me;
+
+    pin->status = pin->ops->get_status(pin);
+
+    return pin->status;
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param status 
+ */
+void ems_pin_set_status(ems_object_t * const me, bool status)
+{
+    ems_assert(me != NULL);
+
+    ems_pin_t *pin = (ems_pin_t *)me;
+    ems_assert(pin->mode == PIN_MODE_OUTPUT || pin->mode == PIN_MODE_OUTPUT_OD);
+    
+    if (status != pin->status)
+    {
+        pin->ops->set_status(pin, status);
+        ems_pin_get_status(me);
+        ems_assert(pin->status == status);
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/dev_pin.h b/Device/src/dev_pin.h
new file mode 100644
index 0000000..423ee87
--- /dev/null
+++ b/Device/src/dev_pin.h
@@ -0,0 +1,61 @@
+/*
+ * eLesson Project
+ * Copyright (c) 2023, EventOS Team, <event-os@outlook.com>
+ */
+
+#ifndef EMS_PIN_H
+#define EMS_PIN_H
+
+/* includes ----------------------------------------------------------------- */
+#include "eio_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pin_mode
+{
+    PIN_MODE_INPUT = 0,
+    PIN_MODE_INPUT_PULLUP,
+    PIN_MODE_INPUT_PULLDOWN,
+    PIN_MODE_OUTPUT_PP,
+    PIN_MODE_OUTPUT_OD,
+
+    PIN_MODE_MAX
+};
+
+
+typedef struct eio_pin
+{
+    eio_object_t super;
+
+    const struct ems_pin_ops *ops;
+    uint8_t mode;
+    bool status;
+} ems_pin_t;
+
+typedef struct ems_pin_ops
+{
+    void (* init)(ems_pin_t * const me);
+    void (* set_mode)(ems_pin_t * const me, uint8_t mode);
+    bool (* get_status)(ems_pin_t * const me);
+    void (* set_status)(ems_pin_t * const me, bool status);
+} ems_pin_ops_t;
+
+
+void ems_pin_register(ems_pin_t * const me,
+                        const char *name,
+                        const ems_pin_ops_t *ops,
+                        void *user_data);
+
+void ems_pin_set_mode(eio_object_t * const me, uint8_t mode);
+bool ems_pin_get_status(eio_object_t * const me);
+void ems_pin_set_status(eio_object_t * const me, bool status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/dev_pwm.c b/Device/src/dev_pwm.c
new file mode 100644
index 0000000..a7f6c8d
--- /dev/null
+++ b/Device/src/dev_pwm.c
@@ -0,0 +1,84 @@
+/**
+ * @file dev_pwm.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#include <string.h>
+#include "dev_pwm.h"
+#include "ems_assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EMS_TAG("EMS_PWM")
+
+/* private variables -------------------------------------------------------- */
+static ems_ops_t _obj_ops =
+{
+    .open = NULL,
+    .close = NULL,
+    .read = NULL,
+    .write = NULL,
+};
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param name 
+ * @param ops 
+ * @param user_data 
+ */
+void ems_pwm_register(ems_pwm_t * const me,
+                        const char *name,
+                        const ems_pwm_ops_t *ops,
+                        void *user_data)
+{
+    ems_assert(me != NULL);
+    ems_assert(name != NULL);
+    ems_assert(ops != NULL);
+
+    ems_obj_attr_t attr =
+    {
+        .user_data = user_data,
+        .standlone = true,
+        .type = EMS_OBJ_PWM,
+    };
+
+    ems_register(&me->super, name, &_obj_ops, &attr);
+
+    me->ops = ops;
+    me->duty_ratio = 0;
+    me->ops->init(me);
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param duty_ratio 
+ */
+void ems_pwm_set_duty(ems_object_t * const me, uint8_t duty_ratio)
+{
+    ems_assert(me != NULL);
+    ems_assert(duty_ratio <= 100);
+    ems_assert(me->attr.type == EMS_OBJ_PWM);
+    
+    ems_pwm_t *pwm = (ems_pwm_t *)me;
+    if (duty_ratio != pwm->duty_ratio)
+    {
+        pwm->ops->set_duty(pwm, duty_ratio);
+        pwm->duty_ratio = duty_ratio;
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Device/src/dev_pwm.h b/Device/src/dev_pwm.h
new file mode 100644
index 0000000..942b2d5
--- /dev/null
+++ b/Device/src/dev_pwm.h
@@ -0,0 +1,47 @@
+/**
+ * @file dev_pwm.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_PWM_H
+#define EMS_PWM_H
+
+#include "ems_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ems_pwm
+{
+    ems_object_t super;
+
+    const struct ems_pwm_ops *ops;
+    uint8_t duty_ratio;
+} ems_pwm_t;
+
+typedef struct ems_pwm_ops
+{
+    void (* init)(ems_pwm_t * const me);
+    void (* set_duty)(ems_pwm_t * const me, uint8_t duty_ratio);
+} ems_pwm_ops_t;
+
+
+void ems_pwm_register(ems_pwm_t * const me,
+                        const char *name,
+                        const ems_pwm_ops_t *ops,
+                        void *user_data);
+
+void ems_pwm_set_duty(ems_object_t * const me, uint8_t duty_ratio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Device/src/dev_time.c b/Device/src/dev_time.c
new file mode 100644
index 0000000..79f9ef4
--- /dev/null
+++ b/Device/src/dev_time.c
@@ -0,0 +1,43 @@
+/**
+ * @file dev_time.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+#include "ems_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static uint32_t sys_time_ms = 0;
+
+/* public functions --------------------------------------------------------- */
+/**
+  * @brief  SysTick ISR function.
+  * @retval None
+  */
+uint32_t ems_time_ms(void)
+{
+    return sys_time_ms;
+}
+
+/* private functions -------------------------------------------------------- */
+/**
+  * @brief  SysTick ISR function.
+  * @retval None
+  */
+void SysTick_Handler(void)
+{
+    sys_time_ms ++;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Device/src/ems_object.c b/Device/src/ems_object.c
new file mode 100644
index 0000000..671ff25
--- /dev/null
+++ b/Device/src/ems_object.c
@@ -0,0 +1,186 @@
+/**
+ * @file Ems_object.c
+ * @author your name (you@domain.com)
+ * @brief
+ * @version 0.1
+ * @date 2023-04-05
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+/* includes ----------------------------------------------------------------- */
+#include <string.h>
+#include "ems_object.h"
+#include "ems_assert.h"
+
+/* private variables -------------------------------------------------------- */
+static ems_object_t *ems_list = NULL;
+
+/* public functions --------------------------------------------------------- */
+/**
+ * @brief
+ *
+ * @param me
+ * @param name
+ * @param ops
+ * @param attr
+ */
+void ems_register(ems_object_t *const me, const char *name,
+                  const ems_ops_t *ops,
+                  ems_obj_attr_t *attr)
+{
+    ems_assert(me != NULL);
+    ems_assert(name != NULL);
+    ems_assert(ops != NULL);
+    ems_assert(attr != NULL);
+
+    me->name = name;
+    me->ops = ops;
+
+    me->next = ems_list;
+    ems_list = me;
+
+    memcpy(&me->attr, attr, sizeof(ems_obj_attr_t));
+}
+
+/**
+ * @brief
+ *
+ * @param name
+ * @return ems_object_t*
+ */
+ems_object_t *ems_find(const char *name)
+{
+    ems_assert(name != NULL);
+    ems_object_t *obj = ems_list;
+    while (obj != NULL)
+    {
+        if (strcmp(obj->name, name) == 0)
+        {
+            break;
+        }
+        obj = obj->next;
+    }
+
+    return obj;
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @return ems_err_t 
+ */
+ems_err_t ems_open(ems_object_t *const me)
+{
+    ems_assert(me->ops->open != NULL);
+
+    ems_err_t ret = EMS_OK;
+
+    if (me->attr.standlone)
+    {
+        if (me->count_open != 0)
+        {
+            ret = EMS_ERROR;
+            goto exit;
+        }
+    }
+
+    ret = me->ops->open(me);
+    if (ret == EMS_OK)
+    {
+        me->count_open++;
+    }
+
+exit:
+    return ret;
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @return ems_err_t 
+ */
+ems_err_t ems_close(ems_object_t *const me)
+{
+    ems_assert(me->ops->close != NULL);
+
+    ems_err_t ret = EMS_OK;
+
+    if (me->count_open > 0)
+    {
+        ret = me->ops->close(me);
+        if (ret == EMS_OK)
+        {
+            me->count_open--;
+            goto exit;
+        }
+    }
+    else
+    {
+        ret = EMS_ERROR;
+    }
+
+exit:
+    return ret;
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param buffer 
+ * @param size 
+ * @return int32_t 
+ */
+int32_t ems_read(ems_object_t *const me, void *buffer, uint32_t size)
+{
+    ems_assert(me != NULL);
+    ems_assert(buffer != NULL);
+    ems_assert(size != 0);
+    ems_assert(me->ops->read != NULL);
+
+    int32_t ret = 0;
+
+    if (me->count_open != 0)
+    {
+        ret = me->ops->read(me, buffer, size);
+    }
+    else
+    {
+        ret = (int32_t)EMS_ERROR;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief 
+ * 
+ * @param me 
+ * @param buffer 
+ * @param size 
+ * @return int32_t 
+ */
+int32_t ems_write(ems_object_t *const me, const void *buffer, uint32_t size)
+{
+    ems_assert(me != NULL);
+    ems_assert(buffer != NULL);
+    ems_assert(size != 0);
+    ems_assert(me->ops->write != NULL);
+
+    int32_t ret = 0;
+
+    if (me->count_open != 0)
+    {
+        ret = me->ops->write(me, buffer, size);
+    }
+    else
+    {
+        ret = (int32_t)EMS_ERROR;
+    }
+
+    return ret;
+}
diff --git a/Device/src/ems_object.h b/Device/src/ems_object.h
new file mode 100644
index 0000000..9223c56
--- /dev/null
+++ b/Device/src/ems_object.h
@@ -0,0 +1,80 @@
+/**
+ * @file Ems_object.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef Ems_OBJECT_H
+#define Ems_OBJECT_H
+
+/* includes ----------------------------------------------------------------- */
+#include <stdbool.h>
+#include <stdint.h>
+#include "Ems_def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public define ------------------------------------------------------------ */
+enum ems_obect_type
+{
+    EMS_OBJ_PIN = 0,
+    EMS_OBJ_PWM,
+    EMS_OBJ_ADC,
+    EMS_OBJ_DAC,
+    EMS_OBJ_UART,
+    EMS_OBJ_SPI,
+    EMS_OBJ_I2C,
+    EMS_OBJ_CAN,
+    EMS_OBJ_MAX
+};
+
+/* public typedef ----------------------------------------------------------- */
+typedef struct ems_obj_attr
+{
+    void *user_data;
+    uint8_t type;
+    bool standlone;
+} ems_obj_attr_t;
+
+typedef struct ems_object
+{
+    struct ems_object *next;
+    const char *name;
+    const struct ems_ops *ops;
+    uint16_t count_open;
+    ems_obj_attr_t attr;
+} ems_object_t;
+
+typedef struct ems_ops
+{
+    ems_err_t (* open)(ems_object_t * const me);
+    ems_err_t (* close)(ems_object_t * const me);
+    int32_t (* read)(ems_object_t * const me, void *buffer, uint32_t size);
+    int32_t (* write)(ems_object_t * const me, const void *buffer, uint32_t size);
+} ems_ops_t;
+
+
+/* For io-level driver. */
+void ems_register(ems_object_t * const me, const char *name,
+                    const ems_ops_t *ops,
+                    ems_obj_attr_t *attr);
+
+/* For high-level code. */
+ems_object_t *ems_find(const char *name);
+ems_err_t ems_open(ems_object_t * const me);
+ems_err_t ems_close(ems_object_t * const me);
+int32_t ems_read(ems_object_t * const me, void *buffer, uint32_t size);
+int32_t ems_write(ems_object_t * const me, const void *buffer, uint32_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* EMS_OBJECT_H */
diff --git a/Device/src/os_clock.c b/Device/src/os_clock.c
new file mode 100644
index 0000000..c35b312
--- /dev/null
+++ b/Device/src/os_clock.c
@@ -0,0 +1,19 @@
+#include "os_clock.h"
+#include "os_task.h"
+#include "stm32l4xx_hal.h"
+
+volatile int OS_TickFlag = 0;
+
+void os_SetTickFlag(void)
+{
+    OS_TickFlag = 1;
+}
+int os_GetTickFlag(void)
+{
+    return OS_TickFlag;
+}
+void os_ClearTickFlag(void)
+{
+    OS_TickFlag = 0;
+}
+
diff --git a/CAHB_Hal/src/os_task.c b/Device/src/os_task.c
similarity index 94%
rename from CAHB_Hal/src/os_task.c
rename to Device/src/os_task.c
index 6388027..f454daf 100644
--- a/CAHB_Hal/src/os_task.c
+++ b/Device/src/os_task.c
@@ -1,10 +1,11 @@
 
 #include "os_task.h"
+#include "os_clock.h"
 // extern int OS_TickFlag = 0;
 static OS_TASK_MSG *g_p_task = NULL; 
 static int g_task_cnt = 0;           
 static int g_task_pos = 0;          
-volatile int OS_TickFlag = 0;
+
 /**
  * @brief 
  * 
@@ -84,7 +85,7 @@
 
 void OS_GetTick(void)
 {
-    while (1 != OS_TickFlag)
+    while (1 != os_GetTickFlag())
         ;
-    OS_TickFlag = 0;
+    os_ClearTickFlag();
 }
diff --git a/Core/Inc/adc.h b/Driver/Inc/adc.h
similarity index 96%
rename from Core/Inc/adc.h
rename to Driver/Inc/adc.h
index 218e684..42107d4 100644
--- a/Core/Inc/adc.h
+++ b/Driver/Inc/adc.h
@@ -33,7 +33,7 @@
 /* USER CODE END Includes */
 
 extern ADC_HandleTypeDef hadc1;
-
+extern DMA_HandleTypeDef hdma_adc1;
 /* USER CODE BEGIN Private defines */
 
 /* USER CODE END Private defines */
diff --git a/Core/Inc/can.h b/Driver/Inc/can.h
similarity index 100%
rename from Core/Inc/can.h
rename to Driver/Inc/can.h
diff --git a/Driver/Inc/clock.h b/Driver/Inc/clock.h
new file mode 100644
index 0000000..d101473
--- /dev/null
+++ b/Driver/Inc/clock.h
@@ -0,0 +1,7 @@
+#ifndef CLOCK_H
+#define CLOCK_H
+#include "stdint.h"
+extern void SystemClock_Config(void);
+extern void assert_failed(uint8_t *file, uint32_t line);
+extern void Error_Handler(void);
+#endif
diff --git a/Core/Inc/crc.h b/Driver/Inc/crc.h
similarity index 100%
rename from Core/Inc/crc.h
rename to Driver/Inc/crc.h
diff --git a/Core/Inc/dma.h b/Driver/Inc/dma.h
similarity index 100%
rename from Core/Inc/dma.h
rename to Driver/Inc/dma.h
diff --git a/Core/Inc/gpio.h b/Driver/Inc/gpio.h
similarity index 100%
rename from Core/Inc/gpio.h
rename to Driver/Inc/gpio.h
diff --git a/Core/Inc/i2c.h b/Driver/Inc/i2c.h
similarity index 100%
rename from Core/Inc/i2c.h
rename to Driver/Inc/i2c.h
diff --git a/Core/Inc/main.h b/Driver/Inc/main.h
similarity index 100%
rename from Core/Inc/main.h
rename to Driver/Inc/main.h
diff --git a/Core/Inc/stm32l4xx_hal_conf.h b/Driver/Inc/stm32l4xx_hal_conf.h
similarity index 100%
rename from Core/Inc/stm32l4xx_hal_conf.h
rename to Driver/Inc/stm32l4xx_hal_conf.h
diff --git a/Core/Inc/stm32l4xx_it.h b/Driver/Inc/stm32l4xx_it.h
similarity index 97%
rename from Core/Inc/stm32l4xx_it.h
rename to Driver/Inc/stm32l4xx_it.h
index 83f5517..cbfc055 100644
--- a/Core/Inc/stm32l4xx_it.h
+++ b/Driver/Inc/stm32l4xx_it.h
@@ -56,7 +56,6 @@
 void PendSV_Handler(void);
 void SysTick_Handler(void);
 void DMA1_Channel1_IRQHandler(void);
-void TIM6_DAC_IRQHandler(void);
 /* USER CODE BEGIN EFP */
 
 /* USER CODE END EFP */
diff --git a/Core/Inc/tim.h b/Driver/Inc/tim.h
similarity index 100%
rename from Core/Inc/tim.h
rename to Driver/Inc/tim.h
diff --git a/Driver/Src/Hal_adc.c b/Driver/Src/Hal_adc.c
new file mode 100644
index 0000000..ede0888
--- /dev/null
+++ b/Driver/Src/Hal_adc.c
@@ -0,0 +1,87 @@
+#include "stdint.h"
+#include "main.h"
+#include "adc.h"
+#include "Hal_adc.h"
+
+#include "dma.h"
+#include "stm32l4xx_hal_dma.h"
+/**
+ * @brief half PWM duty trigger start adc. when adc convert complete and trigger DMA interrupt. do filt in the interrupt callbackfun.
+ *
+ */
+typedef void (*ADC_RESULTFILTER_t)(uint16_t input, uint16_t *output);
+extern uint16_t Hal_GetADCChannelValue(uint8_t channel);
+static void Hal_AdcDmaCallback(DMA_HandleTypeDef *_hdma);
+static void Hal_PCBTemperatureFilter(uint16_t input, uint16_t *output);
+static void Hal_BusVoltageFilter(uint16_t input, uint16_t *output);
+static void Hal_BusCurrentFilter(uint16_t input, uint16_t *output);
+static void Hal_PhaseCurrentFilter(uint16_t input, uint16_t *output);
+static void Hal_MCUTemperFilter(uint16_t input, uint16_t *output);
+static void Hal_MCUVoltageFilter(uint16_t input, uint16_t *output);
+
+static uint16_t Hal_O_AdcFilterResult[7] = {0};
+static volatile uint16_t Hal_ADC_DMA_RawResult[7] = {0};
+static const ADC_RESULTFILTER_t Hal_adcResultFilterFun[MAX_ADC_CHANNEL_NUM] = {Hal_PCBTemperatureFilter, Hal_BusVoltageFilter, Hal_BusCurrentFilter, Hal_PhaseCurrentFilter, Hal_MCUTemperFilter, Hal_MCUVoltageFilter};
+
+/**
+ * @brief 
+ * 
+ */
+extern void Hal_ADCInit(void)
+{
+
+    HAL_DMA_RegisterCallback(&hdma_adc1, HAL_DMA_XFER_CPLT_CB_ID, Hal_AdcDmaCallback);
+    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&Hal_ADC_DMA_RawResult, 6);
+}
+
+extern uint16_t Hal_GetADCChannelValue(uint8_t channel)
+{
+    uint16_t retvalue = 0;
+    if (channel < MAX_ADC_CHANNEL_NUM)
+    {
+        retvalue = Hal_O_AdcFilterResult[channel];
+    }
+    else
+    {
+    }
+    return retvalue;
+}
+static void Hal_AdcDmaCallback(DMA_HandleTypeDef *_hdma)
+{
+    uint8_t i = 0;
+    for (i = 0; i < MAX_ADC_CHANNEL_NUM; i++)
+    {
+        Hal_adcResultFilterFun[i](Hal_ADC_DMA_RawResult[i], &Hal_O_AdcFilterResult[i]);
+    }
+}
+
+static void Hal_PCBTemperatureFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 3u * (temp >> 2u) + (input >> 2u);
+}
+static void Hal_BusVoltageFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 7u * (temp >> 3u) + (input >> 3u);
+}
+static void Hal_BusCurrentFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 3u * (temp >> 2u) + (input >> 2u);
+}
+static void Hal_PhaseCurrentFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 3u * (temp >> 2u) + (input >> 2u);
+}
+static void Hal_MCUTemperFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 3u * (temp >> 2u) + (input >> 2u);
+}
+static void Hal_MCUVoltageFilter(uint16_t input, uint16_t *output)
+{
+    uint16_t temp = *output;
+    *output = 3u * (temp >> 2u) + (input >> 2u);
+}
\ No newline at end of file
diff --git a/Core/Src/adc.c b/Driver/Src/adc.c
similarity index 100%
rename from Core/Src/adc.c
rename to Driver/Src/adc.c
diff --git a/Core/Src/can.c b/Driver/Src/can.c
similarity index 100%
rename from Core/Src/can.c
rename to Driver/Src/can.c
diff --git a/Core/Src/clock.c b/Driver/Src/clock.c
similarity index 87%
rename from Core/Src/clock.c
rename to Driver/Src/clock.c
index 1bf3abd..498345a 100644
--- a/Core/Src/clock.c
+++ b/Driver/Src/clock.c
@@ -52,7 +52,6 @@
 /* USER CODE END PV */
 
 /* Private function prototypes -----------------------------------------------*/
-void SystemClock_Config(void);
 /* USER CODE BEGIN PFP */
 
 /* USER CODE END PFP */
@@ -116,26 +115,6 @@
 /* USER CODE BEGIN 4 */
 
 /* USER CODE END 4 */
-
-/**
-  * @brief  Period elapsed callback in non blocking mode
-  * @note   This function is called  when TIM6 interrupt took place, inside
-  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
-  * a global variable "uwTick" used as application time base.
-  * @param  htim : TIM handle
-  * @retval None
-  */
-void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
-{
-  /* USER CODE BEGIN Callback 0 */
-
-  /* USER CODE END Callback 0 */
-  if (htim->Instance == TIM6) {
-    HAL_IncTick();
-  }
-  /* USER CODE BEGIN Callback 1 */
-  /* USER CODE END Callback 1 */
-}
 
 /**
   * @brief  This function is executed in case of error occurrence.
diff --git a/Core/Src/crc.c b/Driver/Src/crc.c
similarity index 100%
rename from Core/Src/crc.c
rename to Driver/Src/crc.c
diff --git a/Core/Src/dma.c b/Driver/Src/dma.c
similarity index 100%
rename from Core/Src/dma.c
rename to Driver/Src/dma.c
diff --git a/Driver/Src/drv_gpio.c b/Driver/Src/drv_gpio.c
new file mode 100644
index 0000000..8c0afb4
--- /dev/null
+++ b/Driver/Src/drv_gpio.c
@@ -0,0 +1,86 @@
+#include "Hal_gpio.h"
+#include "gpio.h"
+#include "main.h"
+#include "stm32l4xx_hal_gpio.h"
+
+extern void Hal_ExtendEndSetActive(void)
+{
+    HAL_GPIO_WritePin(EXT_END_GPIO_Port,EXT_END_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_ExtendEndSetInactive(void)
+{
+    HAL_GPIO_WritePin(EXT_END_GPIO_Port,EXT_END_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_RetractEndSetActive(void)
+{
+    HAL_GPIO_WritePin(RET_END_GPIO_Port,RET_END_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_RetractEndSetInactive(void)
+{
+    HAL_GPIO_WritePin(RET_END_GPIO_Port,RET_END_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_AlarmSetActive(void)
+{
+    HAL_GPIO_WritePin(ALARM_C_GPIO_Port,ALARM_C_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_AlarmSetInactive(void)
+{
+    HAL_GPIO_WritePin(ALARM_C_GPIO_Port,ALARM_C_Pin,GPIO_PIN_RESET);
+}
+
+
+extern void Hal_SensorPowerEnable(void)
+{
+    HAL_GPIO_WritePin(SENSOR_EN_GPIO_Port,SENSOR_EN_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_SensorPowerDisable(void)
+{
+    HAL_GPIO_WritePin(SENSOR_EN_GPIO_Port,SENSOR_EN_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_MCU2PowerEnable(void)
+{
+    HAL_GPIO_WritePin(POWER_MCU2_GPIO_Port,POWER_MCU2_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_MCU2PowerDisable(void)
+{
+    HAL_GPIO_WritePin(POWER_MCU2_GPIO_Port,POWER_MCU2_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_CANEnable(void)
+{
+    HAL_GPIO_WritePin(CAN_STB_GPIO_Port,CAN_STB_Pin,GPIO_PIN_RESET);
+}
+
+extern void Hal_CANDisable(void)
+{
+    HAL_GPIO_WritePin(CAN_STB_GPIO_Port,CAN_STB_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_HBridgeEnable(void)
+{
+    HAL_GPIO_WritePin(DRV_L_EN_GPIO_Port,DRV_L_EN_Pin,GPIO_PIN_SET);
+}
+
+extern void Hal_HBridgeDisable(void)
+{
+    HAL_GPIO_WritePin(DRV_L_EN_GPIO_Port,DRV_L_EN_Pin,GPIO_PIN_RESET);
+}
+
+
+extern uint8_t Hal_GetExtendInLevel(void)
+{
+    return HAL_GPIO_ReadPin(EXTEND_IN_GPIO_Port,EXTEND_IN_Pin);
+}
+
+extern uint8_t Hal_GetRetactInLevel(void)
+{
+    return HAL_GPIO_ReadPin(RETRACT_IN_GPIO_Port,RETRACT_IN_Pin);
+}
\ No newline at end of file
diff --git a/Driver/Src/drv_pin.c b/Driver/Src/drv_pin.c
new file mode 100644
index 0000000..d99910e
--- /dev/null
+++ b/Driver/Src/drv_pin.c
@@ -0,0 +1,209 @@
+
+/**
+ * @file drv_pin.c
+ * @author your name (you@domain.com)
+ * @brief
+ * @version 0.1
+ * @date 2023-04-05
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+#include <string.h>
+#include "ems_pin.h"
+#include "ems_assert.h"
+#include "ems_def.h"
+#include "ems_export.h"
+#include "stm32l4xx_hal.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    EMS_TAG("Driver_PIN")
+
+    /* public typedef ----------------------------------------------------------- */
+    typedef struct ems_pin_data
+    {
+        ems_pin_t *device;
+        const char *name;
+        GPIO_TypeDef *gpio_x;
+        uint16_t pin;
+        GPIO_PinState Init_level;
+    } ems_pin_data_t;
+
+    /* private function prototype ----------------------------------------------- */
+    static void _init(ems_pin_t *const me);
+    static void _set_mode(ems_pin_t *const me, uint8_t mode);
+    static bool _get_status(ems_pin_t *const me);
+    static void _set_status(ems_pin_t *const me, bool status);
+
+    /* private variables -------------------------------------------------------- */
+    static ems_pin_t ems_l_pin[14] = {0};
+
+    static const ems_pin_ops_t pin_driver_ops =
+        {
+            .init = _init,
+            .set_mode = _set_mode,
+            .get_status = _get_status,
+            .set_status = _set_status,
+    };
+
+    const static ems_pin_data_t ems_pin_driver_data[] =
+        {
+            {&ems_l_pin[0], "CAN_DET", GPIOC, GPIO_PIN_15, GPIO_PIN_RESET},
+            {&ems_l_pin[1], "EXT_END", GPIOA, GPIO_PIN_0, GPIO_PIN_RESET},
+            {&ems_l_pin[2], "RET_END", GPIOA, GPIO_PIN_1, GPIO_PIN_RESET},
+            {&ems_l_pin[3], "SENSOR_EN", GPIOA, GPIO_PIN_4, GPIO_PIN_RESET},
+            {&ems_l_pin[4], "ALARM", GPIOA, GPIO_PIN_5, GPIO_PIN_RESET},
+            {&ems_l_pin[5], "INCSIMA", GPIOA, GPIO_PIN_6, GPIO_PIN_RESET},
+            {&ems_l_pin[6], "INCSIMB", GPIOA, GPIO_PIN_7, GPIO_PIN_RESET},
+            {&ems_l_pin[7], "POWER_MCU2", GPIOB, GPIO_PIN_2, GPIO_PIN_RESET},
+            {&ems_l_pin[8], "EXT_IN", GPIOB, GPIO_PIN_10, GPIO_PIN_RESET},
+            {&ems_l_pin[9], "RET_IN", GPIOB, GPIO_PIN_11, GPIO_PIN_RESET},
+            {&ems_l_pin[10], "CAN_STB", GPIOB, GPIO_PIN_12, GPIO_PIN_RESET},
+            {&ems_l_pin[11], "DRV_L_EN", GPIOB, GPIO_PIN_3, GPIO_PIN_RESET},
+            {&ems_l_pin[12], "DIAG_M1", GPIOB, GPIO_PIN_4, GPIO_PIN_RESET},
+            {&ems_l_pin[13], "DIAG_M2", GPIOB, GPIO_PIN_5, GPIO_PIN_RESET},
+    };
+#define PIN_NUM (sizeof(ems_pin_driver_data) / sizeof(ems_pin_data_t))
+    /* public functions --------------------------------------------------------- */
+    static void ems_pin_dirver_init(void)
+    {
+        for (uint32_t i = 0; i < PIN_NUM; i++)
+        {
+            /* Enable the clock. */
+            if (ems_pin_driver_data[i].gpio_x == GPIOA)
+            {
+                __HAL_RCC_GPIOA_CLK_ENABLE();
+            }
+            else if (ems_pin_driver_data[i].gpio_x == GPIOB)
+            {
+                __HAL_RCC_GPIOB_CLK_ENABLE();
+            }
+            else if (ems_pin_driver_data[i].gpio_x == GPIOC)
+            {
+                __HAL_RCC_GPIOC_CLK_ENABLE();
+            }
+            else
+            {
+                ;
+            }
+
+            /* Device registering. */
+            ems_pin_register(ems_pin_driver_data[i].device,
+                             ems_pin_driver_data[i].name,
+                             &pin_driver_ops,
+                             &ems_pin_driver_data[i]);
+        }
+    }
+    INIT_IO_DRIVER_EXPORT(ems_pin_dirver_init);
+
+    /* private functions -------------------------------------------------------- */
+    /**
+     * @brief  The PIN driver initialization function.
+     * @param  me  PIN device handle.
+     * @retval None.
+     */
+    static void _init(ems_pin_t *const me)
+    {
+        ems_pin_data_t *driver_data = (ems_pin_data_t *)me->super.attr.user_data;
+
+        /* Configure GPIO pin. */
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Pin = driver_data->pin;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+        HAL_GPIO_Init(driver_data->gpio_x, &GPIO_InitStruct);
+
+        HAL_GPIO_WritePin(driver_data->gpio_x,
+                          driver_data->pin,
+                          GPIO_PIN_RESET);
+    }
+
+    /**
+     * @brief  The PIN driver set_mode function.
+     * @param  me  PIN device handle.
+     * @retval None.
+     */
+    static void _set_mode(ems_pin_t *const me, uint8_t mode)
+    {
+        ems_assert(me != NULL);
+        ems_assert(mode < PIN_MODE_MAX);
+
+        ems_pin_data_t *driver_data = (ems_pin_data_t *)me->super.attr.user_data;
+
+        /* Configure GPIO pin. */
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+        if (mode == PIN_MODE_INPUT)
+        {
+            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+            GPIO_InitStruct.Pull = GPIO_NOPULL;
+        }
+        else if (mode == PIN_MODE_INPUT_PULLUP)
+        {
+            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+            GPIO_InitStruct.Pull = GPIO_PULLUP;
+        }
+        else if (mode == PIN_MODE_INPUT_PULLDOWN)
+        {
+            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+        }
+        else if (mode == PIN_MODE_OUTPUT_PP)
+        {
+            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+            GPIO_InitStruct.Pull = GPIO_NOPULL;
+        }
+        else if (mode == PIN_MODE_OUTPUT_OD)
+        {
+            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
+            GPIO_InitStruct.Pull = GPIO_PULLUP;
+        }
+        GPIO_InitStruct.Pin = driver_data->pin;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+        HAL_GPIO_Init(driver_data->gpio_x, &GPIO_InitStruct);
+    }
+
+    /**
+     * @brief  The PIN driver set_mode function.
+     * @param  me  PIN device handle.
+     * @retval GPIO status.
+     */
+    static bool _get_status(ems_pin_t *const me)
+    {
+        ems_assert(me != NULL);
+        ems_assert(mode < PIN_MODE_MAX);
+
+        ems_pin_data_t *driver_data = (ems_pin_data_t *)me->super.attr.user_data;
+
+        GPIO_PinState status = HAL_GPIO_ReadPin(driver_data->gpio_x, driver_data->pin);
+
+        return (status == GPIO_PIN_SET) ? true : false;
+    }
+
+    /**
+     * @brief  The PIN driver set_status function.
+     * @param  me      PIN device handle.
+     * @param  status  GPIO status.
+     * @retval None.
+     */
+    static void _set_status(ems_pin_t *const me, bool status)
+    {
+        ems_assert(me != NULL);
+        ems_assert(mode < PIN_MODE_MAX);
+
+        ems_pin_data_t *driver_data = (ems_pin_data_t *)me->super.attr.user_data;
+
+        HAL_GPIO_WritePin(driver_data->gpio_x,
+                          driver_data->pin,
+                          status ? GPIO_PIN_SET : GPIO_PIN_RESET);
+    }
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Driver/Src/drv_pwm.c b/Driver/Src/drv_pwm.c
new file mode 100644
index 0000000..c82d794
--- /dev/null
+++ b/Driver/Src/drv_pwm.c
@@ -0,0 +1,184 @@
+
+/*
+ * eLesson Project
+ * Copyright (c) 2023, EventOS Team, <event-os@outlook.com>
+ */
+
+/* includes ----------------------------------------------------------------- */
+#include "eio_pwm.h"
+#include "stm32g0xx_hal.h"
+#include "ems_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public typedef ----------------------------------------------------------- */
+typedef struct eio_pwm_data
+{
+    eio_pwm_t *device;
+    const char *name;
+    GPIO_TypeDef *gpio_x;
+    uint16_t pin;
+    uint32_t alternate;
+    TIM_HandleTypeDef *htim;
+    uint32_t channel;
+} eio_pwm_data_t;
+
+/* private function prototype ----------------------------------------------- */
+static void _init(eio_pwm_t * const me);
+static void _set_duty(eio_pwm_t * const me, uint8_t duty_ratio);
+
+static void _timer_pwm_init(eio_pwm_data_t *data);
+static void _gpio_pwm_init(eio_pwm_data_t *data);
+
+/* private variables -------------------------------------------------------- */
+static eio_pwm_t pwm_led3;
+static eio_pwm_t pwm_led4;
+static eio_pwm_t pwm_adc_in;
+
+static TIM_HandleTypeDef htim1;
+static TIM_HandleTypeDef htim15;
+
+static eio_pwm_data_t pwm_driver_data[] =
+{
+    {
+        &pwm_led3, "pwmled3",
+        GPIOC, GPIO_PIN_8, GPIO_AF2_TIM1, &htim1, TIM_CHANNEL_1,
+    },
+    {
+        &pwm_led4, "pwmled4",
+        GPIOC, GPIO_PIN_9, GPIO_AF2_TIM1, &htim1, TIM_CHANNEL_2,
+    },
+    {
+        &pwm_adc_in, "adc_in",
+        GPIOC, GPIO_PIN_1, GPIO_AF2_TIM15, &htim15, TIM_CHANNEL_1,
+    },
+};
+
+static const eio_pwm_ops_t pwm_driver_ops =
+{
+    .init = _init,
+    .set_duty = _set_duty,
+};
+
+/* public functions --------------------------------------------------------- */
+static void driver_pwm_init(void)
+{
+    __HAL_RCC_TIM1_CLK_ENABLE();
+    __HAL_RCC_TIM15_CLK_ENABLE();
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+
+    htim1.Instance = TIM1;
+    htim1.Init.Prescaler = 63;
+    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
+    htim1.Init.Period = 999;
+    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+    htim1.Init.RepetitionCounter = 0;
+    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+    HAL_TIM_PWM_Init(&htim1);
+
+    htim15.Instance = TIM15;
+    htim15.Init.Prescaler = 63;
+    htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
+    htim15.Init.Period = 999;
+    htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+    htim15.Init.RepetitionCounter = 0;
+    htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+    HAL_TIM_PWM_Init(&htim15);
+
+    for (uint32_t i = 0;
+            i < sizeof(pwm_driver_data) / sizeof(eio_pwm_data_t); i ++)
+    {
+        /* Device registering. */
+        eio_pwm_register(pwm_driver_data[i].device,
+                            pwm_driver_data[i].name,
+                            &pwm_driver_ops,
+                            &pwm_driver_data[i]);
+    }
+}
+INIT_IO_DRIVER_EXPORT(driver_pwm_init);
+
+/* private functions -------------------------------------------------------- */
+static void _init(eio_pwm_t * const me)
+{
+    eio_pwm_data_t *data = me->super.attr.user_data;
+
+    
+    _timer_pwm_init(data);
+    _gpio_pwm_init(data);
+
+    HAL_TIM_PWM_Start(data->htim, data->channel);
+}
+
+static void _set_duty(eio_pwm_t * const me, uint8_t duty)
+{
+    eio_pwm_data_t *data = me->super.attr.user_data;
+
+    HAL_TIM_PWM_Stop(data->htim, data->channel);
+    
+    TIM_OC_InitTypeDef sConfigOC = {0};
+    sConfigOC.OCMode = TIM_OCMODE_PWM1;
+    sConfigOC.Pulse = duty * 10;
+    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
+    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
+    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
+    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+    HAL_TIM_PWM_ConfigChannel(data->htim, &sConfigOC, data->channel);
+
+    HAL_TIM_PWM_Start(data->htim, data->channel);
+}
+
+static void _timer_pwm_init(eio_pwm_data_t *data)
+{
+    TIM_MasterConfigTypeDef sMasterConfig = {0};
+    TIM_OC_InitTypeDef sConfigOC = {0};
+    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
+
+    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+    sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
+    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+    HAL_TIMEx_MasterConfigSynchronization(data->htim, &sMasterConfig);
+
+    sConfigOC.OCMode = TIM_OCMODE_PWM1;
+    sConfigOC.Pulse = 0;
+    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
+    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
+    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
+    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+    HAL_TIM_PWM_ConfigChannel(data->htim, &sConfigOC, data->channel);
+
+    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
+    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
+    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
+    sBreakDeadTimeConfig.DeadTime = 0;
+    sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
+    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
+    sBreakDeadTimeConfig.BreakFilter = 0;
+    sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
+    sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
+    sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
+    sBreakDeadTimeConfig.Break2Filter = 0;
+    sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
+    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
+    HAL_TIMEx_ConfigBreakDeadTime(data->htim, &sBreakDeadTimeConfig);
+}
+
+static void _gpio_pwm_init(eio_pwm_data_t *data)
+{
+    GPIO_InitTypeDef GPIO_InitStruct = {0};
+    GPIO_InitStruct.Pin = data->pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = data->alternate;
+    HAL_GPIO_Init(data->gpio_x, &GPIO_InitStruct);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Core/Src/gpio.c b/Driver/Src/gpio.c
similarity index 100%
rename from Core/Src/gpio.c
rename to Driver/Src/gpio.c
diff --git a/Core/Src/i2c.c b/Driver/Src/i2c.c
similarity index 100%
rename from Core/Src/i2c.c
rename to Driver/Src/i2c.c
diff --git a/Core/Src/tim.c b/Driver/Src/tim.c
similarity index 100%
rename from Core/Src/tim.c
rename to Driver/Src/tim.c
diff --git a/Ems/3rd/Shell/shell.c b/Ems/3rd/Shell/shell.c
new file mode 100644
index 0000000..29c3d25
--- /dev/null
+++ b/Ems/3rd/Shell/shell.c
@@ -0,0 +1,1972 @@
+/**
+ * @file shell.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @version 3.0.0
+ * @date 2019-12-30
+ * 
+ * @copyright (c) 2020 Letter
+ * 
+ */
+
+#include <stdint.h>
+#include "shell.h"
+#include "string.h"
+#include "stdio.h"
+#include "stdarg.h"
+#include "shell_ext.h"
+
+
+#if SHELL_USING_CMD_EXPORT == 1
+/**
+ * @brief 默认用户
+ */
+const char shellCmdDefaultUser[] = SHELL_DEFAULT_USER;
+const char shellPasswordDefaultUser[] = SHELL_DEFAULT_USER_PASSWORD;
+const char shellDesDefaultUser[] = "default user";
+SHELL_USED const ShellCommand shellUserDefault SHELL_SECTION("shellCommand") =
+{
+    .attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
+    .data.user.name = shellCmdDefaultUser,
+    .data.user.password = shellPasswordDefaultUser,
+    .data.user.desc = shellDesDefaultUser
+};
+#endif
+
+#if SHELL_USING_CMD_EXPORT == 1
+    #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
+        extern const unsigned int shellCommand$$Base;
+        extern const unsigned int shellCommand$$Limit;
+    #elif defined(__ICCARM__) || defined(__ICCRX__)
+        #pragma section="shellCommand"
+    #elif defined(__GNUC__)
+        extern const unsigned int _shell_command_start;
+        extern const unsigned int _shell_command_end;
+    #endif
+#else
+    extern const ShellCommand shellCommandList[];
+    extern const unsigned short shellCommandCount;
+#endif
+
+
+/**
+ * @brief shell 常量文本索引
+ */
+enum
+{
+#if SHELL_SHOW_INFO == 1
+    SHELL_TEXT_INFO,                                    /**< shell信息 */
+#endif
+    SHELL_TEXT_CMD_TOO_LONG,                            /**< 命令过长 */
+    SHELL_TEXT_CMD_LIST,                                /**< 可执行命令列表标题 */
+    SHELL_TEXT_VAR_LIST,                                /**< 变量列表标题 */
+    SHELL_TEXT_USER_LIST,                               /**< 用户列表标题 */
+    SHELL_TEXT_KEY_LIST,                                /**< 按键列表标题 */
+    SHELL_TEXT_CMD_NOT_FOUND,                           /**< 命令未找到 */
+    SHELL_TEXT_POINT_CANNOT_MODIFY,                     /**< 指针变量不允许修改 */
+    SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY,             /**< 只读变量不允许修改 */
+    SHELL_TEXT_NOT_VAR,                                 /**< 命令不是变量 */
+    SHELL_TEXT_VAR_NOT_FOUND,                           /**< 变量未找到 */
+    SHELL_TEXT_HELP_HEADER,                             /**< help头 */
+    SHELL_TEXT_PASSWORD_HINT,                           /**< 密码输入提示 */
+    SHELL_TEXT_PASSWORD_ERROR,                          /**< 密码错误 */
+    SHELL_TEXT_CLEAR_CONSOLE,                           /**< 清空控制台 */
+    SHELL_TEXT_CLEAR_LINE,                              /**< 清空当前行 */
+    SHELL_TEXT_TYPE_CMD,                                /**< 命令类型 */
+    SHELL_TEXT_TYPE_VAR,                                /**< 变量类型 */
+    SHELL_TEXT_TYPE_USER,                               /**< 用户类型 */
+    SHELL_TEXT_TYPE_KEY,                                /**< 按键类型 */
+    SHELL_TEXT_TYPE_NONE,                               /**< 非法类型 */
+#if SHELL_EXEC_UNDEF_FUNC == 1
+    SHELL_TEXT_PARAM_ERROR,                             /**< 参数错误 */
+#endif
+};
+
+
+static const char *shellText[] =
+{
+#if SHELL_SHOW_INFO == 1
+    [SHELL_TEXT_INFO] =
+        "\r\n"
+        "eLab project\r\n"
+        "Version:     "SHELL_VERSION"\r\n"
+        "Copyright:   (c) 2023 eLab Team & GouGe\r\n",
+#endif
+    [SHELL_TEXT_CMD_TOO_LONG] = 
+        "\r\nWarning: Command is too long\r\n",
+    [SHELL_TEXT_CMD_LIST] = 
+        "\r\nCommand List:\r\n",
+    [SHELL_TEXT_VAR_LIST] = 
+        "\r\nVar List:\r\n",
+    [SHELL_TEXT_USER_LIST] = 
+        "\r\nUser List:\r\n",
+    [SHELL_TEXT_KEY_LIST] =
+        "\r\nKey List:\r\n",
+    [SHELL_TEXT_CMD_NOT_FOUND] = 
+        "Command not Found\r\n",
+    [SHELL_TEXT_POINT_CANNOT_MODIFY] = 
+        "can't set pointer\r\n",
+    [SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY] = 
+        "can't set read only var\r\n",
+    [SHELL_TEXT_NOT_VAR] =
+        " is not a var\r\n",
+    [SHELL_TEXT_VAR_NOT_FOUND] = 
+        "Var not Fount\r\n",
+    [SHELL_TEXT_HELP_HEADER] =
+        "command help of ",
+    [SHELL_TEXT_PASSWORD_HINT] = 
+        "\r\nPlease input password:",
+    [SHELL_TEXT_PASSWORD_ERROR] = 
+        "\r\npassword error\r\n",
+    [SHELL_TEXT_CLEAR_CONSOLE] = 
+        "\033[2J\033[1H",
+    [SHELL_TEXT_CLEAR_LINE] = 
+        "\033[2K\r",
+    [SHELL_TEXT_TYPE_CMD] = 
+        "CMD ",
+    [SHELL_TEXT_TYPE_VAR] = 
+        "VAR ",
+    [SHELL_TEXT_TYPE_USER] = 
+        "USER",
+    [SHELL_TEXT_TYPE_KEY] = 
+        "KEY ",
+    [SHELL_TEXT_TYPE_NONE] = 
+        "NONE",
+#if SHELL_EXEC_UNDEF_FUNC == 1
+    [SHELL_TEXT_PARAM_ERROR] = 
+        "Parameter error\r\n",
+#endif
+};
+
+
+/**
+ * @brief shell对象表
+ */
+static Shell *shellList[SHELL_MAX_NUMBER] = {NULL};
+
+
+static void shellAdd(Shell *shell);
+static void shellWritePrompt(Shell *shell, unsigned char newline);
+static void shellWriteReturnValue(Shell *shell, int value);
+static int shellShowVar(Shell *shell, ShellCommand *command);
+static void shellSetUser(Shell *shell, const ShellCommand *user);
+ShellCommand* shellSeekCommand(Shell *shell,
+                               const char *cmd,
+                               ShellCommand *base,
+                               unsigned short compareLength);
+static void shellWriteCommandHelp(Shell *shell, char *cmd);
+
+void shellEcho(Shell *shell, unsigned int enable)
+{
+    if(enable == 0)
+	{
+        shell->echo = 0;
+    }
+    else
+	{
+        shell->echo = 1;
+    }
+}
+
+/**
+ * @brief shell 初始化
+ * 
+ * @param shell shell对象
+ */
+void shellInit(Shell *shell, char *buffer, unsigned short size)
+{
+    shell->parser.length = 0;
+    shell->parser.cursor = 0;
+    shell->info.user = NULL;
+    shell->status.isChecked = 1;
+
+    shell->parser.buffer = buffer;
+    shell->parser.bufferSize = size / (SHELL_HISTORY_MAX_NUMBER + 1);
+	shell->echo = 1;
+    
+#if SHELL_HISTORY_MAX_NUMBER > 0
+    shell->history.offset = 0;
+    shell->history.number = 0;
+    shell->history.record = 0;
+    for (short i = 0; i < SHELL_HISTORY_MAX_NUMBER; i++)
+    {
+        shell->history.item[i] = buffer + shell->parser.bufferSize * (i + 1);
+    }
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+#if SHELL_USING_CMD_EXPORT == 1
+    #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
+        shell->commandList.base = (ShellCommand *)(&shellCommand$$Base);
+        shell->commandList.count = ((unsigned int)(&shellCommand$$Limit)
+                                - (unsigned int)(&shellCommand$$Base))
+                                / sizeof(ShellCommand);
+
+    #elif defined(__ICCARM__) || defined(__ICCRX__)
+        shell->commandList.base = (ShellCommand *)(__section_begin("shellCommand"));
+        shell->commandList.count = ((unsigned int)(__section_end("shellCommand"))
+                                - (unsigned int)(__section_begin("shellCommand")))
+                                / sizeof(ShellCommand);
+    #elif defined(__GNUC__)
+        shell->commandList.base = (ShellCommand *)(&_shell_command_start);
+        shell->commandList.count = ((unsigned int)(&_shell_command_end)
+                                - (unsigned int)(&_shell_command_start))
+                                / sizeof(ShellCommand);
+    #else
+        #error not supported compiler, please use command table mode
+    #endif
+#else
+    shell->commandList.base = (ShellCommand *)shellCommandList;
+    shell->commandList.count = shellCommandCount;
+#endif
+
+    shellAdd(shell);
+
+    shellSetUser(shell, shellSeekCommand(shell,
+                                         SHELL_DEFAULT_USER,
+                                         shell->commandList.base,
+                                         0));
+    shellWritePrompt(shell, 1);
+}
+
+
+/**
+ * @brief 添加shell
+ * 
+ * @param shell shell对象
+ */
+static void shellAdd(Shell *shell)
+{
+    for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+    {
+        if (shellList[i] == NULL)
+        {
+            shellList[i] = shell;
+            return;
+        }
+    }
+}
+
+
+/**
+ * @brief 获取当前活动shell
+ * 
+ * @return Shell* 当前活动shell对象
+ */
+Shell* shellGetCurrent(void)
+{
+    for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+    {
+        if (shellList[i] && shellList[i]->status.isActive)
+        {
+            return shellList[i];
+        }
+    }
+    return NULL;
+}
+
+
+/**
+ * @brief shell写字符
+ * 
+ * @param shell shell对象
+ * @param data 字符数据
+ */
+static void shellWriteByte(Shell *shell, char data)
+{
+    shell->write(&data, 1);
+}
+
+
+/**
+ * @brief shell 写字符串
+ * 
+ * @param shell shell对象
+ * @param string 字符串数据
+ * 
+ * @return unsigned short 写入字符的数量
+ */
+unsigned short shellWriteString(Shell *shell, const char *string)
+{
+    unsigned short count = 0;
+    const char *p = string;
+    SHELL_ASSERT(shell->write, return 0);
+    while(*p++)
+    {
+        count ++;
+    }
+    return shell->write((char *)string, count);
+}
+
+
+/**
+ * @brief shell 写命令描述字符串
+ * 
+ * @param shell shell对象
+ * @param string 字符串数据
+ * 
+ * @return unsigned short 写入字符的数量
+ */
+static unsigned short shellWriteCommandDesc(Shell *shell, const char *string)
+{
+    unsigned short count = 0;
+    const char *p = string;
+    SHELL_ASSERT(shell->write, return 0);
+    while (*p && *p != '\r' && *p != '\n')
+    {
+        p++;
+        count++;
+    }
+    
+    if (count > 36)
+    {
+        shell->write((char *)string, 36);
+        shell->write("...", 3);
+    }
+    else
+    {
+        shell->write((char *)string, count);
+    }
+    return count > 36 ? 36 : 39;
+}
+
+
+/**
+ * @brief shell写命令提示符
+ * 
+ * @param shell shell对象
+ * @param newline 新行
+ * 
+ */
+static void shellWritePrompt(Shell *shell, unsigned char newline)
+{
+    if (shell->status.isChecked)
+    {
+        if (newline)
+        {
+            shellWriteString(shell, "\r\n");
+        }
+        shellWriteString(shell, shell->info.user->data.user.name);
+        shellWriteString(shell, ":");
+        shellWriteString(shell, shell->info.path ? shell->info.path : "/");
+        shellWriteString(shell, "$ ");
+    }
+    else
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_PASSWORD_HINT]);
+    }
+}
+
+
+#if SHELL_PRINT_BUFFER > 0
+/**
+ * @brief shell格式化输出
+ * 
+ * @param shell shell对象
+ * @param fmt 格式化字符串
+ * @param ... 参数
+ */
+void shellPrint(Shell *shell, char *fmt, ...)
+{
+    char buffer[SHELL_PRINT_BUFFER];
+    va_list vargs;
+
+    SHELL_ASSERT(shell, return);
+
+    va_start(vargs, fmt);
+    vsnprintf(buffer, SHELL_PRINT_BUFFER - 1, fmt, vargs);
+    va_end(vargs);
+    
+    shellWriteString(shell, buffer);
+}
+#endif
+
+
+#if SHELL_SCAN_BUFFER > 0
+/**
+ * @brief shell格式化输入
+ * 
+ * @param shell shell对象
+ * @param fmt 格式化字符串
+ * @param ... 参数
+ */
+void shellScan(Shell *shell, char *fmt, ...)
+{
+    char buffer[SHELL_SCAN_BUFFER];
+    va_list vargs;
+    short index = 0;
+
+    SHELL_ASSERT(shell, return);
+
+    if (shell->read)
+    {
+        do {
+            if (shell->read(&buffer[index], 1) == 1)
+            {
+                shell->write(&buffer[index], 1);
+                index++;
+            }
+        } while (buffer[index -1] != '\r' && buffer[index -1] != '\n' && index < SHELL_SCAN_BUFFER);
+        shellWriteString(shell, "\r\n");
+        buffer[index] = '\0';
+    }
+
+    va_start(vargs, fmt);
+    vsscanf(buffer, fmt, vargs);
+    va_end(vargs);
+}
+#endif
+
+
+/**
+ * @brief shell 检查命令权限
+ * 
+ * @param shell shell对象
+ * @param command ShellCommand
+ * 
+ * @return signed char 0 当前用户具有该命令权限
+ * @return signec char -1 当前用户不具有该命令权限
+ */
+signed char shellCheckPermission(Shell *shell, ShellCommand *command)
+{
+    return ((!command->attr.attrs.permission
+                || command->attr.attrs.type == SHELL_TYPE_USER
+                || (command->attr.attrs.permission 
+                    & shell->info.user->attr.attrs.permission))
+            && (shell->status.isChecked
+                || command->attr.attrs.enableUnchecked))
+            ? 0 : -1;
+}
+
+
+/**
+ * @brief int转16进制字符串
+ * 
+ * @param value 数值
+ * @param buffer 缓冲
+ * 
+ * @return signed char 转换后有效数据长度
+ */
+signed char shellToHex(unsigned int value, char *buffer)
+{
+    char byte;
+    unsigned char i = 8;
+    buffer[8] = 0;
+    while (value)
+    {
+        byte = value & 0x0000000F;
+        buffer[--i] = (byte > 9) ? (byte + 87) : (byte + 48);
+        value >>= 4;
+    }
+    return 8 - i;
+}
+
+
+/**
+* @brief int转10进制字符串
+ * 
+ * @param value 数值
+ * @param buffer 缓冲
+ * 
+ * @return signed char 转换后有效数据长度
+ */
+signed char shellToDec(int value, char *buffer)
+{
+    unsigned char i = 11;
+    int v = value;
+    if (value < 0)
+    {
+        v = -value;
+    }
+    buffer[11] = 0;
+    while (v)
+    {
+        buffer[--i] = v % 10 + 48;
+        v /= 10;
+    }
+    if (value < 0)
+    {
+        buffer[--i] = '-';
+    }
+    if (value == 0) {
+        buffer[--i] = '0';
+    }
+    return 11 - i;
+}
+
+
+/**
+ * @brief shell字符串复制
+ * 
+ * @param dest 目标字符串
+ * @param src 源字符串
+ * @return unsigned short 字符串长度
+ */
+static unsigned short shellStringCopy(char *dest, char* src)
+{
+    unsigned short count = 0;
+    while (*(src + count))
+    {
+        *(dest + count) = *(src + count);
+        count++;
+    }
+    *(dest + count) = 0;
+    return count;
+}
+
+
+/**
+ * @brief shell字符串比较
+ * 
+ * @param dest 目标字符串
+ * @param src 源字符串
+ * @return unsigned short 匹配长度
+ */
+static unsigned short shellStringCompare(char* dest, char *src)
+{
+    unsigned short match = 0;
+    unsigned short i = 0;
+
+    while (*(dest +i) && *(src + i))
+    {
+        if (*(dest + i) != *(src +i))
+        {
+            break;
+        }
+        match ++;
+        i++;
+    }
+    return match;
+}
+
+
+/**
+ * @brief shell获取命令名
+ * 
+ * @param command 命令
+ * @return const char* 命令名
+ */
+static const char* shellGetCommandName(ShellCommand *command)
+{
+    static char buffer[9];
+    for (unsigned char i = 0; i < 9; i++)
+    {
+        buffer[i] = '0';
+    }
+    if (command->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+    {
+        return command->data.cmd.name;
+    }
+    else if (command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+    {
+        return command->data.var.name;
+    }
+    else if (command->attr.attrs.type <= SHELL_TYPE_USER)
+    {
+        return command->data.user.name;
+    }
+    else
+    {
+        shellToHex(command->data.key.value, buffer);
+        return buffer;
+    }
+}
+
+
+/**
+ * @brief shell获取命令描述
+ * 
+ * @param command 命令
+ * @return const char* 命令描述
+ */
+static const char* shellGetCommandDesc(ShellCommand *command)
+{
+    if (command->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+    {
+        return command->data.cmd.desc;
+    }
+    else if (command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+    {
+        return command->data.var.desc;
+    }
+    else if (command->attr.attrs.type <= SHELL_TYPE_USER)
+    {
+        return command->data.user.desc;
+    }
+    else
+    {
+        return command->data.key.desc;
+    }
+}
+
+/**
+ * @brief shell 列出命令条目
+ * 
+ * @param shell shell对象
+ * @param item 命令条目
+ */
+void shellListItem(Shell *shell, ShellCommand *item)
+{
+    short spaceLength;
+
+    spaceLength = 22 - shellWriteString(shell, shellGetCommandName(item));
+    spaceLength = (spaceLength > 0) ? spaceLength : 4;
+    do {
+        shellWriteByte(shell, ' ');
+    } while (--spaceLength);
+    if (item->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_TYPE_CMD]);
+    }
+    else if (item->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_TYPE_VAR]);
+    }
+    else if (item->attr.attrs.type <= SHELL_TYPE_USER)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_TYPE_USER]);
+    }
+    else if (item->attr.attrs.type <= SHELL_TYPE_KEY)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_TYPE_KEY]);
+    }
+    else
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_TYPE_NONE]);
+    }
+#if SHELL_HELP_SHOW_PERMISSION == 1
+    shellWriteString(shell, "  ");
+    for (signed char i = 7; i >= 0; i--)
+    {
+        shellWriteByte(shell, item->attr.attrs.permission & (1 << i) ? 'x' : '-');
+    }
+#endif
+    shellWriteString(shell, "  ");
+    shellWriteCommandDesc(shell, shellGetCommandDesc(item));
+    shellWriteString(shell, "\r\n");
+}
+
+
+/**
+ * @brief shell列出可执行命令
+ * 
+ * @param shell shell对象
+ */
+void shellListCommand(Shell *shell)
+{
+    ShellCommand *base = (ShellCommand *)shell->commandList.base;
+    shellWriteString(shell, shellText[SHELL_TEXT_CMD_LIST]);
+    for (short i = 0; i < shell->commandList.count; i++)
+    {
+        if (base[i].attr.attrs.type <= SHELL_TYPE_CMD_FUNC
+            && shellCheckPermission(shell, &base[i]) == 0)
+        {
+            shellListItem(shell, &base[i]);
+        }
+    }
+}
+
+
+/**
+ * @brief shell列出变量
+ * 
+ * @param shell shell对象
+ */
+void shellListVar(Shell *shell)
+{
+    ShellCommand *base = (ShellCommand *)shell->commandList.base;
+    shellWriteString(shell, shellText[SHELL_TEXT_VAR_LIST]);
+    for (short i = 0; i < shell->commandList.count; i++)
+    {
+        if (base[i].attr.attrs.type > SHELL_TYPE_CMD_FUNC
+            && base[i].attr.attrs.type <= SHELL_TYPE_VAR_NODE
+            && shellCheckPermission(shell, &base[i]) == 0)
+        {
+            shellListItem(shell, &base[i]);
+        }
+    }
+}
+
+
+/**
+ * @brief shell列出用户
+ * 
+ * @param shell shell对象
+ */
+void shellListUser(Shell *shell)
+{
+    ShellCommand *base = (ShellCommand *)shell->commandList.base;
+    shellWriteString(shell, shellText[SHELL_TEXT_USER_LIST]);
+    for (short i = 0; i < shell->commandList.count; i++)
+    {
+        if (base[i].attr.attrs.type > SHELL_TYPE_VAR_NODE
+            && base[i].attr.attrs.type <= SHELL_TYPE_USER
+            && shellCheckPermission(shell, &base[i]) == 0)
+        {
+            shellListItem(shell, &base[i]);
+        }
+    }
+}
+
+
+/**
+ * @brief shell列出按键
+ * 
+ * @param shell shell对象
+ */
+void shellListKey(Shell *shell)
+{
+    ShellCommand *base = (ShellCommand *)shell->commandList.base;
+    shellWriteString(shell, shellText[SHELL_TEXT_KEY_LIST]);
+    for (short i = 0; i < shell->commandList.count; i++)
+    {
+        if (base[i].attr.attrs.type > SHELL_TYPE_USER
+            && base[i].attr.attrs.type <= SHELL_TYPE_KEY
+            && shellCheckPermission(shell, &base[i]) == 0)
+        {
+            shellListItem(shell, &base[i]);
+        }
+    }
+}
+
+
+/**
+ * @brief shell列出所有命令
+ * 
+ * @param shell shell对象
+ */
+void shellListAll(Shell *shell)
+{
+#if SHELL_HELP_LIST_USER == 1
+    shellListUser(shell);
+#endif
+    shellListCommand(shell);
+#if SHELL_HELP_LIST_VAR == 1
+    shellListVar(shell);
+#endif
+#if SHELL_HELP_LIST_KEY == 1
+    shellListKey(shell);
+#endif
+}
+
+
+/**
+ * @brief shell删除命令行数据
+ * 
+ * @param shell shell对象
+ * @param length 删除长度
+ */
+static const char *shell_delete_string[] =
+{
+    "\b \b",
+    " \b",
+};
+void shellDeleteCommandLine(Shell *shell, unsigned char length)
+{
+    while (length--)
+    {
+        shellWriteString(shell, shell_delete_string[(uint8_t)(shell->backsapceMode)]);
+    }
+}
+
+
+/**
+ * @brief shell 清空命令行输入
+ * 
+ * @param shell shell对象
+ */
+void shellClearCommandLine(Shell *shell)
+{
+    for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+    {
+        shellWriteByte(shell, ' ');
+    }
+    shellDeleteCommandLine(shell, shell->parser.length);
+}
+
+
+/**
+ * @brief shell插入一个字符到光标位置
+ * 
+ * @param shell shell对象
+ * @param data 字符数据
+ */
+void shellInsertByte(Shell *shell, char data)
+{
+    /* 判断输入数据是否过长 */
+    if (shell->parser.length >= shell->parser.bufferSize - 1)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_CMD_TOO_LONG]);
+        shellWritePrompt(shell, 1);
+        shellWriteString(shell, shell->parser.buffer);
+        return;
+    }
+
+    /* 插入数据 */
+    if (shell->parser.cursor == shell->parser.length)
+    {
+        shell->parser.buffer[shell->parser.length++] = data;
+        shell->parser.buffer[shell->parser.length] = 0;
+        shell->parser.cursor++;
+		if(shell->echo == 1)
+		{
+			shellWriteByte(shell, data);
+		}
+    }
+    else if (shell->parser.cursor < shell->parser.length)
+    {
+        for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+        {
+            shell->parser.buffer[shell->parser.cursor + i] = 
+                shell->parser.buffer[shell->parser.cursor + i - 1];
+        }
+        shell->parser.buffer[shell->parser.cursor++] = data;
+        shell->parser.buffer[++shell->parser.length] = 0;
+        for (short i = shell->parser.cursor - 1; i < shell->parser.length; i++)
+        {
+            shellWriteByte(shell, shell->parser.buffer[i]);
+        }
+        for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+        {
+            shellWriteByte(shell, '\b');
+        }
+    }
+}
+
+
+/**
+ * @brief shell 删除字节
+ * 
+ * @param shell shell对象
+ * @param direction 删除方向 {@code 1}删除光标前字符 {@code -1}删除光标处字符
+ */
+void shellDeleteByte(Shell *shell, signed char direction)
+{
+    char offset = (direction == -1) ? 1 : 0;
+
+    if ((shell->parser.cursor == 0 && direction == 1)
+        || (shell->parser.cursor == shell->parser.length && direction == -1))
+    {
+        return;
+    }
+    if (shell->parser.cursor == shell->parser.length && direction == 1)
+    {
+        shell->parser.cursor--;
+        shell->parser.length--;
+        shell->parser.buffer[shell->parser.length] = 0;
+        shellDeleteCommandLine(shell, 1);
+    }
+    else
+    {
+        for (short i = offset; i < shell->parser.length - shell->parser.cursor; i++)
+        {
+            shell->parser.buffer[shell->parser.cursor + i - 1] = 
+                shell->parser.buffer[shell->parser.cursor + i];
+        }
+        shell->parser.length--;
+        if (!offset)
+        {
+            shell->parser.cursor--;
+            shellWriteByte(shell, '\b');
+        }
+        shell->parser.buffer[shell->parser.length] = 0;
+        for (short i = shell->parser.cursor; i < shell->parser.length; i++)
+        {
+            shellWriteByte(shell, shell->parser.buffer[i]);
+        }
+        shellWriteByte(shell, ' ');
+        for (short i = shell->parser.length - shell->parser.cursor + 1; i > 0; i--)
+        {
+            shellWriteByte(shell, '\b');
+        }
+    }
+}
+
+
+/**
+ * @brief shell 解析参数
+ * 
+ * @param shell shell对象
+ */
+static void shellParserParam(Shell *shell)
+{
+    unsigned char quotes = 0;
+    unsigned char record = 1;
+
+    for (short i = 0; i < SHELL_PARAMETER_MAX_NUMBER; i++)
+    {
+        shell->parser.param[i] = NULL;
+    }
+
+    shell->parser.paramCount = 0;
+    for (unsigned short i = 0; i < shell->parser.length; i++)
+    {
+        if (quotes != 0
+            || (shell->parser.buffer[i] != ' '
+                && shell->parser.buffer[i] != 0))
+        {
+            if (shell->parser.buffer[i] == '\"')
+            {
+                quotes = quotes ? 0 : 1;
+            }
+            if (record == 1)
+            {
+                if (shell->parser.paramCount < SHELL_PARAMETER_MAX_NUMBER)
+                {
+                    shell->parser.param[shell->parser.paramCount++] =
+                        &(shell->parser.buffer[i]);
+                }
+                record = 0;
+            }
+            if (shell->parser.buffer[i] == '\\'
+                && shell->parser.buffer[i + 1] != 0)
+            {
+                i++;
+            }
+        }
+        else
+        {
+            shell->parser.buffer[i] = 0;
+            record = 1;
+        }
+    }
+}
+
+
+/**
+ * @brief shell去除字符串参数头尾的双引号
+ * 
+ * @param shell shell对象
+ */
+static void shellRemoveParamQuotes(Shell *shell)
+{
+    unsigned short paramLength;
+    for (unsigned short i = 0; i < shell->parser.paramCount; i++)
+    {
+        if (shell->parser.param[i][0] == '\"')
+        {
+            shell->parser.param[i][0] = 0;
+            shell->parser.param[i] = &shell->parser.param[i][1];
+        }
+        paramLength = strlen(shell->parser.param[i]);
+        if (shell->parser.param[i][paramLength - 1] == '\"')
+        {
+            shell->parser.param[i][paramLength - 1] = 0;
+        }
+    }
+}
+
+
+/**
+ * @brief shell匹配命令
+ * 
+ * @param shell shell对象
+ * @param cmd 命令
+ * @param base 匹配命令表基址
+ * @param compareLength 匹配字符串长度
+ * @return ShellCommand* 匹配到的命令
+ */
+ShellCommand* shellSeekCommand(Shell *shell,
+                               const char *cmd,
+                               ShellCommand *base,
+                               unsigned short compareLength)
+{
+    const char *name;
+    unsigned short count = shell->commandList.count -
+        ((int)base - (int)shell->commandList.base) / sizeof(ShellCommand);
+    for (unsigned short i = 0; i < count; i++)
+    {
+        if (base[i].attr.attrs.type == SHELL_TYPE_KEY
+            || shellCheckPermission(shell, &base[i]) != 0)
+        {
+            continue;
+        }
+        name = shellGetCommandName(&base[i]);
+        if (!compareLength)
+        {
+            if (strcmp(cmd, name) == 0)
+            {
+                return &base[i];
+            }
+        }
+        else
+        {
+            if (strncmp(cmd, name, compareLength) == 0)
+            {
+                return &base[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+
+/**
+ * @brief shell 获取变量值
+ * 
+ * @param shell shell对象
+ * @param command 命令
+ * @return int 变量值
+ */
+int shellGetVarValue(Shell *shell, ShellCommand *command)
+{
+    int value = 0;
+    switch (command->attr.attrs.type)
+    {
+    case SHELL_TYPE_VAR_INT:
+        value = *((int *)(command->data.var.value));
+        break;
+    case SHELL_TYPE_VAR_SHORT:
+        value = *((short *)(command->data.var.value));
+        break;
+    case SHELL_TYPE_VAR_CHAR:
+        value = *((char *)(command->data.var.value));
+        break;
+    case SHELL_TYPE_VAR_STRING:
+    case SHELL_TYPE_VAR_POINT:
+        value = (int)(command->data.var.value);
+        break;
+    case SHELL_TYPE_VAR_NODE:
+        value = ((ShellNodeVarAttr *)command->data.var.value)->get ?
+                    ((ShellNodeVarAttr *)command->data.var.value)
+                        ->get(((ShellNodeVarAttr *)command->data.var.value)->var) : 0;
+        break;
+    default:
+        break;
+    }
+    return value;
+}
+
+
+/**
+ * @brief shell设置变量值
+ * 
+ * @param shell shell对象
+ * @param command 命令
+ * @param value 值
+ * @return int 返回变量值
+ */
+int shellSetVarValue(Shell *shell, ShellCommand *command, int value)
+{
+    if (command->attr.attrs.readOnly)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY]);
+    }
+    else
+    {
+        switch (command->attr.attrs.type)
+        {
+        case SHELL_TYPE_VAR_INT:
+            *((int *)(command->data.var.value)) = value;
+            break;
+        case SHELL_TYPE_VAR_SHORT:
+            *((short *)(command->data.var.value)) = value;
+            break;
+        case SHELL_TYPE_VAR_CHAR:
+            *((char *)(command->data.var.value)) = value;
+            break;
+        case SHELL_TYPE_VAR_STRING:
+            shellStringCopy(((char *)(command->data.var.value)), (char *)value);
+            break;
+        case SHELL_TYPE_VAR_POINT:
+            shellWriteString(shell, shellText[SHELL_TEXT_POINT_CANNOT_MODIFY]);
+            break;
+        case SHELL_TYPE_VAR_NODE:
+            if (((ShellNodeVarAttr *)command->data.var.value)->set)
+            {
+                if (((ShellNodeVarAttr *)command->data.var.value)->var)
+                {
+                    ((ShellNodeVarAttr *)command->data.var.value)
+                        ->set(((ShellNodeVarAttr *)command->data.var.value)->var, value);
+                }
+                else
+                {
+                    ((ShellNodeVarAttr *)command->data.var.value)->set(value);
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    return shellShowVar(shell, command);
+}
+
+
+/**
+ * @brief shell变量输出
+ * 
+ * @param shell shell对象
+ * @param command 命令
+ * @return int 返回变量值
+ */
+static int shellShowVar(Shell *shell, ShellCommand *command)
+{
+    char buffer[12] = "00000000000";
+    int value = shellGetVarValue(shell, command);
+    
+    shellWriteString(shell, command->data.var.name);
+    shellWriteString(shell, " = ");
+
+    switch (command->attr.attrs.type)
+    {
+    case SHELL_TYPE_VAR_STRING:
+        shellWriteString(shell, "\"");
+        shellWriteString(shell, (char *)value);
+        shellWriteString(shell, "\"");
+        break;
+    // case SHELL_TYPE_VAR_INT:
+    // case SHELL_TYPE_VAR_SHORT:
+    // case SHELL_TYPE_VAR_CHAR:
+    // case SHELL_TYPE_VAR_POINT:
+    default:
+        shellWriteString(shell, &buffer[11 - shellToDec(value, buffer)]);
+        shellWriteString(shell, ", 0x");
+        for (short i = 0; i < 11; i++)
+        {
+            buffer[i] = '0';
+        }
+        shellToHex(value, buffer);
+        shellWriteString(shell, buffer);
+        break;
+    }
+
+    shellWriteString(shell, "\r\n");
+    return value;
+}
+
+
+/**
+ * @brief shell设置变量
+ * 
+ * @param name 变量名
+ * @param value 变量值
+ * @return int 返回变量值
+ */
+int shellSetVar(char *name, int value)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell == NULL)
+    {
+        return 0;
+    }
+    ShellCommand *command = shellSeekCommand(shell,
+                                             name,
+                                             shell->commandList.base,
+                                             0);
+    if (!command)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_VAR_NOT_FOUND]);
+        return 0;
+    }
+    if (command->attr.attrs.type < SHELL_TYPE_VAR_INT
+        || command->attr.attrs.type > SHELL_TYPE_VAR_NODE)
+    {
+        shellWriteString(shell, name);
+        shellWriteString(shell, shellText[SHELL_TEXT_NOT_VAR]);
+        return 0;
+    }
+    return shellSetVarValue(shell, command, value);
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+setVar, shellSetVar, set var);
+
+
+/**
+ * @brief shell运行命令
+ * 
+ * @param shell shell对象
+ * @param command 命令
+ * 
+ * @return unsigned int 命令返回值
+ */
+unsigned int shellRunCommand(Shell *shell, ShellCommand *command)
+{
+    int returnValue = 0;
+    shell->status.isActive = 1;
+    if (command->attr.attrs.type == SHELL_TYPE_CMD_MAIN)
+    {
+        shellRemoveParamQuotes(shell);
+        returnValue = command->data.cmd.function(shell->parser.paramCount,
+                                                 shell->parser.param);
+        if (!command->attr.attrs.disableReturn)
+        {
+            shellWriteReturnValue(shell, returnValue);
+        }
+    }
+    else if (command->attr.attrs.type == SHELL_TYPE_CMD_FUNC)
+    {
+        returnValue = shellExtRun(shell,
+                                  command,
+                                  shell->parser.paramCount,
+                                  shell->parser.param);
+        if (!command->attr.attrs.disableReturn)
+        {
+            shellWriteReturnValue(shell, returnValue);
+        }
+    }
+    else if (command->attr.attrs.type >= SHELL_TYPE_VAR_INT
+        && command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+    {
+        shellShowVar(shell, command);
+    }
+    else if (command->attr.attrs.type == SHELL_TYPE_USER)
+    {
+        shellSetUser(shell, command);
+    }
+    shell->status.isActive = 0;
+
+    return returnValue;
+}
+
+
+/**
+ * @brief shell校验密码
+ * 
+ * @param shell shell对象
+ */
+static void shellCheckPassword(Shell *shell)
+{
+    if (strcmp(shell->parser.buffer, shell->info.user->data.user.password) == 0)
+    {
+        shell->status.isChecked = 1;
+    #if SHELL_SHOW_INFO == 1
+        shellWriteString(shell, shellText[SHELL_TEXT_INFO]);
+    #endif
+    }
+    else
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_PASSWORD_ERROR]);
+    }
+    shell->parser.length = 0;
+    shell->parser.cursor = 0;
+}
+
+
+/**
+ * @brief shell设置用户
+ * 
+ * @param shell shell对象
+ * @param user 用户
+ */
+static void shellSetUser(Shell *shell, const ShellCommand *user)
+{
+    shell->info.user = user;
+    shell->status.isChecked = 
+        ((user->data.user.password && strlen(user->data.user.password) != 0)
+            && (shell->parser.paramCount < 2
+                || strcmp(user->data.user.password, shell->parser.param[1]) != 0))
+         ? 0 : 1;
+        
+#if SHELL_CLS_WHEN_LOGIN == 1
+    shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
+#endif
+#if SHELL_SHOW_INFO == 1
+    if (shell->status.isChecked)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_INFO]);
+    }
+#endif
+}
+
+
+/**
+ * @brief shell写返回值
+ * 
+ * @param shell shell对象
+ * @param value 返回值
+ */
+static void shellWriteReturnValue(Shell *shell, int value)
+{
+    char buffer[12] = "00000000000";
+    shellWriteString(shell, "Return: ");
+    shellWriteString(shell, &buffer[11 - shellToDec(value, buffer)]);
+    shellWriteString(shell, ", 0x");
+    for (short i = 0; i < 11; i++)
+    {
+        buffer[i] = '0';
+    }
+    shellToHex(value, buffer);
+    shellWriteString(shell, buffer);
+    shellWriteString(shell, "\r\n");
+}
+
+
+#if SHELL_HISTORY_MAX_NUMBER > 0
+/**
+ * @brief shell历史记录添加
+ * 
+ * @param shell shell对象
+ */
+static void shellHistoryAdd(Shell *shell)
+{
+    shell->history.offset = 0;
+    if (shell->history.number > 0
+        && strcmp(shell->history.item[(shell->history.record == 0 ? 
+                SHELL_HISTORY_MAX_NUMBER : shell->history.record) - 1],
+                shell->parser.buffer) == 0)
+    {
+        return;
+    }
+    if (shellStringCopy(shell->history.item[shell->history.record],
+                        shell->parser.buffer) != 0)
+    {
+        shell->history.record++;
+    }
+    if (++shell->history.number > SHELL_HISTORY_MAX_NUMBER)
+    {
+        shell->history.number = SHELL_HISTORY_MAX_NUMBER;
+    }
+    if (shell->history.record >= SHELL_HISTORY_MAX_NUMBER)
+    {
+        shell->history.record = 0;
+    }
+}
+
+
+/**
+ * @brief shell历史记录查找
+ * 
+ * @param shell shell对象
+ * @param dir 方向 {@code <0}往上查找 {@code >0}往下查找
+ */
+static void shellHistory(Shell *shell, signed char dir)
+{
+    if (dir > 0)
+    {
+        if (shell->history.offset-- <= 
+            -((shell->history.number > shell->history.record) ?
+                shell->history.number : shell->history.record))
+        {
+            shell->history.offset = -((shell->history.number > shell->history.record)
+                                    ? shell->history.number : shell->history.record);
+        }
+    }
+    else if (dir < 0)
+    {
+        if (++shell->history.offset > 0)
+        {
+            shell->history.offset = 0;
+            return;
+        }
+    }
+    else
+    {
+        return;
+    }
+    shellClearCommandLine(shell);
+    if (shell->history.offset == 0)
+    {
+        shell->parser.cursor = shell->parser.length = 0;
+    }
+    else
+    {
+        if ((shell->parser.length = shellStringCopy(shell->parser.buffer,
+                shell->history.item[(shell->history.record + SHELL_HISTORY_MAX_NUMBER
+                    + shell->history.offset) % SHELL_HISTORY_MAX_NUMBER])) == 0)
+        {
+            return;
+        }
+        shell->parser.cursor = shell->parser.length;
+        shellWriteString(shell, shell->parser.buffer);
+    }
+    
+}
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+
+/**
+ * @brief shell 常规输入
+ * 
+ * @param shell shell 对象
+ * @param data 输入字符
+ */
+void shellNormalInput(Shell *shell, char data)
+{
+    shell->status.tabFlag = 0;
+    shellInsertByte(shell, data);
+}
+
+
+/**
+ * @brief shell运行命令
+ * 
+ * @param shell shell对象
+ */
+void shellExec(Shell *shell)
+{
+    
+    if (shell->parser.length == 0)
+    {
+        return;
+    }
+
+    shell->parser.buffer[shell->parser.length] = 0;
+
+    if (shell->status.isChecked)
+    {
+    #if SHELL_HISTORY_MAX_NUMBER > 0
+        shellHistoryAdd(shell);
+    #endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+        shellParserParam(shell);
+        shell->parser.length = shell->parser.cursor = 0;
+        if (shell->parser.paramCount == 0)
+        {
+            return;
+        }
+        shellWriteString(shell, "\r\n");
+
+        ShellCommand *command = shellSeekCommand(shell,
+                                                 shell->parser.param[0],
+                                                 shell->commandList.base,
+                                                 0);
+        if (command != NULL)
+        {
+            shellRunCommand(shell, command);
+        }
+        else
+        {
+            shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]);
+        }
+    }
+    else
+    {
+        shellCheckPassword(shell);
+    }
+}
+
+
+#if SHELL_HISTORY_MAX_NUMBER > 0
+/**
+ * @brief shell上方向键输入
+ * 
+ * @param shell shell对象
+ */
+void shellUp(Shell *shell)
+{
+    shellHistory(shell, 1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up);
+
+
+/**
+ * @brief shell下方向键输入
+ * 
+ * @param shell shell对象
+ */
+void shellDown(Shell *shell)
+{
+    shellHistory(shell, -1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down);
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+
+/**
+ * @brief shell右方向键输入
+ * 
+ * @param shell shell对象
+ */
+void shellRight(Shell *shell)
+{
+    if (shell->parser.cursor < shell->parser.length)
+    {
+        shellWriteByte(shell, shell->parser.buffer[shell->parser.cursor++]);
+    }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B4300, shellRight, right);
+
+
+/**
+ * @brief shell左方向键输入
+ * 
+ * @param shell shell对象
+ */
+void shellLeft(Shell *shell)
+{
+    if (shell->parser.cursor > 0)
+    {
+        shellWriteByte(shell, '\b');
+        shell->parser.cursor--;
+    }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B4400, shellLeft, left);
+
+
+/**
+ * @brief shell Tab按键处理
+ * 
+ * @param shell shell对象
+ */
+void shellTab(Shell *shell)
+{
+    unsigned short maxMatch = shell->parser.bufferSize;
+    unsigned short lastMatchIndex = 0;
+    unsigned short matchNum = 0;
+    unsigned short length;
+
+    if (shell->parser.length == 0)
+    {
+        shellListAll(shell);
+        shellWritePrompt(shell, 1);
+    }
+    else if (shell->parser.length > 0)
+    {
+        shell->parser.buffer[shell->parser.length] = 0;
+        ShellCommand *base = (ShellCommand *)shell->commandList.base;
+        for (short i = 0; i < shell->commandList.count; i++)
+        {
+            if (shellCheckPermission(shell, &base[i]) == 0
+                && shellStringCompare(shell->parser.buffer,
+                                   (char *)shellGetCommandName(&base[i]))
+                        == shell->parser.length)
+            {
+                if (matchNum != 0)
+                {
+                    if (matchNum == 1)
+                    {
+                        shellWriteString(shell, "\r\n");
+                    }
+                    shellListItem(shell, &base[lastMatchIndex]);
+                    length = 
+                        shellStringCompare((char *)shellGetCommandName(&base[lastMatchIndex]),
+                                           (char *)shellGetCommandName(&base[i]));
+                    maxMatch = (maxMatch > length) ? length : maxMatch;
+                }
+                lastMatchIndex = i;
+                matchNum++;
+            }
+        }
+        if (matchNum == 0)
+        {
+            return;
+        }
+        if (matchNum == 1)
+        {
+            shellClearCommandLine(shell);
+        }
+        if (matchNum != 0)
+        {
+            shell->parser.length = 
+                shellStringCopy(shell->parser.buffer,
+                                (char *)shellGetCommandName(&base[lastMatchIndex]));
+        }
+        if (matchNum > 1)
+        {
+            shellListItem(shell, &base[lastMatchIndex]);
+            shellWritePrompt(shell, 1);
+            shell->parser.length = maxMatch;
+        }
+        shell->parser.buffer[shell->parser.length] = 0;
+        shell->parser.cursor = shell->parser.length;
+        shellWriteString(shell, shell->parser.buffer);
+    }
+
+    if (SHELL_GET_TICK())
+    {
+        if (matchNum == 1
+            && shell->status.tabFlag
+            && SHELL_GET_TICK() - shell->info.activeTime < SHELL_DOUBLE_Clike_TIME)
+        {
+        #if SHELL_QUICK_HELP == 1
+            shellWriteString(shell, "\r\n");
+            shellWriteCommandHelp(shell, shell->parser.buffer);
+            shellWritePrompt(shell, 1);
+            shellWriteString(shell, shell->parser.buffer);
+        #else
+            shellClearCommandLine(shell);
+            for (short i = shell->parser.length; i >= 0; i--)
+            {
+                shell->parser.buffer[i + 5] = shell->parser.buffer[i];
+            }
+            shellStringCopy(shell->parser.buffer, "help");
+            shell->parser.buffer[4] = ' ';
+            shell->parser.length += 5;
+            shell->parser.cursor = shell->parser.length;
+            shellWriteString(shell, shell->parser.buffer);
+        #endif
+        }
+        else
+        {
+            shell->status.tabFlag = 1;
+        }
+    }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab);
+
+
+/**
+ * @brief shell 退格
+ * 
+ * @param shell shell对象
+ */
+void shellBackspace(Shell *shell)
+{
+    shellDeleteByte(shell, 1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x08000000, shellBackspace, backspace);
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x7F000000, shellBackspace, backspace);
+
+
+/**
+ * @brief shell 删除
+ * 
+ * @param shell shell对象
+ */
+void shellDelete(Shell *shell)
+{
+    shellDeleteByte(shell, -1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B337E, shellDelete, delete);
+
+
+/**
+ * @brief shell 回车处理
+ * 
+ * @param shell shell对象
+ */
+void shellEnter(Shell *shell)
+{
+    shellExec(shell);
+    shellWritePrompt(shell, 1);
+}
+#if SHELL_ENTER_LF == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0A000000, shellEnter, enter);
+#endif
+#if SHELL_ENTER_CR == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0D000000, shellEnter, enter);
+#endif
+#if SHELL_ENTER_CRLF == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0D0A0000, shellEnter, enter);
+#endif
+
+/**
+ * @brief shell 写命令帮助信息
+ * 
+ * @param shell shell对象
+ * @param cmd 命令字符串
+ */
+static void shellWriteCommandHelp(Shell *shell, char *cmd)
+{
+    ShellCommand *command = shellSeekCommand(shell,
+                                             cmd,
+                                             shell->commandList.base,
+                                             0);
+    if (command)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_HELP_HEADER]);
+        shellWriteString(shell, shellGetCommandName(command));
+        shellWriteString(shell, "\r\n");
+        shellWriteString(shell, shellGetCommandDesc(command));
+        shellWriteString(shell, "\r\n");
+    }
+    else
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]);
+    }
+}
+
+/**
+ * @brief shell help
+ * 
+ * @param argc 参数个数
+ * @param argv 参数
+ */
+void shellHelp(int argc, char *argv[])
+{
+    Shell *shell = shellGetCurrent();
+    SHELL_ASSERT(shell, return);
+    if (argc == 1)
+    {
+        shellListAll(shell);
+    }
+    else if (argc > 1)
+    {
+        shellWriteCommandHelp(shell, argv[1]);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+help, shellHelp, show command info\r\nhelp [cmd]);
+
+/**
+ * @brief shell 输入处理
+ * 
+ * @param shell shell对象
+ * @param data 输入数据
+ */
+void shellHandler(Shell *shell, char data)
+{
+    SHELL_ASSERT(data, return);
+    SHELL_LOCK(shell);
+
+#if SHELL_LOCK_TIMEOUT > 0
+    if (shell->info.user->data.user.password
+        && strlen(shell->info.user->data.user.password) != 0
+        && SHELL_GET_TICK())
+    {
+        if (SHELL_GET_TICK() - shell->info.activeTime > SHELL_LOCK_TIMEOUT)
+        {
+            shell->status.isChecked = 0;
+        }
+    }
+#endif
+
+    /* 根据记录的按键键值计算当前字节在按键键值中的偏移 */
+    char keyByteOffset = 24;
+    int keyFilter = 0x00000000;
+    if ((shell->parser.keyValue & 0x0000FF00) != 0x00000000)
+    {
+        keyByteOffset = 0;
+        keyFilter = 0xFFFFFF00;
+    }
+    else if ((shell->parser.keyValue & 0x00FF0000) != 0x00000000)
+    {
+        keyByteOffset = 8;
+        keyFilter = 0xFFFF0000;
+    }
+    else if ((shell->parser.keyValue & 0xFF000000) != 0x00000000)
+    {
+        keyByteOffset = 16;
+        keyFilter = 0xFF000000;
+    }
+
+    /* 遍历ShellCommand列表,尝试进行按键键值匹配 */
+    ShellCommand *base = (ShellCommand *)shell->commandList.base;
+    for (short i = 0; i < shell->commandList.count; i++)
+    {
+        /* 判断是否是按键定义并验证权限 */
+        if (base[i].attr.attrs.type == SHELL_TYPE_KEY
+            && shellCheckPermission(shell, &(base[i])) == 0)
+        {
+            /* 对输入的字节同按键键值进行匹配 */
+            if ((base[i].data.key.value & keyFilter) == shell->parser.keyValue
+                && (base[i].data.key.value & (0xFF << keyByteOffset))
+                    == (data << keyByteOffset))
+            {
+                shell->parser.keyValue |= data << keyByteOffset;
+                data = 0x00;
+                if (keyByteOffset == 0 
+                    || (base[i].data.key.value & (0xFF << (keyByteOffset - 8)))
+                        == 0x00000000)
+                {
+                    if (base[i].data.key.function)
+                    {
+                        base[i].data.key.function(shell);
+                    }
+                    shell->parser.keyValue = 0x00000000;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (data != 0x00)
+    {
+        shell->parser.keyValue = 0x00000000;
+        shellNormalInput(shell, data);
+    }
+
+    if (SHELL_GET_TICK())
+    {
+        shell->info.activeTime = SHELL_GET_TICK();
+    }
+    SHELL_UNLOCK(shell);
+}
+
+
+#if SHELL_SUPPORT_END_LINE == 1
+void shellWriteEndLine(Shell *shell, char *buffer, int len)
+{
+    SHELL_LOCK(shell);
+    if (!shell->status.isActive)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_LINE]);
+    }
+    shell->write(buffer, len);
+
+    if (!shell->status.isActive)
+    {
+        shellWritePrompt(shell, 0);
+        if (shell->parser.length > 0)
+        {
+            shellWriteString(shell, shell->parser.buffer);
+            for (short i = 0; i < shell->parser.length - shell->parser.cursor; i++)
+            {
+                shellWriteByte(shell, '\b');
+            }
+        }
+    }
+    SHELL_UNLOCK(shell);
+}
+#endif /** SHELL_SUPPORT_END_LINE == 1 */
+
+
+/**
+ * @brief shell 任务
+ * 
+ * @param param 参数(shell对象)
+ * 
+ */
+void shellTask(void *param)
+{
+    Shell *shell = (Shell *)param;
+    char data;
+#if SHELL_TASK_WHILE == 1
+    while(1)
+    {
+#endif
+        if (shell->read && shell->read(&data, 1) == 1)
+        {
+            shellHandler(shell, data);
+        }
+#if SHELL_TASK_WHILE == 1
+    }
+#endif
+}
+
+/**
+ * @brief shell 输出用户列表(shell调用)
+ */
+void shellUsers(void)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell)
+    {
+        shellListUser(shell);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+users, shellUsers, list all user);
+
+
+/**
+ * @brief shell 输出命令列表(shell调用)
+ */
+void shellCmds(void)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell)
+    {
+        shellListCommand(shell);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+cmds, shellCmds, list all cmd);
+
+
+/**
+ * @brief shell 输出变量列表(shell调用)
+ */
+void shellVars(void)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell)
+    {
+        shellListVar(shell);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+vars, shellVars, list all var);
+
+
+/**
+ * @brief shell 输出按键列表(shell调用)
+ */
+void shellKeys(void)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell)
+    {
+        shellListKey(shell);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+keys, shellKeys, list all key);
+
+
+/**
+ * @brief shell 清空控制台(shell调用)
+ */
+void shellClear(void)
+{
+    Shell *shell = shellGetCurrent();
+    if (shell)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+clear, shellClear, clear console);
+
+
+/**
+ * @brief shell执行命令
+ * 
+ * @param shell shell对象
+ * @param cmd 命令字符串
+ * @return int 返回值
+ */
+int shellRun(Shell *shell, const char *cmd)
+{
+    SHELL_ASSERT(shell && cmd, return -1);
+    char active = shell->status.isActive;
+    if (strlen(cmd) > shell->parser.bufferSize - 1)
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_CMD_TOO_LONG]);
+        return -1;
+    }
+    else
+    {
+        shell->parser.length = shellStringCopy(shell->parser.buffer, (char *)cmd);
+        shellExec(shell);
+        shell->status.isActive = active;
+        return 0;
+    }
+}
+
+
+#if SHELL_EXEC_UNDEF_FUNC == 1
+/**
+ * @brief shell执行未定义函数
+ * 
+ * @param argc 参数个数
+ * @param argv 参数
+ * @return int 返回值
+ */
+int shellExecute(int argc, char *argv[])
+{
+    Shell *shell = shellGetCurrent();
+    if (shell && argc >= 2)
+    {
+        int (*func)() = (int (*)())shellExtParsePara(shell, argv[1]);
+        ShellCommand command = {
+            .attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)
+                          |SHELL_CMD_DISABLE_RETURN,
+            .data.cmd.function = func,
+        };
+        return shellExtRun(shell, &command, argc - 1, &argv[1]);
+    }
+    else
+    {
+        shellWriteString(shell, shellText[SHELL_TEXT_PARAM_ERROR]);
+        return -1;
+    }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+exec, shellExecute, execute function undefined);
+#endif
+
diff --git a/Ems/3rd/Shell/shell.h b/Ems/3rd/Shell/shell.h
new file mode 100644
index 0000000..0201a63
--- /dev/null
+++ b/Ems/3rd/Shell/shell.h
@@ -0,0 +1,477 @@
+/**
+ * @file shell.h
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief letter shell
+ * @version 3.0.0
+ * @date 2019-12-30
+ * 
+ * @copyright (c) 2020 Letter
+ * 
+ */
+
+#ifndef     __SHELL_H__
+#define     __SHELL_H__
+
+#include "shell_cfg.h"
+
+#define     SHELL_VERSION               "3.1.1"                 /**< 版本号 */
+
+
+/**
+ * @brief shell 断言
+ * 
+ * @param expr 表达式
+ * @param action 断言失败操作
+ */
+#define     SHELL_ASSERT(expr, action) \
+            if (!(expr)) { \
+                action; \
+            }
+
+#if SHELL_USING_LOCK == 1
+#define     SHELL_LOCK(shell)           shell->lock(shell)
+#define     SHELL_UNLOCK(shell)         shell->unlock(shell)
+#else
+#define     SHELL_LOCK(shell)
+#define     SHELL_UNLOCK(shell)
+#endif /** SHELL_USING_LOCK == 1 */
+/**
+ * @brief shell 命令权限
+ * 
+ * @param permission 权限级别
+ */
+#define     SHELL_CMD_PERMISSION(permission) \
+            (permission & 0x000000FF)
+
+/**
+ * @brief shell 命令类型
+ * 
+ * @param type 类型
+ */
+#define     SHELL_CMD_TYPE(type) \
+            ((type & 0x0000000F) << 8)
+
+/**
+ * @brief 使能命令在未校验密码的情况下使用
+ */
+#define     SHELL_CMD_ENABLE_UNCHECKED \
+            (1 << 12)
+
+/**
+ * @brief 禁用返回值打印
+ */
+#define     SHELL_CMD_DISABLE_RETURN \
+            (1 << 13)
+
+/**
+ * @brief 只读属性(仅对变量生效)
+ */
+#define     SHELL_CMD_READ_ONLY \
+            (1 << 14)
+
+/**
+ * @brief 命令参数数量
+ */
+#define     SHELL_CMD_PARAM_NUM(num) \
+            ((num & 0x0000000F)) << 16
+
+#ifndef SHELL_SECTION
+    #if defined(__CC_ARM) || defined(__CLANG_ARM)
+        #define SHELL_SECTION(x)                __attribute__((section(x)))
+    #elif defined (__IAR_SYSTEMS_ICC__)
+        #define SHELL_SECTION(x)                @ x
+    #elif defined(__GNUC__)
+        #define SHELL_SECTION(x)                __attribute__((section(x)))
+    #else
+        #define SHELL_SECTION(x)
+    #endif
+#endif
+
+#ifndef SHELL_USED
+    #if defined(__CC_ARM) || defined(__CLANG_ARM)
+        #define SHELL_USED                      __attribute__((used))
+    #elif defined (__IAR_SYSTEMS_ICC__)
+        #define SHELL_USED                      __root
+    #elif defined(__GNUC__)
+        #define SHELL_USED                      __attribute__((used))
+    #else
+        #define SHELL_USED
+    #endif
+#endif
+
+/**
+ * @brief shell float型参数转换
+ */
+#define     SHELL_PARAM_FLOAT(x)            (*(float *)(&x))
+
+/**
+ * @brief shell 代理函数名
+ */
+#define     SHELL_AGENCY_FUNC_NAME(_func)   agency##_func
+
+/**
+ * @brief shell代理函数定义
+ * 
+ * @param _func 被代理的函数
+ * @param ... 代理参数
+ */
+#define     SHELL_AGENCY_FUNC(_func, ...) \
+            void SHELL_AGENCY_FUNC_NAME(_func)(int p1, int p2, int p3, int p4, int p5, int p6, int p7) \
+            { _func(__VA_ARGS__); }
+
+#if SHELL_USING_CMD_EXPORT == 1
+
+    /**
+     * @brief shell 命令定义
+     * 
+     * @param _attr 命令属性
+     * @param _name 命令名
+     * @param _func 命令函数
+     * @param _desc 命令描述
+     */
+    #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
+            const char shellCmd##_name[] = #_name; \
+            const char shellDesc##_name[] = #_desc; \
+            SHELL_USED const ShellCommand \
+            shellCommand##_name SHELL_SECTION("shellCommand") =  \
+            { \
+                .attr.value = _attr, \
+                .data.cmd.name = shellCmd##_name, \
+                .data.cmd.function = (int (*)())_func, \
+                .data.cmd.desc = shellDesc##_name \
+            }
+
+    /**
+     * @brief shell 代理命令定义
+     * 
+     * @param _attr 命令属性
+     * @param _name 命令名
+     * @param _func 命令函数
+     * @param _desc 命令描述
+     * @param ... 代理参数
+     */
+    #define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...) \
+            SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
+            SHELL_EXPORT_CMD(_attr, _name, SHELL_AGENCY_FUNC_NAME(_func), _desc)
+
+    /**
+     * @brief shell 变量定义
+     * 
+     * @param _attr 变量属性
+     * @param _name 变量名
+     * @param _value 变量值
+     * @param _desc 变量描述
+     */
+    #define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
+            const char shellCmd##_name[] = #_name; \
+            const char shellDesc##_name[] = #_desc; \
+            SHELL_USED const ShellCommand \
+            shellVar##_name SHELL_SECTION("shellCommand") =  \
+            { \
+                .attr.value = _attr, \
+                .data.var.name = shellCmd##_name, \
+                .data.var.value = (void *)_value, \
+                .data.var.desc = shellDesc##_name \
+            }
+
+    /**
+     * @brief shell 用户定义
+     * 
+     * @param _attr 用户属性
+     * @param _name 用户名
+     * @param _password 用户密码
+     * @param _desc 用户描述
+     */
+    #define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
+            const char shellCmd##_name[] = #_name; \
+            const char shellPassword##_name[] = #_password; \
+            const char shellDesc##_name[] = #_desc; \
+            SHELL_USED const ShellCommand \
+            shellUser##_name SHELL_SECTION("shellCommand") =  \
+            { \
+                .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
+                .data.user.name = shellCmd##_name, \
+                .data.user.password = shellPassword##_name, \
+                .data.user.desc = shellDesc##_name \
+            }
+
+    /**
+     * @brief shell 按键定义
+     * 
+     * @param _attr 按键属性
+     * @param _value 按键键值
+     * @param _func 按键函数
+     * @param _desc 按键描述
+     */
+    #define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
+            const char shellDesc##_value[] = #_desc; \
+            SHELL_USED const ShellCommand \
+            shellKey##_value SHELL_SECTION("shellCommand") =  \
+            { \
+                .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
+                .data.key.value = _value, \
+                .data.key.function = (void (*)(Shell *))_func, \
+                .data.key.desc = shellDesc##_value \
+            }
+
+    /**
+     * @brief shell 代理按键定义
+     * 
+     * @param _attr 按键属性
+     * @param _value 按键键值
+     * @param _func 按键函数
+     * @param _desc 按键描述
+     * @param ... 代理参数
+     */
+    #define SHELL_EXPORT_KEY_AGENCY(_attr, _value, _func, _desc, ...) \
+            SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
+            SHELL_EXPORT_KEY(_attr, _value, SHELL_AGENCY_FUNC_NAME(_func), _desc)
+#else
+    /**
+     * @brief shell 命令item定义
+     * 
+     * @param _attr 命令属性
+     * @param _name 命令名
+     * @param _func 命令函数
+     * @param _desc 命令描述
+     */
+    #define SHELL_CMD_ITEM(_attr, _name, _func, _desc) \
+            { \
+                .attr.value = _attr, \
+                .data.cmd.name = #_name, \
+                .data.cmd.function = (int (*)())_func, \
+                .data.cmd.desc = #_desc \
+            }
+
+    /**
+     * @brief shell 变量item定义
+     * 
+     * @param _attr 变量属性
+     * @param _name 变量名
+     * @param _value 变量值
+     * @param _desc 变量描述
+     */
+    #define SHELL_VAR_ITEM(_attr, _name, _value, _desc) \
+            { \
+                .attr.value = _attr, \
+                .data.var.name = #_name, \
+                .data.var.value = (void *)_value, \
+                .data.var.desc = #_desc \
+            }
+
+    /**
+     * @brief shell 用户item定义
+     * 
+     * @param _attr 用户属性
+     * @param _name 用户名
+     * @param _password 用户密码
+     * @param _desc 用户描述
+     */
+    #define SHELL_USER_ITEM(_attr, _name, _password, _desc) \
+            { \
+                .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
+                .data.user.name = #_name, \
+                .data.user.password = #_password, \
+                .data.user.desc = #_desc \
+            }
+
+    /**
+     * @brief shell 按键item定义
+     * 
+     * @param _attr 按键属性
+     * @param _value 按键键值
+     * @param _func 按键函数
+     * @param _desc 按键描述
+     */
+    #define SHELL_KEY_ITEM(_attr, _value, _func, _desc) \
+            { \
+                .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
+                .data.key.value = _value, \
+                .data.key.function = (void (*)(Shell *))_func, \
+                .data.key.desc = #_desc \
+            }
+
+    #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc)
+    #define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...)
+    #define SHELL_EXPORT_VAR(_attr, _name, _value, _desc)
+    #define SHELL_EXPORT_USER(_attr, _name, _password, _desc)
+    #define SHELL_EXPORT_KEY(_attr, _value, _func, _desc)
+    #define SHELL_EXPORT_KEY_AGENCY(_attr, _name, _func, _desc, ...)
+#endif /** SHELL_USING_CMD_EXPORT == 1 */
+
+/**
+ * @brief shell command类型
+ */
+typedef enum
+{
+    SHELL_TYPE_CMD_MAIN = 0,                                    /**< main形式命令 */
+    SHELL_TYPE_CMD_FUNC,                                        /**< C函数形式命令 */
+    SHELL_TYPE_VAR_INT,                                         /**< int型变量 */
+    SHELL_TYPE_VAR_SHORT,                                       /**< short型变量 */
+    SHELL_TYPE_VAR_CHAR,                                        /**< char型变量 */
+    SHELL_TYPE_VAR_STRING,                                      /**< string型变量 */
+    SHELL_TYPE_VAR_POINT,                                       /**< 指针型变量 */
+    SHELL_TYPE_VAR_NODE,                                        /**< 节点变量 */
+    SHELL_TYPE_USER,                                            /**< 用户 */
+    SHELL_TYPE_KEY,                                             /**< 按键 */
+} ShellCommandType;
+
+/**
+ * @brief shell backspace mode类型
+ */
+typedef enum
+{
+    SHELL_BACKSPACE_MODE_BACK_SPACE_BACK = 0,
+    SHELL_BACKSPACE_MODE_SPACE_BACK,
+} ShellBackspaceModeType;
+
+/**
+ * @brief Shell定义
+ */
+typedef struct shell_def
+{
+    struct
+    {
+        const struct shell_command *user;                       /**< 当前用户 */
+        int activeTime;                                         /**< shell激活时间 */
+        char *path;                                             /**< 当前shell路径 */
+    #if SHELL_USING_COMPANION == 1
+        struct shell_companion_object *companions;              /**< 伴生对象 */
+    #endif
+    } info;
+    struct
+    {
+        unsigned short length;                                  /**< 输入数据长度 */
+        unsigned short cursor;                                  /**< 当前光标位置 */
+        char *buffer;                                           /**< 输入缓冲 */
+        char *param[SHELL_PARAMETER_MAX_NUMBER];                /**< 参数 */
+        unsigned short bufferSize;                              /**< 输入缓冲大小 */
+        unsigned short paramCount;                              /**< 参数数量 */
+        int keyValue;                                           /**< 输入按键键值 */
+    } parser;
+#if SHELL_HISTORY_MAX_NUMBER > 0
+    struct
+    {
+        char *item[SHELL_HISTORY_MAX_NUMBER];                   /**< 历史记录 */
+        unsigned short number;                                  /**< 历史记录数 */
+        unsigned short record;                                  /**< 当前记录位置 */
+        signed short offset;                                    /**< 当前历史记录偏移 */
+    } history;
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+    struct
+    {
+        void *base;                                             /**< 命令表基址 */
+        unsigned short count;                                   /**< 命令数量 */
+    } commandList;
+    struct
+    {
+        unsigned char isChecked : 1;                            /**< 密码校验通过 */
+        unsigned char isActive : 1;                             /**< 当前活动Shell */
+        unsigned char tabFlag : 1;                              /**< tab标志 */
+    } status;
+    signed short (*read)(char *, unsigned short);               /**< shell读函数 */
+    signed short (*write)(char *, unsigned short);              /**< shell写函数 */
+#if SHELL_USING_LOCK == 1
+    int (*lock)(struct shell_def *);                              /**< shell 加锁 */
+    int (*unlock)(struct shell_def *);                            /**< shell 解锁 */
+#endif
+	int echo;
+    ShellBackspaceModeType backsapceMode;
+} Shell;
+
+
+/**
+ * @brief shell command定义
+ */
+typedef struct shell_command
+{
+    union
+    {
+        struct
+        {
+            unsigned char permission : 8;                       /**< command权限 */
+            ShellCommandType type : 4;                          /**< command类型 */
+            unsigned char enableUnchecked : 1;                  /**< 在未校验密码的情况下可用 */
+            unsigned char disableReturn : 1;                    /**< 禁用返回值输出 */
+            unsigned char  readOnly : 1;                        /**< 只读 */
+            unsigned char reserve : 1;                          /**< 保留 */
+            unsigned char paramNum : 4;                         /**< 参数数量 */
+        } attrs;
+        int value;
+    } attr;                                                     /**< 属性 */
+    union
+    {
+        struct
+        {
+            const char *name;                                   /**< 命令名 */
+            int (*function)();                                  /**< 命令执行函数 */
+            const char *desc;                                   /**< 命令描述 */
+        } cmd;                                                  /**< 命令定义 */
+        struct
+        {
+            const char *name;                                   /**< 变量名 */
+            void *value;                                        /**< 变量值 */
+            const char *desc;                                   /**< 变量描述 */
+        } var;                                                  /**< 变量定义 */
+        struct
+        {
+            const char *name;                                   /**< 用户名 */
+            const char *password;                               /**< 用户密码 */
+            const char *desc;                                   /**< 用户描述 */
+        } user;                                                 /**< 用户定义 */
+        struct
+        {
+            int value;                                          /**< 按键键值 */
+            void (*function)(Shell *);                          /**< 按键执行函数 */
+            const char *desc;                                   /**< 按键描述 */
+        } key;                                                  /**< 按键定义 */
+    } data; 
+} ShellCommand;
+
+/**
+ * @brief shell节点变量属性
+ */
+typedef struct
+{
+    void *var;                                                  /**< 变量引用 */
+    int (*get)();                                               /**< 变量get方法 */
+    int (*set)();                                               /**< 变量set方法 */
+} ShellNodeVarAttr;
+
+
+#define shellSetPath(_shell, _path)     (_shell)->info.path = _path
+#define shellGetPath(_shell)            ((_shell)->info.path)
+
+void shellInit(Shell *shell, char *buffer, unsigned short size);
+void shellEcho(Shell *shell, unsigned int enable);
+unsigned short shellWriteString(Shell *shell, const char *string);
+void shellPrint(Shell *shell, char *fmt, ...);
+void shellScan(Shell *shell, char *fmt, ...);
+Shell* shellGetCurrent(void);
+void shellHandler(Shell *shell, char data);
+void shellWriteEndLine(Shell *shell, char *buffer, int len);
+void shellTask(void *param);
+int shellRun(Shell *shell, const char *cmd);
+
+
+
+#if SHELL_USING_COMPANION == 1
+/**
+ * @brief shell伴生对象定义
+ */
+typedef struct shell_companion_object
+{
+    int id;                                                     /**< 伴生对象ID */
+    void *obj;                                                  /**< 伴生对象 */
+    struct shell_companion_object *next;                        /**< 下一个伴生对象 */
+} ShellCompanionObj;
+
+
+signed char shellCompanionAdd(Shell *shell, int id, void *object);
+signed char shellCompanionDel(Shell *shell, int id);
+void *shellCompanionGet(Shell *shell, int id);
+#endif
+
+#endif
+
+
diff --git a/Ems/3rd/Shell/shell_cfg.h b/Ems/3rd/Shell/shell_cfg.h
new file mode 100644
index 0000000..d0c5887
--- /dev/null
+++ b/Ems/3rd/Shell/shell_cfg.h
@@ -0,0 +1,183 @@
+/**
+ * @file shell_cfg.h
+ * @author Letter (nevermindzzt@gmail.com)
+ * @brief shell config
+ * @version 3.0.0
+ * @date 2019-12-31
+ * 
+ * @copyright (c) 2019 Letter
+ * 
+ */
+
+#ifndef __SHELL_CFG_H__
+#define __SHELL_CFG_H__
+
+
+/**
+ * @brief 是否使用默认shell任务while循环,使能宏`SHELL_USING_TASK`后此宏有意义
+ *        使能此宏,则`shellTask()`函数会一直循环读取输入,一般使用操作系统建立shell
+ *        任务时使能此宏,关闭此宏的情况下,一般适用于无操作系统,在主循环中调用`shellTask()`
+ */
+#define     SHELL_TASK_WHILE            1
+
+/**
+ * @brief 是否使用命令导出方式
+ *        使能此宏后,可以使用`SHELL_EXPORT_CMD()`等导出命令
+ *        定义shell命令,关闭此宏的情况下,需要使用命令表的方式
+ */
+#define     SHELL_USING_CMD_EXPORT      1
+
+/**
+ * @brief 是否使用shell伴生对象
+ *        一些扩展的组件(文件系统支持,日志工具等)需要使用伴生对象
+ */
+#define     SHELL_USING_COMPANION       0
+
+/**
+ * @brief 支持shell尾行模式
+ */
+#define     SHELL_SUPPORT_END_LINE      0
+
+/**
+ * @brief 是否在输出命令列表中列出用户
+ */
+#define     SHELL_HELP_LIST_USER        0
+
+/**
+ * @brief 是否在输出命令列表中列出变量
+ */
+#define     SHELL_HELP_LIST_VAR         0
+
+/**
+ * @brief 是否在输出命令列表中列出按键
+ */
+#define     SHELL_HELP_LIST_KEY         0
+
+/**
+ * @brief 是否在输出命令列表中展示命令权限
+ */
+#define     SHELL_HELP_SHOW_PERMISSION  1
+
+/**
+ * @brief 使用LF作为命令行回车触发
+ *        可以和SHELL_ENTER_CR同时开启
+ */
+#define     SHELL_ENTER_LF              1
+
+/**
+ * @brief 使用CR作为命令行回车触发
+ *        可以和SHELL_ENTER_LF同时开启
+ */
+#define     SHELL_ENTER_CR              1
+
+/**
+ * @brief 使用CRLF作为命令行回车触发
+ *        不可以和SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
+ */
+#define     SHELL_ENTER_CRLF            0
+
+/**
+ * @brief 使用执行未导出函数的功能
+ *        启用后,可以通过`exec [addr] [args]`直接执行对应地址的函数
+ * @attention 如果地址错误,可能会直接引起程序崩溃
+ */
+#define     SHELL_EXEC_UNDEF_FUNC       0
+
+/**
+ * @brief shell命令参数最大数量
+ *        包含命令名在内,超过16个参数并且使用了参数自动转换的情况下,需要修改源码
+ */
+#define     SHELL_PARAMETER_MAX_NUMBER  8
+
+/**
+ * @brief 历史命令记录数量
+ */
+#define     SHELL_HISTORY_MAX_NUMBER    5
+
+/**
+ * @brief 双击间隔(ms)
+ *        使能宏`SHELL_LONG_HELP`后此宏生效,定义双击tab补全help的时间间隔
+ */
+#define     SHELL_DOUBLE_Clike_TIME     200
+
+/**
+ * @brief 快速帮助
+ *        作用于双击tab的场景,当使能此宏时,双击tab不会对命令进行help补全,而是直接显示对应命令的帮助信息
+ */
+#define     SHELL_QUICK_HELP            1
+
+
+/**
+ * @brief 管理的最大shell数量
+ */
+#define     SHELL_MAX_NUMBER            5
+
+/**
+ * @brief shell格式化输出的缓冲大小
+ *        为0时不使用shell格式化输出
+ */
+#define     SHELL_PRINT_BUFFER          128
+
+/**
+ * @brief shell格式化输入的缓冲大小
+ *        为0时不使用shell格式化输入
+ * @note shell格式化输入会阻塞shellTask, 仅适用于在有操作系统的情况下使用
+ */
+#define     SHELL_SCAN_BUFFER          0
+
+/**
+ * @brief 获取系统时间(ms)
+ *        定义此宏为获取系统Tick,如`HAL_GetTick()`
+ * @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定
+ */
+#define     SHELL_GET_TICK()            0
+
+/**
+ * @brief 使用锁
+ * @note 使用shell锁时,需要对加锁和解锁进行实现
+ */
+#define     SHELL_USING_LOCK            0
+
+/**
+ * @brief shell内存分配
+ *        shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define     SHELL_MALLOC(size)          0
+
+/**
+ * @brief shell内存释放
+ *        shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define     SHELL_FREE(obj)             0
+
+/**
+ * @brief 是否显示shell信息
+ */
+#define     SHELL_SHOW_INFO             1
+
+/**
+ * @brief 是否在登录后清除命令行
+ */
+#define     SHELL_CLS_WHEN_LOGIN        1
+
+/**
+ * @brief shell默认用户
+ */
+#define     SHELL_DEFAULT_USER          "eLab"
+
+/**
+ * @brief shell默认用户密码
+ *        若默认用户不需要密码,设为""
+ */
+//#define     SHELL_DEFAULT_USER_PASSWORD "123456"
+#define     SHELL_DEFAULT_USER_PASSWORD ""
+
+/**
+ * @brief shell自动锁定超时
+ *        shell当前用户密码有效的时候生效,超时后会自动重新锁定shell
+ *        设置为0时关闭自动锁定功能,时间单位为`SHELL_GET_TICK()`单位
+ * @note 使用超时锁定必须保证`SHELL_GET_TICK()`有效
+ */
+#define     SHELL_LOCK_TIMEOUT          0 * 60 * 1000
+
+#endif
diff --git a/Ems/3rd/Shell/shell_cmd_list.c b/Ems/3rd/Shell/shell_cmd_list.c
new file mode 100644
index 0000000..139a531
--- /dev/null
+++ b/Ems/3rd/Shell/shell_cmd_list.c
@@ -0,0 +1,103 @@
+/**
+ * @file shell_cmd_list.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell cmd list
+ * @version 3.0.0
+ * @date 2020-01-17
+ * 
+ * @copyright (c) 2020 Letter
+ * 
+ */
+
+#include "shell.h"
+
+#if SHELL_USING_CMD_EXPORT != 1
+
+extern int shellSetVar(char *name, int value);
+extern void shellUp(Shell *shell);
+extern void shellDown(Shell *shell);
+extern void shellRight(Shell *shell);
+extern void shellLeft(Shell *shell);
+extern void shellTab(Shell *shell);
+extern void shellBackspace(Shell *shell);
+extern void shellDelete(Shell *shell);
+extern void shellEnter(Shell *shell);
+extern void shellHelp(int argc, char *argv[]);
+extern void shellUsers(void);
+extern void shellCmds(void);
+extern void shellVars(void);
+extern void shellKeys(void);
+extern void shellClear(void);
+#if SHELL_EXEC_UNDEF_FUNC == 1
+extern int shellExecute(int argc, char *argv[]);
+#endif
+
+SHELL_AGENCY_FUNC(shellRun, shellGetCurrent(), (const char *)p1);
+
+
+/**
+ * @brief shell命令表
+ * 
+ */
+const ShellCommand shellCommandList[] = 
+{
+    {.attr.value=SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
+    .data.user.name = SHELL_DEFAULT_USER,
+    .data.user.password = SHELL_DEFAULT_USER_PASSWORD,
+    .data.user.desc = "default user"},
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
+                   setVar, shellSetVar, set var),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x1B5B4300, shellRight, right),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x1B5B4400, shellLeft, left),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x08000000, shellBackspace, backspace),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x7F000000, shellDelete, delete),
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x1B5B337E, shellDelete, delete),
+#if SHELL_ENTER_LF == 1
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x0A000000, shellEnter, enter),
+#endif
+#if SHELL_ENTER_CR == 1
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x0D000000, shellEnter, enter),
+#endif
+#if SHELL_ENTER_CRLF == 1
+    SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+                   0x0D0A0000, shellEnter, enter),
+#endif
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+                   help, shellHelp, show command info\r\nhelp [cmd]),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   users, shellUsers, list all user),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   cmds, shellCmds, list all cmd),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   vars, shellVars, list all var),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   keys, shellKeys, list all key),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   clear, shellClear, clear console),
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+                   sh, SHELL_AGENCY_FUNC_NAME(shellRun), run command directly),
+#if SHELL_EXEC_UNDEF_FUNC == 1
+    SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+                   exec, shellExecute, execute function undefined),
+#endif
+};
+
+
+/**
+ * @brief shell命令表大小
+ * 
+ */
+const unsigned short shellCommandCount 
+    = sizeof(shellCommandList) / sizeof(ShellCommand);
+
+#endif
diff --git a/Ems/3rd/Shell/shell_companion.c b/Ems/3rd/Shell/shell_companion.c
new file mode 100644
index 0000000..eb494c7
--- /dev/null
+++ b/Ems/3rd/Shell/shell_companion.c
@@ -0,0 +1,87 @@
+/**
+ * @file shell_companion.c
+ * @author Letter (nevermindzzt@gmail.com)
+ * @brief shell companion object support
+ * @version 3.0.3
+ * @date 2020-07-22
+ * 
+ * @copyright (c) 2020 Letter
+ * 
+ */
+ #include "shell.h"
+ 
+#if SHELL_USING_COMPANION == 1
+/**
+ * @brief shell添加伴生对象
+ * 
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @param object 伴生对象
+ * @return signed char 0 添加成功 -1 添加失败
+ */
+signed char shellCompanionAdd(Shell *shell, int id, void *object)
+{
+    ShellCompanionObj *companions = shell->info.companions;
+    ShellCompanionObj *node = SHELL_MALLOC(sizeof(ShellCompanionObj));
+    SHELL_ASSERT(node, return -1);
+    node->id = id;
+    node->obj = object;
+    node->next = companions;
+    shell->info.companions = node;
+    return 0;
+}
+
+/**
+ * @brief shell删除伴生对象
+ * 
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @return signed char 0 删除成功 -1 无匹配对象
+ */
+signed char shellCompanionDel(Shell *shell, int id)
+{
+    ShellCompanionObj *companions = shell->info.companions;
+    ShellCompanionObj *front = companions;
+    while (companions)
+    {
+        if (companions->id == id)
+        {
+            if (companions == shell->info.companions && !(companions->next)) 
+            {
+                shell->info.companions = (void *)0;
+            }
+            else
+            {
+                front->next = companions->next;
+            }
+            SHELL_FREE(companions);
+            return 0;
+        }
+        front = companions;
+        companions = companions->next;
+    }
+    return -1;
+}
+
+/**
+ * @brief shell获取伴生对象
+ * 
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @return void* 伴生对象,无匹配对象时返回NULL
+ */
+void *shellCompanionGet(Shell *shell, int id)
+{
+    SHELL_ASSERT(shell, return (void *)0);
+    ShellCompanionObj *companions = shell->info.companions;
+    while (companions)
+    {
+        if (companions->id == id)
+        {
+            return companions->obj;
+        }
+        companions = companions->next;
+    }
+    return (void *)0;
+}
+#endif /** SHELL_USING_COMPANION == 1 */
diff --git a/Ems/3rd/Shell/shell_ext.c b/Ems/3rd/Shell/shell_ext.c
new file mode 100644
index 0000000..7fbbc61
--- /dev/null
+++ b/Ems/3rd/Shell/shell_ext.c
@@ -0,0 +1,447 @@
+/**
+ * @file shell_ext.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell extensions
+ * @version 3.0.0
+ * @date 2019-12-31
+ * 
+ * @copyright (c) 2019 Letter
+ * 
+ */
+
+#include "shell_cfg.h"
+#include "shell.h"
+#include "shell_ext.h"
+
+
+extern ShellCommand* shellSeekCommand(Shell *shell,
+                                      const char *cmd,
+                                      ShellCommand *base,
+                                      unsigned short compareLength);
+extern int shellGetVarValue(Shell *shell, ShellCommand *command);
+
+/**
+ * @brief 判断数字进制
+ * 
+ * @param string 参数字符串
+ * @return ShellNumType 进制
+ */
+static ShellNumType shellExtNumType(char *string)
+{
+    char *p = string;
+    ShellNumType type = NUM_TYPE_DEC;
+
+    if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X')))
+    {
+        type = NUM_TYPE_HEX;
+    }
+    else if ((*p == '0') && ((*(p + 1) == 'b') || (*(p + 1) == 'B')))
+    {
+        type = NUM_TYPE_BIN;
+    }
+    else if (*p == '0')
+    {
+        type = NUM_TYPE_OCT;
+    }
+    
+    while (*p++)
+    {
+        if (*p == '.' && *(p + 1) != 0)
+        {
+            type = NUM_TYPE_FLOAT;
+            break;
+        }
+    }
+
+    return type;
+}
+
+
+/**
+ * @brief 字符转数字
+ * 
+ * @param code 字符
+ * @return char 数字
+ */
+static char shellExtToNum(char code)
+{
+    if ((code >= '0') && (code <= '9'))
+    {
+        return code -'0';
+    }
+    else if ((code >= 'a') && (code <= 'f'))
+    {
+        return code - 'a' + 10;
+    }
+    else if ((code >= 'A') && (code <= 'F'))
+    {
+        return code - 'A' + 10;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+/**
+ * @brief 解析字符参数
+ * 
+ * @param string 字符串参数
+ * @return char 解析出的字符
+ */
+static char shellExtParseChar(char *string)
+{
+    char *p = string + 1;
+    char value = 0;
+
+    if (*p == '\\')
+    {
+        switch (*(p + 1))
+        {
+        case 'b':
+            value = '\b';
+            break;
+        case 'r':
+            value = '\r';
+            break;
+        case 'n':
+            value = '\n';
+            break;
+        case 't':
+            value = '\t';
+            break;
+        case '0':
+            value = 0;
+            break;
+        default:
+            value = *(p + 1);
+            break;
+        }
+    }
+    else
+    {
+        value = *p;
+    }
+    return value;
+}
+
+
+/**
+ * @brief 解析字符串参数
+ * 
+ * @param string 字符串参数
+ * @return char* 解析出的字符串
+ */
+static char* shellExtParseString(char *string)
+{
+    char *p = string;
+    unsigned short index = 0;
+
+    if (*string == '\"')
+    {
+        p = ++string;
+    }
+
+    while (*p)
+    {
+        if (*p == '\\')
+        {
+            *(string + index) = shellExtParseChar(p - 1);
+            p++;
+        }
+        else if (*p == '\"')
+        {
+            *(string + index) = 0;
+        }
+        else
+        {
+            *(string + index) = *p;
+        }
+        p++;
+        index ++;
+    }
+    *(string + index) = 0;
+    return string;
+}
+
+
+/**
+ * @brief 解析数字参数
+ * 
+ * @param string 字符串参数
+ * @return unsigned int 解析出的数字
+ */
+static unsigned int shellExtParseNumber(char *string)
+{
+    ShellNumType type = NUM_TYPE_DEC;
+    char radix = 10;
+    char *p = string;
+    char offset = 0;
+    signed char sign = 1;
+    unsigned int valueInt = 0;
+    float valueFloat = 0.0;
+    unsigned int devide = 0;
+
+    if (*string == '-')
+    {
+        sign = -1;
+    }
+
+    type = shellExtNumType(string + ((sign == -1) ? 1 : 0));
+
+    switch ((char)type)
+    {
+    case NUM_TYPE_HEX:
+        radix = 16;
+        offset = 2;
+        break;
+    
+    case NUM_TYPE_OCT:
+        radix = 8;
+        offset = 1;
+        break;
+
+    case NUM_TYPE_BIN:
+        radix = 2;
+        offset = 2;
+        break;
+    
+    default:
+        break;
+    }
+
+    p = string + offset + ((sign == -1) ? 1 : 0);
+
+    while (*p)
+    {
+        if (*p == '.')
+        {
+            devide = 1;
+            p++;
+            continue;
+        }
+        valueInt = valueInt * radix + shellExtToNum(*p);
+        devide *= 10;
+        p++;
+    }
+    if (type == NUM_TYPE_FLOAT && devide != 0)
+    {
+        valueFloat = (float)valueInt / devide * sign;
+        return *(unsigned int *)(&valueFloat);
+    }
+    else
+    {
+        return valueInt * sign;
+    }
+}
+
+
+/**
+ * @brief 解析变量参数
+ * 
+ * @param shell shell对象
+ * @param var 变量
+ * @return unsigned int 变量值
+ */
+static unsigned int shellExtParseVar(Shell *shell, char *var)
+{
+    ShellCommand *command = shellSeekCommand(shell,
+                                             var + 1,
+                                             shell->commandList.base,
+                                             0);
+    if (command)
+    {
+        return shellGetVarValue(shell, command);
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+/**
+ * @brief 解析参数
+ * 
+ * @param shell shell对象
+ * @param string 参数
+ * @return unsigned int 解析结果
+ */
+unsigned int shellExtParsePara(Shell *shell, char *string)
+{
+    if (*string == '\'' && *(string + 1))
+    {
+        return (unsigned int)shellExtParseChar(string);
+    }
+    else if (*string == '-' || (*string >= '0' && *string <= '9'))
+    {
+        return (unsigned int)shellExtParseNumber(string);
+    }
+    else if (*string == '$' && *(string + 1))
+    {
+        return shellExtParseVar(shell, string);
+    }
+    else if (*string)
+    {
+        return (unsigned int)shellExtParseString(string);
+    }
+    return 0;
+}
+
+
+/**
+ * @brief 执行命令
+ * 
+ * @param shell shell对象
+ * @param command 命令
+ * @param argc 参数个数
+ * @param argv 参数
+ * @return int 返回值
+ */
+int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
+{
+    unsigned int params[SHELL_PARAMETER_MAX_NUMBER] = {0};
+    int paramNum = command->attr.attrs.paramNum > (argc - 1) ? 
+        command->attr.attrs.paramNum : (argc - 1);
+    for (int i = 0; i < argc - 1; i++)
+    {
+        params[i] = shellExtParsePara(shell, argv[i + 1]);
+    }
+    switch (paramNum)
+    {
+#if SHELL_PARAMETER_MAX_NUMBER >= 1
+    case 0:
+        return command->data.cmd.function();
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 2
+    case 1:
+        return command->data.cmd.function(params[0]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 3
+    case 2:
+        return command->data.cmd.function(params[0], params[1]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 4
+    case 3:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 5
+    case 4:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 6
+    case 5:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 7
+    case 6:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 8
+    case 7:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 9
+    case 8:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 10
+    case 9:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 11
+    case 10:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 12
+    case 11:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9],
+                                          params[10]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 13
+    case 12:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9],
+                                          params[10], params[11]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 14
+    case 13:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9],
+                                          params[10], params[11],
+                                          params[12]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 15
+    case 14:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9],
+                                          params[10], params[11],
+                                          params[12], params[13]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 16
+    case 15:
+        return command->data.cmd.function(params[0], params[1],
+                                          params[2], params[3],
+                                          params[4], params[5],
+                                          params[6], params[7],
+                                          params[8], params[9],
+                                          params[10], params[11],
+                                          params[12], params[13],
+                                          params[14]);
+        // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */
+    default:
+        return -1;
+        // break;
+    }
+}
+
diff --git a/Ems/3rd/Shell/shell_ext.h b/Ems/3rd/Shell/shell_ext.h
new file mode 100644
index 0000000..2e6158c
--- /dev/null
+++ b/Ems/3rd/Shell/shell_ext.h
@@ -0,0 +1,33 @@
+/**
+ * @file shell_ext.h
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell extensions
+ * @version 3.0.0
+ * @date 2019-12-31
+ * 
+ * @copyright (c) 2019 Letter
+ * 
+ */
+
+#ifndef __SHELL_EXT_H__
+#define __SHELL_EXT_H__
+
+#include "shell.h"
+
+/**
+ * @brief 数字类型
+ * 
+ */
+typedef enum
+{
+    NUM_TYPE_DEC,                                           /**< 十进制整型 */
+    NUM_TYPE_BIN,                                           /**< 二进制整型 */
+    NUM_TYPE_OCT,                                           /**< 八进制整型 */
+    NUM_TYPE_HEX,                                           /**< 十六进制整型 */
+    NUM_TYPE_FLOAT                                          /**< 浮点型 */
+} ShellNumType;
+
+unsigned int shellExtParsePara(Shell *shell, char *string);
+int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]);
+
+#endif
diff --git a/Ems/common/Ems_assert.h b/Ems/common/Ems_assert.h
new file mode 100644
index 0000000..6e728be
--- /dev/null
+++ b/Ems/common/Ems_assert.h
@@ -0,0 +1,29 @@
+/**
+ * @file Ems_assert.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_ASSERT_H
+#define EMS_ASSERT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public define ------------------------------------------------------------ */
+#define EMS_TAG(tag)
+#define ems_assert(ex)                     ((void)0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/common/Ems_common.c b/Ems/common/Ems_common.c
new file mode 100644
index 0000000..1af335f
--- /dev/null
+++ b/Ems/common/Ems_common.c
@@ -0,0 +1,46 @@
+/**
+ * @file Ems_common.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+/* include ------------------------------------------------------------------ */
+#include "ems.h"
+
+/* public function ---------------------------------------------------------- */
+/**
+  * @brief  eLab debug uart weak initialization function.
+  * @param  baudrate    The uart port baudrate.
+  * @retval None
+  */
+EMS_WEAK void ems_debug_uart_init(uint32_t baudrate)
+{
+    (void)baudrate;
+}
+
+EMS_WEAK int16_t ems_debug_uart_send(void *buffer, uint16_t size)
+{
+    (void)buffer;
+    (void)size;
+
+    return 0;
+}
+
+EMS_WEAK int16_t ems_debug_uart_receive(void *buffer, uint16_t size)
+{
+    (void)buffer;
+    (void)size;
+
+    return 0;
+}
+
+EMS_WEAK void ems_debug_uart_buffer_clear(void)
+{
+}
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/common/Ems_common.h b/Ems/common/Ems_common.h
new file mode 100644
index 0000000..a5ac527
--- /dev/null
+++ b/Ems/common/Ems_common.h
@@ -0,0 +1,52 @@
+/**
+ * @file Ems_common.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_COMMON_H
+#define EMS_COMMON_H
+
+/* includes ----------------------------------------------------------------- */
+#include <stdint.h>
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+#include "ems_port.h"
+#include "cmsis_os.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public typedef ----------------------------------------------------------- */
+/* time related. */
+uint32_t ems_time_ms(void);
+
+/* uart debug related. */
+void ems_debug_uart_init(uint32_t baudrate);
+int16_t ems_debug_uart_send(void *buffer, uint16_t size);
+int16_t ems_debug_uart_receive(void *buffer, uint16_t size);
+void ems_debug_uart_buffer_clear(void);
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+/* thread related. */
+osThreadId_t ems_thread_init(ems_thread_t *const me,
+                                void (*entry)(void *parameter),
+                                const char *name, void *data,
+                                void *stack, uint32_t stack_size,
+                                uint8_t priority);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/common/Ems_def.h b/Ems/common/Ems_def.h
new file mode 100644
index 0000000..23d233c
--- /dev/null
+++ b/Ems/common/Ems_def.h
@@ -0,0 +1,107 @@
+/**
+ * @file Ems_def.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_DEF_H
+#define EMS_DEF_H
+
+/* includes ----------------------------------------------------------------- */
+#include <stdint.h>
+#include "EMS_config.h"
+
+#if (EMS_QPC_EN != 0)
+#include "qpc.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public typedef ----------------------------------------------------------- */
+typedef enum EMS_err
+{
+    EMS_OK                             = 0,
+    EMS_ERROR                          = -1,
+    EMS_ERR_EMPTY                      = -2,
+    EMS_ERR_FULL                       = -3,
+    EMS_ERR_TIMEOUT                    = -4,
+    EMS_ERR_BUSY                       = -5,
+    EMS_ERR_NO_MEMORY                  = -6,
+    EMS_ERR_IO                         = -7,
+    EMS_ERR_INVALID                    = -8,
+    EMS_ERR_MEM_OVERLAY                = -9,
+    EMS_ERR_MALLOC                     = -10,
+    EMS_ERR_NOT_ENOUGH                 = -11,
+} ems_err_t;
+
+#if (EMS_QPC_EN != 0)
+
+typedef struct EMS_event
+{
+    QEvt super;
+    uint8_t data[EMS_EVENT_DATA_SIZE];
+} EMS_event_t;
+
+#endif
+
+/**
+ * Cast a member of a structure out to the containing structure.
+ * @ptr:    the pointer to the member.
+ * @type:   the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ */
+#ifndef container_of
+#define container_of(pointer, type, member)                                    \
+    ({                                                                         \
+        void *__pointer = (void *)(pointer);                                   \
+        ((type *)(__pointer - offsetof(type, member)));                        \
+    })
+#endif
+
+#ifndef offsetof
+#define offsetof(type, member)          ((uint32_t)&((type *)0)->member)
+#endif
+
+/* Compiler Related Definitions */
+#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM Compiler */
+    #include <stdarg.h>
+    #define EMS_SECTION(x)             __attribute__((section(x)))
+    #define EMS_USED                   __attribute__((used))
+    #define EMS_ALIGN(n)               __attribute__((aligned(n)))
+    #define EMS_WEAK                   __attribute__((weak))
+    #define EMS_INLINE                 static __inline
+
+#elif defined (__IAR_SYSTEMS_ICC__)           /* for IAR Compiler */
+    #include <stdarg.h>
+    #define EMS_SECTION(x)             @ x
+    #define EMS_USED                   __root
+    #define EMS_PRAGMA(x)              _Pragma(#x)
+    #define EMS_ALIGN(n)               EMS_PRAGMA(data_alignment=n)
+    #define EMS_WEAK                   __weak
+    #define EMS_INLINE                 static inline
+
+#elif defined (__GNUC__)                      /* GNU GCC Compiler */
+    #include <stdarg.h>
+    #define EMS_SECTION(x)             __attribute__((section(x)))
+    #define EMS_USED                   __attribute__((used))
+    #define EMS_ALIGN(n)               __attribute__((aligned(n)))
+    #define EMS_WEAK                   __attribute__((weak))
+    #define EMS_INLINE                 static __inline
+#else
+    #error The compiler is not supported!
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/common/Ems_export.c b/Ems/common/Ems_export.c
new file mode 100644
index 0000000..ca6706d
--- /dev/null
+++ b/Ems/common/Ems_export.c
@@ -0,0 +1,242 @@
+/**
+ * @file Ems_export.c
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+/* include ------------------------------------------------------------------ */
+#include <stdlib.h>
+#include <stdint.h>
+#include "ems_export.h"
+#include "ems_common.h"
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+#include "cmsis_os.h"
+#endif
+
+#if (EMS_QPC_EN != 0)
+Q_DEFINE_THIS_FILE
+#include "qpc.h"
+#endif
+
+/* private function prototype ----------------------------------------------- */
+static void module_null_init(void);
+static void _export_func_execute(uint8_t level);
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+static void _entry_start_poll(void *para);
+#endif
+
+/* private variables -------------------------------------------------------- */
+INIT_BSP_EXPORT(module_null_init);
+POLL_EXPORT(module_null_init, (1000 * 60 * 60));
+
+static const uint32_t export_id_table[EXPORT_MAX + 1] =
+{
+    EXPORT_ID_INIT,
+    EXPORT_ID_INIT,
+    EXPORT_ID_INIT,
+    EXPORT_ID_INIT,
+    EXPORT_ID_INIT,
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+    EXPORT_ID_INIT,
+#endif
+#if (EMS_QPC_EN != 0)
+    EXPORT_ID_INIT,
+#endif
+    EXPORT_ID_INIT,
+    EXPORT_ID_POLL,
+};
+
+static ems_export_t *export_init_table = NULL;
+static ems_export_t *export_poll_table = NULL;
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+/**
+ * @brief  The thread attribute for testing.
+ */
+static const osThreadAttr_t thread_attr_start_poll = 
+{
+    .name = "ThreadStartPoll",
+    .attr_bits = osThreadDetached,
+    .priority = osPriorityNormal,
+    .stack_size = 2048,
+};
+#endif
+
+/* public function ---------------------------------------------------------- */
+/**
+  * @brief  eLab unit test exporting function.
+  * @retval None
+  */
+void ems_unit_test(void)
+{
+    _export_func_execute(EXPORT_TEST);
+}
+
+/**
+  * @brief  eLab polling exporting function.
+  * @retval None
+  */
+void ems_run(void)
+{
+    /* Start polling function in metal eLab, or start the RTOS kernel in RTOS 
+       eLab. */
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+    osKernelInitialize();
+    osThreadNew(_entry_start_poll, NULL, &thread_attr_start_poll);
+    osKernelStart();
+#else
+    /* Initialize all module in eLab. */
+    for (uint8_t level = EXPORT_BSP; level <= EXPORT_APP; level ++)
+    {
+        _export_func_execute(level);
+    }
+
+    /* Start polling function in metal eLab. */
+    while (1)
+    {
+        _export_func_execute(EXPORT_MAX);
+    }
+#endif
+}
+
+/* private function --------------------------------------------------------- */
+/**
+  * @brief  Get the export table.
+  */
+static ems_export_t * _get_export_table(uint8_t level)
+{
+    ems_export_t *func_block = 
+                    level < EXPORT_MAX ?
+                    ((ems_export_t *)&init_module_null_init) :
+                    ((ems_export_t *)&poll_module_null_init);
+    
+    while (1)
+    {
+        uint32_t address_last = ((uint32_t)func_block - sizeof(ems_export_t));
+        ems_export_t *table = (ems_export_t *)address_last;
+        if (table->magic_head != export_id_table[level] ||
+            table->magic_tail != export_id_table[level])
+        {
+            break;
+        }
+        func_block = table;
+    }
+
+    return func_block;
+}
+
+/**
+  * @brief  eLab exporting function executing.
+  * @param  level export level.
+  * @retval None
+  */
+static void _export_func_execute(uint8_t level)
+{
+    uint32_t export_id = export_id_table[level];
+
+    /* Get the start address of exported poll table. */
+    if (export_init_table == NULL)
+    {
+        export_init_table = _get_export_table(EXPORT_BSP);
+    }
+    if (export_poll_table == NULL)
+    {
+        export_poll_table = _get_export_table(EXPORT_MAX);
+    }
+
+    /* Execute the poll function in the specific level. */
+    ems_export_t *export_table = level < EXPORT_MAX ?
+                                    export_init_table : export_poll_table;
+    for (uint32_t i = 0; ; i ++)
+    {
+        if (export_table[i].magic_head == export_id &&
+            export_table[i].magic_tail == export_id)
+        {
+            if (export_table[i].level == level && level <= EXPORT_APP)
+            {
+                ((void (*)(void))export_table[i].func)();
+            }
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+            else if (export_table[i].level == level && level == EXPORT_THREAD)
+            {
+                ems_thread_init((ems_thread_t *)export_table[i].object,
+                                    (void (*)(void *))export_table[i].func,
+                                    export_table[i].name, export_table[i].data,
+                                    export_table[i].stack,
+                                    export_table[i].stack_size,
+                                    export_table[i].priority);
+            }
+#endif
+#if (EMS_QPC_EN != 0)
+            else if (export_table[i].level == level && level == EXPORT_HSM)
+            {
+                QActive_ctor((QActive *)export_table[i].object,
+                                Q_STATE_CAST(export_table[i].func));
+                QACTIVE_START((QActive *)export_table[i].object,
+                                export_table[i].priority,
+                                export_table[i].data, export_table[i].queue_size,
+                                export_table[i].stack, export_table[i].stack_size,
+                                (QEvt *)0);
+            }
+#endif
+            else if (export_table[i].level == level && level == EXPORT_MAX)
+            {
+                ems_export_poll_data_t *data = export_table[i].data;
+                while (ems_time_ms() >= data->timeout_ms)
+                {
+                    data->timeout_ms += export_table[i].period_ms;
+                    ((void (*)(void))export_table[i].func)();
+                }
+            }
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+void ao_led_init(void);
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+/**
+  * @brief  eLab startup and poll function.
+  * @retval None
+  */
+static void _entry_start_poll(void *para)
+{
+    /* Initialize all module in eLab. */
+    for (uint8_t level = EXPORT_BSP; level <= EXPORT_APP; level ++)
+    {
+        _export_func_execute(level);
+    }
+    _export_func_execute(EXPORT_THREAD);
+#if (EMS_QPC_EN != 0)
+    _export_func_execute(EXPORT_HSM);
+#endif
+
+    /* Start polling function in metal eLab. */
+    while (1)
+    {
+        _export_func_execute(EXPORT_MAX);
+        osDelay(10);
+    }
+}
+#endif
+
+/**
+  * @brief  eLab null exporting function.
+  * @retval None
+  */
+static void module_null_init(void)
+{
+    /* NULL */
+}
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/common/Ems_export.h b/Ems/common/Ems_export.h
new file mode 100644
index 0000000..07f1678
--- /dev/null
+++ b/Ems/common/Ems_export.h
@@ -0,0 +1,249 @@
+/**
+ * @file Ems_export.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef __EMS_EXPORT_H__
+#define __EMS_EXPORT_H__
+
+/* include ------------------------------------------------------------------ */
+#include <stdint.h>
+#include "ems_def.h"
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+#include "ems_port.h"
+#endif
+
+#if (EMS_QPC_EN != 0)
+#include "qpc.h"
+#endif
+
+/* public define ------------------------------------------------------------ */
+#define EXPORT_ID_INIT                  (0xa5a5a5a5)
+#define EXPORT_ID_POLL                  (0xbeefbeef)
+
+/* public define ------------------------------------------------------------ */
+enum ems_export_level
+{
+    EXPORT_BSP = 0,
+    EXPORT_IO_DRIVER,
+    EXPORT_COMPONENT,
+    EXPORT_DEVICE,
+    EXPORT_APP,
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+    EXPORT_THREAD,
+#endif
+#if (EMS_QPC_EN != 0)
+    EXPORT_HSM,
+#endif
+    EXPORT_TEST,
+
+    EXPORT_MAX,
+};
+
+/* public typedef ----------------------------------------------------------- */
+typedef struct ems_export_poll_data
+{
+    uint32_t timeout_ms;
+} ems_export_poll_data_t;
+
+typedef struct ems_export
+{
+    uint32_t magic_head;
+    const char *name;
+    void *data;
+    void *stack;
+    void *object;
+    void *func;
+    uint16_t stack_size;
+    uint16_t queue_size;
+    uint16_t priority;
+    uint16_t level;
+    uint32_t period_ms;
+    uint32_t temp[6];
+    uint32_t magic_tail;
+} ems_export_t;
+
+/* private function --------------------------------------------------------- */
+void ems_unit_test(void);
+void ems_run(void);
+
+/* public export ------------------------------------------------------------ */
+/**
+  * @brief  Initialization function exporting macro.
+  * @param  _func   The polling function.
+  * @param  _level  The export level. See enum ems_export_level.
+  * @retval None.
+  */
+#define INIT_EXPORT(_func, _level)                                             \
+EMS_USED const ems_export_t init_##_func EMS_SECTION("ems_export") =   \
+    {                                                                          \
+        .name = "init",                                                        \
+        .func = (void *)&_func,                                                \
+        .level = _level,                                                       \
+        .magic_head = EXPORT_ID_INIT,                                          \
+        .magic_tail = EXPORT_ID_INIT,                                          \
+    }
+
+#if (EMS_QPC_EN != 0)
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+/**
+  * @brief  State machine exporting macro.
+  * @param  _name       name of the state machine.
+  * @param  me          The state machine object.
+  * @param  _state_init The initial state of the state machine.
+  * @param  _priority   The priority of the state machine.
+  * @param  _queue_size The queue size of the state machine.
+  * @param  _stack_size The stack size of the state machine's internal thread.
+  * @retval None.
+  */
+#define HSM_EXPORT(_name, me, _state_init, _priority, _queue_size, _stack_size)\
+    static QEvt const * sm_##_name##_queue[_queue_size];                       \
+    static uint8_t sm_##_name##_stack[_stack_size];                            \
+    EMS_USED const ems_export_t sm_##_name EMS_SECTION("ems_export") =     \
+    {                                                                          \
+        .name = (const char *)#_name,                                          \
+        .object = (void *)me,                                                  \
+        .func = (void *)(&_state_init),                                        \
+        .data = (void *)sm_##_name##_queue,                                    \
+        .queue_size = _queue_size,                                             \
+        .stack = (void *)sm_##_name##_stack,                                   \
+        .stack_size = _stack_size,                                             \
+        .priority = _priority,                                                 \
+        .level = EXPORT_HSM,                                                   \
+        .magic_head = EXPORT_ID_INIT,                                          \
+        .magic_tail = EXPORT_ID_INIT,                                          \
+    }
+#else
+
+/**
+  * @brief  State machine exporting macro.
+  * @param  _name       name of the state machine.
+  * @param  me          The state machine object.
+  * @param  _state_init The initial state of the state machine.
+  * @param  _priority   The priority of the state machine.
+  * @param  _queue_size The queue size of the state machine.
+  * @retval None.
+  */
+#define HSM_EXPORT(_name, me, _state_init, _priority, _queue_size)             \
+    static QEvt const * sm_##_name##_queue[_queue_size];                       \
+    EMS_USED const ems_export_t sm_##_name EMS_SECTION("ems_export") =     \
+    {                                                                          \
+        .name = (const char *)#_name,                                          \
+        .object = (void *)me,                                                  \
+        .func = (void *)(&_state_init),                                        \
+        .data = (void *)sm_##_name##_queue,                                    \
+        .queue_size = _queue_size,                                             \
+        .priority = _priority,                                                 \
+        .level = EXPORT_HSM,                                                   \
+        .magic_head = EXPORT_ID_INIT,                                          \
+        .magic_tail = EXPORT_ID_INIT,                                          \
+    }
+#endif
+#else
+#define HSM_EXPORT(_name, me, _state_init, _priority, _queue_size, _stack_size)
+#endif
+
+#if (EMS_RTOS_CMSIS_OS_EN != 0)
+/**
+  * @brief  Thread exporting macro.
+  * @param  _name       name of the state machine.
+  * @param  _entry      The thread entry function.
+  * @param  _priority   The priority of the state machine.
+  * @param  _data       user data.
+  * @param  _stack_size The stack size of the state machine.
+  * @retval None.
+  */
+#define THREAD_EXPORT(_name, _entry, _priority, _data, _stack_size)            \
+    static ems_thread_t thread_##_name;                                       \
+    static uint8_t thread_##_name##_stack[_stack_size];                        \
+    EMS_USED const ems_export_t thread##_name EMS_SECTION("ems_export") =  \
+    {                                                                          \
+        .func = (void *)&_entry,                                               \
+        .name = #_name,                                                        \
+        .data = (void *)_data,                                                 \
+        .object = (void *)&thread_##_name,                                     \
+        .stack = (void *)thread_##_name##_stack,                               \
+        .stack_size = _stack_size,                                             \
+        .priority = _priority,                                                 \
+        .level = EXPORT_THREAD,                                                \
+        .magic_head = EXPORT_ID_INIT,                                          \
+        .magic_tail = EXPORT_ID_INIT,                                          \
+    }
+#else
+#define THREAD_EXPORT(_name, _entry, _priority, _data, _stack_size)
+#endif
+
+/**
+  * @brief  Poll function exporting macro.
+  * @param  _func       The polling function.
+  * @param  _period_ms  The polling period in ms.
+  * @retval None.
+  */
+#define POLL_EXPORT(_func, _period_ms)                                         \
+    static ems_export_poll_data_t poll_##_func##_data =                       \
+    {                                                                          \
+        .timeout_ms = 0,                                                       \
+    };                                                                         \
+    EMS_USED const ems_export_t poll_##_func EMS_SECTION("expoll") =        \
+    {                                                                          \
+        .name = "poll", \
+        .func = (void *)&_func,                                                \
+        .data = (void *)&poll_##_func##_data,                                  \
+        .level = EXPORT_MAX,                                                   \
+        .period_ms = (uint32_t)(_period_ms),                                   \
+        .magic_head = EXPORT_ID_POLL,                                          \
+        .magic_tail = EXPORT_ID_POLL,                                          \
+    }
+
+/* public function ---------------------------------------------------------- */
+/**
+  * @brief  Initialization function in BSP layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_BSP_EXPORT(_func)              INIT_EXPORT(_func, EXPORT_BSP)
+
+/**
+  * @brief  Initialization function in IO driver layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_IO_DRIVER_EXPORT(_func)        INIT_EXPORT(_func, EXPORT_IO_DRIVER)
+
+/**
+  * @brief  Initialization function in component layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_COMPONENT_EXPORT(_func)        INIT_EXPORT(_func, EXPORT_COMPONENT)
+
+/**
+  * @brief  Initialization function in device layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_DEV_EXPORT(_func)              INIT_EXPORT(_func, EXPORT_DEVICE)
+
+/**
+  * @brief  Initialization function in appliation layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_APP_EXPORT(_func)              INIT_EXPORT(_func, EXPORT_APP)
+
+/**
+  * @brief  Testing function in unit test layer.
+  * @param  _func       The initialization function.
+  * @retval None.
+  */
+#define INIT_EXPORT_TEST(_func)             INIT_EXPORT(_func, EXPORT_TEST)
+
+#endif /* __EMS_EXPORT_H__ */
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Ems/ems.h b/Ems/ems.h
new file mode 100644
index 0000000..5ba0b60
--- /dev/null
+++ b/Ems/ems.h
@@ -0,0 +1,24 @@
+/**
+ * @file ems.h
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2023-04-05
+ * 
+ * @copyright Copyright (c) 2023
+ * 
+ */
+
+#ifndef EMS_H
+#define EMS_H
+
+/* includes ----------------------------------------------------------------- */
+#include "common/ems_def.h"
+#include "common/ems_assert.h"
+#include "common/ems_export.h"
+#include "common/ems_common.h"
+
+
+#endif
+
+/* ----------------------------- end of file -------------------------------- */
diff --git a/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32l443xx.h b/MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l443xx.h
similarity index 100%
rename from Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32l443xx.h
rename to MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l443xx.h
diff --git a/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32l4xx.h b/MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l4xx.h
similarity index 100%
rename from Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32l4xx.h
rename to MCU/CMSIS/Device/ST/STM32L4xx/Include/stm32l4xx.h
diff --git a/Drivers/CMSIS/Device/ST/STM32L4xx/Include/system_stm32l4xx.h b/MCU/CMSIS/Device/ST/STM32L4xx/Include/system_stm32l4xx.h
similarity index 100%
rename from Drivers/CMSIS/Device/ST/STM32L4xx/Include/system_stm32l4xx.h
rename to MCU/CMSIS/Device/ST/STM32L4xx/Include/system_stm32l4xx.h
diff --git a/Drivers/CMSIS/Device/ST/STM32L4xx/LICENSE.txt b/MCU/CMSIS/Device/ST/STM32L4xx/LICENSE.txt
similarity index 100%
rename from Drivers/CMSIS/Device/ST/STM32L4xx/LICENSE.txt
rename to MCU/CMSIS/Device/ST/STM32L4xx/LICENSE.txt
diff --git a/Drivers/CMSIS/Device/ST/STM32L4xx/License.md b/MCU/CMSIS/Device/ST/STM32L4xx/License.md
similarity index 100%
rename from Drivers/CMSIS/Device/ST/STM32L4xx/License.md
rename to MCU/CMSIS/Device/ST/STM32L4xx/License.md
diff --git a/Drivers/CMSIS/Include/cmsis_armcc.h b/MCU/CMSIS/Include/cmsis_armcc.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_armcc.h
rename to MCU/CMSIS/Include/cmsis_armcc.h
diff --git a/Drivers/CMSIS/Include/cmsis_armclang.h b/MCU/CMSIS/Include/cmsis_armclang.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_armclang.h
rename to MCU/CMSIS/Include/cmsis_armclang.h
diff --git a/Drivers/CMSIS/Include/cmsis_armclang_ltm.h b/MCU/CMSIS/Include/cmsis_armclang_ltm.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_armclang_ltm.h
rename to MCU/CMSIS/Include/cmsis_armclang_ltm.h
diff --git a/Drivers/CMSIS/Include/cmsis_compiler.h b/MCU/CMSIS/Include/cmsis_compiler.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_compiler.h
rename to MCU/CMSIS/Include/cmsis_compiler.h
diff --git a/Drivers/CMSIS/Include/cmsis_gcc.h b/MCU/CMSIS/Include/cmsis_gcc.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_gcc.h
rename to MCU/CMSIS/Include/cmsis_gcc.h
diff --git a/Drivers/CMSIS/Include/cmsis_iccarm.h b/MCU/CMSIS/Include/cmsis_iccarm.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_iccarm.h
rename to MCU/CMSIS/Include/cmsis_iccarm.h
diff --git a/Drivers/CMSIS/Include/cmsis_version.h b/MCU/CMSIS/Include/cmsis_version.h
similarity index 100%
rename from Drivers/CMSIS/Include/cmsis_version.h
rename to MCU/CMSIS/Include/cmsis_version.h
diff --git a/Drivers/CMSIS/Include/core_armv81mml.h b/MCU/CMSIS/Include/core_armv81mml.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_armv81mml.h
rename to MCU/CMSIS/Include/core_armv81mml.h
diff --git a/Drivers/CMSIS/Include/core_armv8mbl.h b/MCU/CMSIS/Include/core_armv8mbl.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_armv8mbl.h
rename to MCU/CMSIS/Include/core_armv8mbl.h
diff --git a/Drivers/CMSIS/Include/core_armv8mml.h b/MCU/CMSIS/Include/core_armv8mml.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_armv8mml.h
rename to MCU/CMSIS/Include/core_armv8mml.h
diff --git a/Drivers/CMSIS/Include/core_cm0.h b/MCU/CMSIS/Include/core_cm0.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm0.h
rename to MCU/CMSIS/Include/core_cm0.h
diff --git a/Drivers/CMSIS/Include/core_cm0plus.h b/MCU/CMSIS/Include/core_cm0plus.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm0plus.h
rename to MCU/CMSIS/Include/core_cm0plus.h
diff --git a/Drivers/CMSIS/Include/core_cm1.h b/MCU/CMSIS/Include/core_cm1.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm1.h
rename to MCU/CMSIS/Include/core_cm1.h
diff --git a/Drivers/CMSIS/Include/core_cm23.h b/MCU/CMSIS/Include/core_cm23.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm23.h
rename to MCU/CMSIS/Include/core_cm23.h
diff --git a/Drivers/CMSIS/Include/core_cm3.h b/MCU/CMSIS/Include/core_cm3.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm3.h
rename to MCU/CMSIS/Include/core_cm3.h
diff --git a/Drivers/CMSIS/Include/core_cm33.h b/MCU/CMSIS/Include/core_cm33.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm33.h
rename to MCU/CMSIS/Include/core_cm33.h
diff --git a/Drivers/CMSIS/Include/core_cm35p.h b/MCU/CMSIS/Include/core_cm35p.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm35p.h
rename to MCU/CMSIS/Include/core_cm35p.h
diff --git a/Drivers/CMSIS/Include/core_cm4.h b/MCU/CMSIS/Include/core_cm4.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm4.h
rename to MCU/CMSIS/Include/core_cm4.h
diff --git a/Drivers/CMSIS/Include/core_cm7.h b/MCU/CMSIS/Include/core_cm7.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_cm7.h
rename to MCU/CMSIS/Include/core_cm7.h
diff --git a/Drivers/CMSIS/Include/core_sc000.h b/MCU/CMSIS/Include/core_sc000.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_sc000.h
rename to MCU/CMSIS/Include/core_sc000.h
diff --git a/Drivers/CMSIS/Include/core_sc300.h b/MCU/CMSIS/Include/core_sc300.h
similarity index 100%
rename from Drivers/CMSIS/Include/core_sc300.h
rename to MCU/CMSIS/Include/core_sc300.h
diff --git a/Drivers/CMSIS/Include/mpu_armv7.h b/MCU/CMSIS/Include/mpu_armv7.h
similarity index 100%
rename from Drivers/CMSIS/Include/mpu_armv7.h
rename to MCU/CMSIS/Include/mpu_armv7.h
diff --git a/Drivers/CMSIS/Include/mpu_armv8.h b/MCU/CMSIS/Include/mpu_armv8.h
similarity index 100%
rename from Drivers/CMSIS/Include/mpu_armv8.h
rename to MCU/CMSIS/Include/mpu_armv8.h
diff --git a/Drivers/CMSIS/Include/tz_context.h b/MCU/CMSIS/Include/tz_context.h
similarity index 100%
rename from Drivers/CMSIS/Include/tz_context.h
rename to MCU/CMSIS/Include/tz_context.h
diff --git a/Drivers/CMSIS/LICENSE.txt b/MCU/CMSIS/LICENSE.txt
similarity index 100%
rename from Drivers/CMSIS/LICENSE.txt
rename to MCU/CMSIS/LICENSE.txt
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h b/MCU/STM32L4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_adc_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_can.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_can.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_can.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_can.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_cortex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_cortex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_cortex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_cortex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_crc_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_def.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_def.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_def.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_def.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_dma_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_exti.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_exti.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_exti.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_exti.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ramfunc.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ramfunc.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ramfunc.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_flash_ramfunc.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_gpio_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_pwr_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim_ex.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim_ex.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim_ex.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_tim_ex.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h b/MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h
rename to MCU/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h
diff --git a/Drivers/STM32L4xx_HAL_Driver/LICENSE.txt b/MCU/STM32L4xx_HAL_Driver/LICENSE.txt
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/LICENSE.txt
rename to MCU/STM32L4xx_HAL_Driver/LICENSE.txt
diff --git a/Drivers/STM32L4xx_HAL_Driver/License.md b/MCU/STM32L4xx_HAL_Driver/License.md
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/License.md
rename to MCU/STM32L4xx_HAL_Driver/License.md
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_can.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_can.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_can.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_can.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c
diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c b/MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c
similarity index 100%
rename from Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c
rename to MCU/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c
diff --git a/Core/Inc/stm32l4xx_hal_conf.h b/MCU/stm32l4xx_hal_conf.h
similarity index 100%
copy from Core/Inc/stm32l4xx_hal_conf.h
copy to MCU/stm32l4xx_hal_conf.h
diff --git a/Core/Src/stm32l4xx_hal_msp.c b/MCU/stm32l4xx_hal_msp.c
similarity index 100%
rename from Core/Src/stm32l4xx_hal_msp.c
rename to MCU/stm32l4xx_hal_msp.c
diff --git a/Core/Src/stm32l4xx_it.c b/MCU/stm32l4xx_it.c
similarity index 93%
rename from Core/Src/stm32l4xx_it.c
rename to MCU/stm32l4xx_it.c
index 76594d9..6042337 100644
--- a/Core/Src/stm32l4xx_it.c
+++ b/MCU/stm32l4xx_it.c
@@ -22,6 +22,7 @@
 #include "stm32l4xx_it.h"
 /* Private includes ----------------------------------------------------------*/
 /* USER CODE BEGIN Includes */
+#include "os_clock.h"
 /* USER CODE END Includes */
 
 /* Private typedef -----------------------------------------------------------*/
@@ -56,8 +57,6 @@
 
 /* External variables --------------------------------------------------------*/
 extern DMA_HandleTypeDef hdma_adc1;
-extern TIM_HandleTypeDef htim6;
-
 /* USER CODE BEGIN EV */
 
 /* USER CODE END EV */
@@ -185,9 +184,9 @@
 void SysTick_Handler(void)
 {
   /* USER CODE BEGIN SysTick_IRQn 0 */
-
+  os_SetTickFlag();
   /* USER CODE END SysTick_IRQn 0 */
-
+  HAL_IncTick();
   /* USER CODE BEGIN SysTick_IRQn 1 */
 
   /* USER CODE END SysTick_IRQn 1 */
@@ -212,20 +211,6 @@
   /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
 
   /* USER CODE END DMA1_Channel1_IRQn 1 */
-}
-
-/**
-  * @brief This function handles TIM6 global interrupt, DAC channel1 and channel2 underrun error interrupts.
-  */
-void TIM6_DAC_IRQHandler(void)
-{
-  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */
-
-  /* USER CODE END TIM6_DAC_IRQn 0 */
-  HAL_TIM_IRQHandler(&htim6);
-  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
-
-  /* USER CODE END TIM6_DAC_IRQn 1 */
 }
 
 /* USER CODE BEGIN 1 */
diff --git a/Core/Inc/stm32l4xx_it.h b/MCU/stm32l4xx_it.h
similarity index 97%
copy from Core/Inc/stm32l4xx_it.h
copy to MCU/stm32l4xx_it.h
index 83f5517..cbfc055 100644
--- a/Core/Inc/stm32l4xx_it.h
+++ b/MCU/stm32l4xx_it.h
@@ -56,7 +56,6 @@
 void PendSV_Handler(void);
 void SysTick_Handler(void);
 void DMA1_Channel1_IRQHandler(void);
-void TIM6_DAC_IRQHandler(void);
 /* USER CODE BEGIN EFP */
 
 /* USER CODE END EFP */
diff --git a/Core/Src/system_stm32l4xx.c b/MCU/system_stm32l4xx.c
similarity index 100%
rename from Core/Src/system_stm32l4xx.c
rename to MCU/system_stm32l4xx.c
diff --git a/Makefile b/Makefile
index 8af1291..0d469b8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 ##########################################################################################################################
-# File automatically-generated by tool: [projectgenerator] version: [3.15.2] date: [Tue Nov 01 16:45:18 CST 2022] 
+# File automatically-generated by tool: [projectgenerator] version: [3.15.2] date: [Wed Nov 30 15:04:45 CST 2022] 
 ##########################################################################################################################
 
 # ------------------------------------------------
@@ -37,8 +37,10 @@
 # C sources
 C_SOURCES =  \
 APP/main.c \
-CAHB_Hal/src/os_clock.c\
-CAHB_Hal/src/os_task.c\
+CAHB_Hal/src/os_clock.c \
+CAHB_Hal/src/os_task.c \
+CAHB_Hal/src/Hal_gpio.c \
+CAHB_Hal/src/Hal_adc.c \
 Core/Src/clock.c \
 Core/Src/gpio.c \
 Core/Src/adc.c \
@@ -48,7 +50,6 @@
 Core/Src/tim.c \
 Core/Src/stm32l4xx_it.c \
 Core/Src/stm32l4xx_hal_msp.c \
-Core/Src/stm32l4xx_hal_timebase_tim.c \
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c \
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c \
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c \
@@ -72,7 +73,7 @@
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c \
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c \
 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc.c \
-Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c
+Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_crc_ex.c \
 
 # ASM sources
 ASM_SOURCES =  \
@@ -129,7 +130,7 @@
 
 # C includes
 C_INCLUDES =  \
--ICAHB_Hal/inc\
+-ICAHB_Hal/inc \
 -ICore/Inc \
 -IDrivers/STM32L4xx_HAL_Driver/Inc \
 -IDrivers/STM32L4xx_HAL_Driver/Inc/Legacy \

--
Gitblit v1.8.0