diff --git a/README.md b/README.md
index af55d0be6c03f78e411ebfe93a299b4382ba9325..0b156b378ab9d52ef8ef360bd0456e93e513343f 100644
--- a/README.md
+++ b/README.md
@@ -31,11 +31,21 @@
| | **src/common文件夹内容↓↓↓** |
| all_include | 所有组件头文件集合 |
| common_include | 公共引用文件(所有组件都需包含此文件) |
+| | **src/devices/communication文件夹内容↓↓↓** |
+| esp8266 | ESP8266模组AT指令集 |
+| hongjia_ble | 宏佳电子HJ-131蓝牙模组指令集 |
+| sim900a | SIM900A模组AT指令集 |
+| | **src/devices/display文件夹内容↓↓↓** |
+| oled_096 | 0.96英寸OLED屏幕驱动 |
+| | **src/devices/sensor文件夹内容↓↓↓** |
+| by9301 | BY9301语音播报模块驱动 |
+| dht11 | DHT11温湿度模块驱动 |
| | **src/modbus文件夹内容↓↓↓** |
| modbus_common | modbus通用文件(modbus主从机都需包含此文件) |
| modbus_host | modbus主机程序(RTU ASCII) |
| modbus_slave | modbus从机程序(RTU ASCII) |
| | **src/modules文件夹内容↓↓↓** |
+| command_at | AT指令交互 |
| command_line | 命令行交互 |
| data_check | 数据校验方法集合 |
| data_convert | 数据转换方法集合 |
diff --git a/documents/doxygen/Doxyfile b/documents/doxygen/Doxyfile
index 8d3a2cc18368fcb458942c7b4a0126e19f1daf2a..e0442bed0ab0426186c5c2b70173feb08f45a74d 100644
--- a/documents/doxygen/Doxyfile
+++ b/documents/doxygen/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = mcu_reuse_development_module
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 2.2
+PROJECT_NUMBER = 2.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -1570,7 +1570,7 @@ GENERATE_HTMLHELP = YES
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-CHM_FILE = mcu_reuse_development_module_V2.2.chm
+CHM_FILE = mcu_reuse_development_module_V2.3.chm
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
diff --git a/documents/mcu_reuse_development_module_V2.2.chm b/documents/mcu_reuse_development_module_V2.2.chm
deleted file mode 100644
index c6a8252b3257f6395cdcc8bee97e9807606285dc..0000000000000000000000000000000000000000
Binary files a/documents/mcu_reuse_development_module_V2.2.chm and /dev/null differ
diff --git a/documents/mcu_reuse_development_module_V2.3.chm b/documents/mcu_reuse_development_module_V2.3.chm
new file mode 100644
index 0000000000000000000000000000000000000000..a535ee0eb858f558c63e6644a46a187b9ac8adea
Binary files /dev/null and b/documents/mcu_reuse_development_module_V2.3.chm differ
diff --git a/examples/command_at/MDK/use_example.uvoptx b/examples/command_at/MDK/use_example.uvoptx
new file mode 100644
index 0000000000000000000000000000000000000000..e9255727324a08e80c7370030fb78c6d120348f6
--- /dev/null
+++ b/examples/command_at/MDK/use_example.uvoptx
@@ -0,0 +1,676 @@
+
+
+
+ 1.0
+
+ ### uVision Project, (C) Keil Software
+
+
+ *.c
+ *.s*; *.src; *.a*
+ *.obj; *.o
+ *.lib
+ *.txt; *.h; *.inc; *.md
+ *.plm
+ *.cpp; *.cc; *.cxx
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ Target 1
+ 0x4
+ ARM-ADS
+
+ 12000000
+
+ 1
+ 1
+ 0
+ 1
+ 0
+
+
+ 1
+ 65535
+ 0
+ 0
+ 0
+
+
+ 79
+ 66
+ 8
+ .\Listings\
+
+
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+
+
+ 1
+ 0
+ 1
+
+ 18
+
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+ 4
+
+
+
+
+
+
+
+
+
+
+ Segger\JL2CM3.dll
+
+
+
+ 0
+ JL2CM3
+ -U59522627 -O78 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(1BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO15 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128.FLM -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM)
+
+
+ 0
+ UL2CM3
+ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128 -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM))
+
+
+
+
+ 0
+
+
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 0
+ 2
+ 10000000
+
+
+
+
+
+ cmsis
+ 0
+ 0
+ 0
+ 0
+
+ 1
+ 1
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\core_cm3.c
+ core_cm3.c
+ 0
+ 0
+
+
+ 1
+ 2
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\stm32f10x_it.c
+ stm32f10x_it.c
+ 0
+ 0
+
+
+ 1
+ 3
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\system_stm32f10x.c
+ system_stm32f10x.c
+ 0
+ 0
+
+
+ 1
+ 4
+ 2
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\startup\startup_stm32f10x_md.s
+ startup_stm32f10x_md.s
+ 0
+ 0
+
+
+
+
+ libs
+ 0
+ 0
+ 0
+ 0
+
+ 2
+ 5
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\misc.c
+ misc.c
+ 0
+ 0
+
+
+ 2
+ 6
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_adc.c
+ stm32f10x_adc.c
+ 0
+ 0
+
+
+ 2
+ 7
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_bkp.c
+ stm32f10x_bkp.c
+ 0
+ 0
+
+
+ 2
+ 8
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_can.c
+ stm32f10x_can.c
+ 0
+ 0
+
+
+ 2
+ 9
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_cec.c
+ stm32f10x_cec.c
+ 0
+ 0
+
+
+ 2
+ 10
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_crc.c
+ stm32f10x_crc.c
+ 0
+ 0
+
+
+ 2
+ 11
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dac.c
+ stm32f10x_dac.c
+ 0
+ 0
+
+
+ 2
+ 12
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dbgmcu.c
+ stm32f10x_dbgmcu.c
+ 0
+ 0
+
+
+ 2
+ 13
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dma.c
+ stm32f10x_dma.c
+ 0
+ 0
+
+
+ 2
+ 14
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_exti.c
+ stm32f10x_exti.c
+ 0
+ 0
+
+
+ 2
+ 15
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_flash.c
+ stm32f10x_flash.c
+ 0
+ 0
+
+
+ 2
+ 16
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_fsmc.c
+ stm32f10x_fsmc.c
+ 0
+ 0
+
+
+ 2
+ 17
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_gpio.c
+ stm32f10x_gpio.c
+ 0
+ 0
+
+
+ 2
+ 18
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_i2c.c
+ stm32f10x_i2c.c
+ 0
+ 0
+
+
+ 2
+ 19
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_iwdg.c
+ stm32f10x_iwdg.c
+ 0
+ 0
+
+
+ 2
+ 20
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_pwr.c
+ stm32f10x_pwr.c
+ 0
+ 0
+
+
+ 2
+ 21
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_rcc.c
+ stm32f10x_rcc.c
+ 0
+ 0
+
+
+ 2
+ 22
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_rtc.c
+ stm32f10x_rtc.c
+ 0
+ 0
+
+
+ 2
+ 23
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_sdio.c
+ stm32f10x_sdio.c
+ 0
+ 0
+
+
+ 2
+ 24
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_spi.c
+ stm32f10x_spi.c
+ 0
+ 0
+
+
+ 2
+ 25
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_tim.c
+ stm32f10x_tim.c
+ 0
+ 0
+
+
+ 2
+ 26
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_usart.c
+ stm32f10x_usart.c
+ 0
+ 0
+
+
+ 2
+ 27
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_wwdg.c
+ stm32f10x_wwdg.c
+ 0
+ 0
+
+
+
+
+ segger
+ 1
+ 0
+ 0
+ 0
+
+ 3
+ 28
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\segger_rtt\SEGGER_RTT.c
+ SEGGER_RTT.c
+ 0
+ 0
+
+
+ 3
+ 29
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\segger_rtt\SEGGER_RTT_printf.c
+ SEGGER_RTT_printf.c
+ 0
+ 0
+
+
+
+
+ system
+ 1
+ 0
+ 0
+ 0
+
+ 4
+ 30
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_sys\tim.c
+ tim.c
+ 0
+ 0
+
+
+ 4
+ 31
+ 1
+ 0
+ 0
+ 0
+ ..\..\[base_on_stm32f1]\stm32f1_sys\usart.c
+ usart.c
+ 0
+ 0
+
+
+
+
+ source
+ 1
+ 0
+ 0
+ 0
+
+ 5
+ 32
+ 1
+ 0
+ 0
+ 0
+ ..\SRC\main.c
+ main.c
+ 0
+ 0
+
+
+ 5
+ 33
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\common\common_include.c
+ common_include.c
+ 0
+ 0
+
+
+ 5
+ 34
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\modules\uart_handler.c
+ uart_handler.c
+ 0
+ 0
+
+
+ 5
+ 35
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\modules\ring_buffer.c
+ ring_buffer.c
+ 0
+ 0
+
+
+ 5
+ 36
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\modules\command_at.c
+ command_at.c
+ 0
+ 0
+
+
+
+
+ readme
+ 1
+ 0
+ 0
+ 0
+
+ 6
+ 37
+ 5
+ 0
+ 0
+ 0
+ ..\README.txt
+ README.txt
+ 0
+ 0
+
+
+
+
diff --git a/examples/command_at/MDK/use_example.uvprojx b/examples/command_at/MDK/use_example.uvprojx
new file mode 100644
index 0000000000000000000000000000000000000000..6553c4a37dc49e62e2401f650b6237af8073209b
--- /dev/null
+++ b/examples/command_at/MDK/use_example.uvprojx
@@ -0,0 +1,617 @@
+
+
+
+ 2.1
+
+ ### uVision Project, (C) Keil Software
+
+
+
+ Target 1
+ 0x4
+ ARM-ADS
+ 5060960::V5.06 update 7 (build 960)::.\ARMCC
+ 0
+
+
+ STM32F103C8
+ STMicroelectronics
+ Keil.STM32F1xx_DFP.2.4.0
+ http://www.keil.com/pack/
+ IRAM(0x20000000,0x00005000) IROM(0x08000000,0x00010000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE
+
+
+ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128 -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM))
+ 0
+ $$Device:STM32F103C8$Device\Include\stm32f10x.h
+
+
+
+
+
+
+
+
+
+ $$Device:STM32F103C8$SVD\STM32F103xx.svd
+ 0
+ 0
+
+
+
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 1
+
+ .\Objects\
+ use_example
+ 1
+ 0
+ 1
+ 1
+ 1
+ .\Listings\
+ 1
+ 0
+ 0
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 3
+
+
+ 1
+
+
+ SARMCM3.DLL
+ -REMAP
+ DCM.DLL
+ -pCM3
+ SARMCM3.DLL
+
+ TCM.DLL
+ -pCM3
+
+
+
+ 1
+ 0
+ 0
+ 0
+ 16
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+ 1
+ -1
+
+ 1
+ BIN\UL2CM3.DLL
+
+
+
+
+
+ 0
+
+
+
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ "Cortex-M3"
+
+ 0
+ 0
+ 0
+ 1
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 8
+ 1
+ 0
+ 0
+ 0
+ 3
+ 3
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x20000000
+ 0x5000
+
+
+ 1
+ 0x8000000
+ 0x10000
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x8000000
+ 0x10000
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x20000000
+ 0x5000
+
+
+ 0
+ 0x0
+ 0x0
+
+
+
+
+
+ 1
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 2
+ 0
+ 0
+ 1
+ 0
+ 0
+ 3
+ 3
+ 1
+ 1
+ 0
+ 0
+ 0
+
+
+ STM32F10X_MD,USE_STDPERIPH_DRIVER
+
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\inc;..\..\[base_on_stm32f1]\stm32f1_lib\cmsis;..\..\[base_on_stm32f1]\stm32f1_sys;..\..\..\src\common;..\..\..\src\modules;..\..\..\src\segger_rtt
+
+
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0x08000000
+ 0x20000000
+
+
+
+
+
+
+
+
+
+
+
+
+ cmsis
+
+
+ core_cm3.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\core_cm3.c
+
+
+ stm32f10x_it.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\stm32f10x_it.c
+
+
+ system_stm32f10x.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\system_stm32f10x.c
+
+
+ startup_stm32f10x_md.s
+ 2
+ ..\..\[base_on_stm32f1]\stm32f1_lib\cmsis\startup\startup_stm32f10x_md.s
+
+
+
+
+ libs
+
+
+ misc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\misc.c
+
+
+ stm32f10x_adc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_adc.c
+
+
+ stm32f10x_bkp.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_bkp.c
+
+
+ stm32f10x_can.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_can.c
+
+
+ stm32f10x_cec.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_cec.c
+
+
+ stm32f10x_crc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_crc.c
+
+
+ stm32f10x_dac.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dac.c
+
+
+ stm32f10x_dbgmcu.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dbgmcu.c
+
+
+ stm32f10x_dma.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_dma.c
+
+
+ stm32f10x_exti.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_exti.c
+
+
+ stm32f10x_flash.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_flash.c
+
+
+ stm32f10x_fsmc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_fsmc.c
+
+
+ stm32f10x_gpio.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_gpio.c
+
+
+ stm32f10x_i2c.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_i2c.c
+
+
+ stm32f10x_iwdg.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_iwdg.c
+
+
+ stm32f10x_pwr.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_pwr.c
+
+
+ stm32f10x_rcc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_rcc.c
+
+
+ stm32f10x_rtc.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_rtc.c
+
+
+ stm32f10x_sdio.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_sdio.c
+
+
+ stm32f10x_spi.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_spi.c
+
+
+ stm32f10x_tim.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_tim.c
+
+
+ stm32f10x_usart.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_usart.c
+
+
+ stm32f10x_wwdg.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\src\stm32f10x_wwdg.c
+
+
+
+
+ segger
+
+
+ SEGGER_RTT.c
+ 1
+ ..\..\..\src\segger_rtt\SEGGER_RTT.c
+
+
+ SEGGER_RTT_printf.c
+ 1
+ ..\..\..\src\segger_rtt\SEGGER_RTT_printf.c
+
+
+
+
+ system
+
+
+ tim.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_sys\tim.c
+
+
+ usart.c
+ 1
+ ..\..\[base_on_stm32f1]\stm32f1_sys\usart.c
+
+
+
+
+ source
+
+
+ main.c
+ 1
+ ..\SRC\main.c
+
+
+ common_include.c
+ 1
+ ..\..\..\src\common\common_include.c
+
+
+ uart_handler.c
+ 1
+ ..\..\..\src\modules\uart_handler.c
+
+
+ ring_buffer.c
+ 1
+ ..\..\..\src\modules\ring_buffer.c
+
+
+ command_at.c
+ 1
+ ..\..\..\src\modules\command_at.c
+
+
+
+
+ readme
+
+
+ README.txt
+ 5
+ ..\README.txt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ use_example
+ 1
+
+
+
+
+
diff --git a/examples/command_at/README.txt b/examples/command_at/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..648e9e77d2de92d75b04e8bf0c42832a972eacbc
--- /dev/null
+++ b/examples/command_at/README.txt
@@ -0,0 +1,47 @@
+================================================================================
+ 用例使用说明
+================================================================================
+Date Author MDK MCU
+2024-03-08 ashuai0110 5.35 STM32F103
+
+================================================================================
+功能描述
+================================================================================
+本用例展示了AT指令交互组件的使用方法。
+
+================================================================================
+测试环境
+================================================================================
+测试用板:
+---------------------
+任意开发板
+
+辅助工具:
+---------------------
+J-Link
+串口工具
+
+辅助软件:
+---------------------
+J-Link RTT Viewer
+串口调试软件
+
+源码文件:
+---------------------
+command_at.c
+command_at.h
+
+================================================================================
+使用步骤
+================================================================================
+1)使用J-Link连接目标板;
+2)打开工程,重新编译,启动调试或直接下载程序运行;
+3)打开串口调试软件,连接J-Link RTT Viewer软件;
+4)重启开发板查看串口发送内容,并回复AT+OK\r\n或者不回复查看RTT打印消息。
+
+================================================================================
+注意
+================================================================================
+1)用户根据需求可前往源码头文件修改宏定义参数
+
+================================================================================
diff --git a/examples/command_at/SRC/main.c b/examples/command_at/SRC/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..3e2fc99058fd70398f791ef909a7f93fc78b597a
--- /dev/null
+++ b/examples/command_at/SRC/main.c
@@ -0,0 +1,274 @@
+/**
+ ******************************************************************************
+ * @file main.c
+ * @author ashuai0110
+ * @version V1.0
+ * @date 2024-03-08
+ * @brief 使用举例-AT指令交互
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "stm32f10x.h"
+#include "tim.h"
+#include "usart.h"
+
+#include "uart_handler.h"
+#include "command_at.h"
+
+/* 私有宏定义-----------------------------------------------------------------*/
+#define _USE_CMD_AT_WAY (1u) /* AT指令交互处理方式选择 0:搜索帧头帧尾的方式 1:外部接收标志的方式 */
+
+#define USART1_UART_HR_CH (0u) /* 串口管理序号 */
+
+#define CMD_AT_HEAD "AT+" /* 帧头 */
+#define CMD_AT_TAIL "\r\n" /* 帧尾 */
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+static uint8_t txBuf[128]; /* 串口管理所需发送缓冲区 */
+static uint8_t rxBuf[128]; /* 串口管理所需接收缓冲区 */
+
+static cmd_at_t CmdAT; /* AT指令交互管理实例 */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+
+/**
+ * @brief 定时器中断函数
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void TIM1_UP_IRQHandler(void)
+{
+ if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
+ {
+ /* 组件计时节拍接口 */
+ module_tick_inc(1);
+
+ TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);
+ }
+}
+
+/**
+ * @brief 串口中断函数
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void USART1_IRQHandler(void)
+{
+ static uint8_t rxData, txData, ret;
+
+ if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
+ {
+ rxData = USART_ReceiveData(USART1);
+ /* 写入接收缓存 */
+ ret = uart_hr_write_rx_buf(USART1_UART_HR_CH, &rxData, 1);
+ if(0 == ret)
+ {
+ WARN_LOG("uart_hr_write_rx_buf failure");
+ }
+
+ USART_ClearITPendingBit(USART1, USART_IT_RXNE);
+ }
+
+ if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
+ {
+ /* 读出发送缓存 */
+ ret = uart_hr_read_tx_buf(USART1_UART_HR_CH, &txData, 1);
+ if(1 == ret)
+ {
+ USART_SendData(USART1, txData);
+ }
+
+ USART_ClearITPendingBit(USART1, USART_IT_TXE);
+ }
+}
+
+/**
+ * @brief 串口发送中断开关函数
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void uart_tx_en(uint8_t enState)
+{
+ if(enState)
+ {
+ /* 使能发送中断 */
+ USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
+ }
+ else
+ {
+ /* 关闭发送中断 */
+ USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
+ }
+}
+
+/**
+ * @brief AT指令交互用户写数据接口
+ *
+ * @param data : 数据缓冲区
+ *
+ * @param len : 写入的数据长度
+ *
+ * @retval 实际写入的长度
+ */
+uint32_t cmd_at_write_user(void *data, uint32_t len)
+{
+ return uart_hr_write_tx_buf(USART1_UART_HR_CH, data, len);
+}
+
+/**
+ * @brief AT指令交互用户读数据接口
+ *
+ * @param buf : 数据缓存区
+ *
+ * @param len : 读出的数据长度
+ *
+ * @retval 实际读出的长度
+ */
+uint32_t cmd_at_read_user(void *buf, uint32_t len)
+{
+ return uart_hr_read_rx_buf(USART1_UART_HR_CH, buf, len);
+}
+
+/**
+ * @brief main
+ */
+int main(int argc, char *argv[])
+{
+ static uint8_t ret, state;
+
+ VERSION_LOG("example-command_at", 1, 0, 0);
+
+ /* 定时器初始化 1ms */
+ tim1_init_config(100-1, 720-1);
+ /* 串口初始化 115200 */
+ usart1_init_config(115200);
+
+ /* 串口管理初始化 帧间隔100ms 接收超时时间2000ms */
+ uart_hr_init(USART1_UART_HR_CH, txBuf, sizeof(txBuf), rxBuf, sizeof(rxBuf), uart_tx_en, 100, 2000);
+ /* AT指令交互初始化 回复超时时间1000ms 超时重发次数2次 */
+ cmd_at_init(&CmdAT, CMD_AT_HEAD, CMD_AT_TAIL, cmd_at_read_user, cmd_at_write_user, 1000, 2);
+
+#if (!_USE_CMD_AT_WAY)
+ /* AT指令交互(阻塞式) */
+ ret = cmd_at_process_block(&CmdAT, CMD_AT_RESERVE, CMD_AT_WAY_SEARCH, "AT+OK\r\n", "AT+NAME=%s\r\n", "ashuai0110");
+ if(ret != RET_OK)
+ {
+ ERROR_LOG("cmd_at_process_block return %s! rsp data:%s", ret == RET_ERR ? "error" : "timeout", cmd_at_rsp_data(&CmdAT));
+ }
+#endif
+
+ state = 1; /* 开启轮询式处理 */
+
+ while(1)
+ {
+ /* 串口管理轮询处理 */
+ ret = uart_hr_poll(USART1_UART_HR_CH);
+
+#if (_USE_CMD_AT_WAY)
+ /* 接收完成 */
+ if(RET_OK == ret)
+ {
+ cmd_at_set_rec_flag(&CmdAT); /* 设置外部接收标志 */
+ DEBUG_LOG("uart rec complate");
+ } /* 接收超时 无需求可忽略此返回值 */
+ else if(RET_TIMEOUT == ret)
+ {
+ WARN_LOG("uart rec timeout");
+ }
+ /* AT指令交互(轮询式) */
+ switch(state)
+ {
+ case 1: /* 设置名称 */
+ ret = cmd_at_process_poll(&CmdAT, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, "AT+OK\r\n", "AT+NAME=%s\r\n", "ashuai0110");
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ /* 超时或错误直接结束 */
+ state = 0;
+ ERROR_LOG("cmd_at_process_poll return %s! rsp data:%s", ret == RET_ERR ? "error" : "timeout", cmd_at_rsp_data(&CmdAT));
+ }
+ else if(RET_OK == ret)
+ {
+ /* 成功则进入下一状态 */
+ state = 2;
+ }
+ break;
+ case 2: /* 设置时间 */
+ ret = cmd_at_process_poll(&CmdAT, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, "AT+OK\r\n", "AT+TIME=%d\r\n", 1000);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ /* 超时或错误直接结束 */
+ state = 0;
+ ERROR_LOG("cmd_at_process_poll return %s! rsp data:%s", ret == RET_ERR ? "error" : "timeout", cmd_at_rsp_data(&CmdAT));
+ }
+ else if(RET_OK == ret)
+ {
+ /* 成功则结束 */
+ state = 0;
+ }
+ break;
+ }
+#else
+ /* 接收完成 */
+ if(RET_OK == ret)
+ {
+ DEBUG_LOG("uart rec complate");
+ } /* 接收超时 无需求可忽略此返回值 */
+ else if(RET_TIMEOUT == ret)
+ {
+ WARN_LOG("uart rec timeout");
+ }
+ /* AT指令交互(轮询式) */
+ switch(state)
+ {
+ case 1: /* 设置名称 */
+ ret = cmd_at_process_poll(&CmdAT, CMD_AT_RESERVE, CMD_AT_WAY_SEARCH, "AT+OK\r\n", "AT+NAME=%s\r\n", "ashuai0110");
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ /* 超时或错误直接结束 */
+ state = 0;
+ ERROR_LOG("cmd_at_process_poll return %s! rsp data:%s", ret == RET_ERR ? "error" : "timeout", cmd_at_rsp_data(&CmdAT));
+ }
+ else if(RET_OK == ret)
+ {
+ /* 成功则进入下一状态 */
+ state = 2;
+ }
+ break;
+ case 2: /* 设置时间 */
+ ret = cmd_at_process_poll(&CmdAT, CMD_AT_RESERVE, CMD_AT_WAY_SEARCH, "AT+OK\r\n", "AT+TIME=%d\r\n", 1000);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ /* 超时或错误直接结束 */
+ state = 0;
+ ERROR_LOG("cmd_at_process_poll return %s! rsp data:%s", ret == RET_ERR ? "error" : "timeout", cmd_at_rsp_data(&CmdAT));
+ }
+ else if(RET_OK == ret)
+ {
+ /* 成功则结束 */
+ state = 0;
+ }
+ break;
+ }
+#endif
+
+ }
+}
+
diff --git a/examples/project_template/MDK/use_example.uvoptx b/examples/project_template/MDK/use_example.uvoptx
index 07a9259de79f8e4c56febfb3ecb56df55e98ee2d..afd34386787edb0f6c8ed74d8732c759f540e443 100644
--- a/examples/project_template/MDK/use_example.uvoptx
+++ b/examples/project_template/MDK/use_example.uvoptx
@@ -895,6 +895,134 @@
0
0
+
+ 10
+ 54
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\modules\command_at.c
+ command_at.c
+ 0
+ 0
+
+
+
+
+ devices/communication
+ 1
+ 0
+ 0
+ 0
+
+ 11
+ 55
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\communication\esp8266.c
+ esp8266.c
+ 0
+ 0
+
+
+ 11
+ 56
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\communication\hongjia_ble.c
+ hongjia_ble.c
+ 0
+ 0
+
+
+ 11
+ 57
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\communication\sim900a.c
+ sim900a.c
+ 0
+ 0
+
+
+
+
+ devices/display
+ 1
+ 0
+ 0
+ 0
+
+ 12
+ 58
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\display\oled_096.c
+ oled_096.c
+ 0
+ 0
+
+
+
+
+ devices/sensor
+ 1
+ 0
+ 0
+ 0
+
+ 13
+ 59
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\sensor\by9301.c
+ by9301.c
+ 0
+ 0
+
+
+ 13
+ 60
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\devices\sensor\dht11.c
+ dht11.c
+ 0
+ 0
+
+
+
+
+ other
+ 0
+ 0
+ 0
+ 0
+
+ 14
+ 61
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\src\other\cJSON.c
+ cJSON.c
+ 0
+ 0
+
diff --git a/examples/project_template/MDK/use_example.uvprojx b/examples/project_template/MDK/use_example.uvprojx
index cd2711665fe5e4ec9802af97874de3e4ca59c2cd..8505f8bc439a5f48751764af9568f6fe47e93066 100644
--- a/examples/project_template/MDK/use_example.uvprojx
+++ b/examples/project_template/MDK/use_example.uvprojx
@@ -339,7 +339,7 @@
STM32F10X_MD,USE_STDPERIPH_DRIVER
- ..\..\[base_on_stm32f1]\stm32f1_lib\driver\inc;..\..\[base_on_stm32f1]\stm32f1_lib\cmsis;..\..\[base_on_stm32f1]\stm32f1_sys;..\..\..\src\common;..\..\..\src\modules;..\..\..\src\segger_rtt;..\..\..\src\modbus;..\..\..\src\bootloader
+ ..\..\[base_on_stm32f1]\stm32f1_lib\driver\inc;..\..\[base_on_stm32f1]\stm32f1_lib\cmsis;..\..\[base_on_stm32f1]\stm32f1_sys;..\..\..\src\common;..\..\..\src\modules;..\..\..\src\segger_rtt;..\..\..\src\modbus;..\..\..\src\bootloader;..\..\..\src\devices\communication;..\..\..\src\devices\display;..\..\..\src\devices\sensor;..\..\..\src\other
@@ -693,6 +693,66 @@
1
..\..\..\src\modules\uart_handler.c
+
+ command_at.c
+ 1
+ ..\..\..\src\modules\command_at.c
+
+
+
+
+ devices/communication
+
+
+ esp8266.c
+ 1
+ ..\..\..\src\devices\communication\esp8266.c
+
+
+ hongjia_ble.c
+ 1
+ ..\..\..\src\devices\communication\hongjia_ble.c
+
+
+ sim900a.c
+ 1
+ ..\..\..\src\devices\communication\sim900a.c
+
+
+
+
+ devices/display
+
+
+ oled_096.c
+ 1
+ ..\..\..\src\devices\display\oled_096.c
+
+
+
+
+ devices/sensor
+
+
+ by9301.c
+ 1
+ ..\..\..\src\devices\sensor\by9301.c
+
+
+ dht11.c
+ 1
+ ..\..\..\src\devices\sensor\dht11.c
+
+
+
+
+ other
+
+
+ cJSON.c
+ 1
+ ..\..\..\src\other\cJSON.c
+
diff --git a/examples/uart_handler/MDK/use_example.uvprojx b/examples/uart_handler/MDK/use_example.uvprojx
index 48ab2c0ee7a1324b158e16eff544f5eb9159697f..f4cff6a4a1d87bfaebf13a248a47749e89355b3e 100644
--- a/examples/uart_handler/MDK/use_example.uvprojx
+++ b/examples/uart_handler/MDK/use_example.uvprojx
@@ -16,8 +16,8 @@
STM32F103C8
STMicroelectronics
- Keil.STM32F1xx_DFP.2.4.1
- https://www.keil.com/pack/
+ Keil.STM32F1xx_DFP.2.4.0
+ http://www.keil.com/pack/
IRAM(0x20000000,0x00005000) IROM(0x08000000,0x00010000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE
diff --git a/examples/uart_handler/README.txt b/examples/uart_handler/README.txt
index e33e5c214ae592b99a35d61c12076d26c075dac0..46a59e5f84e4f04ab19e7200ad27d1daea3352fc 100644
--- a/examples/uart_handler/README.txt
+++ b/examples/uart_handler/README.txt
@@ -2,7 +2,7 @@
用例使用说明
================================================================================
Date Author MDK MCU
-2024-01-28 ashuai0110 5.35 STM32F103
+2024-03-08 ashuai0110 5.35 STM32F103
================================================================================
功能描述
@@ -36,7 +36,7 @@ uart_handler.h
================================================================================
1)使用J-Link连接目标板;
2)打开工程,重新编译,启动调试或直接下载程序运行;
-3) 打开串口调试软件,重启开发板查看接收内容,再发送任意数据
+3)打开串口调试软件,重启开发板查看接收内容,再发送任意数据;
4)用J-Link RTT Viewer软件连接,查看打印消息。
================================================================================
diff --git a/examples/uart_handler/SRC/main.c b/examples/uart_handler/SRC/main.c
index ce6fee7495afce582107e9903da5764e9b34179e..55e6ea0ce1717720d0e8cd6d33b5b7f699a8deb5 100644
--- a/examples/uart_handler/SRC/main.c
+++ b/examples/uart_handler/SRC/main.c
@@ -3,7 +3,7 @@
* @file main.c
* @author ashuai0110
* @version V1.0
- * @date 2024-01-28
+ * @date 2024-03-08
* @brief 使用举例-串口管理
*
******************************************************************************
@@ -123,8 +123,8 @@ int main(int argc, char *argv[])
/* 串口初始化 115200 */
usart1_init_config(115200);
- /* 串口管理初始化 波特率115200bps 接收超时时间2000ms */
- uart_hr_init(USART1_UART_HR_CH, txBuf, sizeof(txBuf), rxBuf, sizeof(rxBuf), uart_tx_en, 115200, 2000);
+ /* 串口管理初始化 帧间隔500ms 接收超时时间2000ms */
+ uart_hr_init(USART1_UART_HR_CH, txBuf, sizeof(txBuf), rxBuf, sizeof(rxBuf), uart_tx_en, 500, 2000);
while(1)
{
diff --git a/examples/xmodem/README.txt b/examples/xmodem/README.txt
index 2b29fc0d1533bc4249cc3b04cbe176b5a73474a4..67867b06f0354d5bc401f325c38589fb67a47d04 100644
--- a/examples/xmodem/README.txt
+++ b/examples/xmodem/README.txt
@@ -2,7 +2,7 @@
用例使用说明
================================================================================
Date Author MDK MCU
-2024-01-28 ashuai0110 5.35 STM32F103
+2024-03-05 ashuai0110 5.35 STM32F103
================================================================================
功能描述
diff --git a/examples/xmodem/SRC/main.c b/examples/xmodem/SRC/main.c
index 70d502aaf64f7142894b6aa95c8ec8490a4c1e31..7840fc4148400a21ffcce5b6724cebd1ea584aa0 100644
--- a/examples/xmodem/SRC/main.c
+++ b/examples/xmodem/SRC/main.c
@@ -3,7 +3,7 @@
* @file main.c
* @author ashuai0110
* @version V1.0
- * @date 2024-01-28
+ * @date 2024-03-05
* @brief 使用举例-xmodem
*
******************************************************************************
@@ -31,7 +31,7 @@
static uint8_t usart1DmaTxBuf[200]; /* 串口1dma发送缓存区 */
static uint8_t usart1DmaRxBuf[200]; /* 串口1dma接收缓存区 */
-xmodem_t xmodem; /* xmodem实例 */
+static xmodem_t xmodem; /* xmodem实例 */
static uint8_t xmodemBuf[1029]; /* xmodem数据缓存区 */
/* 全局变量-------------------------------------------------------------------*/
@@ -200,7 +200,7 @@ int main(int argc, char *argv[])
tim1_init_config(100-1, 720-1);
/* xmodem组件初始化 */
- xmodem_init(&xmodem, xmodemBuf, sizeof(xmodemBuf), usart1_tx_en, xmodem_get_packet_callback, xmodem_set_packet_callback, 1000);
+ xmodem_init(&xmodem, xmodemBuf, sizeof(xmodemBuf), usart1_tx_en, xmodem_get_packet_callback, xmodem_set_packet_callback, 1000, 2);
#if XMODEM_TX_RX_TEST
/* 启动xmodem接收 */
xmodem_rx_start(&xmodem, XMODEM_RX_FLAG_CRC);
diff --git a/examples/ymodem/README.txt b/examples/ymodem/README.txt
index 8261eaa493369cd7aaf4db8df8777a2704456550..8f150f577c03b5428516d49071b57769156e77ef 100644
--- a/examples/ymodem/README.txt
+++ b/examples/ymodem/README.txt
@@ -2,7 +2,7 @@
用例使用说明
================================================================================
Date Author MDK MCU
-2024-01-28 ashuai0110 5.35 STM32F103
+2024-03-04 ashuai0110 5.35 STM32F103
================================================================================
功能描述
diff --git a/examples/ymodem/SRC/main.c b/examples/ymodem/SRC/main.c
index 551c91fd2f90a957c82b957127acad96b51f2e0b..0a78ad84327e18cac3c1a17a8dc80ac07b57eb66 100644
--- a/examples/ymodem/SRC/main.c
+++ b/examples/ymodem/SRC/main.c
@@ -3,7 +3,7 @@
* @file main.c
* @author ashuai0110
* @version V1.0
- * @date 2024-01-28
+ * @date 2024-03-04
* @brief 使用举例-ymodem
*
******************************************************************************
@@ -31,9 +31,12 @@
static uint8_t usart1DmaTxBuf[200]; /* 串口1dma发送缓存区 */
static uint8_t usart1DmaRxBuf[200]; /* 串口1dma接收缓存区 */
-ymodem_t ymodem; /* ymodem实例 */
+static ymodem_t ymodem; /* ymodem实例 */
static uint8_t ymodemBuf[1029]; /* ymodem数据缓存区 */
-file_info_t fileInfo; /* 文件信息结构体 */
+static file_info_t fileInfo; /* 文件信息结构体 */
+
+static uint8_t fileCnt = 0; /* 文件计数 */
+static uint32_t sendCnt = 0; /* 已发送字节 */
/* 全局变量-------------------------------------------------------------------*/
@@ -156,7 +159,7 @@ void ymodem_get_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
uint16_t lenTmp = *len;
/* 文件信息 */
- if(YMODEM_FILE_FLAG(ymodem))
+ if(ymodem_get_file_flag(&ymodem))
{
ymodem_get_file_info(&ymodem, &fileInfo); /* 获取文件信息保存至fileInfo结构体 */
PRINT_LOG("ymodem rec file name:%s, size:%d Byte\r\n", fileInfo.fileName, fileInfo.fileSize);
@@ -185,11 +188,8 @@ void ymodem_get_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
*/
void ymodem_set_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
- static uint8_t fileCnt = 0; /* 文件计数 */
- static uint32_t sendCnt = 0; /* 已发送字节 */
-
/* 文件信息 */
- if(YMODEM_FILE_FLAG(ymodem))
+ if(ymodem_get_file_flag(&ymodem))
{
/* 只发送一个文件 */
if(fileCnt < 1)
@@ -243,7 +243,7 @@ int main(int argc, char *argv[])
tim1_init_config(100-1, 720-1);
/* ymodem组件初始化 */
- ymodem_init(&ymodem, ymodemBuf, sizeof(ymodemBuf), usart1_tx_en, ymodem_get_packet_callback, ymodem_set_packet_callback, 1000);
+ ymodem_init(&ymodem, ymodemBuf, sizeof(ymodemBuf), usart1_tx_en, ymodem_get_packet_callback, ymodem_set_packet_callback, 1000, 2);
#if YMODEM_TX_RX_TEST
/* 启动ymodem接收 */
ymodem_rx_start(&ymodem, YMODEM_RX_FLAG_CRC);
@@ -270,14 +270,20 @@ int main(int argc, char *argv[])
ret = ymodem_tx_poll(&ymodem); /* ymodem发送轮询处理 */
if(RET_OK == ret)
{
+ fileCnt = 0;
+ sendCnt = 0;
DEBUG_LOG("ymodem tx success");
}
else if(RET_ERR == ret)
{
+ fileCnt = 0;
+ sendCnt = 0;
DEBUG_LOG("ymodem tx failed");
}
else if(RET_TIMEOUT == ret)
{
+ fileCnt = 0;
+ sendCnt = 0;
DEBUG_LOG("ymodem tx timeout");
}
#endif
diff --git a/src/bootloader/bootloader.c b/src/bootloader/bootloader.c
index a8ca57e742f099ae5929a857b872b46ef823c9f3..fa6dd9fb7295f30e3b0f3135ad94c4c792451839 100644
--- a/src/bootloader/bootloader.c
+++ b/src/bootloader/bootloader.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file bootloader.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 升级引导程序
*
******************************************************************************
@@ -15,6 +15,7 @@
* Change Logs:
* Date Author Notes
* 2024-01-21 ashuai0110 完成基本内容
+ * 2024-03-05 ashuai0110 增加跳转至升级引导程序接口
*
******************************************************************************
*/
@@ -222,7 +223,7 @@ void boot_program_app_version(uint16_t appVersion)
}
/**
- * @brief bootloader跳转应用程序
+ * @brief 跳转至应用程序
*
* @param None
*
@@ -241,7 +242,7 @@ void boot_to_application(void)
boot_recover_all();
/* 将应用程序地址+4后强转为函数指针 */
bootCtrl.jumpFn = (boot_jump_fn_t)*(volatile uint32_t *)(BOOT_ROM_START_ADDR + BOOT_APP_ADDR_OFFSET + 4u);
- /* 设置用户应用程序栈顶指针 */
+ /* 设置程序栈顶指针 */
BOOT_SET_STACK_POINT(stackTop);
/* 跳转应用程序 */
bootCtrl.jumpFn();
@@ -253,7 +254,7 @@ void boot_to_application(void)
}
/**
- * @brief bootloader跳转备份(出厂)程序
+ * @brief 跳转至备份(出厂)程序
*
* @param None
*
@@ -267,12 +268,31 @@ void boot_to_factory(void)
boot_recover_all();
/* 将备份(出厂)程序地址+4后强转为函数指针 */
bootCtrl.jumpFn = (boot_jump_fn_t)*(volatile uint32_t *)(BOOT_ROM_START_ADDR + BOOT_FACTORY_ADDR_OFFSET + 4u);
- /* 设置用户应用程序栈顶指针 */
+ /* 设置程序栈顶指针 */
BOOT_SET_STACK_POINT(*(volatile uint32_t *)(BOOT_ROM_START_ADDR + BOOT_FACTORY_ADDR_OFFSET));
/* 跳转备份(出厂)程序 */
bootCtrl.jumpFn();
}
+/**
+ * @brief 跳转至升级引导程序
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void boot_to_bootloader(void)
+{
+ /* 恢复已使用的中断和外设 */
+ boot_recover_all();
+ /* 将bootloader程序地址+4后强转为函数指针 */
+ bootCtrl.jumpFn = (boot_jump_fn_t)*(volatile uint32_t *)(BOOT_ROM_START_ADDR + BOOT_ADDR_OFFSET + 4u);
+ /* 设置程序栈顶指针 */
+ BOOT_SET_STACK_POINT(*(volatile uint32_t *)(BOOT_ROM_START_ADDR + BOOT_ADDR_OFFSET));
+ /* 跳转bootloader程序 */
+ bootCtrl.jumpFn();
+}
+
/**
* @brief 恢复/失能已使用的外设/中断(用户实现)
*
diff --git a/src/bootloader/bootloader.h b/src/bootloader/bootloader.h
index c6feaec9b6688ad72ba41cde9801b082ed0395b9..f2c867b85ea63fbb344d6f8bb329d89d0f5aa04b 100644
--- a/src/bootloader/bootloader.h
+++ b/src/bootloader/bootloader.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file bootloader.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 升级引导程序
*
******************************************************************************
@@ -56,13 +56,15 @@ extern "C" {
* | bootloader | application | factory | updata info |
* | xxx | xxx | xxx | 8 |
* \--------------------------------------------------/ */
-#define BOOT_APP_ADDR_OFFSET (0x2C00) /*!< 应用程序起始地址偏移量 */
+#define BOOT_ADDR_OFFSET (0x0) /*!< 升级引导程序起始地址偏移量 */
+#define BOOT_SIZE_MAX (0x2C00) /*!< 升级引导程序最大大小 */
+#define BOOT_APP_ADDR_OFFSET (BOOT_ADDR_OFFSET + BOOT_SIZE_MAX + 0x0) /*!< 应用程序起始地址偏移量 */
#define BOOT_APP_SIZE_MAX (0x2800) /*!< 应用程序最大大小 */
-#define BOOT_FACTORY_ADDR_OFFSET (BOOT_APP_ADDR_OFFSET + BOOT_APP_SIZE_MAX + 0u) /*!< 备份(出厂)程序起始地址偏移量 */
+#define BOOT_FACTORY_ADDR_OFFSET (BOOT_APP_ADDR_OFFSET + BOOT_APP_SIZE_MAX + 0x0) /*!< 备份(出厂)程序起始地址偏移量 */
#define BOOT_FACTORY_SIZE_MAX (0x2800) /*!< 备份(出厂)程序最大大小 */
/* 升级信息存放起始地址偏移量 (应处于BOOT,APP,FACTORY存储之外的FLASH扇区,保证不会被意外擦除或改写) */
-#define BOOT_INFO_ADDR_OFFSET (BOOT_FACTORY_ADDR_OFFSET + BOOT_FACTORY_SIZE_MAX + 0u)
-#define BOOT_VERSION (100u) /*!< bootloader版本号 100 = V1.0.0 */
+#define BOOT_INFO_ADDR_OFFSET (BOOT_FACTORY_ADDR_OFFSET + BOOT_FACTORY_SIZE_MAX + 0x0)
+#define BOOT_VERSION (0x100) /*!< bootloader版本号 0x100 = V1.0.0 */
/**
* @}
*/
@@ -126,8 +128,8 @@ typedef uint8_t (* boot_flash_erase_fn_t)(uint32_t startAddr, uint32_t bytes);
*/
typedef struct boot_info {
uint32_t updataFlag; /*!< 升级标志 @ref boot_updata_flag */
- uint16_t bootVersion; /*!< bootloader版本 100代表V1.0.0 */
- uint16_t appVersion; /*!< application版本 100代表V1.0.0 */
+ uint16_t bootVersion; /*!< bootloader版本 0x100代表V1.0.0 */
+ uint16_t appVersion; /*!< application版本 0x100代表V1.0.0 */
} boot_info_t;
/**
@@ -163,11 +165,13 @@ void boot_check_updata_flag(void);
uint8_t boot_erase_application(uint32_t appSize);
uint8_t boot_program_application(void *data, uint16_t len);
+
void boot_program_updata_flag(uint32_t updataFlag);
void boot_program_app_version(uint16_t appVersion);
void boot_to_application(void);
void boot_to_factory(void);
+void boot_to_bootloader(void);
/* 弱定义函数 */
void boot_recover_all(void);
diff --git a/src/bootloader/xmodem.c b/src/bootloader/xmodem.c
index 44a7f2b491f02ca54450c0a798403b1dd0416741..1e34b65340ac3c506037dfd16d79b2ec88b0e4e3 100644
--- a/src/bootloader/xmodem.c
+++ b/src/bootloader/xmodem.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file xmodem.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief xmodem协议
*
******************************************************************************
@@ -18,6 +18,7 @@
* 2024-01-14 ashuai0110 修改接收使用校验和的逻辑错误,增加一些协议信息的宏定义
* 2024-01-21 ashuai0110 增加收发轮询处理返回状态,优化逻辑
* 2024-01-22 ashuai0110 增加发送缓存读出完毕关闭发送中断的处理
+ * 2024-03-05 ashuai0110 增加接收到脏数据时重发当前包的处理,增加部分接口
*
******************************************************************************
*/
@@ -135,11 +136,15 @@ static uint8_t xmodem_check_sum(uint8_t *data, uint16_t len)
*/
inline static void xmodem_init_state(xmodem_t *_xmodem)
{
- _xmodem->eotFlag = 0;
+ _xmodem->dataLen = 0;
+ _xmodem->readLen = 0;
+ _xmodem->dataLenTmp = 0;
_xmodem->rspTimeoutCnt = 0;
- _xmodem->rspTimeoutTimes = 0;
+ _xmodem->resendTimesCnt = 0;
_xmodem->packetNum = 1;
_xmodem->state = XMODEM_STATE_IDLE;
+ _xmodem->eotFlag = 0;
+ _xmodem->recFlag = 0;
}
/**
@@ -158,7 +163,7 @@ inline static void xmodem_init_state(xmodem_t *_xmodem)
*
* @param pBuf : 数据缓存区
*
- * @param bufLen : 数据缓存区长度byte(可根据xmodem.h:50行xmodem协议格式定义)
+ * @param bufLen : 数据缓存区长度byte(根据xmodem.h:50行xmodem协议格式定义长度)
*
* @param txEnFn : 串口发送前准备函数
*
@@ -166,12 +171,14 @@ inline static void xmodem_init_state(xmodem_t *_xmodem)
*
* @param setPacketFn : 设置数据包回调函数(不用可填NULL)
*
- * @param rspTimeout : 回复超时时间sec
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @param resendTimes : 超时重发次数
*
* @retval None
*/
void xmodem_init(xmodem_t *_xmodem, void *dataBuf, uint16_t bufLen, xmodem_tx_en_t txEnFn, \
- xmodem_user_packet_cb_t getPacketFn, xmodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout)
+ xmodem_user_packet_cb_t getPacketFn, xmodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout, uint8_t resendTimes)
{
ASSERT_PARAM(IS_VALID_POINT(_xmodem));
ASSERT_PARAM(IS_VALID_POINT(dataBuf));
@@ -185,8 +192,8 @@ void xmodem_init(xmodem_t *_xmodem, void *dataBuf, uint16_t bufLen, xmodem_tx_en
_xmodem->getPacketFn = getPacketFn;
_xmodem->setPacketFn = setPacketFn;
_xmodem->rspTimeout = rspTimeout;
+ _xmodem->resendTimes = resendTimes;
_xmodem->packetNum = 1;
- _xmodem->state = XMODEM_STATE_IDLE;
}
/**
@@ -218,8 +225,15 @@ uint8_t xmodem_rx_poll(xmodem_t *_xmodem)
if(tickTmp && (module_tick_get() - tickTmp) > _xmodem->rspTimeout)
{
_xmodem->rspTimeoutCnt = 0;
+ /* 接受标志置位说明接收到了脏数据 */
+ if(_xmodem->recFlag)
+ {
+ _xmodem->dataLenTmp = _xmodem->dataLen;
+ _xmodem->state = XMODEM_STATE_CHECK_DATA; /* 切换状态 */
+ break;
+ }
/* 若回复超时次数达到预设值 则直接中断接收回到IDLE状态 */
- if(_xmodem->rspTimeoutTimes++ >= XMODEM_RSP_TIMES)
+ if(_xmodem->resendTimesCnt++ >= _xmodem->resendTimes)
{
xmodem_init_state(_xmodem);
ret = RET_TIMEOUT; /* 回复超时 */
@@ -233,75 +247,79 @@ uint8_t xmodem_rx_poll(xmodem_t *_xmodem)
case XMODEM_STATE_CHECK_HEAD:
/* 根据包头和数据长度进行初步检查 */
/* SOH为包头 携带128byte数据 */
- if(XMODEM_SOH == _xmodem->dataBuf[YMODEM_START_INDEX] && (YMODEM_HEADER_SIZE + YMODEM_DATA_SIZE + _xmodem->checkNum) <= _xmodem->dataLen)
+ if(XMODEM_SOH == _xmodem->dataBuf[XMODEM_START_INDEX] && (XMODEM_HEADER_SIZE + XMODEM_DATA_SIZE + _xmodem->checkNum) <= _xmodem->dataLen)
{
_xmodem->state = XMODEM_STATE_CHECK_DATA; /* 切换状态 */
- _xmodem->dataLenTmp = YMODEM_DATA_SIZE;
+ _xmodem->dataLenTmp = XMODEM_DATA_SIZE;
} /* STX为包头 携带1024byte数据 */
- else if(XMODEM_STX == _xmodem->dataBuf[YMODEM_START_INDEX] && (YMODEM_HEADER_SIZE + YMODEM_DATA_1K_SIZE + _xmodem->checkNum) <= _xmodem->dataLen)
+ else if(XMODEM_STX == _xmodem->dataBuf[XMODEM_START_INDEX] && (XMODEM_HEADER_SIZE + XMODEM_DATA_1K_SIZE + _xmodem->checkNum) <= _xmodem->dataLen)
{
_xmodem->state = XMODEM_STATE_CHECK_DATA; /* 切换状态 */
- _xmodem->dataLenTmp = YMODEM_DATA_1K_SIZE;
+ _xmodem->dataLenTmp = XMODEM_DATA_1K_SIZE;
} /* EOT为包头 表示传输结束 */
- else if(XMODEM_EOT == _xmodem->dataBuf[YMODEM_START_INDEX])
+ else if(XMODEM_EOT == _xmodem->dataBuf[XMODEM_START_INDEX])
{
xmodem_init_state(_xmodem);
/* 回复ACK */
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_ACK;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_ACK;
_xmodem->dataLen = 1;
_xmodem->txEnFn(1);
ret = RET_OK; /* 传输完成 */
break;
} /* CAN为包头 表示传输取消 */
- else if(XMODEM_CAN == _xmodem->dataBuf[YMODEM_START_INDEX])
+ else if(XMODEM_CAN == _xmodem->dataBuf[XMODEM_START_INDEX])
{
xmodem_init_state(_xmodem);
ret = RET_ERR; /* 传输错误 */
break;
- }
+ } /* 其它则回到等待状态 */
else
{
- _xmodem->state = XMODEM_STATE_WAIT;
+ _xmodem->recFlag = 1; /* 置位接收标志 */
+ _xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
+ _xmodem->rspTimeoutCnt = module_tick_get(); /* 开启超时计数 */
break;
}
case XMODEM_STATE_CHECK_DATA:
/* 包序号和包序号反码满足条件 */
- if(_xmodem->packetNum == _xmodem->dataBuf[YMODEM_NUMBER_INDEX] && 0xFF == (_xmodem->dataBuf[YMODEM_NUMBER_INDEX] + _xmodem->dataBuf[YMODEM_CNUMBER_INDEX]))
+ if(_xmodem->packetNum == _xmodem->dataBuf[XMODEM_NUMBER_INDEX] && 0xFF == (_xmodem->dataBuf[XMODEM_NUMBER_INDEX] + _xmodem->dataBuf[XMODEM_CNUMBER_INDEX]))
{
/* 1字节累加和校验 */
if(1 == _xmodem->checkNum)
{
/* 校验成功 */
- if(_xmodem->dataBuf[_xmodem->dataLenTmp + YMODEM_HEADER_SIZE] == xmodem_check_sum(&_xmodem->dataBuf[YMODEM_DATA_INDEX], _xmodem->dataLenTmp))
+ if(_xmodem->dataBuf[_xmodem->dataLenTmp + XMODEM_HEADER_SIZE] == xmodem_check_sum(&_xmodem->dataBuf[XMODEM_DATA_INDEX], _xmodem->dataLenTmp))
{
/* 用户get回调函数 */
- _xmodem->getPacketFn(_xmodem->packetNum++, &_xmodem->dataBuf[YMODEM_DATA_INDEX], &_xmodem->dataLenTmp);
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_ACK; /* 回复ACK */
+ _xmodem->getPacketFn(_xmodem->packetNum++, &_xmodem->dataBuf[XMODEM_DATA_INDEX], &_xmodem->dataLenTmp);
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_ACK; /* 回复ACK */
} /* 校验失败 */
else
{
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_NAK; /* 回复NAK */
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_NAK; /* 回复NAK */
}
} /* 2字节CRC16校验 */
else if(2 == _xmodem->checkNum)
{
/* 校验成功 */
- if(0 == xmodem_check_crc16(&_xmodem->dataBuf[YMODEM_DATA_INDEX], _xmodem->dataLenTmp + _xmodem->checkNum))
+ if(0 == xmodem_check_crc16(&_xmodem->dataBuf[XMODEM_DATA_INDEX], _xmodem->dataLenTmp + _xmodem->checkNum))
{
- _xmodem->getPacketFn(_xmodem->packetNum++, &_xmodem->dataBuf[YMODEM_DATA_INDEX], &_xmodem->dataLenTmp); /* 用户回调函数 */
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_ACK; /* 回复ACK */
+ _xmodem->getPacketFn(_xmodem->packetNum++, &_xmodem->dataBuf[XMODEM_DATA_INDEX], &_xmodem->dataLenTmp); /* 用户回调函数 */
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_ACK; /* 回复ACK */
} /* 校验失败 */
else
{
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_NAK; /* 回复NAK */
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_NAK; /* 回复NAK */
}
}
} /* 否则回复NAK */
else
{
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_NAK;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_NAK;
}
- _xmodem->rspTimeoutTimes = 0;
+ /* 恢复默认参数 */
+ _xmodem->recFlag = 0;
+ _xmodem->resendTimesCnt = 0;
_xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
/* 发送回复内容 */
_xmodem->dataLen = 1;
@@ -338,7 +356,7 @@ void xmodem_rx_start(xmodem_t *_xmodem, uint8_t startFlag)
_xmodem->checkNum = (startFlag == XMODEM_RX_FLAG_NAK) ? 1 : 2; /* 记录校验方式 */
_xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
/* 发送启动内容 */
- _xmodem->dataBuf[YMODEM_START_INDEX] = startFlag;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = startFlag;
_xmodem->dataLen = 1;
_xmodem->dataLenTmp = _xmodem->dataLen;
_xmodem->txEnFn(1);
@@ -394,7 +412,7 @@ uint8_t xmodem_tx_poll(xmodem_t *_xmodem)
{
_xmodem->rspTimeoutCnt = 0;
/* 若回复超时次数达到预设值 则直接中断接收回到IDLE状态 */
- if(_xmodem->rspTimeoutTimes++ >= XMODEM_RSP_TIMES)
+ if(_xmodem->resendTimesCnt++ >= _xmodem->resendTimes)
{
xmodem_init_state(_xmodem);
ret = RET_TIMEOUT; /* 回复超时 */
@@ -407,7 +425,7 @@ uint8_t xmodem_tx_poll(xmodem_t *_xmodem)
break;
case XMODEM_STATE_CHECK_HEAD:
/* 收到ACK则继续发下一包 */
- if(XMODEM_ACK == _xmodem->dataBuf[YMODEM_START_INDEX])
+ if(XMODEM_ACK == _xmodem->dataBuf[XMODEM_START_INDEX])
{
/* 发送EOT后收到ACK则认为是传输结束 */
if(_xmodem->eotFlag)
@@ -418,12 +436,12 @@ uint8_t xmodem_tx_poll(xmodem_t *_xmodem)
}
_xmodem->state = XMODEM_STATE_CHECK_DATA; /* 切换状态 */
} /* 收到NAK则重发当前包 */
- else if(XMODEM_NAK == _xmodem->dataBuf[YMODEM_START_INDEX])
+ else if(XMODEM_NAK == _xmodem->dataBuf[XMODEM_START_INDEX])
{
_xmodem->packetNum--; /* 包序号-1 */
_xmodem->state = XMODEM_STATE_CHECK_DATA; /* 切换状态 */
} /* 收到CAN则取消传输 */
- else if(XMODEM_CAN == _xmodem->dataBuf[YMODEM_START_INDEX])
+ else if(XMODEM_CAN == _xmodem->dataBuf[XMODEM_START_INDEX])
{
xmodem_init_state(_xmodem);
ret = RET_ERR; /* 传输错误 */
@@ -432,30 +450,34 @@ uint8_t xmodem_tx_poll(xmodem_t *_xmodem)
else
{
_xmodem->dataLen = 0;
- _xmodem->state = XMODEM_STATE_WAIT;
+ _xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
+ _xmodem->rspTimeoutCnt = module_tick_get(); /* 开启超时计数 */
break;
}
case XMODEM_STATE_CHECK_DATA:
+ _xmodem->readLen = 0;
+ _xmodem->resendTimesCnt = 0;
+ _xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
/* 用户set回调函数 */
- _xmodem->setPacketFn(_xmodem->packetNum, &_xmodem->dataBuf[YMODEM_DATA_INDEX], &_xmodem->dataLen);
+ _xmodem->setPacketFn(_xmodem->packetNum, &_xmodem->dataBuf[XMODEM_DATA_INDEX], &_xmodem->dataLen);
/* 超过128但不超过1024的按1024byte */
- if(YMODEM_DATA_SIZE < _xmodem->dataLen && YMODEM_DATA_1K_SIZE >= _xmodem->dataLen)
+ if(XMODEM_DATA_SIZE < _xmodem->dataLen && XMODEM_DATA_1K_SIZE >= _xmodem->dataLen)
{
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_STX; /* 包头STX携带1024byte数据 */
- memset(&_xmodem->dataBuf[YMODEM_HEADER_SIZE + _xmodem->dataLen], XMODEM_CTRLZ, YMODEM_DATA_1K_SIZE - _xmodem->dataLen); /* 填充字节 */
- _xmodem->dataLen = YMODEM_DATA_1K_SIZE;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_STX; /* 包头STX携带1024byte数据 */
+ memset(&_xmodem->dataBuf[XMODEM_HEADER_SIZE + _xmodem->dataLen], XMODEM_CTRLZ, XMODEM_DATA_1K_SIZE - _xmodem->dataLen); /* 填充字节 */
+ _xmodem->dataLen = XMODEM_DATA_1K_SIZE;
} /* 超过0但不超过128的按128byte */
- else if(0 < _xmodem->dataLen && YMODEM_DATA_SIZE >= _xmodem->dataLen)
+ else if(0 < _xmodem->dataLen && XMODEM_DATA_SIZE >= _xmodem->dataLen)
{
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_SOH; /* 包头STX携带128byte数据 */
- memset(&_xmodem->dataBuf[YMODEM_HEADER_SIZE + _xmodem->dataLen], XMODEM_CTRLZ, YMODEM_DATA_SIZE - _xmodem->dataLen); /* 填充字节 */
- _xmodem->dataLen = YMODEM_DATA_SIZE;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_SOH; /* 包头STX携带128byte数据 */
+ memset(&_xmodem->dataBuf[XMODEM_HEADER_SIZE + _xmodem->dataLen], XMODEM_CTRLZ, XMODEM_DATA_SIZE - _xmodem->dataLen); /* 填充字节 */
+ _xmodem->dataLen = XMODEM_DATA_SIZE;
} /* 其它认为是传输结束 */
else
{
_xmodem->eotFlag = 1;
/* 回复EOT传输结束 */
- _xmodem->dataBuf[YMODEM_START_INDEX] = XMODEM_EOT;
+ _xmodem->dataBuf[XMODEM_START_INDEX] = XMODEM_EOT;
_xmodem->dataLen = 1;
_xmodem->dataLenTmp = _xmodem->dataLen;
_xmodem->txEnFn(1);
@@ -464,23 +486,21 @@ uint8_t xmodem_tx_poll(xmodem_t *_xmodem)
/* 1字节累加和校验 */
if(1 == _xmodem->checkNum)
{
- checkVal = xmodem_check_sum(&_xmodem->dataBuf[YMODEM_DATA_INDEX], _xmodem->dataLen);
- _xmodem->dataBuf[_xmodem->dataLen + YMODEM_HEADER_SIZE] = checkVal;
+ checkVal = xmodem_check_sum(&_xmodem->dataBuf[XMODEM_DATA_INDEX], _xmodem->dataLen);
+ _xmodem->dataBuf[_xmodem->dataLen + XMODEM_HEADER_SIZE] = checkVal;
} /* 2字节CRC16校验 */
else if(2 == _xmodem->checkNum)
{
- checkVal = xmodem_check_crc16(&_xmodem->dataBuf[YMODEM_DATA_INDEX], _xmodem->dataLen);
- _xmodem->dataBuf[_xmodem->dataLen + YMODEM_HEADER_SIZE] = checkVal >> 8;
- _xmodem->dataBuf[_xmodem->dataLen + YMODEM_HEADER_SIZE + 1] = checkVal & 0xFF;
+ checkVal = xmodem_check_crc16(&_xmodem->dataBuf[XMODEM_DATA_INDEX], _xmodem->dataLen);
+ _xmodem->dataBuf[_xmodem->dataLen + XMODEM_HEADER_SIZE] = checkVal >> 8;
+ _xmodem->dataBuf[_xmodem->dataLen + XMODEM_HEADER_SIZE + 1] = checkVal & 0xFF;
}
- _xmodem->rspTimeoutTimes = 0;
- _xmodem->state = XMODEM_STATE_WAIT; /* 切换状态 */
/* 设置包序号和其反码 */
- _xmodem->dataBuf[YMODEM_NUMBER_INDEX] = _xmodem->packetNum;
- _xmodem->dataBuf[YMODEM_CNUMBER_INDEX] = 0xFF - _xmodem->packetNum;
+ _xmodem->dataBuf[XMODEM_NUMBER_INDEX] = _xmodem->packetNum;
+ _xmodem->dataBuf[XMODEM_CNUMBER_INDEX] = 0xFF - _xmodem->packetNum;
_xmodem->packetNum++;
/* 发送包内容 */
- _xmodem->dataLen = _xmodem->dataLen + YMODEM_HEADER_SIZE + _xmodem->checkNum;
+ _xmodem->dataLen = _xmodem->dataLen + XMODEM_HEADER_SIZE + _xmodem->checkNum;
_xmodem->dataLenTmp = _xmodem->dataLen;
_xmodem->txEnFn(1);
break;
@@ -590,6 +610,58 @@ uint16_t xmodem_read_tx_buf(xmodem_t *_xmodem, void *pBuf, uint16_t len)
return len;
}
+/**
+ * @brief xmodem设置回复超时时间ms
+ *
+ * @param _xmodem : xmodem管理实例
+ *
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @retval None
+ */
+void xmodem_set_rsp_timeout(xmodem_t *_xmodem, uint16_t rspTimeout)
+{
+ _xmodem->rspTimeout = rspTimeout;
+}
+
+/**
+ * @brief xmodem获取回复超时时间ms
+ *
+ * @param _xmodem : xmodem管理实例
+ *
+ * @retval 返回回复超时时间ms
+ */
+uint16_t xmodem_get_rsp_timeout(xmodem_t *_xmodem)
+{
+ return _xmodem->rspTimeout;
+}
+
+/**
+ * @brief xmodem设置重发次数
+ *
+ * @param _xmodem : xmodem管理实例
+ *
+ * @param resendTimes : 重发次数
+ *
+ * @retval None
+ */
+void xmodem_set_resend_times(xmodem_t *_xmodem, uint8_t resendTimes)
+{
+ _xmodem->resendTimes = resendTimes;
+}
+
+/**
+ * @brief xmodem获取重发次数
+ *
+ * @param _xmodem : xmodem管理实例
+ *
+ * @retval 返回重发次数
+ */
+uint8_t xmodem_get_resend_times(xmodem_t *_xmodem)
+{
+ return _xmodem->resendTimes;
+}
+
/**
* @}
*/
diff --git a/src/bootloader/xmodem.h b/src/bootloader/xmodem.h
index 07575ade0f14ca104396367f9799514620f08db1..84e7a227782c88720089e6946bbddd1b592ad68c 100644
--- a/src/bootloader/xmodem.h
+++ b/src/bootloader/xmodem.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file xmodem.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief xmodem协议
*
******************************************************************************
@@ -41,8 +41,6 @@ extern "C" {
* @{
*/
-#define XMODEM_RSP_TIMES (3u) /*!< 回复超时次数默认3次(0~255) */
-
/**
* @defgroup xmodem_info xmodem info
* @{
@@ -51,13 +49,13 @@ extern "C" {
* | 命令符 | 包序号 | 包序号反码 | 有效数据 | 校验 |
* | 1 | 1 | 1 | 128/1024 | 1/2 |
* \--------------------------------------------------/ */
-#define YMODEM_START_INDEX (0u)
-#define YMODEM_NUMBER_INDEX (1u)
-#define YMODEM_CNUMBER_INDEX (2u)
-#define YMODEM_DATA_INDEX (3u)
-#define YMODEM_HEADER_SIZE (3u)
-#define YMODEM_DATA_SIZE (128u)
-#define YMODEM_DATA_1K_SIZE (1024u)
+#define XMODEM_START_INDEX (0u)
+#define XMODEM_NUMBER_INDEX (1u)
+#define XMODEM_CNUMBER_INDEX (2u)
+#define XMODEM_DATA_INDEX (3u)
+#define XMODEM_HEADER_SIZE (3u)
+#define XMODEM_DATA_SIZE (128u)
+#define XMODEM_DATA_1K_SIZE (1024u)
/**
* @}
*/
@@ -140,22 +138,24 @@ typedef void (* xmodem_user_packet_cb_t)(uint8_t packetNum, uint8_t *data, uint1
* @brief xmodem structure definition
*/
typedef struct xmodem {
- uint8_t *dataBuf; /*!< 数据缓冲区 */
- uint16_t dataBufLen; /*!< 数据缓冲区大小 */
- volatile uint16_t dataLen; /*!< 存放数据数量 */
- volatile uint16_t readLen; /*!< 数据读出数量 */
- uint16_t dataLenTmp; /*!< 存放数据数量暂存 */
+ uint8_t *dataBuf; /*!< 数据缓冲区 */
+ uint16_t dataBufLen; /*!< 数据缓冲区大小 */
+ uint16_t dataLen; /*!< 存放数据数量 */
+ uint16_t readLen; /*!< 数据读出数量 */
+ uint16_t dataLenTmp; /*!< 存放数据数量暂存 */
- uint16_t rspTimeout; /*!< 回复超时时间ms */
- uint32_t rspTimeoutCnt; /*!< 回复超时时间计数 */
- uint8_t rspTimeoutTimes; /*!< 回复超时次数 */
- uint8_t packetNum; /*!< 包序号 */
+ uint16_t rspTimeout; /*!< 回复超时时间ms */
+ uint32_t rspTimeoutCnt; /*!< 回复超时时间计数 */
+ uint8_t resendTimes; /*!< 超时重发次数 */
+ uint8_t resendTimesCnt; /*!< 超时重发计数 */
+ uint8_t packetNum; /*!< 包序号 */
- uint8_t state : 3; /*!< xmodem状态 @ref xmodem_rx_state */
- uint8_t checkNum : 2; /*!< 校验字节数 1:累加和 2:CRC16 */
- uint8_t eotFlag : 1; /*!< 传输结束标志 */
+ uint8_t state : 3; /*!< xmodem状态 @ref xmodem_rx_state */
+ uint8_t checkNum : 2; /*!< 校验字节数 1:累加和 2:CRC16 */
+ uint8_t eotFlag : 1; /*!< 传输结束标志 0:未结束 1:传输结束 */
+ uint8_t recFlag : 1; /*!< 接收标志 0:未接收到 1:接收到 */
- xmodem_tx_en_t txEnFn; /*!< 串口发送准备函数 */
+ xmodem_tx_en_t txEnFn; /*!< 串口发送准备函数 */
xmodem_user_packet_cb_t getPacketFn; /*!< 获取数据包回调函数 */
xmodem_user_packet_cb_t setPacketFn; /*!< 设置数据包回调函数 */
} xmodem_t;
@@ -173,7 +173,7 @@ typedef struct xmodem {
*/
void xmodem_init(xmodem_t *_xmodem, void *dataBuf, uint16_t bufLen, xmodem_tx_en_t txEnFn, \
- xmodem_user_packet_cb_t getPacketFn, xmodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout);
+ xmodem_user_packet_cb_t getPacketFn, xmodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout, uint8_t resendTimes);
uint8_t xmodem_rx_poll(xmodem_t *_xmodem);
uint8_t xmodem_tx_poll(xmodem_t *_xmodem);
@@ -183,6 +183,12 @@ void xmodem_rx_start(xmodem_t *_xmodem, uint8_t startFlag);
uint16_t xmodem_write_rx_buf(xmodem_t *_xmodem, void *pBuf, uint16_t len);
uint16_t xmodem_read_tx_buf(xmodem_t *_xmodem, void *pBuf, uint16_t len);
+/* set/get interface */
+void xmodem_set_rsp_timeout(xmodem_t *_xmodem, uint16_t rspTimeout);
+uint16_t xmodem_get_rsp_timeout(xmodem_t *_xmodem);
+void xmodem_set_resend_times(xmodem_t *_xmodem, uint8_t resendTimes);
+uint8_t xmodem_get_resend_times(xmodem_t *_xmodem);
+
/**
* @}
*/
diff --git a/src/bootloader/ymodem.c b/src/bootloader/ymodem.c
index ad08fed43a49d10df4258367768b06dcb0e5e6dc..7e18d9729368218bcd132a6ea2d8583adff8b879 100644
--- a/src/bootloader/ymodem.c
+++ b/src/bootloader/ymodem.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file ymodem.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief ymodem协议
*
******************************************************************************
@@ -17,6 +17,7 @@
* 2024-01-17 ashuai0110 完成基本内容
* 2024-01-21 ashuai0110 增加收发轮询处理返回状态
* 2024-01-22 ashuai0110 增加发送缓存读出完毕关闭发送中断的处理
+ * 2024-03-04 ashuai0110 增加接收到脏数据时重发当前包的处理,增加部分接口
*
******************************************************************************
*/
@@ -138,11 +139,12 @@ inline static void ymodem_init_state(ymodem_t *_ymodem)
_ymodem->readLen = 0;
_ymodem->dataLenTmp = 0;
_ymodem->rspTimeoutCnt = 0;
- _ymodem->rspTimeoutTimes = 0;
+ _ymodem->resendTimesCnt = 0;
_ymodem->packetNum = 0;
_ymodem->state = YMODEM_STATE_IDLE;
_ymodem->fileFlag = 0;
_ymodem->eotFlag = 0;
+ _ymodem->recFlag = 0;
}
/**
@@ -161,7 +163,7 @@ inline static void ymodem_init_state(ymodem_t *_ymodem)
*
* @param pBuf : 数据缓存区
*
- * @param bufLen : 数据缓存区长度byte(可根据ymodem.h:50行ymodem协议格式定义)
+ * @param bufLen : 数据缓存区长度byte(根据ymodem.h:50行ymodem协议格式定义长度)
*
* @param txEnFn : 串口发送前准备函数
*
@@ -169,12 +171,14 @@ inline static void ymodem_init_state(ymodem_t *_ymodem)
*
* @param setPacketFn : 设置数据包回调函数(不用可填NULL)
*
- * @param rspTimeout : 回复超时时间sec
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @param resendTimes : 超时重发次数
*
* @retval None
*/
void ymodem_init(ymodem_t *_ymodem, void *dataBuf, uint16_t bufLen, ymodem_tx_en_t txEnFn, \
- ymodem_user_packet_cb_t getPacketFn, ymodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout)
+ ymodem_user_packet_cb_t getPacketFn, ymodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout, uint8_t resendTimes)
{
ASSERT_PARAM(IS_VALID_POINT(_ymodem));
ASSERT_PARAM(IS_VALID_POINT(dataBuf));
@@ -188,7 +192,7 @@ void ymodem_init(ymodem_t *_ymodem, void *dataBuf, uint16_t bufLen, ymodem_tx_en
_ymodem->getPacketFn = getPacketFn;
_ymodem->setPacketFn = setPacketFn;
_ymodem->rspTimeout = rspTimeout;
- _ymodem->state = YMODEM_STATE_IDLE;
+ _ymodem->resendTimes = resendTimes;
}
/**
@@ -218,8 +222,15 @@ uint8_t ymodem_rx_poll(ymodem_t *_ymodem)
if(tickTmp && (module_tick_get() - tickTmp) > _ymodem->rspTimeout)
{
_ymodem->rspTimeoutCnt = 0;
+ /* 接受标志置位说明接收到了脏数据 */
+ if(_ymodem->recFlag)
+ {
+ _ymodem->dataLenTmp = _ymodem->dataLen;
+ _ymodem->state = YMODEM_STATE_CHECK_DATA; /* 切换状态 */
+ break;
+ }
/* 若回复超时次数达到预设值 则直接中断接收回到IDLE状态 */
- if(_ymodem->rspTimeoutTimes++ >= YMODEM_RSP_TIMES)
+ if(_ymodem->resendTimesCnt++ >= _ymodem->resendTimes)
{
ymodem_init_state(_ymodem);
ret = RET_TIMEOUT; /* 回复超时 */
@@ -305,7 +316,9 @@ uint8_t ymodem_rx_poll(ymodem_t *_ymodem)
} /* 其它则回到等待状态 */
else
{
+ _ymodem->recFlag = 1; /* 置位接收标志 */
_ymodem->state = YMODEM_STATE_WAIT; /* 切换状态 */
+ _ymodem->rspTimeoutCnt = module_tick_get(); /* 开启超时计数 */
break;
}
case YMODEM_STATE_CHECK_DATA:
@@ -345,7 +358,9 @@ uint8_t ymodem_rx_poll(ymodem_t *_ymodem)
{
_ymodem->dataBuf[YMODEM_START_INDEX] = YMODEM_NAK;
}
- _ymodem->rspTimeoutTimes = 0;
+ /* 恢复默认参数 */
+ _ymodem->recFlag = 0;
+ _ymodem->resendTimesCnt = 0;
_ymodem->state = YMODEM_STATE_WAIT; /* 切换状态 */
/* 发送回复内容 */
_ymodem->dataLen = 1;
@@ -444,7 +459,7 @@ uint8_t ymodem_tx_poll(ymodem_t *_ymodem)
{
_ymodem->rspTimeoutCnt = 0;
/* 若回复超时次数达到预设值 则直接中断接收回到IDLE状态 */
- if(_ymodem->rspTimeoutTimes++ >= YMODEM_RSP_TIMES)
+ if(_ymodem->resendTimesCnt++ >= _ymodem->resendTimes)
{
ymodem_init_state(_ymodem);
ret = RET_TIMEOUT; /* 回复超时 */
@@ -492,26 +507,27 @@ uint8_t ymodem_tx_poll(ymodem_t *_ymodem)
{
_ymodem->dataLen = 0;
_ymodem->state = YMODEM_STATE_WAIT; /* 切换状态 */
+ _ymodem->rspTimeoutCnt = module_tick_get(); /* 开启超时计数 */
break;
}
case YMODEM_STATE_CHECK_DATA:
_ymodem->readLen = 0;
- _ymodem->rspTimeoutTimes = 0;
+ _ymodem->resendTimesCnt = 0;
_ymodem->state = YMODEM_STATE_WAIT; /* 切换状态 */
/* 用户set回调函数 */
_ymodem->setPacketFn(_ymodem->packetNum, &_ymodem->dataBuf[3], &_ymodem->dataLen);
/* 超过128但不超过1024的按1024byte */
- if(128 < _ymodem->dataLen && 1024 >= _ymodem->dataLen)
+ if(YMODEM_DATA_SIZE < _ymodem->dataLen && YMODEM_DATA_1K_SIZE >= _ymodem->dataLen)
{
_ymodem->dataBuf[0] = YMODEM_STX; /* 包头STX携带1024byte数据 */
- memset(&_ymodem->dataBuf[3 + _ymodem->dataLen], YMODEM_CTRLZ, 1024 - _ymodem->dataLen); /* 填充字节 */
- _ymodem->dataLen = 1024;
+ memset(&_ymodem->dataBuf[3 + _ymodem->dataLen], YMODEM_CTRLZ, YMODEM_DATA_1K_SIZE - _ymodem->dataLen); /* 填充字节 */
+ _ymodem->dataLen = YMODEM_DATA_1K_SIZE;
} /* 超过0但不超过128的按128byte */
- else if(0 < _ymodem->dataLen && 128 >= _ymodem->dataLen)
+ else if(0 < _ymodem->dataLen && YMODEM_DATA_SIZE >= _ymodem->dataLen)
{
_ymodem->dataBuf[0] = YMODEM_SOH; /* 包头STX携带128byte数据 */
- memset(&_ymodem->dataBuf[3 + _ymodem->dataLen], YMODEM_CTRLZ, 128 - _ymodem->dataLen); /* 填充字节 */
- _ymodem->dataLen = 128;
+ memset(&_ymodem->dataBuf[3 + _ymodem->dataLen], YMODEM_CTRLZ, YMODEM_DATA_SIZE - _ymodem->dataLen); /* 填充字节 */
+ _ymodem->dataLen = YMODEM_DATA_SIZE;
} /* 其它认为是传输结束 */
else
{
@@ -576,8 +592,8 @@ uint16_t ymodem_write_rx_buf(ymodem_t *_ymodem, void *pBuf, uint16_t len)
ASSERT_PARAM(IS_VALID_POINT(_ymodem->dataBuf));
ASSERT_PARAM(IS_VALID_POINT(pBuf));
- /* 在IDLE和WAIT状态下可以接收数据 */
- if(YMODEM_STATE_WAIT >= _ymodem->state)
+ /* 在指定状态可以接收数据 */
+ if(YMODEM_STATE_CHECK_HEAD >= _ymodem->state)
{
/* 计算可写数量 */
unusedLen = _ymodem->dataBufLen - _ymodem->dataLen;
@@ -672,7 +688,7 @@ void ymodem_set_file_info(ymodem_t *_ymodem, file_info_t *_info)
memcpy((void *)&_ymodem->dataBuf[YMODEM_DATA_INDEX], (void *)_info->fileName, lenTmp);
/* 写入文件大小 */
sprintf((char *)&_ymodem->dataBuf[YMODEM_DATA_INDEX + lenTmp + 1], "%d", _info->fileSize);
- _ymodem->dataLen = 128;
+ _ymodem->dataLen = YMODEM_DATA_SIZE;
}
}
@@ -698,6 +714,74 @@ void ymodem_get_file_info(ymodem_t *_ymodem, file_info_t *_info)
_info->fileSize = atoi((char *)&_ymodem->dataBuf[YMODEM_DATA_INDEX + lenTmp + 1]);
}
+/**
+ * @brief ymodem获取文件标志
+ *
+ * @note 用户通过此接口区分文件信息包或正常数据包
+ *
+ * @param _ymodem : ymodem管理实例
+ *
+ * @retval 返回文件标志
+ * @arg 0 : 正常数据包
+ * @arg 1 : 文件信息包
+ */
+uint8_t ymodem_get_file_flag(ymodem_t *_ymodem)
+{
+ return _ymodem->fileFlag;
+}
+
+/**
+ * @brief ymodem设置回复超时时间ms
+ *
+ * @param _ymodem : ymodem管理实例
+ *
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @retval None
+ */
+void ymodem_set_rsp_timeout(ymodem_t *_ymodem, uint16_t rspTimeout)
+{
+ _ymodem->rspTimeout = rspTimeout;
+}
+
+/**
+ * @brief ymodem获取回复超时时间ms
+ *
+ * @param _ymodem : ymodem管理实例
+ *
+ * @retval 返回回复超时时间ms
+ */
+uint16_t ymodem_get_rsp_timeout(ymodem_t *_ymodem)
+{
+ return _ymodem->rspTimeout;
+}
+
+/**
+ * @brief ymodem设置重发次数
+ *
+ * @param _ymodem : ymodem管理实例
+ *
+ * @param resendTimes : 重发次数
+ *
+ * @retval None
+ */
+void ymodem_set_resend_times(ymodem_t *_ymodem, uint8_t resendTimes)
+{
+ _ymodem->resendTimes = resendTimes;
+}
+
+/**
+ * @brief ymodem获取重发次数
+ *
+ * @param _ymodem : ymodem管理实例
+ *
+ * @retval 返回重发次数
+ */
+uint8_t ymodem_get_resend_times(ymodem_t *_ymodem)
+{
+ return _ymodem->resendTimes;
+}
+
/**
* @}
*/
diff --git a/src/bootloader/ymodem.h b/src/bootloader/ymodem.h
index 294b71df16150162853e2528b5e8e86b244a0ba9..2e6d99a17996a3f7cd7b598fac44b7af1b9866da 100644
--- a/src/bootloader/ymodem.h
+++ b/src/bootloader/ymodem.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file ymodem.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief ymodem协议
*
******************************************************************************
@@ -41,11 +41,8 @@ extern "C" {
* @{
*/
-#define YMODEM_RSP_TIMES (3u) /*!< 回复超时次数默认3次(0~255) */
#define YMODEM_FILE_NAME_LEN (32u) /*!< 文件名长度 用户根据需求更改 */
-#define YMODEM_FILE_FLAG(x) ((x).fileFlag) /* 文件标志 用户通过此接口区分文件信息包和正常数据包 */
-
/**
* @defgroup ymodem_info ymodem info
* @{
@@ -143,23 +140,25 @@ typedef void (* ymodem_user_packet_cb_t)(uint8_t packetNum, uint8_t *data, uint1
* @brief ymodem structure definition
*/
typedef struct ymodem {
- uint8_t *dataBuf; /*!< 数据缓冲区 */
- uint16_t dataBufLen; /*!< 数据缓冲区大小 */
- volatile uint16_t dataLen; /*!< 存放数据数量 */
- volatile uint16_t readLen; /*!< 数据读出数量 */
- uint16_t dataLenTmp; /*!< 存放数据数量暂存 */
+ uint8_t *dataBuf; /*!< 数据缓冲区 */
+ uint16_t dataBufLen; /*!< 数据缓冲区大小 */
+ uint16_t dataLen; /*!< 存放数据数量 */
+ uint16_t readLen; /*!< 数据读出数量 */
+ uint16_t dataLenTmp; /*!< 存放数据数量暂存 */
- uint16_t rspTimeout; /*!< 回复超时时间ms */
- uint32_t rspTimeoutCnt; /*!< 回复超时时间计数 */
- uint8_t rspTimeoutTimes; /*!< 回复超时次数 */
- uint8_t packetNum; /*!< 包序号 */
+ uint16_t rspTimeout; /*!< 回复超时时间ms */
+ uint32_t rspTimeoutCnt; /*!< 回复超时时间计数 */
+ uint8_t resendTimes; /*!< 超时重发次数 */
+ uint8_t resendTimesCnt; /*!< 超时重发计数 */
+ uint8_t packetNum; /*!< 包序号 */
- uint8_t state : 3; /*!< ymodem状态 @ref ymodem_rx_state */
- uint8_t checkNum : 2; /*!< 校验字节数 1:累加和 2:CRC16 */
- uint8_t fileFlag : 1; /*!< 文件信息标志 1:此包数据为文件信息 */
- uint8_t eotFlag : 2; /*!< 首次EOT标志 0:首次 1:非首次 */
+ uint8_t state : 2; /*!< ymodem状态 @ref ymodem_rx_state */
+ uint8_t checkNum : 2; /*!< 校验字节数 1:累加和 2:CRC16 */
+ uint8_t fileFlag : 1; /*!< 文件信息标志 1:此包数据为文件信息 */
+ uint8_t eotFlag : 2; /*!< 首次EOT标志 0:首次 !0:非首次 */
+ uint8_t recFlag : 1; /*!< 接收标志 0:未接收到 1:接收到 */
- ymodem_tx_en_t txEnFn; /*!< 串口发送准备函数 */
+ ymodem_tx_en_t txEnFn; /*!< 串口发送准备函数 */
ymodem_user_packet_cb_t getPacketFn; /*!< 获取数据包回调函数 */
ymodem_user_packet_cb_t setPacketFn; /*!< 设置数据包回调函数 */
} ymodem_t;
@@ -185,7 +184,7 @@ typedef struct file_info {
*/
void ymodem_init(ymodem_t *_ymodem, void *dataBuf, uint16_t bufLen, ymodem_tx_en_t txEnFn, \
- ymodem_user_packet_cb_t getPacketFn, ymodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout);
+ ymodem_user_packet_cb_t getPacketFn, ymodem_user_packet_cb_t setPacketFn, uint16_t rspTimeout, uint8_t resendTimes);
uint8_t ymodem_rx_poll(ymodem_t *_ymodem);
uint8_t ymodem_tx_poll(ymodem_t *_ymodem);
@@ -198,6 +197,14 @@ uint16_t ymodem_read_tx_buf(ymodem_t *_ymodem, void *pBuf, uint16_t len);
void ymodem_set_file_info(ymodem_t *_ymodem, file_info_t *_info);
void ymodem_get_file_info(ymodem_t *_ymodem, file_info_t *_info);
+uint8_t ymodem_get_file_flag(ymodem_t *_ymodem);
+
+/* set/get interface */
+void ymodem_set_rsp_timeout(ymodem_t *_ymodem, uint16_t rspTimeout);
+uint16_t ymodem_get_rsp_timeout(ymodem_t *_ymodem);
+void ymodem_set_resend_times(ymodem_t *_ymodem, uint8_t resendTimes);
+uint8_t ymodem_get_resend_times(ymodem_t *_ymodem);
+
/**
* @}
*/
diff --git a/src/common/all_include.h b/src/common/all_include.h
index 595819bebe21f1d3e6d600892c998ad2333954b8..0f03a4821efa289a772625b787c628ee1b8d6cb2 100644
--- a/src/common/all_include.h
+++ b/src/common/all_include.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file all_include.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief 所有组件头文件集合
*
******************************************************************************
@@ -25,7 +25,15 @@ extern "C" {
/* 包含头文件-----------------------------------------------------------------*/
/* common */
#include "common_include.h" /*!< 公共引用文件(所有组件都需包含此文件) */
+/* devices */
+#include "esp8266.h" /*!< ESP8266模组AT指令集 */
+#include "hongjia_ble.h" /*!< 宏佳电子HJ-131蓝牙模组指令集 */
+#include "sim900a.h" /*!< SIM900A模组AT指令集 */
+#include "oled_096.h" /*!< 0.96英寸OLED屏幕驱动 */
+#include "by9301.h" /*!< BY9301语音播报模块驱动 */
+#include "dht11.h" /*!< DHT11温湿度模块驱动 */
/* modules */
+#include "command_at.h" /*!< AT指令交互 */
#include "command_line.h" /*!< 命令行交互 */
#include "data_check.h" /*!< 数据校验方法集合 */
#include "data_convert.h" /*!< 数据转换方法集合 */
diff --git a/src/common/common_include.c b/src/common/common_include.c
index 04043d67a62130d835b52c54b5a2d5842be196fa..ca98c5d39fa48bf8eee7916bce1ede7ae921f8a1 100644
--- a/src/common/common_include.c
+++ b/src/common/common_include.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file common_include.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 公共引用文件(所有组件都需包含此文件)
*
******************************************************************************
@@ -17,6 +17,8 @@
* 2023-10-17 ashuai0110 完成基本内容
* 2023-12-28 ashuai0110 新增组件计时节拍接口
* 2024-01-04 ashuai0110 修改组件计时节拍初值为1
+ * 2024-03-26 ashuai0110 增加组件时间戳相关接口
+ * 2024-07-01 ashuai0110 增加常用函数指针类型重定义
*
******************************************************************************
*/
@@ -46,6 +48,14 @@
static volatile uint32_t moduleTick = 1; /* 组件计时节拍(计时溢出需49.7天,溢出后可能造成计时异常影响组件功能) */
+#if _USE_TIME_STAMP
+/* 月简称对照表 */
+static const char monthTable[12][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+/* 周简称对照表 */
+static const char weekTable[7][3] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static volatile uint32_t moduleTimeStamp; /* 组件时间戳 */
+#endif
+
/**
* @}
*/
@@ -53,6 +63,68 @@ static volatile uint32_t moduleTick = 1; /* 组件计时节拍(计时溢出需49
/* 全局变量-------------------------------------------------------------------*/
/* 私有函数原型---------------------------------------------------------------*/
+/**
+ * @defgroup common_include_local_functions common include local functions
+ * @{
+ */
+
+#if _USE_TIME_STAMP
+/**
+ * @brief 以指定分割符分割字符串
+ *
+ * @note pSrc = "cmd 1 2 3", 空格分割
+ * pBuf[0] = "cmd"
+ * pBuf[1] = "1"
+ * pBuf[2] = "2"
+ * pBuf[3] = "3"
+ *
+ * @param pBuf : 分解后存放的缓存区
+ *
+ * @param pSrc : 源数据
+ *
+ * @param flg : 单字节分割符
+ *
+ * @param num : 期望分割数量
+ *
+ * @retval 0:错误 !0:实际分割数量
+ */
+static uint16_t module_split(char *pBuf[], char *pSrc, char flg, uint16_t num)
+{
+ uint16_t cnt = 0;
+
+ ASSERT_PARAM(IS_VALID_POINT(pBuf));
+ ASSERT_PARAM(IS_VALID_POINT(pSrc));
+
+ /* 缓存区先存放第一个字符串首地址 */
+ pBuf[cnt++] = pSrc;
+ while(1)
+ {
+ /* 若当前字符与参数flg相同 */
+ if(*pSrc == flg)
+ {
+ *pSrc = '\0'; /* 当前字符改为'\0' 代表字符串到此结束 */
+ /* 若分割数量达到参数num则break */
+ if(cnt >= num)
+ {
+ break;
+ }
+ pBuf[cnt++] = pSrc + 1; /* 缓存区存放下一个字符串首地址 */
+ } /* 若当前字符与结束符1或结束符2或'\0'相同则break */
+ else if('\r' == *pSrc || '\n' == *pSrc|| '\0' == *pSrc)
+ {
+ *pSrc = '\0';
+ break;
+ }
+ pSrc++; /* 当前字符地址自增 */
+ }
+
+ return cnt;
+}
+#endif
+
+/**
+ * @}
+ */
/**
* @defgroup common_include_global_functions common include global functions
@@ -87,6 +159,131 @@ uint32_t module_tick_get(void)
return moduleTick;
}
+#if _USE_TIME_STAMP
+/**
+ * @brief 组件时间戳初始化
+ *
+ * @param baseTime : 时间戳
+ *
+ * @retval None
+ */
+void module_time_stamp_init(uint32_t baseTime)
+{
+ moduleTimeStamp = baseTime;
+}
+
+/**
+ * @brief 组件时间戳1s计时累计
+ *
+ * @note 此接口需用户对接底层systick或timer等
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void module_time_stamp_1s(void)
+{
+ moduleTimeStamp += 1;
+}
+
+/**
+ * @brief 获取组件时间戳
+ *
+ * @param None
+ *
+ * @retval 返回当前时间戳
+ */
+uint32_t module_time_stamp_get(void)
+{
+ return moduleTimeStamp;
+}
+
+/**
+ * @brief 由组件时间结构体转换为时间戳
+ *
+ * @param moduleTime : 组件时间结构体
+ *
+ * @retval 返回时间戳
+ */
+uint32_t module_time_stamp_conv(module_time_t moduleTime)
+{
+ uint32_t timeTmp;
+ struct tm tmTmp;
+
+ tmTmp.tm_year = moduleTime.year - 1900;
+ tmTmp.tm_mon = moduleTime.month - 1;
+ tmTmp.tm_mday = moduleTime.day;
+ tmTmp.tm_hour = moduleTime.hour;
+ tmTmp.tm_min = moduleTime.minute;
+ tmTmp.tm_sec = moduleTime.second;
+ timeTmp = mktime(&tmTmp);
+
+ return timeTmp;
+}
+
+/**
+ * @brief 由时间戳转换为组件时间结构体
+ *
+ * @param _time : 组件时间结构体指针
+ *
+ * @param timeStamp : 时间戳
+ *
+ * @retval None
+ */
+void module_time_std_conv(module_time_t *_time, uint32_t timeStamp)
+{
+ time_t timeTmp = (time_t)timeStamp;
+ struct tm tmTmp;
+
+ tmTmp = *localtime(&timeTmp);
+ _time->year = tmTmp.tm_year + 1900;
+ _time->month = tmTmp.tm_mon + 1;
+ _time->day = tmTmp.tm_mday;
+ _time->week = tmTmp.tm_wday == 0 ? 7 : tmTmp.tm_wday;
+ _time->hour = tmTmp.tm_hour;
+ _time->minute = tmTmp.tm_min;
+ _time->second = tmTmp.tm_sec;
+}
+
+/**
+ * @brief 由sntp时间字符串格式转换为组件时间结构体
+ *
+ * @param _time : 组件时间结构体指针
+ *
+ * @param sntpTime : sntp时间字符串
+ *
+ * @retval None
+ */
+void module_time_sntp_conv(module_time_t *_time, char *sntpTime)
+{
+ char *buf[5];
+ uint8_t index;
+
+ sntpTime = strstr(sntpTime, ":") + sizeof(char);
+ if(5 == module_split(buf, sntpTime, ' ', 5))
+ {
+ index = 0;
+ do {
+ if(0 == strncmp(buf[0], weekTable[index++], strlen(buf[0]))) { break; }
+ } while(index < 7);
+ _time->week = index;
+ index = 0;
+ do {
+ if(0 == strncmp(buf[1], monthTable[index++], strlen(buf[1]))) { break; }
+ } while(index < 12);
+ _time->month = index;
+ _time->day = atoi(buf[2]);
+ _time->year = atoi(buf[4]);
+ if(3 == module_split(buf, buf[3], ':', 3))
+ {
+ _time->hour = atoi(buf[0]);
+ _time->minute = atoi(buf[1]);
+ _time->second = atoi(buf[2]);
+ }
+ }
+}
+#endif
+
/**
* @}
*/
diff --git a/src/common/common_include.h b/src/common/common_include.h
index d30d5194bd0174d77701a1bdc327e2cd20116e4e..ff59e2a49e122880bb25a0fbde3fd1d530d4b1d1 100644
--- a/src/common/common_include.h
+++ b/src/common/common_include.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file common_include.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 公共引用文件(所有组件都需包含此文件)
*
******************************************************************************
@@ -29,6 +29,8 @@ extern "C" {
#include
#include
#include
+#include
+#include
/**
* @addtogroup common
@@ -46,6 +48,10 @@ extern "C" {
* @{
*/
+#define _USE_PRINT_LOG (1u) /*!< 打印接口开关 0:关闭 1:打开 */
+#define _USE_ASSERT_PARAM (1u) /*!< 参数检查开关 0:关闭 1:打开 */
+#define _USE_TIME_STAMP (1u) /*!< 时间戳相关内容开关 0:关闭 1:打开 */
+
/**
* @defgroup generic_error_codes generic error codes
* @{
@@ -66,9 +72,9 @@ extern "C" {
* @defgroup print_log_macros print log macros
* @{
*/
-#define _USE_PRINT_LOG (1u) /*!< 打印接口开关 0:关闭 1:打开 */
#if _USE_PRINT_LOG
- #include "SEGGER_RTT.h"
+/* 用户引入头文件并修改PRINT_LOG宏定义内容以对接打印接口 */
+#include "SEGGER_RTT.h"
/* 普通级别日志输出 */
#ifndef PRINT_LOG
#define PRINT_LOG(fmt, args...) do { \
@@ -77,7 +83,7 @@ extern "C" {
#endif
#else
#ifndef PRINT_LOG
- #define PRINT_LOG(fmt, args...) (void)(0)
+ #define PRINT_LOG(fmt, args...) ((void)0)
#endif
#endif
/* DEBUG级别日志输出 */
@@ -146,8 +152,8 @@ extern "C" {
#define CRITICAL_UNLOCK() BASEPRI = lockState; \
}
#else
-#define CRITICAL_LOCK() (void)(0)
-#define CRITICAL_UNLOCK() (void)(0)
+#define CRITICAL_LOCK() ((void)0)
+#define CRITICAL_UNLOCK() ((void)0)
#endif
/**
* @}
@@ -226,9 +232,9 @@ extern "C" {
#ifndef BIT_TOGGLE
#define BIT_TOGGLE(val, bitx) ((val) ^ (1u << (bitx)))
#endif
-/* 替换位 BIT_REPLACE(0xF0,0x03,1)=0xF1 BIT_REPLACE(0x0F,0xF7,4)=0x07 */
+/* 替换位 BIT_REPLACE(0xF0,0x03,0)=0xF1 BIT_REPLACE(0x0F,0xFE,0)=0x0E */
#ifndef BIT_REPLACE
- #define BIT_REPLACE(sVal, dVal, num) (((sVal) & (~((1u << (num)) - 1u))) | ((dVal) & ((1u << (num)) - 1u)))
+ #define BIT_REPLACE(sVal, dVal, num) (((sVal) & (~(1u << (num)))) | ((dVal) & (1u << (num))))
#endif
/**
* @}
@@ -259,7 +265,6 @@ extern "C" {
* @defgroup parameter_check_macros parameter check macros
* @{
*/
-#define _USE_ASSERT_PARAM (1u) /*!< 参数检查开关 0:关闭 1:打开 */
#if _USE_ASSERT_PARAM
/* 参数检查 */
#ifndef ASSERT_PARAM
@@ -272,7 +277,7 @@ extern "C" {
#endif
#else
#ifndef ASSERT_PARAM
- #define ASSERT_PARAM(x) (void)(0)
+ #define ASSERT_PARAM(x) ((void)0)
#endif
#endif
/* 指针有效性检查 */
@@ -310,6 +315,49 @@ extern "C" {
*/
/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup common_include_global_types common include global types
+ * @{
+ */
+
+/**
+ * @brief 常用普通函数类型
+ *
+ * @param None
+ *
+ * @retval None
+ */
+typedef void (* module_normal_fn_t)(void);
+
+/**
+ * @brief 常用读写数据类型
+ *
+ * @param data : 写入数据的存储区 / 读取数据的存储区
+ *
+ * @param len : 写入的数据大小 / 读取的数据大小 byte
+ *
+ * @retval 实际写入的数据大小 / 实际读取的数据大小 byte
+ */
+typedef uint32_t (* module_read_write_fn_t)(void *data, uint32_t len);
+
+/**
+ * @brief 组件时间 structure definition
+ */
+#if _USE_TIME_STAMP
+typedef struct module_time {
+ uint16_t year; /*!< 年 20xx */
+ uint8_t month; /*!< 月 1~12 */
+ uint8_t day; /*!< 日 1~31 */
+ uint8_t week; /*!< 周 1~7 */
+ uint8_t hour; /*!< 时 0~23 */
+ uint8_t minute; /*!< 分 0~59 */
+ uint8_t second; /*!< 秒 0~59 */
+} module_time_t;
+#endif
+
+/**
+ * @}
+ */
/* 全局变量-------------------------------------------------------------------*/
@@ -322,6 +370,16 @@ extern "C" {
void module_tick_inc(uint32_t ticks);
uint32_t module_tick_get(void);
+#if _USE_TIME_STAMP
+void module_time_stamp_init(uint32_t baseTime);
+void module_time_stamp_1s(void);
+uint32_t module_time_stamp_get(void);
+
+uint32_t module_time_stamp_conv(module_time_t moduleTime);
+void module_time_std_conv(module_time_t *_time, uint32_t timeStamp);
+void module_time_sntp_conv(module_time_t *_time, char *sntpTime);
+#endif
+
/**
* @}
*/
diff --git a/src/devices/communication/esp8266.c b/src/devices/communication/esp8266.c
new file mode 100644
index 0000000000000000000000000000000000000000..cf2446c6fb6a7e41c84f87f5d03c1d9fa6bad0d5
--- /dev/null
+++ b/src/devices/communication/esp8266.c
@@ -0,0 +1,447 @@
+/**
+ ******************************************************************************
+ * @file esp8266.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief ESP8266模组AT指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-09 ashuai0110 完成基本内容
+ * 2024-03-26 ashuai0110 增加联网,SNTP,TCP GET相关接口
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "esp8266.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup esp8266 esp8266
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+/* WIFI名称和密码 */
+#define WIFI_SSID "MNIAS"
+#define WIFI_PWD "1234567890"
+
+/* 实时时间API NowAPI网站提供 */
+#define TIME_REMOTE_ADDR "103.205.5.228" /* 远程地址 */
+#define TIME_REMOTE_PORT (80u) /* 远程端口 */
+#define TIME_API_APPKEY "62987"
+#define TIME_API_SIGN "7310da9ba4f82cd822b861cea2a387a7"
+#define REAL_TIME_API "https://sapi.k780.com/?app=life.time&appkey="TIME_API_APPKEY"&sign="TIME_API_SIGN"&format=json"
+
+/* 实时天气API 心知天气网站提供 */
+#define WEATHER_REMOTE_ADDR "116.62.81.138" /* 远程地址 */
+#define WEATHER_REMOTE_PORT (80u) /* 远程端口 */
+#define WEATHER_KEY "Syma8NgtbsU1_xJ34"
+#define WEATHER_LOCATION "nanjing"
+#define REAL_WEATHER_API "https://api.seniverse.com/v3/weather/now.json?key="WEATHER_KEY"&location="WEATHER_LOCATION"&language=zh-Hans&unit=c"
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+/**
+ * @defgroup esp8266_local_variables esp8266 local variables
+ * @{
+ */
+
+static esp8266_t esp8266; /*!< esp8266管理实例 */
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+/**
+ * @defgroup esp8266_local_functions esp8266 local functions
+ * @{
+ */
+
+/**
+ * @brief 删除指定字符并重组字符串
+ *
+ * @param str : 重组的字符串
+ *
+ * @param target : 删除的字符
+ *
+ * @retval None
+ */
+static void esp8266_delete_char(char *str, char target)
+{
+ uint16_t i, j;
+
+ for(i = 0, j = 0; i < strlen(str); i++)
+ {
+ if(str[i] != target)
+ {
+ str[j++] = str[i];
+ }
+ }
+ str[j] = '\0';
+}
+
+/**
+ * @brief 处理心知天气json数据
+ *
+ * @param src : json源数据
+ *
+ * @param _weather : 存放天气信息的结构体
+ *
+ * @retval None
+ */
+static void weather_json_handle(char *src, weather_t *_weather)
+{
+ cJSON *res, *now, *res2;
+ cJSON *cjson;
+
+ esp8266_delete_char(src, '[');
+ esp8266_delete_char(src, ']');
+ cjson = cJSON_Parse(src);
+ if(cjson)
+ {
+ res = cJSON_GetObjectItem(cjson, "results");
+ now = cJSON_GetObjectItem(res, "now");
+ res2 = cJSON_GetObjectItem(now, "code");
+ _weather->weatherCode = atoi(res2->valuestring);
+ res2 = cJSON_GetObjectItem(now, "temperature");
+ if(*res2->valuestring < '0')
+ {
+ _weather->temperature = 0;
+ }
+ else
+ {
+ _weather->temperature = atoi(res2->valuestring);
+ }
+ res2 = cJSON_GetObjectItem(now, "pressure");
+ _weather->pressure = atoi(res2->valuestring);
+ res2 = cJSON_GetObjectItem(now, "humidity");
+ _weather->humidity = atoi(res2->valuestring);
+ res2 = cJSON_GetObjectItem(now, "wind_scale");
+ _weather->windScale = atoi(res2->valuestring);
+ DEBUG_LOG("tianqi:%d, temperature:%d, pressure:%d, humidity:%d, windScale:%d", _weather->weatherCode, _weather->temperature, _weather->pressure, _weather->humidity, _weather->windScale);
+ }
+ else
+ {
+ ERROR_LOG("weather json error!");
+ }
+ cJSON_Delete(cjson);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup esp8266_global_functions esp8266 global functions
+ * @{
+ */
+
+/**
+ * @brief esp8266初始化
+ *
+ * @param readFn : 读数据接口
+ *
+ * @param writeFn : 写数据接口
+ *
+ * @retval None
+ */
+void esp8266_init(cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn)
+{
+ cmd_at_init(&esp8266.esp8266CmdAt, ESP8266_HEAD, ESP8266_TAIL, readFn, writeFn, 3000, 0);
+}
+
+/**
+ * @brief esp8266置位外部接收标志
+ *
+ * @note 在接收完成的地方调用
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void esp8266_set_rec_flag(void)
+{
+ cmd_at_set_rec_flag(&esp8266.esp8266CmdAt);
+}
+
+/**
+ * @brief esp8266获取管理实例
+ *
+ * @param None
+ *
+ * @retval 返回esp8266管理实例
+ */
+esp8266_t *esp8266_get_this(void)
+{
+ return &esp8266;
+}
+
+/**
+ * @brief 连接WIFI
+ *
+ * @param None
+ *
+ * @retval 返回结果
+ * @arg RET_OK : 连接成功
+ * @arg RET_ERR : 连接失败
+ * @arg RET_ING : 运行中
+ */
+uint8_t esp8266_connect_wifi(void)
+{
+ uint8_t ret = RET_ING;
+
+ switch(esp8266.state)
+ {
+ case 0:
+ /* 关闭回显 Tx:ATE0\r\n Rx:OK */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_ATE_RET, ESP8266_W_ATE, 0);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("close re-display error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 1: /* 设置WIFI模式为STA Tx:AT+CWMODE=1\r\n Rx:OK */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CWMODE_RET, ESP8266_W_CWMODE, 1);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("set wifi mode sta error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 2: /* 设置WIFI参数并连接WIFI Tx:AT+CWJAP="ssid","pwd"\r\n Rx:GOT IP */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CWJAP_RET, ESP8266_W_CWJAP, WIFI_SSID, WIFI_PWD);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_OK; /* 因为连接时间较长,回复内容多段且间隔大,故不做错误处理 */
+ esp8266.state = 0;
+ }
+ else if(RET_OK == ret)
+ {
+ esp8266.state = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief SNTP获取时间
+ *
+ * @param None
+ *
+ * @retval 返回结果
+ * @arg RET_OK : 连接成功
+ * @arg RET_ERR : 连接失败
+ * @arg RET_ING : 运行中
+ */
+uint8_t esp8266_sntp(void)
+{
+ uint8_t ret = RET_ING;
+
+ switch(esp8266.state)
+ {
+ case 0:
+ /* 设置SNTP Tx:AT+CIPSNTPCFG=1,8,"xxx"\r\n Rx:OK */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPSNTPCFG_RET, ESP8266_W_CIPSNTPCFG);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("set sntp error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 1: /* 读取SNTP时间 Tx:AT+CIPSNTPTIME?\r\n Rx:+CIPSNTPTIME: */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_R_CIPSNTPTIME_RET, ESP8266_R_CIPSNTPTIME);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("read sntp error!");
+ }
+ else if(RET_OK == ret)
+ {
+ module_time_sntp_conv(&esp8266.sntpTime, cmd_at_rsp_data(&esp8266.esp8266CmdAt));
+ module_time_stamp_init(module_time_stamp_conv(esp8266.sntpTime));
+ esp8266.state = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief 建立TCP使用GET方法获取API内容(心知天气)
+ *
+ * @param None
+ *
+ * @retval 返回结果
+ * @arg RET_OK : 连接成功
+ * @arg RET_ERR : 连接失败
+ * @arg RET_ING : 运行中
+ */
+uint8_t esp8266_tcp_get_weather(void)
+{
+ uint8_t ret = RET_ING;
+
+ switch(esp8266.state)
+ {
+ case 0: /* 设置单连接 Tx:AT+CIPMUX=0\r\n Rx:OK */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPMUX_RET, ESP8266_W_CIPMUX, 0);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("set single connect error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 1: /* 建立TCP连接 Tx:AT+CIPSTART="TCP","addr",port\r\n Rx:CONNECT */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPSTART_RET, ESP8266_W_CIPSTART, "TCP", WEATHER_REMOTE_ADDR, WEATHER_REMOTE_PORT);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("set tcp connect error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 2: /* 设置WIFI透传传输模式 Tx:AT+CIPMODE=1\r\n Rx:OK */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPMODE_RET, ESP8266_W_CIPMODE, 1);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("set wifi transmit mode error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 3: /* 进入发送数据模式 Tx:AT+CIPSEND\r\n Rx:> */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPSEND_RET, ESP8266_W_CIPSEND);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("entry transmit mode error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 4: /* 发送数据 Tx:GET https://xxx.com\r\n Rx:results */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, "results", ESP8266_W_GET, REAL_WEATHER_API);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ING;
+ esp8266.state = 6;
+ ERROR_LOG("transmit data error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 5:
+// DEBUG_LOG("ret:%s", cmd_at_rsp_data(&esp8266.esp8266CmdAt));
+ weather_json_handle(cmd_at_rsp_data(&esp8266.esp8266CmdAt), &esp8266.weather);
+ ret = RET_ING;
+ esp8266.state += 1;
+ break;
+ case 6: /* 退出透传 Tx:+++ Rx: */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, NULL, ESP8266_W_EXIT);
+ if(RET_ERR == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("exit transmit error!");
+ }
+ else if(RET_OK == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 7: /* 关闭TCP连接 Tx:AT+CIPCLOSE\r\n Rx:CLOSED */
+ ret = cmd_at_process_poll(&esp8266.esp8266CmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, ESP8266_W_CIPCLOSE_RET, ESP8266_W_CIPCLOSE);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ esp8266.state = 0;
+ ERROR_LOG("tcp disconnect error!");
+ }
+ else if(RET_OK == ret)
+ {
+ ret = RET_ING;
+ esp8266.state += 1;
+ }
+ break;
+ case 8:
+ ret = RET_OK;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/src/devices/communication/esp8266.h b/src/devices/communication/esp8266.h
new file mode 100644
index 0000000000000000000000000000000000000000..49756fd8006982eea4e4b9b3fbb4d137a101ead7
--- /dev/null
+++ b/src/devices/communication/esp8266.h
@@ -0,0 +1,165 @@
+/**
+ ******************************************************************************
+ * @file esp8266.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief ESP8266模组AT指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __ESP8266_H
+#define __ESP8266_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+#include "command_at.h"
+#include "cJSON.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup esp8266 esp8266
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup esp8266_global_macros esp8266 global macros
+ * @{
+ */
+
+#define ESP8266_HEAD "AT+" /* AT指令帧头 */
+#define ESP8266_TAIL "\r\n" /* AT指令帧尾 */
+
+/* 设置回显开关 */
+#define ESP8266_W_ATE "ATE%d\r\n" /* 设置回显开关 0:关闭 1:开启 */
+#define ESP8266_W_ATE_RET "OK" /*!< 设置命令的回复 */
+
+/* 设置WIFI模式 */
+#define ESP8266_W_CWMODE "AT+CWMODE=%d\r\n" /*!< 设置WIFI模式 1:STA 2:AP */
+#define ESP8266_W_CWMODE_RET "OK" /*!< 设置命令的回复 */
+/* 设置WIFI参数并连接WIFI */
+#define ESP8266_W_CWJAP "AT+CWJAP=\"%s\",\"%s\"\r\n" /*!< 设置WIFI参数 ssid 密码 */
+#define ESP8266_W_CWJAP_RET "GOT IP" /*!< 设置命令的回复 */
+/* 读取WIFI状态和信息 */
+#define ESP8266_R_CWSTATE "AT+CWSTATE?\r\n" /*!< 获取WIFI状态和信息 */
+#define ESP8266_R_CWSTATE_RET "+CWSTATE:" /*!< 读取命令的回复 */
+
+/* 读取/设置时区和SNTP服务器 */
+#define ESP8266_W_CIPSNTPCFG "AT+CIPSNTPCFG=1,8,\"210.72.145.44\",\"cn.ntp.org.cn\",\"ntp.sjtu.edu.cn\"\r\n" /*!< 设置时区和SNTP服务器 中国北京时间 */
+#define ESP8266_W_CIPSNTPCFG_RET "OK" /*!< 设置命令的回复 */
+#define ESP8266_R_CIPSNTPCFG "AT+CIPSNTPCFG?\r\n" /*!< 读取时区和SNTP服务器 */
+#define ESP8266_R_CIPSNTPCFG_RET "+CIPSNTPCFG:" /*!< 读取命令的回复 */
+/* 读取SNTP时间 */
+#define ESP8266_R_CIPSNTPTIME "AT+CIPSNTPTIME?\r\n" /*!< 读取SNTP时间 */
+#define ESP8266_R_CIPSNTPTIME_RET "+CIPSNTPTIME:" /*!< 读取命令的回复 */
+/* 读取TCP/UDP/SSL连接信息 */
+#define ESP8266_R_CIPSTATE "AT+CIPSTATE?\r\n" /*!< 读取TCP/UDP/SSL连接信息 */
+#define ESP8266_R_CIPSTATE_RET "+CIPSTATE:" /*!< 读取命令的回复 */
+/* 域名解析 */
+#define ESP8266_R_CIPDOMAIN "AT+CIPDOMAIN=\"%s\"\r\n" /*!< 域名解析 网址 */
+#define ESP8266_R_CIPDOMAIN_RET "+CIPDOMAIN:" /*!< 读取命令的回复 */
+/* 设置连接模式 */
+#define ESP8266_W_CIPMUX "AT+CIPMUX=%d\r\n" /*!< 设置连接模式 0:单连接 1:多连接 */
+#define ESP8266_W_CIPMUX_RET "OK" /*!< 设置命令的回复 */
+/* 建立TCP/UDP/SSL连接 */
+#define ESP8266_W_CIPSTART "AT+CIPSTART=\"%s\",\"%s\",%d\r\n" /*!< 建立TCP/UDP/SSL连接 网络类型:"TCP","UDP" 远端ipv4地址 远端端口号 */
+#define ESP8266_W_CIPSTART_RET "CONNECT" /*!< 设置命令的回复 */
+/* 关闭TCP/UDP/SSL连接 */
+#define ESP8266_W_CIPCLOSE "AT+CIPCLOSE\r\n" /*!< 关闭TCP/UDP/SSL单连接 */
+#define ESP8266_W_CIPCLOSE_RET "CLOSED" /*!< 设置命令的回复 */
+/* 设置传输模式 */
+#define ESP8266_W_CIPMODE "AT+CIPMODE=%d\r\n" /*!< 设置传输模式 0:普通传输模式 1:WIFI透传模式 */
+#define ESP8266_W_CIPMODE_RET "OK" /*!< 设置命令的回复 */
+/* 在普通传输模式或WIFI透传模式下发送数据 */
+#define ESP8266_W_CIPSEND "AT+CIPSEND\r\n" /*!< WIFI透传模式下发送数据 */
+#define ESP8266_W_CIPSEND_RET ">" /*!< 设置命令的回复 */
+/* GET */
+#define ESP8266_W_GET "GET %s\r\n" /*!< 发送GET请求 网址 */
+/* 退出数据模式(普通传输模式或WIFI透传模式) */
+#define ESP8266_W_EXIT "+++" /*!< 退出数据模式 发送前后需保证至少50ms没有数据传输 下一条AT指令应间隔1s再发 */
+/* 设置本地TCP/SSL服务器超时时间 */
+#define ESP8266_W_CIPSTO "AT+CIPSTO=%d\r\n" /*!< 设置本地TCP/SSL超时时间 0~7200s */
+#define ESP8266_W_CIPSTO_RET "OK" /*!< 设置命令的回复 */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup esp8266_global_types esp8266 global types
+ * @{
+ */
+
+typedef struct weather {
+ uint8_t weatherCode; /*!< 天气代码 */
+ uint8_t temperature; /*!< 温度℃ */
+ uint16_t pressure; /*!< 气压mb */
+ uint8_t humidity; /*!< 湿度% */
+ uint8_t windScale; /*!< 风力等级 */
+} weather_t;
+
+/**
+ * @brief esp8266 structure definition
+ */
+typedef struct esp8266 {
+ cmd_at_t esp8266CmdAt; /*!< AT指令管理实例 */
+ module_time_t sntpTime; /*!< sntp时间信息 */
+ weather_t weather; /*!< 天气信息 */
+ uint8_t state; /*!< 流程状态 */
+} esp8266_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup esp8266_global_functions
+ * @{
+ */
+
+void esp8266_init(cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn);
+
+void esp8266_set_rec_flag(void);
+esp8266_t *esp8266_get_this(void);
+
+uint8_t esp8266_connect_wifi(void);
+uint8_t esp8266_sntp(void);
+uint8_t esp8266_tcp_get_weather(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* esp8266.h */
diff --git a/src/devices/communication/hongjia_ble.c b/src/devices/communication/hongjia_ble.c
new file mode 100644
index 0000000000000000000000000000000000000000..039ffefda69afa31c6132d956568feb1254a806b
--- /dev/null
+++ b/src/devices/communication/hongjia_ble.c
@@ -0,0 +1,52 @@
+/**
+ ******************************************************************************
+ * @file hongjia_ble.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief 宏佳电子HJ-131蓝牙模组指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-02-20 ashuai0110 完成基本内容
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "hongjia_ble.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup hongjia_ble hongjia_ble
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/src/devices/communication/hongjia_ble.h b/src/devices/communication/hongjia_ble.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c9d2d7efdc37de94c2b17a529789a08b337b5c0
--- /dev/null
+++ b/src/devices/communication/hongjia_ble.h
@@ -0,0 +1,133 @@
+/**
+ ******************************************************************************
+ * @file hongjia_ble.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief 宏佳电子HJ-131蓝牙模组指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __HONGJIA_BLE_H
+#define __HONGJIA_BLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup hongjia_ble hongjia_ble
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup hongjia_ble_global_macros hongjia ble global macros
+ * @{
+ */
+
+#define HJ_BLE_AT_CMD_HEAD "<" /* AT指令帧头 */
+#define HJ_BLE_AT_CMD_TAIL ">" /* AT指令帧尾 */
+
+/* 设置/读取蓝牙英文名称 */
+#define HJ_BLE_ST_NAME "" /*!< 设置蓝牙英文名称 */
+#define HJ_BLE_RD_NAME "" /*!< 读取蓝牙英文名称 */
+#define HJ_BLE_ST_NAME_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_NAME_RET "" /*!< 读取成功的应答 */
+/* 广播开启与停止/查询 */
+#define HJ_BLE_ST_ADV_ONOFF "" /*!< 开关广播 1:开启 0:关闭 */
+#define HJ_BLE_RD_ADV_ONOFF "" /*!< 查询广播状态 */
+#define HJ_BLE_ST_ADV_ONOFF_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_ADV_ONOFF_RET "" /*!< 查询成功的应答 同上 */
+/* 设置/读取广播数据 */
+#define HJ_BLE_ST_ADV_DATA "" /*!< 设置广播数据 "1234"表示广播0x12 0x34 */
+#define HJ_BLE_RD_ADV_DATA "" /*!< 读取广播数据 */
+#define HJ_BLE_ST_ADV_DATA_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_ADV_DATA_RET "" /*!< 读取成功的应答 同上 */
+/* 设置/读取广播间隙 */
+#define HJ_BLE_ST_ADV_GAP "" /*!< 设置广播间隙 20~10000对应20ms~10s */
+#define HJ_BLE_RD_ADV_GAP "" /*!< 读取广播间隙 */
+#define HJ_BLE_ST_ADV_GAP_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_ADV_GAP_RET "" /*!< 读取成功的应答 同上 */
+/* 主动断开连接/读取当前连接状态 */
+#define HJ_BLE_ST_DIS_LINK "" /*!< 主动断开连接 */
+#define HJ_BLE_RD_LINK "" /*!< 读取当前连接状态 */
+#define HJ_BLE_ST_DIS_LINK_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_LINK_RET "" /*!< 读取成功的应答 x:"1"正常连接 "0"断开连接 */
+/* 设置/读取模组发射功率 */
+#define HJ_BLE_ST_TX_POWER "" /*!< 设置发射功率dBm "-19.5" "-13.5" "-10" "-7" "-5" "-3.5" "-2" "-1" "0" "+1" "+1.5" "+2.5" */
+#define HJ_BLE_RD_TX_POWER "" /*!< 读取发射功率 */
+#define HJ_BLE_ST_TX_POWER_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_TX_POWER_RET "" /*!< 读取成功的应答 同上 */
+/* 蓝牙复位指令 */
+#define HJ_BLE_ST_RESET_BLE "" /*!< 设置蓝牙复位 模组反馈成功后,将在500ms后复位 */
+#define HJ_BLE_ST_RESET_BLE_RET "" /*!< 设置成功的应答 */
+/* 设置/读取串口波特率 */
+#define HJ_BLE_ST_BAUD "" /*!< 设置串口波特率bps 1200 2400 4800 9600 14400 19200 ... 57600 115200 ... 1000000 */
+#define HJ_BLE_RD_BAUD "" /*!< 读取串口波特率 */
+#define HJ_BLE_ST_BAUD_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_BAUD_RET "" /*!< 读取成功的应答 同上 */
+/* 设置/读取从机最小连接间隙 */
+#define HJ_BLE_ST_CON_MIN_GAP "" /*!< 设置从机最小连接间隙 75~40000对应7.5ms~4s */
+#define HJ_BLE_RD_CON_MIN_GAP "" /*!< 读取从机最小连接间隙 */
+#define HJ_BLE_ST_CON_MIN_GAP_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_CON_MIN_GAP_RET "" /*!< 读取成功的应答 同上 */
+/* 设置/读取从机最大连接间隙 */
+#define HJ_BLE_ST_CON_MAX_GAP "" /*!< 设置从机最大连接间隙 75~40000对应7.5ms~4s */
+#define HJ_BLE_RD_CON_MAX_GAP "" /*!< 读取从机最大连接间隙 */
+#define HJ_BLE_ST_CON_MAX_GAP_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_CON_MAX_GAP_RET "" /*!< 读取成功的应答 同上 */
+/* 设置/读取从机连接超时时间 */
+#define HJ_BLE_ST_CON_TIMEOUT "" /*!< 设置从机连接超时时间 500~8000对应500ms~8s */
+#define HJ_BLE_RD_CON_TIMEOUT "" /*!< 读取从机连接超时时间 */
+#define HJ_BLE_ST_CON_TIMEOUT_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_CON_TIMEOUT_RET "" /*!< 读取成功的应答 同上 */
+/* 查询本机的BLE模组的MAC地址 */
+#define HJ_BLE_RD_BLE_MAC "" /*!< 读取本机MAC地址 */
+#define HJ_BLE_RD_BLE_MAC_RET "" /*!< 读取成功的应答 xx:12个字节的MAC地址 */
+/* 设置用户自定义的MAC地址 */
+#define HJ_BLE_ST_OWN_MAC "" /*!< 设置用户自定义的MAC地址 12字节的MAC地址如"12AB34CD56EF"或"0"取消用户自定义MAC */
+#define HJ_BLE_ST_OWN_MAC_RET "" /*!< 设置成功的应答 */
+/* 设置/读取BLE模组工作模式 */
+#define HJ_BLE_ST_WAKE "" /*!< 设置BLE模组工作模式 "ONCE"本次连接内全速运行 "FOREVER"一直全速运行 "NORMAL"正常唤醒工作模式 */
+#define HJ_BLE_RD_WAKE "" /*!< 读取BLE模组工作模式 */
+#define HJ_BLE_ST_WAKE_RET "" /*!< 设置成功的应答 */
+#define HJ_BLE_RD_WAKE_RET "" /*!< 读取成功的应答 同上小写 */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* hongjia_ble.h */
diff --git a/src/devices/communication/sim900a.c b/src/devices/communication/sim900a.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c8b08db75ef9ed2c4162cc98752309e87d1ee37
--- /dev/null
+++ b/src/devices/communication/sim900a.c
@@ -0,0 +1,239 @@
+/**
+ ******************************************************************************
+ * @file sim900a.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief SIM900A模组AT指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-03 ashuai0110 完成基本内容
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "sim900a.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup sim900a sim900a
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+/**
+ * @defgroup sim900a_local_variables sim900a local variables
+ * @{
+ */
+
+static cmd_at_t sim900aCmdAt; /*!< at指令管理实例 */
+
+static sim900a_t sim900a; /*!< sim900a管理实例 */
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+
+
+/**
+ * @defgroup sim900a_global_functions sim900a global functions
+ * @{
+ */
+
+/**
+ * @brief sim900a初始化
+ *
+ * @param readFn : 读数据接口
+ *
+ * @param writeFn : 写数据接口
+ *
+ * @retval None
+ */
+void sim900a_init(cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn)
+{
+ cmd_at_init(&sim900aCmdAt, SIM900A_HEAD, SIM900A_TAIL, readFn, writeFn, 3000, 0);
+}
+
+/**
+ * @brief sim900a置位外部接收标志
+ *
+ * @note 在接收完成的地方调用
+ *
+ * @param None
+ *
+ * @retval None
+ */
+void sim900a_set_rec_flag(void)
+{
+ cmd_at_set_rec_flag(&sim900aCmdAt);
+}
+
+/**
+ * @brief 校验sim卡状态
+ *
+ * @param None
+ *
+ * @retval 校验结果
+ * @arg RET_OK : sim卡正常
+ * @arg RET_ERR : sim卡异常
+ * @arg RET_ING : 运行中
+ */
+uint8_t sim900a_check_sim(void)
+{
+ uint8_t ret = RET_ING;
+
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, SIM900A_R_CPIN_RET, SIM900A_R_CPIN);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ ERROR_LOG("check sim state error!");
+ }
+
+ return ret;
+}
+
+/**
+ * @brief 启动发送短信
+ *
+ * @param phone : 手机号
+ *
+ * @param message : 短信内容
+ *
+ * @retval 启动结果
+ * @arg RET_OK : 启动成功
+ * @arg RET_ERR : 启动失败(上一个短信未发送完成)
+ */
+uint8_t sim900a_send_mes(const char *phone, const char *message)
+{
+ if(0 == sim900a.state)
+ {
+ sim900a.state = 1;
+ strcpy(sim900a.phone, phone);
+ sim900a.phone[strlen(phone)] = 0;
+ strcpy(sim900a.message, message);
+ sim900a.message[strlen(message)] = 0;
+
+ return RET_OK;
+ }
+
+ return RET_ERR;
+}
+
+/**
+ * @brief 发送短信流程轮询处理
+ *
+ * @param None
+ *
+ * @retval 发送结果
+ * @arg RET_OK : 发送成功
+ * @arg RET_ERR : 发送失败
+ * @arg RET_ING : 运行中
+ */
+uint8_t sim900a_send_mes_poll(void)
+{
+ uint8_t ret = RET_ING;
+
+ switch(sim900a.state)
+ {
+ case 1: /* 查询sim卡状态 Tx:AT+CPIN?\r\n Rx:OK */
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, SIM900A_R_CPIN_RET, SIM900A_R_CPIN);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ sim900a.state = 0;
+ ERROR_LOG("check sim state error!");
+ }
+ else if(RET_OK == ret)
+ {
+ sim900a.state++;
+ }
+ break;
+ case 2: /* 设置短信文本模式 Tx:AT+CMGF=1\r\n Rx:OK */
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, SIM900A_W_CMGF_RET, SIM900A_W_CMGF, 1);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ sim900a.state = 0;
+ ERROR_LOG("set message txt mode error!");
+ }
+ else if(RET_OK == ret)
+ {
+ sim900a.state++;
+ }
+ break;
+ case 3: /* 设置目标手机号 Tx:AT+CMGS="18812341234"\r\n Rx:> */
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, SIM900A_W_CMGS_RET, SIM900A_W_CMGS, sim900a.phone);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ sim900a.state = 0;
+ ERROR_LOG("set phone num error!");
+ }
+ else if(RET_OK == ret)
+ {
+ sim900a.state++;
+ }
+ break;
+ case 4: /* 设置短信内容 Tx:this message Rx:> */
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, SIM900A_W_CMGS_RET, "%s\r\n", sim900a.message);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_ERR;
+ sim900a.state = 0;
+ ERROR_LOG("set message data error!");
+ }
+ else if(RET_OK == ret)
+ {
+ sim900a.state++;
+ }
+ break;
+ case 5: /* 确认发送 Tx:0x1A Rx:OK */
+ sim900a.phone[0] = SIM900A_W_SEND_MES;
+ sim900a.phone[1] = 0;
+ ret = cmd_at_process_poll(&sim900aCmdAt, CMD_AT_RESERVE, CMD_AT_WAY_REC_FLAG, NULL, "%s", sim900a.phone);
+ if(RET_ERR == ret || RET_TIMEOUT == ret)
+ {
+ ret = RET_OK;
+ sim900a.state = 0;
+ }
+ else if(RET_OK == ret)
+ {
+ sim900a.state = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/src/devices/communication/sim900a.h b/src/devices/communication/sim900a.h
new file mode 100644
index 0000000000000000000000000000000000000000..2346d09867851ccb0167e41708bac5326747f21a
--- /dev/null
+++ b/src/devices/communication/sim900a.h
@@ -0,0 +1,118 @@
+/**
+ ******************************************************************************
+ * @file sim900a.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief SIM900A模组AT指令集
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __SIM900A_H
+#define __SIM900A_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+#include "command_at.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup sim900a sim900a
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup sim900a_global_macros sim900a global macros
+ * @{
+ */
+
+#define SIM900A_HEAD "AT+" /* AT指令帧头 */
+#define SIM900A_TAIL "\r\n" /* AT指令帧尾 */
+
+/* 读取sim卡状态 */
+#define SIM900A_R_CPIN "AT+CPIN?\r\n" /*!< 读取sim卡状态 */
+#define SIM900A_R_CPIN_RET "OK" /*!< 读取命令的回复 */
+/* 设置短信的收发模式 */
+#define SIM900A_W_CMGF "AT+CMGF=%d\r\n" /*!< 设置短信的收发模式 0:PDU模式 1:TXT文本模式 */
+#define SIM900A_W_CMGF_RET "OK" /*!< 设置命令的回复 */
+/* 设置目标手机号 */
+#define SIM900A_W_CMGS "AT+CMGS=\"%s\"\r\n" /*!< 设置目标手机号 */
+#define SIM900A_W_CMGS_RET ">" /*!< 设置命令的回复 */
+/* 短信确认发送 */
+#define SIM900A_W_SEND_MES (0x1A) /*!< 短信确认发送 */
+#define SIM900A_W_SEND_MES_RET "OK" /*!< 设置命令的回复 */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup sim900a_global_types sim900a global types
+ * @{
+ */
+
+/**
+ * @brief sim900a structure definition
+ */
+typedef struct sim900a {
+ char message[48]; /*!< 短信数据缓存区 */
+ char phone[16]; /*!< 手机号缓存区 */
+ uint8_t state; /*!< 流程状态 */
+} sim900a_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup sim900a_global_functions
+ * @{
+ */
+
+void sim900a_init(cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn);
+
+void sim900a_set_rec_flag(void);
+
+uint8_t sim900a_check_sim(void);
+
+uint8_t sim900a_send_mes(const char *phone, const char *message);
+
+uint8_t sim900a_send_mes_poll(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sim900a.h */
diff --git a/src/devices/display/oled_096.c b/src/devices/display/oled_096.c
new file mode 100644
index 0000000000000000000000000000000000000000..6fe1f7daf114e89be9ea2737a9d362bebb6221a7
--- /dev/null
+++ b/src/devices/display/oled_096.c
@@ -0,0 +1,690 @@
+/**
+ ******************************************************************************
+ * @file oled_096.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief 0.96英寸OLED屏幕驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-02 ashuai0110 完成基本内容
+ * 2024-04-06 ashuai0110 修改驱动为面向对象形式
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "oled_096.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup oled_096 oled_096
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+/**
+ * @defgroup oled_096_local_macros oled 096 local macros
+ * @{
+ */
+
+/**
+ * @defgroup oled_096_check_parameters_validity oled 096 check parameters validity
+ * @{
+ */
+/* 行有效性检查 */
+#define IS_VALID_X(x) \
+( ((x) == 0) || \
+ ((x) > 0) && \
+ ((x) < OLED_096_COLUMN))
+/* 列有效性检查 */
+#define IS_VALID_Y(x) \
+( ((x) == 0) || \
+ ((x) > 0) && \
+ ((x) < OLED_096_ROW / 8))
+/* 发送标志有效性检查 */
+#define IS_VALID_SEND_FLAG(x) \
+( ((x) == OLED_096_SEND_CMD) || \
+ ((x) == OLED_096_SEND_DATA))
+/* 显示大小有效性检查 */
+#define IS_VALID_FONT_SIZE(x) \
+( ((x) == OLED_096_FONT_SIZE_8) || \
+ ((x) == OLED_096_FONT_SIZE_16))
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+/**
+ * @defgroup oled_096_local_variables oled 096 local variables
+ * @{
+ */
+
+/* ASCII码表 6x8点阵 */
+static const uint8_t ascii6x8[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp
+0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !
+0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "
+0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,// #
+0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,// $
+0x00, 0x62, 0x64, 0x08, 0x13, 0x23,// %
+0x00, 0x36, 0x49, 0x55, 0x22, 0x50,// &
+0x00, 0x00, 0x05, 0x03, 0x00, 0x00,// '
+0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,// (
+0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,// )
+0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,// *
+0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,// +
+0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,// ,
+0x00, 0x08, 0x08, 0x08, 0x08, 0x08,// -
+0x00, 0x00, 0x60, 0x60, 0x00, 0x00,// .
+0x00, 0x20, 0x10, 0x08, 0x04, 0x02,// /
+0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
+0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 1
+0x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2
+0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,// 3
+0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,// 4
+0x00, 0x27, 0x45, 0x45, 0x45, 0x39,// 5
+0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
+0x00, 0x01, 0x71, 0x09, 0x05, 0x03,// 7
+0x00, 0x36, 0x49, 0x49, 0x49, 0x36,// 8
+0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,// 9
+0x00, 0x00, 0x36, 0x36, 0x00, 0x00,// :
+0x00, 0x00, 0x56, 0x36, 0x00, 0x00,// ;
+0x00, 0x08, 0x14, 0x22, 0x41, 0x00,// <
+0x00, 0x14, 0x14, 0x14, 0x14, 0x14,// =
+0x00, 0x00, 0x41, 0x22, 0x14, 0x08,// >
+0x00, 0x02, 0x01, 0x51, 0x09, 0x06,// ?
+0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,// @
+0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,// A
+0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,// B
+0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,// C
+0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,// D
+0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,// E
+0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,// F
+0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,// G
+0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,// H
+0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,// I
+0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,// J
+0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,// K
+0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,// L
+0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,// M
+0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,// N
+0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,// O
+0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,// P
+0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
+0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,// R
+0x00, 0x46, 0x49, 0x49, 0x49, 0x31,// S
+0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,// T
+0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,// U
+0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,// V
+0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,// W
+0x00, 0x63, 0x14, 0x08, 0x14, 0x63,// X
+0x00, 0x07, 0x08, 0x70, 0x08, 0x07,// Y
+0x00, 0x61, 0x51, 0x49, 0x45, 0x43,// Z
+0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,// [
+0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,// 55
+0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,// ]
+0x00, 0x04, 0x02, 0x01, 0x02, 0x04,// ^
+0x00, 0x40, 0x40, 0x40, 0x40, 0x40,// _
+0x00, 0x00, 0x01, 0x02, 0x04, 0x00,// '
+0x00, 0x20, 0x54, 0x54, 0x54, 0x78,// a
+0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,// b
+0x00, 0x38, 0x44, 0x44, 0x44, 0x20,// c
+0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,// d
+0x00, 0x38, 0x54, 0x54, 0x54, 0x18,// e
+0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,// f
+0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,// g
+0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,// h
+0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,// i
+0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,// j
+0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,// k
+0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,// l
+0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,// m
+0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,// n
+0x00, 0x38, 0x44, 0x44, 0x44, 0x38,// o
+0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,// p
+0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,// q
+0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,// r
+0x00, 0x48, 0x54, 0x54, 0x54, 0x20,// s
+0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,// t
+0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,// u
+0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,// v
+0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,// w
+0x00, 0x44, 0x28, 0x10, 0x28, 0x44,// x
+0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,// y
+0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,// z
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14,// horiz lines
+};
+/* ASCII码表 8x16点阵 */
+static const uint8_t ascii8x16[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
+0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
+0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
+0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
+0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
+0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
+0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
+0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
+0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
+0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
+0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
+0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
+0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
+0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
+0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
+0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
+0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
+0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
+0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
+0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
+0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
+0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
+0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
+0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
+0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
+0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
+0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
+0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
+0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
+0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
+0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
+0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
+0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
+0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
+0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
+0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
+0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
+0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
+0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
+0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
+0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
+0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
+0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
+0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
+0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
+0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
+0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
+0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
+0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
+0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
+0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
+0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
+0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
+0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
+0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
+0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
+0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
+0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
+0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
+0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
+0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
+0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
+0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
+0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
+0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
+0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
+0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
+0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
+0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
+0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
+0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
+0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
+0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
+0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
+0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
+0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
+0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
+0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
+0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
+0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
+0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
+0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
+0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
+0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
+0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
+0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
+0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
+0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
+0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
+};
+/* 汉字字库(用户自行添加) 16x16点阵 从上到下是bit0~7 从左到右是byte0~7 */
+static const uint8_t chinese16x16[] = {
+/*-- 文字: 在 --*/
+/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
+0x08,0x08,0x88,0xC8,0x38,0x0C,0x0B,0x08,0x08,0xE8,0x08,0x08,0x08,0x08,0x08,0x00,
+0x02,0x01,0x00,0xFF,0x40,0x41,0x41,0x41,0x41,0x7F,0x41,0x41,0x41,0x41,0x40,0x00,
+};
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+/**
+ * @defgroup oled_096_local_functions oled 096 local functions
+ * @{
+ */
+
+/**
+ * @brief iic启动条件
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @retval None
+ */
+static void iic_start(oled_096_t *_oled)
+{
+ _oled->sclWrFn(1);
+ _oled->sdaWrFn(1);
+ _oled->sdaWrFn(0);
+ _oled->sclWrFn(0);
+}
+
+/**
+ * @brief iic停止条件
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @retval None
+ */
+static void iic_stop(oled_096_t *_oled)
+{
+ _oled->sclWrFn(1);
+ _oled->sdaWrFn(0);
+ _oled->sdaWrFn(1);
+}
+
+/**
+ * @brief iic等待ack
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @retval None
+ */
+static void iic_wait_ack(oled_096_t *_oled)
+{
+ _oled->sclWrFn(1);
+ _oled->sclWrFn(0);
+}
+
+/**
+ * @brief iic发送一个字节
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param byte : 一字节数据
+ *
+ * @retval None
+ */
+static void iic_write_byte(oled_096_t *_oled, uint8_t byte)
+{
+ uint8_t cnt;
+
+ for(cnt = 0; cnt < 8; cnt++)
+ {
+ if(byte & 0x80)
+ {
+ _oled->sdaWrFn(1);
+ }
+ else
+ {
+ _oled->sdaWrFn(0);
+ }
+ byte <<= 1;
+ _oled->sclWrFn(1);
+ _oled->sclWrFn(0);
+ }
+}
+
+/**
+ * @brief iic发送多字节
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param bytes : 发送数据
+ *
+ * @param len : 数据长度
+ *
+ * @param sendFlg : 发送标志 @ref oled_096_send_flag
+ * @arg OLED_096_SEND_CMD : 发送命令
+ * @arg OLED_096_SEND_DATA : 发送数据
+ *
+ * @retval None
+ */
+static void iic_write_bytes(oled_096_t *_oled, const uint8_t *bytes, uint8_t len, uint8_t sendFlg)
+{
+ ASSERT_PARAM(IS_VALID_SEND_FLAG(sendFlg));
+
+ iic_start(_oled);
+ iic_write_byte(_oled, OLED_096_WR_ADDR);
+ iic_wait_ack(_oled);
+ iic_write_byte(_oled, sendFlg);
+ iic_wait_ack(_oled);
+ while(len--)
+ {
+ iic_write_byte(_oled, *bytes++);
+ iic_wait_ack(_oled);
+ }
+ iic_stop(_oled);
+}
+
+/**
+ * @brief iic发送相同数据
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param data : 数据
+ *
+ * @param len : 数据长度
+ *
+ * @retval None
+ */
+static void iic_write_same_data(oled_096_t *_oled, uint8_t data, uint8_t len)
+{
+ iic_start(_oled);
+ iic_write_byte(_oled, OLED_096_WR_ADDR);
+ iic_wait_ack(_oled);
+ iic_write_byte(_oled, 0x40);
+ iic_wait_ack(_oled);
+ while(len--)
+ {
+ iic_write_byte(_oled, data);
+ iic_wait_ack(_oled);
+ }
+ iic_stop(_oled);
+}
+
+/**
+ * @brief 设置显示坐标
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @retval None
+ */
+static void oled_096_set_position(oled_096_t *_oled, uint8_t x, uint8_t y)
+{
+ uint8_t cmdTmp[3];
+
+ cmdTmp[0] = 0xB0 + y;
+ cmdTmp[1] = ((x & 0xF0) >> 4) | 0x10;
+ cmdTmp[2] = x & 0x0F;
+
+ iic_write_bytes(_oled, cmdTmp, 3, OLED_096_SEND_CMD);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup oled_096_global_functions oled 096 global functions
+ * @{
+ */
+
+/**
+ * @brief 0.96英寸oled初始化
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param sclWrFn : 时钟线IO写接口
+ *
+ * @param sdaWrFn : 数据线IO写接口
+ *
+ * @retval None
+ */
+void oled_096_init(oled_096_t *_oled, void (* sclWrFn)(uint8_t), void (* sdaWrFn)(uint8_t))
+{
+ uint8_t initCmd[27] = {0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F, 0xC8, \
+ 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12, 0xDB, 0x30, 0x8D, 0x14, 0xAF};
+
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_POINT(sclWrFn));
+ ASSERT_PARAM(IS_VALID_POINT(sdaWrFn));
+
+ _oled->sclWrFn = sclWrFn;
+ _oled->sdaWrFn = sdaWrFn;
+ iic_write_bytes(_oled, initCmd, 27, OLED_096_SEND_CMD);
+ oled_096_clear_display(_oled);
+}
+
+/**
+ * @brief 清除显示内容
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @retval None
+ */
+void oled_096_clear_display(oled_096_t *_oled)
+{
+ uint8_t cnt = 0;
+
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+
+ while(cnt++ < 8)
+ {
+ oled_096_set_position(_oled, 0, cnt);
+ iic_write_same_data(_oled, 0x00, OLED_096_COLUMN);
+ }
+}
+
+/**
+ * @brief 显示数字(长度不够时显示空格)
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @param num : 显示的数字
+ *
+ * @param len : 数字的长度byte
+ *
+ * @param fontSize : 显示的大小 @ref oled_096_font_size
+ * @arg OLED_096_FONT_SIZE_8 : 6x8点阵
+ * @arg OLED_096_FONT_SIZE_16 : 8x16点阵
+ *
+ * @retval None
+ */
+void oled_096_show_num(oled_096_t *_oled, uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t fontSize)
+{
+ char tmp;
+
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_X(x));
+ ASSERT_PARAM(IS_VALID_Y(y));
+ ASSERT_PARAM(IS_VALID_FONT_SIZE(fontSize));
+
+ while(len--)
+ {
+ tmp = num / (uint32_t)pow(10, len) % 10;
+ if(tmp)
+ {
+ oled_096_show_char(_oled, x, y, tmp + '0', fontSize);
+ }
+ else
+ {
+ oled_096_show_char(_oled, x, y, ' ', fontSize);
+ }
+ x = x + (fontSize == OLED_096_FONT_SIZE_8 ? 6 : 8);
+ }
+}
+
+/**
+ * @brief 显示数字(长度不够时显示0)
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @param num : 显示的数字
+ *
+ * @param len : 数字的长度byte
+ *
+ * @param fontSize : 显示的大小 @ref oled_096_font_size
+ * @arg OLED_096_FONT_SIZE_8 : 6x8点阵
+ * @arg OLED_096_FONT_SIZE_16 : 8x16点阵
+ *
+ * @retval None
+ */
+void oled_096_show_num2(oled_096_t *_oled, uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t fontSize)
+{
+ char tmp;
+
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_X(x));
+ ASSERT_PARAM(IS_VALID_Y(y));
+ ASSERT_PARAM(IS_VALID_FONT_SIZE(fontSize));
+
+ while(len--)
+ {
+ tmp = num / (uint32_t)pow(10, len) % 10;
+ if(tmp)
+ {
+ oled_096_show_char(_oled, x, y, tmp + '0', fontSize);
+ }
+ else
+ {
+ oled_096_show_char(_oled, x, y, '0', fontSize);
+ }
+ x = x + (fontSize == OLED_096_FONT_SIZE_8 ? 6 : 8);
+ }
+}
+
+/**
+ * @brief 显示字符
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @param c : 显示的字符
+ *
+ * @param fontSize : 显示的大小 @ref oled_096_font_size
+ * @arg OLED_096_FONT_SIZE_8 : 6x8点阵
+ * @arg OLED_096_FONT_SIZE_16 : 8x16点阵
+ *
+ * @retval None
+ */
+void oled_096_show_char(oled_096_t *_oled, uint8_t x, uint8_t y, char c, uint8_t fontSize)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_X(x));
+ ASSERT_PARAM(IS_VALID_Y(y));
+ ASSERT_PARAM(IS_VALID_FONT_SIZE(fontSize));
+
+ c -= ' ';
+ if(OLED_096_FONT_SIZE_8 == fontSize)
+ {
+ oled_096_set_position(_oled, x, y);
+ iic_write_bytes(_oled, &ascii6x8[c * 6], 6, OLED_096_SEND_DATA);
+ }
+ else if(OLED_096_FONT_SIZE_16 == fontSize)
+ {
+ oled_096_set_position(_oled, x, y);
+ iic_write_bytes(_oled, &ascii8x16[c * 16], 8, OLED_096_SEND_DATA);
+ oled_096_set_position(_oled, x, y + 1);
+ iic_write_bytes(_oled, &ascii8x16[c * 16 + 8], 8, OLED_096_SEND_DATA);
+ }
+}
+
+/**
+ * @brief 显示字符串
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @param str : 显示的字符串
+ *
+ * @param fontSize : 显示的大小 @ref oled_096_font_size
+ * @arg OLED_096_FONT_SIZE_8 : 6x8点阵
+ * @arg OLED_096_FONT_SIZE_16 : 8x16点阵
+ *
+ * @retval None
+ */
+void oled_096_show_string(oled_096_t *_oled, uint8_t x, uint8_t y, const char *str, uint8_t fontSize)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_X(x));
+ ASSERT_PARAM(IS_VALID_Y(y));
+ ASSERT_PARAM(IS_VALID_FONT_SIZE(fontSize));
+
+ while(*str != '\0')
+ {
+ oled_096_show_char(_oled, x, y, *str++, fontSize);
+ x += 8;
+ }
+}
+
+/**
+ * @brief 显示汉字(16x16)
+ *
+ * @param _oled : OLED管理实例
+ *
+ * @param x : x轴坐标(0~127)
+ *
+ * @param y : y轴坐标(0~7)
+ *
+ * @param index : 显示的汉字序号
+ *
+ * @retval None
+ */
+void oled_096_show_chinese(oled_096_t *_oled, uint8_t x, uint8_t y, uint8_t index)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_oled));
+ ASSERT_PARAM(IS_VALID_X(x));
+ ASSERT_PARAM(IS_VALID_Y(y));
+
+ oled_096_set_position(_oled, x, y);
+ iic_write_bytes(_oled, &chinese16x16[index * 32], 16, OLED_096_SEND_DATA);
+ oled_096_set_position(_oled, x, y + 1);
+ iic_write_bytes(_oled, &chinese16x16[index * 32 + 16], 16, OLED_096_SEND_DATA);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/src/devices/display/oled_096.h b/src/devices/display/oled_096.h
new file mode 100644
index 0000000000000000000000000000000000000000..4bfaed953450a9f8e05660535ca19e01c370ac1c
--- /dev/null
+++ b/src/devices/display/oled_096.h
@@ -0,0 +1,124 @@
+/**
+ ******************************************************************************
+ * @file oled_096.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief 0.96英寸OLED屏幕驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __OLED_096_H
+#define __OLED_096_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @addtogroup oled_096
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup oled_096_global_macros oled 096 global macros
+ * @{
+ */
+
+#define OLED_096_WR_ADDR (0x78) /*!< 写地址 */
+#define OLED_096_COLUMN (128u) /*!< 行点数 */
+#define OLED_096_ROW (64u) /*!< 列点数 */
+
+/**
+ * @defgroup oled_096_send_flag oled 096 send flag
+ * @{
+ */
+#define OLED_096_SEND_CMD (0x00) /*!< 发送命令 */
+#define OLED_096_SEND_DATA (0x40) /*!< 发送数据 */
+/**
+ * @}
+ */
+
+/**
+ * @defgroup oled_096_font_size oled 096 font size
+ * @{
+ */
+#define OLED_096_FONT_SIZE_8 (8u) /*!< 6x8点阵 */
+#define OLED_096_FONT_SIZE_16 (16u) /*!< 8x16点阵 */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup oled_096_global_types oled 096 global types
+ * @{
+ */
+
+/**
+ * @brief oled 0.96英寸 structrue definition
+ */
+typedef struct oled_096 {
+ void (* sclWrFn)(uint8_t level); /*!< 时钟线IO写接口 */
+ void (* sdaWrFn)(uint8_t level); /*!< 数据线IO写接口 */
+} oled_096_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup oled_096_global_functions
+ * @{
+ */
+
+void oled_096_init(oled_096_t *_oled, void (* sclWrFn)(uint8_t), void (* sdaWrFn)(uint8_t));
+
+void oled_096_clear_display(oled_096_t *_oled);
+
+void oled_096_show_num(oled_096_t *_oled, uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t fontSize);
+void oled_096_show_num2(oled_096_t *_oled, uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t fontSize);
+void oled_096_show_char(oled_096_t *_oled, uint8_t x, uint8_t y, char c, uint8_t fontSize);
+void oled_096_show_string(oled_096_t *_oled, uint8_t x, uint8_t y, const char *str, uint8_t fontSize);
+void oled_096_show_chinese(oled_096_t *_oled, uint8_t x, uint8_t y, uint8_t index);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* oled_096.h */
diff --git a/src/devices/sensor/by9301.c b/src/devices/sensor/by9301.c
new file mode 100644
index 0000000000000000000000000000000000000000..a8884de62f5bf0e1fc2eaddd416059dd4b601e5c
--- /dev/null
+++ b/src/devices/sensor/by9301.c
@@ -0,0 +1,188 @@
+/**
+ ******************************************************************************
+ * @file by9301.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief BY9301语音播报模块驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-31 ashuai0110 完成基本内容
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "by9301.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup by9301 by9301
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+/**
+ * @defgroup by9301_local_variables by9301 local variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+/**
+ * @defgroup by9301_local_functions by9301 local functions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup by9301_global_functions by9301 global functions
+ * @{
+ */
+
+/**
+ * @brief BY9301初始化
+ *
+ * @param _by9301 : BY9301管理实例
+ *
+ * @param readFn : IO端口模式设置函数
+ *
+ * @param writeFn : IO端口读写函数
+ *
+ * @retval None
+ */
+void by9301_init(by9301_t *_by9301, uint8_t (* ioBusyReadFn)(void), module_read_write_fn_t readFn, module_read_write_fn_t writeFn)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_by9301));
+ ASSERT_PARAM(IS_VALID_POINT(readFn));
+ ASSERT_PARAM(IS_VALID_POINT(writeFn));
+
+ memset((void *)_by9301, 0, sizeof(by9301_t));
+ _by9301->ioBusyReadFn = ioBusyReadFn;
+ _by9301->readFn = readFn;
+ _by9301->writeFn = writeFn;
+}
+
+/**
+ * @brief BY9301指定序号播放
+ *
+ * @param _by9301 : BY9301管理实例
+ *
+ * @param num : 播放MP3的序号1~255
+ *
+ * @param mode : 播放模式
+ * @arg BY9301_BUSY : 忙时不播放(依据busy端口判断是否播放)
+ * @arg BY9301_BREAK : 忙时打断播放(不关心busy端口状态,直接发送播放命令)
+ *
+ * @retval None
+ */
+void by9301_play_with_num(by9301_t *_by9301, uint8_t num, uint8_t mode)
+{
+ uint8_t data[7];
+
+ ASSERT_PARAM(IS_VALID_POINT(_by9301));
+
+ if(BY9301_BUSY == mode)
+ {
+ ASSERT_PARAM(IS_VALID_POINT(_by9301->ioBusyReadFn));
+ if(_by9301->ioBusyReadFn())
+ {
+ return ;
+ }
+ }
+
+ data[0] = 0x7E;
+ data[1] = 0x05;
+ data[2] = 0x41;
+ data[3] = 0x00;
+ data[4] = num;
+ data[5] = data[1]^data[2]^data[3]^data[4];
+ data[6] = 0xEF;
+ _by9301->writeFn((void *)data, 7);
+}
+
+/**
+ * @brief BY9301设置音量
+ *
+ * @param _by9301 : BY9301管理实例
+ *
+ * @param volume : 音量0~30
+ *
+ * @retval None
+ */
+void by9301_set_volume(by9301_t *_by9301, uint8_t volume)
+{
+ uint8_t data[6];
+
+ ASSERT_PARAM(IS_VALID_POINT(_by9301));
+
+ if(volume > 30) volume = 30;
+ data[0] = 0x7E;
+ data[1] = 0x04;
+ data[2] = 0x31;
+ data[3] = volume;
+ data[4] = data[1]^data[2]^data[3];
+ data[5] = 0xEF;
+ _by9301->writeFn((void *)data, 6);
+}
+
+/**
+ * @brief BY9301播放暂停
+ *
+ * @param _by9301 : BY9301管理实例
+ *
+ * @param playPause : 播放暂停标志
+ * @arg BY9301_PAUSE : 暂停
+ * @arg BY9301_PLAY : 播放
+ *
+ * @retval None
+ */
+void by9301_play_pause(by9301_t *_by9301, uint8_t playPause)
+{
+ uint8_t data[5];
+
+ ASSERT_PARAM(IS_VALID_POINT(_by9301));
+
+ data[0] = 0x7E;
+ data[1] = 0x03;
+ data[2] = playPause == BY9301_PLAY ? 0x1 : 0x2;
+ data[3] = data[1]^data[2];
+ data[4] = 0xEF;
+ _by9301->writeFn((void *)data, 5);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/src/devices/sensor/by9301.h b/src/devices/sensor/by9301.h
new file mode 100644
index 0000000000000000000000000000000000000000..29f74d853ec95a26a1163268373f2341ed795e0a
--- /dev/null
+++ b/src/devices/sensor/by9301.h
@@ -0,0 +1,117 @@
+/**
+ ******************************************************************************
+ * @file by9301.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief BY9301语音播报模块驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __BY9301_H
+#define __BY9301_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @addtogroup by9301
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup by9301_global_macros by9301 global macros
+ * @{
+ */
+
+/**
+ * @defgroup by9301_play_pause by9301 play pause
+ * @{
+ */
+#define BY9301_BUSY (0u) /*!< 忙时不播放 */
+#define BY9301_BREAK (1u) /*!< 忙时打断播放 */
+/**
+ * @}
+ */
+
+/**
+ * @defgroup by9301_play_pause by9301 play pause
+ * @{
+ */
+#define BY9301_PAUSE (0u) /*!< 暂停 */
+#define BY9301_PLAY (1u) /*!< 播放 */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup by9301_global_types by9301 global types
+ * @{
+ */
+
+/**
+ * @brief by9301 structure definition
+ */
+typedef struct by9301 {
+ uint8_t (* ioBusyReadFn)(void); /*!< 忙端口读函数 */
+ module_read_write_fn_t readFn; /*!< 数据读函数 */
+ module_read_write_fn_t writeFn; /*!< 数据写函数 */
+} by9301_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup by9301_global_functions
+ * @{
+ */
+
+void by9301_init(by9301_t *_by9301, uint8_t (* ioBusyReadFn)(void), module_read_write_fn_t readFn, module_read_write_fn_t writeFn);
+
+void by9301_play_with_num(by9301_t *_by9301, uint8_t num, uint8_t mode);
+void by9301_set_volume(by9301_t *_by9301, uint8_t volume);
+void by9301_play_pause(by9301_t *_by9301, uint8_t playPause);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* by9301.h */
diff --git a/src/devices/sensor/dht11.c b/src/devices/sensor/dht11.c
new file mode 100644
index 0000000000000000000000000000000000000000..25efbf4ce9baade94e5991b1855c3ffab33d3fb3
--- /dev/null
+++ b/src/devices/sensor/dht11.c
@@ -0,0 +1,267 @@
+/**
+ ******************************************************************************
+ * @file dht11.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief DHT11温湿度模块驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-30 ashuai0110 完成基本内容
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "dht11.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @defgroup dht11 dht11
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+/**
+ * @defgroup dht11_local_variables dht11 local variables
+ * @{
+ */
+
+static void (* dht11DelayUs)(uint32_t us) = NULL;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+/**
+ * @defgroup dht11_local_functions dht11 local functions
+ * @{
+ */
+
+/**
+ * @brief dht11复位信号
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @retval None
+ */
+static __inline void dht11_reset(dht11_t *_dht11)
+{
+ _dht11->ioModeSetFn(DHT11_MODE_OUTPUT);
+ _dht11->ioReadWriteFn(DHT11_MODE_WRITE, 0);
+ dht11DelayUs(20000);
+ _dht11->ioReadWriteFn(DHT11_MODE_WRITE, 1);
+ dht11DelayUs(30);
+}
+
+/**
+ * @brief dht11响应信号
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @retval None
+ */
+static __inline uint8_t dht11_respond(dht11_t *_dht11)
+{
+ uint8_t timeoutCnt = 0;
+
+ _dht11->ioModeSetFn(DHT11_MODE_INPUT);
+
+ while(0 != _dht11->ioReadWriteFn(DHT11_MODE_READ, 0))
+ {
+ if(timeoutCnt++ < 100)
+ {
+ dht11DelayUs(1);
+ }
+ else
+ {
+ return RET_ERR;
+ }
+ }
+ timeoutCnt = 0;
+ while(0 == _dht11->ioReadWriteFn(DHT11_MODE_READ, 0))
+ {
+ if(timeoutCnt++ < 100)
+ {
+ dht11DelayUs(1);
+ }
+ else
+ {
+ return RET_ERR;
+ }
+ }
+
+ return RET_OK;
+}
+
+/**
+ * @brief dht11读1bit
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @retval 0 or 1
+ */
+static __inline uint8_t dht11_read_bit(dht11_t *_dht11)
+{
+ uint8_t timeoutCnt = 0;
+
+ while(0 != _dht11->ioReadWriteFn(DHT11_MODE_READ, 0))
+ {
+ if(timeoutCnt++ < 40)
+ {
+ dht11DelayUs(1);
+ }
+ else
+ {
+ break;
+ }
+ }
+ timeoutCnt = 0;
+ while(0 == _dht11->ioReadWriteFn(DHT11_MODE_READ, 0))
+ {
+ if(timeoutCnt++ < 40)
+ {
+ dht11DelayUs(1);
+ }
+ else
+ {
+ break;
+ }
+ }
+ dht11DelayUs(40);
+
+ return _dht11->ioReadWriteFn(DHT11_MODE_READ, 0);
+}
+
+/**
+ * @brief dht11读1byte
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @retval 1byte数据
+ */
+static uint8_t dht11_read_byte(dht11_t *_dht11)
+{
+ uint8_t cnt = 8, byte = 0;
+
+ while(cnt--)
+ {
+ byte <<= 1;
+ byte |= dht11_read_bit(_dht11);
+ }
+
+ return byte;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup dht11_global_functions dht11 global functions
+ * @{
+ */
+
+/**
+ * @brief 注册us延时函数
+ *
+ * @param delayUsFn : 函数指针
+ *
+ * @retval None
+ */
+void dht11_register_delay_us(void (* delayUsFn)(uint32_t us))
+{
+ dht11DelayUs = delayUsFn;
+}
+
+/**
+ * @brief dht11初始化
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @param ioModeSetFn : IO端口模式设置函数
+ *
+ * @param ioRWFn : IO端口读写函数
+ *
+ * @retval None
+ */
+void dht11_init(dht11_t *_dht11, dht11_io_mode_set_fn_t ioModeSetFn, dht11_io_rw_fn_t ioRWFn)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_dht11));
+ ASSERT_PARAM(IS_VALID_POINT(ioModeSetFn));
+ ASSERT_PARAM(IS_VALID_POINT(ioRWFn));
+
+ memset(_dht11, 0, sizeof(dht11_t));
+ _dht11->ioModeSetFn = ioModeSetFn;
+ _dht11->ioReadWriteFn = ioRWFn;
+}
+
+/**
+ * @brief dht11读取温湿度数据
+ *
+ * @param _dht11 : dht11管理实例
+ *
+ * @retval 读取结果
+ * @arg RET_OK : 读取成功
+ * @arg RET_ERR : 读取失败
+ */
+uint8_t dht11_read_data(dht11_t *_dht11)
+{
+ uint8_t ret;
+
+ ASSERT_PARAM(IS_VALID_POINT(dht11DelayUs));
+ ASSERT_PARAM(IS_VALID_POINT(_dht11->ioModeSetFn));
+ ASSERT_PARAM(IS_VALID_POINT(_dht11->ioReadWriteFn));
+
+ dht11_reset(_dht11);
+ ret = dht11_respond(_dht11);
+ if(RET_OK == ret)
+ {
+ _dht11->humiInte = dht11_read_byte(_dht11);
+ _dht11->humiDeci = dht11_read_byte(_dht11);
+ _dht11->tempInte = dht11_read_byte(_dht11);
+ _dht11->tempDeci = dht11_read_byte(_dht11);
+ ret = dht11_read_byte(_dht11);
+ if(ret == _dht11->humiInte + _dht11->humiDeci + _dht11->tempInte + _dht11->tempDeci)
+ {
+ ret = RET_OK;
+ }
+ else
+ {
+ ret = RET_ERR;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/src/devices/sensor/dht11.h b/src/devices/sensor/dht11.h
new file mode 100644
index 0000000000000000000000000000000000000000..a14a6aa2feb46ecdcaf5d7a97766dbde94c8825f
--- /dev/null
+++ b/src/devices/sensor/dht11.h
@@ -0,0 +1,151 @@
+/**
+ ******************************************************************************
+ * @file dht11.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief DHT11温湿度模块驱动
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __DHT11_H
+#define __DHT11_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+
+/**
+ * @addtogroup devices
+ * @{
+ */
+
+/**
+ * @addtogroup dht11
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup dht11_global_macros dht11 global macros
+ * @{
+ */
+
+/**
+ * @defgroup dht11_io_rw_mode dht11 io read write mode
+ * @{
+ */
+#define DHT11_MODE_READ (0u) /*!< 读IO */
+#define DHT11_MODE_WRITE (1u) /*!< 写IO */
+/**
+ * @}
+ */
+
+/**
+ * @defgroup dht11_io_mode dht11 io mode
+ * @{
+ */
+#define DHT11_MODE_INPUT (0u) /*!< IO输入 */
+#define DHT11_MODE_OUTPUT (1u) /*!< IO输出 */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup dht11_global_types dht11 global types
+ * @{
+ */
+
+/**
+ * @brief IO模式设置函数
+ *
+ * @note 根据IO模式去切换IO口的输入输出模式
+ *
+ * @param mode : IO模式
+ * @arg DHT11_MODE_INPUT : IO输入
+ * @arg DHT11_MODE_OUTPUT : IO输出
+ *
+ * @retval None
+ */
+typedef void (* dht11_io_mode_set_fn_t)(uint8_t mode);
+
+/**
+ * @brief IO读写函数
+ *
+ * @note 根据读写模式去执行写IO还是读IO,写IO时返回值无效,读IO时level参数无效
+ *
+ * @param rwMode : 读写模式
+ * @arg DHT11_MODE_READ : 读IO
+ * @arg DHT11_MODE_WRITE : 写IO
+ *
+ * @param level : 电平
+ * @arg 0 : 低电平
+ * @arg !0 : 高电平
+ *
+ * @retval 返回IO的输入电平
+ */
+typedef uint8_t (* dht11_io_rw_fn_t)(uint8_t rwMode, uint8_t level);
+
+/**
+ * @brief dht11 structure definition
+ */
+typedef struct dht11 {
+ uint8_t humiInte; /*!< 湿度整数部分 */
+ uint8_t humiDeci; /*!< 湿度小数部分 */
+ uint8_t tempInte; /*!< 温度整数部分 */
+ uint8_t tempDeci; /*!< 温度小数部分 */
+
+ dht11_io_mode_set_fn_t ioModeSetFn; /*!< IO模式设置函数 */
+ dht11_io_rw_fn_t ioReadWriteFn; /*!< IO读写函数 */
+} dht11_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup dht11_global_functions
+ * @{
+ */
+
+void dht11_register_delay_us(void (* delayUsFn)(uint32_t us));
+
+void dht11_init(dht11_t *_dht11, dht11_io_mode_set_fn_t ioModeSetFn, dht11_io_rw_fn_t ioRWFn);
+
+uint8_t dht11_read_data(dht11_t *_dht11);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* dht11.h */
diff --git a/src/modbus/modbus_common.c b/src/modbus/modbus_common.c
index dfbf0dad10addb5b52834adbb78ade7213691778..424b5b4c71beb6f01f24cd156ec4b42a1b141c38 100644
--- a/src/modbus/modbus_common.c
+++ b/src/modbus/modbus_common.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_common.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus通用文件
*
******************************************************************************
diff --git a/src/modbus/modbus_common.h b/src/modbus/modbus_common.h
index 5126ddfc234f8b7b39bca6dfb919722e6d3e292b..543aeb3cc1980f7f7bec64ead333add5347da471 100644
--- a/src/modbus/modbus_common.h
+++ b/src/modbus/modbus_common.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_common.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus通用文件
*
******************************************************************************
diff --git a/src/modbus/modbus_host.c b/src/modbus/modbus_host.c
index e305f9673d9048ee56c49737bb779e659d9973cf..6c84ef20c714d4471cfa23627002415aa35b66b0 100644
--- a/src/modbus/modbus_host.c
+++ b/src/modbus/modbus_host.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_host.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus主机程序(RTU ASCII)
*
******************************************************************************
diff --git a/src/modbus/modbus_host.h b/src/modbus/modbus_host.h
index c3815be2a3eef80a400a655dd54344e0d1533949..121cd79398e157fbcd509d5f07c60be54764a953 100644
--- a/src/modbus/modbus_host.h
+++ b/src/modbus/modbus_host.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_host.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus主机程序(RTU ASCII)
*
******************************************************************************
diff --git a/src/modbus/modbus_slave.c b/src/modbus/modbus_slave.c
index c10d917e35b5db0baab994dc746bb9ea7d56c818..0821af90a070ebcdf963d08b15c98fbdc8dc6a55 100644
--- a/src/modbus/modbus_slave.c
+++ b/src/modbus/modbus_slave.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_slave.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus从机程序(RTU ASCII)
*
******************************************************************************
diff --git a/src/modbus/modbus_slave.h b/src/modbus/modbus_slave.h
index bb32485cd3ac0b6871e7786a7d1844d27dad7366..6274e8e8ea5e9e651c2d2afa9341d9d2522c85f1 100644
--- a/src/modbus/modbus_slave.h
+++ b/src/modbus/modbus_slave.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file modbus_slave.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-27
+ * @version V2.3
+ * @date 2024-07-01
* @brief modbus从机程序(RTU ASCII)
*
******************************************************************************
diff --git a/src/modules/command_at.c b/src/modules/command_at.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ab67e8c61923c2adf10b060da278f49eb078532
--- /dev/null
+++ b/src/modules/command_at.c
@@ -0,0 +1,566 @@
+/**
+ ******************************************************************************
+ * @file command_at.c
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief AT指令交互
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-02-20 ashuai0110 完成基本内容
+ * 2024-02-24 ashuai0110 修改AT交互处理为格式化内容输入,增加轮询式交互函数
+ * 2024-03-04 ashuai0110 修改重发次数和回复超时为独立参数并增加其读写接口
+ * 2024-03-17 ashuai0110 修改前缀字符串可以为NULL
+ *
+ ******************************************************************************
+ */
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "command_at.h"
+
+/**
+ * @addtogroup modules
+ * @{
+ */
+
+/**
+ * @defgroup command_at command_at
+ * @{
+ */
+
+/* 私有宏定义-----------------------------------------------------------------*/
+/**
+ * @defgroup command_at_local_macros command at local macros
+ * @{
+ */
+
+/**
+ * @defgroup command_at_check_parameters_validity command at check parameters validity
+ * @{
+ */
+/* 前后缀保留标志有效性检查 */
+#define IS_VALID_RESERVE(x) \
+( ((x) == CMD_AT_NOT_RESERVE) || \
+ ((x) == CMD_AT_RESERVE))
+/* 处理方式有效性检查 */
+#define IS_VALID_WAY(x) \
+( ((x) == CMD_AT_WAY_SEARCH) || \
+ ((x) == CMD_AT_WAY_REC_FLAG))
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 私有类型定义---------------------------------------------------------------*/
+
+/* 私有变量-------------------------------------------------------------------*/
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 私有函数原型---------------------------------------------------------------*/
+
+
+/**
+ * @defgroup command_at_global_functions command at global functions
+ * @{
+ */
+
+/**
+ * @brief AT指令交互初始化
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param head : 前缀字符串(允许前缀为NULL)
+ *
+ * @param tail : 后缀字符串
+ *
+ * @param readFn : 读取数据函数
+ *
+ * @param writeFn : 写入数据函数
+ *
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @param resendTimes : 重发次数
+ *
+ * @retval None
+ */
+void cmd_at_init(cmd_at_t *_at, const char *head, const char *tail, cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn, uint16_t rspTimeout, uint8_t resendTimes)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_at));
+ ASSERT_PARAM(IS_VALID_POINT(tail));
+ ASSERT_PARAM(IS_VALID_POINT(readFn));
+ ASSERT_PARAM(IS_VALID_POINT(writeFn));
+
+ /* 初始化各参数 */
+ memset(_at, 0, sizeof(cmd_at_t));
+ if(NULL != head) { strcpy(_at->head, head); }
+ strcpy(_at->tail, tail);
+ _at->readFn = readFn;
+ _at->writeFn = writeFn;
+ _at->rspTimeout = rspTimeout;
+ _at->resendTimes = resendTimes;
+}
+
+/**
+ * @brief AT指令交互阻塞式处理
+ *
+ * @note 若处理方式使用外部接收标志,则接收标志应在中断中处理,因为此函数是阻塞的
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param reserve : 是否保留前缀和后缀 @ref command_at_reserve
+ * @arg CMD_AT_NOT_RESERVE : 不保留
+ * @arg CMD_AT_RESERVE : 保留
+ *
+ * @param way : 处理方式 @ref command_at_way
+ * @arg CMD_AT_WAY_SEARCH : 搜索前后缀
+ * @arg CMD_AT_WAY_REC_FLAG : 外部接收标志
+ *
+ * @param ret : 期望的回复
+ * @arg NULL : 填写NULL表示不关心回复内容,一般在发送读取命令时使用
+ * @arg !NULL : 填写非NULL表示关心回复内容,回复内容中包含(而非完全相同)期望内容即返回成功
+ *
+ * @param cmdFmt : 发送的命令(完整的命令,注意格式化"AT+NAME=%s\r\n", "ashuai")
+ *
+ * @retval 返回回复结果
+ * @arg RET_OK : 成功,回复内容符合期望
+ * @arg RET_ERR : 失败,回复内容不符合期望
+ * @arg RET_TIMEOUT : 失败,回复超时
+ */
+uint8_t cmd_at_process_block(cmd_at_t *_at, uint8_t reserve, uint8_t way, const char *ret, const char *cmdFmt, ...)
+{
+ uint16_t len;
+ char *newStr;
+ va_list args;
+
+ ASSERT_PARAM(IS_VALID_POINT(_at));
+ ASSERT_PARAM(IS_VALID_RESERVE(reserve));
+ ASSERT_PARAM(IS_VALID_WAY(way));
+
+ while(1)
+ {
+ switch(_at->state)
+ {
+ case CMD_AT_STATE_FORMAT_CMD:
+ /* 格式化内容 */
+ va_start(args, cmdFmt);
+ _at->cmdLen = vsnprintf(_at->cmdBuf, sizeof(_at->cmdBuf), cmdFmt, args);
+ va_end(args);
+ _at->state = CMD_AT_STATE_SEND_CMD; /* 跳转状态至命令发送 */
+ case CMD_AT_STATE_SEND_CMD:
+ _at->dataLen = 0; /* 清零数据长度 */
+ _at->recFlag = 0; /* 清零接收标志 */
+ _at->writeFn((void *)_at->cmdBuf, _at->cmdLen); /* 发送命令 */
+ _at->state = CMD_AT_STATE_WAIT_RSP; /* 跳转状态至等待回复 */
+ _at->rspTimeoutCnt = module_tick_get(); /* 开启回复超时计数 */
+ break;
+ case CMD_AT_STATE_WAIT_RSP:
+ /* 回复时间超出预设值 回复超时 */
+ if((module_tick_get() - _at->rspTimeoutCnt) > _at->rspTimeout)
+ {
+ _at->state = CMD_AT_STATE_SEND_CMD; /* 跳转状态至发送命令 */
+ _at->resendTimesCnt++; /* 累加重发次数 */
+ /* 若重发次数超出预设值则返回RET_TIMEOUT */
+ if(_at->resendTimes < _at->resendTimesCnt)
+ {
+ _at->resendTimesCnt = 0; /* 清零重发次数 */
+ _at->state = CMD_AT_STATE_FORMAT_CMD; /* 初始化状态 */
+
+ return RET_TIMEOUT;
+ }
+ } /* 回复未超时 */
+ else
+ {
+ /* 搜索前后缀的处理方式 */
+ if(CMD_AT_WAY_SEARCH == way)
+ {
+ /* 读取回复内容 */
+ len = _at->readFn((void *)&_at->dataBuf[_at->dataLen], sizeof(_at->dataBuf) - _at->dataLen);
+ if(0 == len) { break; } /* 未读到直接break */
+ /* 累计数据长度并添加结束符 */
+ _at->dataLen += len;
+ _at->dataBuf[_at->dataLen] = '\0';
+ /* 数据长度大于前后缀总长度则进行检索 */
+ if(_at->dataLen > (strlen(_at->head) + strlen(_at->tail)))
+ {
+ newStr = strstr(_at->dataBuf, _at->head); /* 检索是否包含前缀 */
+ /* 返回不为NULL说明包含前缀 */
+ if(NULL != newStr)
+ {
+ _at->startIndex = newStr - _at->dataBuf; /* 记录前缀索引 */
+ newStr = strstr(newStr, _at->tail); /* 检索是否包含后缀 */
+ /* 返回不为NULL说明包含后缀 */
+ if(NULL != newStr)
+ {
+ _at->stopIndex = newStr - _at->dataBuf; /* 记录后缀索引 */
+ _at->state = CMD_AT_STATE_DATA_CHECK; /* 跳转状态至校验回复 */
+ }
+ }
+ }
+ } /* 外部接收标志的处理方式 */
+ else
+ {
+ if(_at->recFlag)
+ {
+ _at->recFlag = 0; /* 清零接收标志 */
+ /* 读取回复内容 */
+ do {
+ len = _at->readFn((void *)&_at->dataBuf[_at->dataLen], sizeof(_at->dataBuf) - _at->dataLen);
+ _at->dataLen += len; /* 累计数据长度 */
+ } while(len);
+ _at->dataBuf[_at->dataLen] = '\0'; /* 添加结束符 */
+ _at->state = CMD_AT_STATE_DATA_CHECK; /* 跳转状态至校验回复 */
+ }
+ }
+ }
+ break;
+ case CMD_AT_STATE_DATA_CHECK:
+ /* 搜索前后缀的处理方式 */
+ if(CMD_AT_WAY_SEARCH == way)
+ {
+ /* 不保留前缀后缀 */
+ if(CMD_AT_NOT_RESERVE == reserve)
+ {
+ _at->startIndex += strlen(_at->head);
+ _at->dataLen = _at->stopIndex - _at->startIndex;
+ } /* 保留前缀后缀 */
+ else
+ {
+ _at->dataLen = _at->stopIndex - _at->startIndex + strlen(_at->tail);
+ }
+ /* 截取数据并从头保存 */
+ for(len = 0; len < _at->dataLen; len++)
+ {
+ _at->dataBuf[len] = _at->dataBuf[_at->startIndex++];
+ }
+ _at->dataBuf[len] = '\0'; /* 添加结束符 */
+ }
+ /* 恢复默认参数 */
+ _at->state = CMD_AT_STATE_FORMAT_CMD;
+ _at->resendTimesCnt = 0;
+ /* 期望回复不是NULL则校验回复内容 */
+ if(NULL != ret)
+ {
+ /* 回复内容中包含(而非完全相同)期望回复 则返回RET_OK 否则返回RET_ERR */
+ newStr = strstr(_at->dataBuf, ret);
+ if(NULL != newStr)
+ {
+ return RET_OK;
+ }
+ else
+ {
+ return RET_ERR;
+ }
+ }
+
+ return RET_OK;
+ }
+ }
+}
+
+/**
+ * @brief AT指令交互轮询式处理(非阻塞式)
+ *
+ * @note 以状态机架构轮询处理
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param reserve : 是否保留前缀和后缀 @ref command_at_reserve
+ * @arg CMD_AT_NOT_RESERVE : 不保留
+ * @arg CMD_AT_RESERVE : 保留
+ *
+ * @param way : 处理方式 @ref command_at_way
+ * @arg CMD_AT_WAY_SEARCH : 搜索前后缀
+ * @arg CMD_AT_WAY_REC_FLAG : 外部接收标志
+ *
+ * @param ret : 期望的回复
+ * @arg NULL : 填写NULL表示不关心回复内容,一般在发送读取命令时使用
+ * @arg !NULL : 填写非NULL表示关心回复内容,回复内容中包含(而非完全相同)期望内容即返回成功
+ *
+ * @param cmdFmt : 发送的命令(完整的命令,注意格式化"AT+NAME=%s\r\n", "ashuai")
+ *
+ * @retval 返回回复结果
+ * @arg RET_OK : 成功,回复内容符合期望
+ * @arg RET_ERR : 失败,回复内容不符合期望
+ * @arg RET_ING : 轮询处理中
+ * @arg RET_TIMEOUT : 失败,回复超时
+ */
+uint8_t cmd_at_process_poll(cmd_at_t *_at, uint8_t reserve, uint8_t way, const char *ret, const char *cmdFmt, ...)
+{
+ uint16_t len;
+ char *newStr;
+ va_list args;
+
+ ASSERT_PARAM(IS_VALID_POINT(_at));
+ ASSERT_PARAM(IS_VALID_RESERVE(reserve));
+ ASSERT_PARAM(IS_VALID_WAY(way));
+
+ switch(_at->state)
+ {
+ case CMD_AT_STATE_FORMAT_CMD:
+ /* 格式化内容 */
+ va_start(args, cmdFmt);
+ _at->cmdLen = vsnprintf(_at->cmdBuf, sizeof(_at->cmdBuf), cmdFmt, args);
+ va_end(args);
+ _at->state = CMD_AT_STATE_SEND_CMD; /* 跳转状态至命令发送 */
+ case CMD_AT_STATE_SEND_CMD:
+ _at->dataLen = 0; /* 清零数据长度 */
+ _at->recFlag = 0; /* 清零接收标志 */
+ _at->writeFn((void *)_at->cmdBuf, _at->cmdLen); /* 发送命令 */
+ _at->state = CMD_AT_STATE_WAIT_RSP; /* 跳转状态至等待回复 */
+ _at->rspTimeoutCnt = module_tick_get(); /* 开启回复超时计数 */
+ break;
+ case CMD_AT_STATE_WAIT_RSP:
+ /* 回复时间超出预设值 回复超时 */
+ if((module_tick_get() - _at->rspTimeoutCnt) > _at->rspTimeout)
+ {
+ _at->state = CMD_AT_STATE_SEND_CMD; /* 跳转状态至发送命令 */
+ _at->resendTimesCnt++; /* 累加重发次数 */
+ /* 若重发次数超出预设值则返回RET_TIMEOUT */
+ if(_at->resendTimes < _at->resendTimesCnt)
+ {
+ _at->resendTimesCnt = 0; /* 清零重发次数 */
+ _at->state = CMD_AT_STATE_FORMAT_CMD; /* 初始化状态 */
+
+ return RET_TIMEOUT;
+ }
+ } /* 回复未超时 */
+ else
+ {
+ /* 搜索前后缀的处理方式 */
+ if(CMD_AT_WAY_SEARCH == way)
+ {
+ /* 读取回复内容 */
+ len = _at->readFn((void *)&_at->dataBuf[_at->dataLen], sizeof(_at->dataBuf) - _at->dataLen);
+ if(0 == len) { break; } /* 未读到直接break */
+ /* 累计数据长度并添加结束符 */
+ _at->dataLen += len;
+ _at->dataBuf[_at->dataLen] = '\0';
+ /* 数据长度大于前后缀总长度则进行检索 */
+ if(_at->dataLen > (strlen(_at->head) + strlen(_at->tail)))
+ {
+ newStr = strstr(_at->dataBuf, _at->head); /* 检索是否包含前缀 */
+ /* 返回不为NULL说明包含前缀 */
+ if(NULL != newStr)
+ {
+ _at->startIndex = newStr - _at->dataBuf; /* 记录前缀索引 */
+ newStr = strstr(newStr, _at->tail); /* 检索是否包含后缀 */
+ /* 返回不为NULL说明包含后缀 */
+ if(NULL != newStr)
+ {
+ _at->stopIndex = newStr - _at->dataBuf; /* 记录后缀索引 */
+ _at->state = CMD_AT_STATE_DATA_CHECK; /* 跳转状态至校验回复 */
+ }
+ }
+ }
+ } /* 外部接收标志的处理方式 */
+ else
+ {
+ if(_at->recFlag)
+ {
+ _at->recFlag = 0; /* 清零接收标志 */
+ /* 读取回复内容 */
+ do {
+ len = _at->readFn((void *)&_at->dataBuf[_at->dataLen], sizeof(_at->dataBuf) - _at->dataLen);
+ _at->dataLen += len; /* 累计数据长度 */
+ } while(len);
+ _at->dataBuf[_at->dataLen] = '\0'; /* 添加结束符 */
+ _at->state = CMD_AT_STATE_DATA_CHECK; /* 跳转状态至校验回复 */
+ }
+ }
+ }
+ break;
+ case CMD_AT_STATE_DATA_CHECK:
+ /* 搜索前后缀的处理方式 */
+ if(CMD_AT_WAY_SEARCH == way)
+ {
+ /* 不保留前缀后缀 */
+ if(CMD_AT_NOT_RESERVE == reserve)
+ {
+ _at->startIndex += strlen(_at->head);
+ _at->dataLen = _at->stopIndex - _at->startIndex;
+ } /* 保留前缀后缀 */
+ else
+ {
+ _at->dataLen = _at->stopIndex - _at->startIndex + strlen(_at->tail);
+ }
+ /* 截取数据并从头保存 */
+ for(len = 0; len < _at->dataLen; len++)
+ {
+ _at->dataBuf[len] = _at->dataBuf[_at->startIndex++];
+ }
+ _at->dataBuf[len] = '\0'; /* 添加结束符 */
+ }
+ /* 恢复默认参数 */
+ _at->state = CMD_AT_STATE_FORMAT_CMD;
+ _at->resendTimesCnt = 0;
+ /* 期望回复不是NULL则校验回复内容 */
+ if(NULL != ret)
+ {
+ /* 回复内容中包含(而非完全相同)期望回复 则返回RET_OK 否则返回RET_ERR */
+ newStr = strstr(_at->dataBuf, ret);
+ if(NULL != newStr) { return RET_OK; }
+ else { return RET_ERR; }
+ }
+
+ return RET_OK;
+ }
+
+ return RET_ING;
+}
+
+/**
+ * @brief AT指令回复内容分割(依据前后缀)
+ *
+ * @note 一般在cmd_at_process()后使用,回复内容形式一般为key-value(键值对)
+ * (cmd_at_process()采用保留前后缀时"AT+NAME=ashuai\r\n" key:"AT+NAME" value:"ashuai\r\n" split:"=")
+ * (cmd_at_process()采用不保留前后缀时"NAME=ashuai" key:"NAME" value:"ashuai" split:"=")
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param key : key-value中的key字符串暂存区(传入数组地址)
+ *
+ * @param value : key-value中的value字符串暂存区(传入数组地址)
+ *
+ * @param split : 分隔符(一般为"=")
+ *
+ * @retval 返回分割结果
+ * @arg RET_OK : 分割成功
+ * @arg RET_ERR : 分割失败,分隔符不存在
+ */
+uint8_t cmd_at_split(cmd_at_t *_at, char *key, char *value, const char *split)
+{
+ char *newStr;
+ uint8_t tmp1, tmp2;
+
+ ASSERT_PARAM(IS_VALID_POINT(_at));
+ /* 寻找分隔符 若返回为NULL则直接退出 */
+ newStr = strstr(_at->dataBuf, split);
+ if(NULL == newStr) { return RET_ERR; }
+ tmp1 = newStr - _at->dataBuf; /* 分隔符前的数据数量 = 分隔符地址-数据缓冲区首地址 */
+ if(NULL != key)
+ {
+ memcpy((void *)key, (void *)_at->dataBuf, tmp1); /* 数据拷贝到key字符串暂存区 */
+ key[tmp1] = '\0';
+ }
+ if(NULL != value)
+ {
+ tmp2 = _at->dataLen - tmp1 - strlen(split); /* 分隔符后的数据数量 = 数据总长 - 分隔符前的数据数量 - 分隔符长度 */
+ memcpy((void *)value, (void *)&_at->dataBuf[tmp1 + strlen(split)], tmp2); /* 数据拷贝到value字符串暂存区 */
+ value[tmp2] = '\0';
+ }
+
+ return RET_OK;
+}
+
+/**
+ * @brief AT指令获取回复内容
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @retval 返回保存的回复内容
+ */
+char *cmd_at_rsp_data(cmd_at_t *_at)
+{
+ return _at->dataBuf;
+}
+
+/**
+ * @brief AT指令设置外部接收标志
+ *
+ * @note 用在处理方式是外部接收标志时,在接收完成的地方调用
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @retval None
+ */
+void cmd_at_set_rec_flag(cmd_at_t *_at)
+{
+ _at->recFlag = 1;
+}
+
+/**
+ * @brief AT指令获取外部接收标志
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @retval 接收标志
+ */
+uint8_t cmd_at_get_rec_flag(cmd_at_t *_at)
+{
+ return _at->recFlag;
+}
+
+/**
+ * @brief AT指令设置回复超时时间ms
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param rspTimeout : 回复超时时间ms
+ *
+ * @retval None
+ */
+void cmd_at_set_rsp_timeout(cmd_at_t *_at, uint16_t rspTimeout)
+{
+ _at->rspTimeout = rspTimeout;
+}
+
+/**
+ * @brief AT指令获取回复超时时间ms
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @retval 返回回复超时时间ms
+ */
+uint16_t cmd_at_get_rsp_timeout(cmd_at_t *_at)
+{
+ return _at->rspTimeout;
+}
+
+/**
+ * @brief AT指令设置重发次数
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @param resendTimes : 重发次数
+ *
+ * @retval None
+ */
+void cmd_at_set_resend_times(cmd_at_t *_at, uint8_t resendTimes)
+{
+ _at->resendTimes = resendTimes;
+}
+
+/**
+ * @brief AT指令获取重发次数
+ *
+ * @param _at : AT指令管理实例
+ *
+ * @retval 返回重发次数
+ */
+uint8_t cmd_at_get_resend_times(cmd_at_t *_at)
+{
+ return _at->resendTimes;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/src/modules/command_at.h b/src/modules/command_at.h
new file mode 100644
index 0000000000000000000000000000000000000000..beb29231cef56be3780d5fdd7896ad329be00529
--- /dev/null
+++ b/src/modules/command_at.h
@@ -0,0 +1,168 @@
+/**
+ ******************************************************************************
+ * @file command_at.h
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
+ * @brief AT指令交互
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
+ *
+ ******************************************************************************
+ */
+
+#ifndef __COMMAND_AT_H
+#define __COMMAND_AT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 包含头文件-----------------------------------------------------------------*/
+#include "common_include.h"
+
+/**
+ * @addtogroup modules
+ * @{
+ */
+
+/**
+ * @defgroup command_at command_at
+ * @{
+ */
+
+/* 宏定义---------------------------------------------------------------------*/
+/**
+ * @defgroup command_at_global_macros command at global macros
+ * @{
+ */
+
+#define CMD_AT_W_BUF_LEN (48u) /*!< 发送缓冲区长度byte 用户按需修改 */
+#define CMD_AT_R_BUF_LEN (48u) /*!< 接收缓冲区长度byte 用户按需修改 */
+#define CMD_AT_MARK_LEN (3u) /*!< 前缀后缀数组长度byte 用户按需修改 */
+
+/**
+ * @defgroup command_at_reserve command at reserve
+ * @{
+ */
+/* 影响cmd_at_process()函数最终保存在dataBuf的回复内容 保留:"AT+NAME=ashuai\r\n" 不保留:"NAME=ashuai" */
+#define CMD_AT_NOT_RESERVE (0u) /*!< 不保留前缀后缀 */
+#define CMD_AT_RESERVE (1u) /*!< 保留前缀后缀 */
+/**
+ * @}
+ */
+
+/**
+ * @defgroup command_at_way command at way
+ * @{
+ */
+#define CMD_AT_WAY_SEARCH (0u) /*!< 搜索前后缀的处理方式 */
+#define CMD_AT_WAY_REC_FLAG (1u) /*!< 外部接收标志的处理方式 */
+/**
+ * @}
+ */
+
+/**
+ * @defgroup command_at_state command at state
+ * @{
+ */
+#define CMD_AT_STATE_FORMAT_CMD (0u) /*!< 状态-格式化命令 */
+#define CMD_AT_STATE_SEND_CMD (1u) /*!< 状态-命令发送 */
+#define CMD_AT_STATE_WAIT_RSP (2u) /*!< 状态-等待回复 */
+#define CMD_AT_STATE_DATA_CHECK (3u) /*!< 状态-校验回复 */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* 类型定义-------------------------------------------------------------------*/
+/**
+ * @defgroup command_at_global_types command at global types
+ * @{
+ */
+
+/**
+ * @brief 写入数据 / 读取数据
+ *
+ * @param data : 写入数据的存储区 / 读取数据的存储区
+ *
+ * @param size : 写入的数据大小 / 读取的数据大小 byte
+ *
+ * @retval 实际写入的数据大小 / 实际读取的数据大小 byte
+ */
+typedef uint32_t (* cmd_at_rw_fn_t)(void *data, uint32_t size);
+
+/**
+ * @brief at指令 structure definition
+ */
+typedef struct cmd_at {
+ char cmdBuf[CMD_AT_W_BUF_LEN]; /*!< 发送命令数据缓冲区 */
+ char dataBuf[CMD_AT_R_BUF_LEN]; /*!< 回复内容数据缓冲区 */
+ char head[CMD_AT_MARK_LEN + 1]; /*!< 前缀字符串 */
+ char tail[CMD_AT_MARK_LEN + 1]; /*!< 后缀字符串 */
+ uint16_t cmdLen; /*!< 发送命令数据长度 */
+ uint16_t dataLen; /*!< 回复内容数据长度 */
+ uint16_t startIndex; /*!< 起始索引 */
+ uint16_t stopIndex; /*!< 结束索引 */
+ uint8_t state : 3; /*!< 交互状态 @ref command_at_state */
+ uint8_t recFlag : 1; /*!< 接受标志 */
+ uint8_t resendTimes; /*!< 重发次数 */
+ uint8_t resendTimesCnt; /*!< 重发次数计数 */
+ uint16_t rspTimeout; /*!< 回复超时ms */
+ uint32_t rspTimeoutCnt; /*!< 回复超时计数ms */
+ cmd_at_rw_fn_t readFn; /*!< 数据读函数 */
+ cmd_at_rw_fn_t writeFn; /*!< 数据写函数 */
+} cmd_at_t;
+
+/**
+ * @}
+ */
+
+/* 全局变量-------------------------------------------------------------------*/
+
+/* 函数原型-------------------------------------------------------------------*/
+/**
+ * @addtogroup command_at_global_functions
+ * @{
+ */
+
+void cmd_at_init(cmd_at_t *_at, const char *head, const char *tail, cmd_at_rw_fn_t readFn, cmd_at_rw_fn_t writeFn, uint16_t rspTimeout, uint8_t resendTimes);
+
+uint8_t cmd_at_process_block(cmd_at_t *_at, uint8_t reserve, uint8_t way, const char *ret, const char *cmdFmt, ...);
+uint8_t cmd_at_process_poll(cmd_at_t *_at, uint8_t reserve, uint8_t way, const char *ret, const char *cmdFmt, ...);
+
+uint8_t cmd_at_split(cmd_at_t *_at, char *key, char *value, const char *split);
+char *cmd_at_rsp_data(cmd_at_t *_at);
+
+/* set/get interface */
+void cmd_at_set_rec_flag(cmd_at_t *_at);
+uint8_t cmd_at_get_rec_flag(cmd_at_t *_at);
+void cmd_at_set_rsp_timeout(cmd_at_t *_at, uint16_t rspTimeout);
+uint16_t cmd_at_get_rsp_timeout(cmd_at_t *_at);
+void cmd_at_set_resend_times(cmd_at_t *_at, uint8_t resendTimes);
+uint8_t cmd_at_get_resend_times(cmd_at_t *_at);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* command_at.h */
diff --git a/src/modules/command_line.c b/src/modules/command_line.c
index 16288d6cf80f3e08a8739aaebfc5062b4a76927b..1f7a9ab364e06d893875c49e719733d9e1b3cc62 100644
--- a/src/modules/command_line.c
+++ b/src/modules/command_line.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file command_line.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 命令行交互
* (类命令行,空格分割 比如:cmd arg1 arg2\r\n或AT+CMD= arg1 arg2\r\n)
*
diff --git a/src/modules/command_line.h b/src/modules/command_line.h
index 1cbca93007fb19cdc3943b8dc2eeb2913b3d65dd..7761868f5806880688fdf511deace0393d5fc1d0 100644
--- a/src/modules/command_line.h
+++ b/src/modules/command_line.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file command_line.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 命令行交互
* (类命令行,空格分割 比如:cmd arg1 arg2\r\n或AT+CMD= arg1 arg2\r\n)
*
diff --git a/src/modules/data_check.c b/src/modules/data_check.c
index c3753ac5096714d9e8b7e2d19f801ccf8b310374..8a02425cdf0e33279c8749d8954b4f4b5df9e844 100644
--- a/src/modules/data_check.c
+++ b/src/modules/data_check.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file data_check.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 数据校验方法集合
*
******************************************************************************
diff --git a/src/modules/data_check.h b/src/modules/data_check.h
index 879fe92fe74cfc082e30076c3c2cf317bda476b0..0b3dfd8e2b5871351724621a1096ed2952bc3789 100644
--- a/src/modules/data_check.h
+++ b/src/modules/data_check.h
@@ -2,15 +2,15 @@
******************************************************************************
* @file data_check.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 数据校验方法集合
*
******************************************************************************
* @attention
*
* 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
- * 出处链接:https://gitee.com/woshiashuai/mcu_development_module.git
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
*
******************************************************************************
*/
diff --git a/src/modules/data_convert.c b/src/modules/data_convert.c
index d591c031c0ce3c6c54a21d206e2c9af339cafe82..5e9c01f4fc6715178af2901710c51efb065f52c7 100644
--- a/src/modules/data_convert.c
+++ b/src/modules/data_convert.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file data_convert.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 数据转换方法集合
*
******************************************************************************
diff --git a/src/modules/data_convert.h b/src/modules/data_convert.h
index 4790583555e6da9d16c59ccfafffa49817952771..684c5add66d92c858c0fa1f117b5bd22e3c431d8 100644
--- a/src/modules/data_convert.h
+++ b/src/modules/data_convert.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file data_convert.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 数据转换方法集合
*
******************************************************************************
diff --git a/src/modules/delay_no_block.c b/src/modules/delay_no_block.c
index 04ed19b3f44de31e42236335d4f64ac96d25f1e6..20afff54c6057821f8b684248d8163979506bced 100644
--- a/src/modules/delay_no_block.c
+++ b/src/modules/delay_no_block.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file delay_no_block.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 非阻塞延时
*
******************************************************************************
diff --git a/src/modules/delay_no_block.h b/src/modules/delay_no_block.h
index 05920460ed8e0e97cf048ceb1dda2d0cf9a93627..b0f92c1ef3258b23ac140032f43e983163bbf60e 100644
--- a/src/modules/delay_no_block.h
+++ b/src/modules/delay_no_block.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file delay_no_block.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 非阻塞延时
*
******************************************************************************
diff --git a/src/modules/input_output.c b/src/modules/input_output.c
index 6486d463a96351233bcfce4b92df3b485bd05a5d..5f261e903d39376485d9d71092166e765e9b8d42 100644
--- a/src/modules/input_output.c
+++ b/src/modules/input_output.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file input_output.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief IO输入输出操作
* (输入可以设置各边沿触发时间,输出可以设置各边沿保持时间)
*
diff --git a/src/modules/input_output.h b/src/modules/input_output.h
index a9f6d5e2968f8bc7ea176e287f51078cab7ae3c1..7a39e6dc31d529acfb3b21f71df9bf6de1605443 100644
--- a/src/modules/input_output.h
+++ b/src/modules/input_output.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file input_output.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief IO输入输出操作
* (输入可以设置各边沿触发时间,输出可以设置各边沿保持时间)
*
diff --git a/src/modules/memory.c b/src/modules/memory.c
index 6ecbe4dace194b0277239ef0ef1b55898414909e..7b388f307be0b5c7375702f3c57ec7d3e9e6e7e2 100644
--- a/src/modules/memory.c
+++ b/src/modules/memory.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file memory.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 内存管理(rt-thread的mem,小内存管理算法<2MB)
*
******************************************************************************
@@ -61,7 +61,7 @@
* @{
*/
-__align(MEM_ALIGN_SIZE) static char memory[MEM_SIZE]; /*!< 管理的内存空间 */
+static char memory[MEM_SIZE] __attribute((aligned(MEM_ALIGN_SIZE))); /*!< 管理的内存空间 */
static mem_t *tailMem; /*!< 末尾管理者 */
static mem_t *freeMem; /*!< 空闲管理者 */
#if _MEM_STATES
diff --git a/src/modules/memory.h b/src/modules/memory.h
index cf7303aa33210abc2f13a629dfabb1817830db81..52e97bc0a81f1f939f1d7d5d9c78dc7bc1c4c6f5 100644
--- a/src/modules/memory.h
+++ b/src/modules/memory.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file memory.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 内存管理(参考rt-thread的mem,小内存管理算法<2MB)
*
******************************************************************************
diff --git a/src/modules/message_queue.c b/src/modules/message_queue.c
index 69989fb681939e4fd9a5062593ccd89576899d32..a476ccf2c1ca2d56218f96b49f26fe8fcd03b44e 100644
--- a/src/modules/message_queue.c
+++ b/src/modules/message_queue.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file message_queue.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 消息队列
* (适合不定长数据和复杂数据,写入时动态申请内存)
*
diff --git a/src/modules/message_queue.h b/src/modules/message_queue.h
index e83a782faa5a353ac21d1acbcccf4aae45f31b18..896e0b18a2358510300cc5288e5810e8f7addab8 100644
--- a/src/modules/message_queue.h
+++ b/src/modules/message_queue.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file message_queue.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 消息队列
* (适合不定长数据和复杂数据,写入时动态申请内存)
*
diff --git a/src/modules/ring_buffer.c b/src/modules/ring_buffer.c
index 3f45f68409d75fc0691d66101d63ef51c1671d16..aea2028d9c3d098bdc64c3685099bbd1c54d798a 100644
--- a/src/modules/ring_buffer.c
+++ b/src/modules/ring_buffer.c
@@ -2,10 +2,10 @@
******************************************************************************
* @file ring_buffer.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 环形缓冲区
- * (适合定长或易分离出的数据,写满后必须读出否则无法写入新数据)
+ * (适合定长或易分离出的数据,提供覆写函数和非覆写函数)
*
******************************************************************************
* @attention
@@ -17,6 +17,7 @@
* Date Author Notes
* 2023-09-24 ashuai0110 完成基本内容
* 2023-12-26 ashuai0110 修改读写接口取有效数量读写
+ * 2024-06-11 ashuai0110 增加覆写函数和头尾节点偏移读写函数
*
******************************************************************************
*/
@@ -174,12 +175,12 @@ uint32_t ring_buffer_read(ring_buffer_t *_rb, void *pBuf, uint32_t len)
len = (len > ring_buffer_can_read(_rb)) ? ring_buffer_can_read(_rb) : len;
if(0 == len) { return 0; }
- /* 头小于尾则说明写入数据未溢出从头写则无需拼接数据 */
+ /* 头小于尾则说明写入数据未溢出从头写则读取无需拼接数据 */
if(_rb->pHead < _rb->pTail)
{
memcpy(pBuf, _rb->pHead, len);
_rb->pHead += len;
- } /* 否则说明写入数据溢出从头写则需拼接数据 */
+ } /* 否则说明写入数据溢出从头写则读取需拼接数据 */
else
{
/* 不计入溢出的数量还剩多少可读出数据 */
@@ -202,7 +203,7 @@ uint32_t ring_buffer_read(ring_buffer_t *_rb, void *pBuf, uint32_t len)
}
/**
- * @brief 写入数据到环形缓冲区
+ * @brief 写入数据到环形缓冲区(写满后无法继续写入)
*
* @param _rb : 环形缓冲区实例
*
@@ -252,6 +253,102 @@ uint32_t ring_buffer_write(ring_buffer_t *_rb, void *pData, uint32_t len)
return len;
}
+/**
+ * @brief 覆盖写入数据到环形缓冲区(写满后继续写入则覆写旧数据)
+ *
+ * @param _rb : 环形缓冲区实例
+ *
+ * @param pData : 写入数据的缓冲区
+ *
+ * @param size : 写入数据的数量byte
+ *
+ * @retval 实际写入数据数量
+ */
+uint32_t ring_buffer_overwrite(ring_buffer_t *_rb, void *pData, uint32_t len)
+{
+ uint32_t freeSize;
+
+ ASSERT_PARAM(IS_VALID_POINT(_rb));
+ ASSERT_PARAM(IS_VALID_POINT(pData));
+
+ freeSize = _rb->bufLen - (_rb->pHead - _rb->pBuf);
+ /* 写入数量超出可写数量则覆盖写入 */
+ if(len > ring_buffer_can_write(_rb))
+ {
+ /* 写入数量超出剩余数量则覆写剩余并从头继续覆写 */
+ if(len > freeSize)
+ {
+ _rb->pHead = _rb->pBuf + len - freeSize;
+ } /* 否则则直接覆写剩余 */
+ else
+ {
+ _rb->pHead += len;
+ }
+ }
+
+ return ring_buffer_write(_rb, pData, len);
+}
+
+/**
+ * @brief 环形缓冲区设置头节点(开始读节点)偏移
+ *
+ * @param _rb : 环形缓冲区实例
+ *
+ * @param offset : 偏移量
+ *
+ * @retval None
+ */
+void ring_buffer_set_read_offset(ring_buffer_t *_rb, uint32_t offset)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_rb));
+
+ _rb->pHead = _rb->pBuf + offset;
+}
+
+/**
+ * @brief 环形缓冲区获取头节点(开始读节点)偏移
+ *
+ * @param _rb : 环形缓冲区实例
+ *
+ * @retval 返回头节点(开始读节点)偏移量
+ */
+uint32_t ring_buffer_get_read_offset(ring_buffer_t *_rb)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_rb));
+
+ return _rb->pHead - _rb->pBuf;
+}
+
+/**
+ * @brief 环形缓冲区设置尾节点(开始写节点)偏移
+ *
+ * @param _rb : 环形缓冲区实例
+ *
+ * @param offset : 偏移量
+ *
+ * @retval None
+ */
+void ring_buffer_set_write_offset(ring_buffer_t *_rb, uint32_t offset)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_rb));
+
+ _rb->pTail = _rb->pBuf + offset;
+}
+
+/**
+ * @brief 环形缓冲区获取尾节点(开始写节点)偏移
+ *
+ * @param _rb : 环形缓冲区实例
+ *
+ * @retval 返回尾节点(开始写节点)偏移量
+ */
+uint32_t ring_buffer_get_write_offset(ring_buffer_t *_rb)
+{
+ ASSERT_PARAM(IS_VALID_POINT(_rb));
+
+ return _rb->pTail - _rb->pBuf;
+}
+
/**
* @}
*/
diff --git a/src/modules/ring_buffer.h b/src/modules/ring_buffer.h
index c96587a814f4b9db85f46c34c182b9ae61b222d2..8677aa65f2289b6d12495700a67c81375c4afc01 100644
--- a/src/modules/ring_buffer.h
+++ b/src/modules/ring_buffer.h
@@ -2,10 +2,10 @@
******************************************************************************
* @file ring_buffer.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 环形缓冲区
- * (适合定长或易分离出的数据,写满后再写会覆写旧数据无论其是否被读出处理过)
+ * (适合定长或易分离出的数据,提供覆写函数和非覆写函数)
*
******************************************************************************
* @attention
@@ -74,6 +74,13 @@ uint32_t ring_buffer_can_write(ring_buffer_t *_rb);
uint32_t ring_buffer_read(ring_buffer_t *_rb, void *pBuf, uint32_t len);
uint32_t ring_buffer_write(ring_buffer_t *_rb, void *pData, uint32_t len);
+uint32_t ring_buffer_overwrite(ring_buffer_t *_rb, void *pData, uint32_t len);
+
+/* set/get interface */
+void ring_buffer_set_read_offset(ring_buffer_t *_rb, uint32_t offset);
+uint32_t ring_buffer_get_read_offset(ring_buffer_t *_rb);
+void ring_buffer_set_write_offset(ring_buffer_t *_rb, uint32_t offset);
+uint32_t ring_buffer_get_write_offset(ring_buffer_t *_rb);
/**
* @}
diff --git a/src/modules/sync_method.c b/src/modules/sync_method.c
index d2385f5bb48f8a4b7ad40956fa54e92202318eea..e42be4bc74af86c0cd7e607777f86b880c542f3e 100644
--- a/src/modules/sync_method.c
+++ b/src/modules/sync_method.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file sync_method.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 伪线程同步方法(信号量,互斥锁,事件集)
*
******************************************************************************
diff --git a/src/modules/sync_method.h b/src/modules/sync_method.h
index 9b6d872a9cd710ff7c2d91e0b4a63825d78f0496..0ac45a24e0e949455826ce776b9cb6c19b22b155 100644
--- a/src/modules/sync_method.h
+++ b/src/modules/sync_method.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file sync_method.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 伪线程同步方法(信号量,互斥锁,事件集)
*
******************************************************************************
diff --git a/src/modules/timer_software.c b/src/modules/timer_software.c
index a9e6583af12341fb0c636722ef3b45a815395fd3..8763d1097da3ac2a80ac03356b1006d260bf46e6 100644
--- a/src/modules/timer_software.c
+++ b/src/modules/timer_software.c
@@ -2,8 +2,8 @@
******************************************************************************
* @file timer_software.c
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 软件定时器
*
******************************************************************************
diff --git a/src/modules/timer_software.h b/src/modules/timer_software.h
index be8ff9760b1614221d9a9557928708f591620aae..aa6674366446b1156e55c5fac4313397208756dc 100644
--- a/src/modules/timer_software.h
+++ b/src/modules/timer_software.h
@@ -2,8 +2,8 @@
******************************************************************************
* @file timer_software.h
* @author ashuai0110
- * @version V2.2
- * @date 2024-01-28
+ * @version V2.3
+ * @date 2024-07-01
* @brief 软件定时器
*
******************************************************************************
diff --git a/src/modules/uart_handler.c b/src/modules/uart_handler.c
index ed59e9a2848137d9d4c90f8a5f3af09f0857bd5d..9b046e297b7ef3d0b99b2c30b778fbaa1731b8a0 100644
--- a/src/modules/uart_handler.c
+++ b/src/modules/uart_handler.c
@@ -1,21 +1,22 @@
/**
******************************************************************************
* @file uart_handler.c
- * @author woshiashuai
- * @version V2.2
- * @date 2024-01-28
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
* @brief 串口管理(使用帧间隔分帧或现有的分帧方法)
*
******************************************************************************
* @attention
*
* 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
- * 出处链接:https://gitee.com/woshiashuai/mcu_development_module.git
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
*
* Change Logs:
* Date Author Notes
* 2023-10-27 ashuai0110 完成基本内容
* 2023-12-29 ashuai0110 修改从组件计时节拍接口获取时基,修改使用ring_buffer组件
+ * 2024-03-03 ashuai0110 修改帧间隔时间为用户自定义参数
*
******************************************************************************
*/
@@ -82,25 +83,25 @@ static uart_handler_t uartHandlerArr[UART_HANDLER_NUM]; /*!< 串口管理数组
/**
* @brief 串口管理初始化
*
- * @param ch : 串口管理序号(即数组索引)
+ * @param ch : 串口管理序号(即数组索引)
*
- * @param txBuf : 串口发送缓冲区
+ * @param txBuf : 串口发送缓冲区
*
- * @param txLen : 串口发送缓冲区大小
+ * @param txLen : 串口发送缓冲区大小
*
- * @param rxBuf : 串口接收缓冲区
+ * @param rxBuf : 串口接收缓冲区
*
- * @param rxLen : 串口接收缓冲区大小
+ * @param rxLen : 串口接收缓冲区大小
*
- * @param txEnFn : 串口发送前准备函数
+ * @param txEnFn : 串口发送前准备函数
*
- * @param baud : 串口波特率(内部转换为帧间隔超时时间,填0则帧间隔超时时间为0)
+ * @param frameIntv : 帧间隔超时时间ms,填0则帧间隔超时时间为0
*
- * @param timeout : 接收超时时间ms(无需求可忽略)
+ * @param timeout : 接收超时时间ms(无需求可忽略)
*
* @retval None
*/
-void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint32_t baud, uint32_t timeout)
+void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint16_t frameIntv, uint16_t timeout)
{
ASSERT_PARAM(IS_VALID_CH(ch));
ASSERT_PARAM(IS_VALID_POINT(txBuf));
@@ -112,7 +113,7 @@ void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t
ring_buffer_init(&uartHandlerArr[ch].rxRingBuffer, rxBuf, rxLen);
/* 初始化各参数 */
uartHandlerArr[ch].uartTxEnFn = txEnFn;
- uart_hr_set_frame_intv(ch, baud);
+ uartHandlerArr[ch].targetFrameIntv = frameIntv;
uartHandlerArr[ch].recTimeout = timeout;
}
@@ -262,27 +263,17 @@ uint32_t uart_hr_write_tx_buf(uint8_t ch, void *pBuf, uint32_t len)
/**
* @brief 设置串口管理帧间隔超时时间ms
*
- * @param ch : 串口管理序号(即数组索引)
+ * @param ch : 串口管理序号(即数组索引)
*
- * @param baud : 波特率(内部转换为帧间隔超时时间,填0则帧间隔超时时间为0)
+ * @param frameIntv : 帧间隔超时时间ms,填0则帧间隔超时时间为0
*
* @retval None
*/
-void uart_hr_set_frame_intv(uint8_t ch, uint32_t baud)
+void uart_hr_set_frame_intv(uint8_t ch, uint16_t frameIntv)
{
- /* 波特率>9600则默认取3ms */
- if(9600 < baud)
- {
- uartHandlerArr[ch].targetFrameIntv = 3;
- } /* 波特率=0则取0ms */
- else if(0 == baud)
- {
- uartHandlerArr[ch].targetFrameIntv = 0;
- } /* 波特率<=9600则取该波特率下传输3.5个字节的时间 */
- else
- {
- uartHandlerArr[ch].targetFrameIntv = 10000 / baud * 3.5;
- }
+ ASSERT_PARAM(IS_VALID_CH(ch));
+
+ uartHandlerArr[ch].targetFrameIntv = frameIntv;
}
/**
@@ -294,6 +285,8 @@ void uart_hr_set_frame_intv(uint8_t ch, uint32_t baud)
*/
uint16_t uart_hr_get_frame_intv(uint8_t ch)
{
+ ASSERT_PARAM(IS_VALID_CH(ch));
+
return uartHandlerArr[ch].targetFrameIntv;
}
diff --git a/src/modules/uart_handler.h b/src/modules/uart_handler.h
index 979b333718692ff584dd2a290854a8fc44f61200..8b38a0aeb7ba8e7928fd1f74c8a2068f88fa5cf6 100644
--- a/src/modules/uart_handler.h
+++ b/src/modules/uart_handler.h
@@ -1,16 +1,16 @@
/**
******************************************************************************
* @file uart_handler.h
- * @author woshiashuai
- * @version V2.2
- * @date 2024-01-28
+ * @author ashuai0110
+ * @version V2.3
+ * @date 2024-07-01
* @brief 串口管理(使用帧间隔分帧或现有的分帧方法)
*
******************************************************************************
* @attention
*
* 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
- * 出处链接:https://gitee.com/woshiashuai/mcu_development_module.git
+ * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
*
******************************************************************************
*/
@@ -42,7 +42,7 @@ extern "C" {
* @{
*/
-#define UART_HANDLER_NUM (3u) /*!< 串口管理数量 用户按需修改 */
+#define UART_HANDLER_NUM (2u) /*!< 串口管理数量 用户按需修改 */
/**
* @}
@@ -69,13 +69,13 @@ typedef void (* uart_tx_en_fn_t)(uint8_t enState);
* @brief 串口管理 structure definition
*/
typedef struct uart_handler {
- uint8_t targetFrameIntv; /*!< 目标帧间隔ms */
- volatile uint32_t curFrameIntv; /*!< 当前帧间隔ms */
- volatile uint32_t recTimeoutCnt; /*!< 接收超时计数ms */
- uint32_t recTimeout; /*!< 接收超时时间ms */
- ring_buffer_t txRingBuffer; /*!< 发送环形队列 */
- ring_buffer_t rxRingBuffer; /*!< 接收环形队列 */
- uart_tx_en_fn_t uartTxEnFn; /*!< 串口发送前准备函数 */
+ uint16_t targetFrameIntv; /*!< 目标帧间隔ms */
+ uint16_t recTimeout; /*!< 接收超时时间ms */
+ uint32_t curFrameIntv; /*!< 当前帧间隔ms */
+ uint32_t recTimeoutCnt; /*!< 接收超时计数ms */
+ ring_buffer_t txRingBuffer; /*!< 发送环形队列 */
+ ring_buffer_t rxRingBuffer; /*!< 接收环形队列 */
+ uart_tx_en_fn_t uartTxEnFn; /*!< 串口发送前准备函数 */
} uart_handler_t;
/**
@@ -90,7 +90,7 @@ typedef struct uart_handler {
* @{
*/
-void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint32_t baud, uint32_t timeout);
+void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint16_t frameIntv, uint16_t timeout);
uint8_t uart_hr_poll(uint8_t ch);
@@ -101,7 +101,7 @@ uint32_t uart_hr_read_tx_buf(uint8_t ch, void *pBuf, uint32_t len);
uint32_t uart_hr_write_tx_buf(uint8_t ch, void *pBuf, uint32_t len);
/* set/get interface */
-void uart_hr_set_frame_intv(uint8_t ch, uint32_t baud);
+void uart_hr_set_frame_intv(uint8_t ch, uint16_t frameIntv);
uint16_t uart_hr_get_frame_intv(uint8_t ch);
void uart_hr_set_rec_timeout(uint8_t ch, uint16_t timeout);
uint16_t uart_hr_get_rec_timeout(uint8_t ch);
diff --git a/src/other/cJSON.c b/src/other/cJSON.c
new file mode 100644
index 0000000000000000000000000000000000000000..72ba3ccc689efe2ca83c04b72d436005f86652f1
--- /dev/null
+++ b/src/other/cJSON.c
@@ -0,0 +1,249 @@
+/* cJSON */
+/* JSON parser in C. */
+#include "cJSON.h"
+#include
+#include
+
+static const char *ep;
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+ if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+ for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
+ return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+// 用户自行对接接口
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+ cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+ if (node) memset(node,0,sizeof(cJSON));
+ return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+ cJSON *next;
+ while (c)
+ {
+ next=c->next;
+ if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+ if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+ if (c->string) cJSON_free(c->string);
+ cJSON_free(c);
+ c=next;
+ }
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+ double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+ if (*num=='-') sign=-1,num++; /* Has sign? */
+ if (*num=='0') num++; /* is zero */
+ if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
+ if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
+ if (*num=='e' || *num=='E') /* Exponent? */
+ { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
+ while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
+ }
+
+ n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
+
+ item->valuedouble=n;
+ item->valueint=(int)n;
+ item->type=cJSON_Number;
+ return num;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+ unsigned h=0;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+ const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+ if (*str!='\"') {ep=str;return 0;} /* not a string! */
+
+ while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
+
+ out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
+ if (!out) return 0;
+
+ ptr=str+1;ptr2=out;
+ while (*ptr!='\"' && *ptr)
+ {
+ if (*ptr!='\\') *ptr2++=*ptr++;
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b': *ptr2++='\b'; break;
+ case 'f': *ptr2++='\f'; break;
+ case 'n': *ptr2++='\n'; break;
+ case 'r': *ptr2++='\r'; break;
+ case 't': *ptr2++='\t'; break;
+ case 'u': /* transcode utf16 to utf8. */
+ uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
+
+ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
+
+ if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
+ {
+ if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
+ uc2=parse_hex4(ptr+3);ptr+=6;
+ if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
+ uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+ }
+
+ len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+
+ switch (len) {
+ case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 1: *--ptr2 =(uc | firstByteMark[len]);
+ }
+ ptr2+=len;
+ break;
+ default: *ptr2++=*ptr; break;
+ }
+ ptr++;
+ }
+ }
+ *ptr2=0;
+ if (*ptr=='\"') ptr++;
+ item->valuestring=out;
+ item->type=cJSON_String;
+ return ptr;
+}
+
+///* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+//static char *print_value(cJSON *item,int depth,int fmt);
+static const char *parse_array(cJSON *item,const char *value);
+//static char *print_array(cJSON *item,int depth,int fmt);
+static const char *parse_object(cJSON *item,const char *value);
+//static char *print_object(cJSON *item,int depth,int fmt);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
+{
+ const char *end=0;
+ cJSON *c=cJSON_New_Item();
+ ep=0;
+ if (!c) return 0; /* memory fail */
+
+ end=parse_value(c,skip(value));
+ if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
+ if (return_parse_end) *return_parse_end=end;
+ return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+ if (!value) return 0; /* Fail on null. */
+ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
+ if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
+ if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
+ if (*value=='\"') { return parse_string(item,value); }
+ if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
+ if (*value=='[') { return parse_array(item,value); }
+ if (*value=='{') { return parse_object(item,value); }
+
+ ep=value;return 0; /* failure. */
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+ cJSON *child;
+ if (*value!='[') {ep=value;return 0;} /* not an array! */
+
+ item->type=cJSON_Array;
+ value=skip(value+1);
+ if (*value==']') return value+1; /* empty array. */
+
+ item->child=child=cJSON_New_Item();
+ if (!item->child) return 0; /* memory fail */
+ value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+
+ while (*value==',')
+ {
+ cJSON *new_item;
+ if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
+ child->next=new_item;new_item->prev=child;child=new_item;
+ value=skip(parse_value(child,skip(value+1)));
+ if (!value) return 0; /* memory fail */
+ }
+
+ if (*value==']') return value+1; /* end of array */
+ ep=value;return 0; /* malformed. */
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+ cJSON *child;
+ if (*value!='{') {ep=value;return 0;} /* not an object! */
+
+ item->type=cJSON_Object;
+ value=skip(value+1);
+ if (*value=='}') return value+1; /* empty array. */
+
+ item->child=child=cJSON_New_Item();
+ if (!item->child) return 0;
+ value=skip(parse_string(child,skip(value)));
+ if (!value) return 0;
+ child->string=child->valuestring;child->valuestring=0;
+ if (*value!=':') {ep=value;return 0;} /* fail! */
+ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+
+ while (*value==',')
+ {
+ cJSON *new_item;
+ if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
+ child->next=new_item;new_item->prev=child;child=new_item;
+ value=skip(parse_string(child,skip(value+1)));
+ if (!value) return 0;
+ child->string=child->valuestring;child->valuestring=0;
+ if (*value!=':') {ep=value;return 0;} /* fail! */
+ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+ }
+
+ if (*value=='}') return value+1; /* end of array */
+ ep=value;return 0; /* malformed. */
+}
+
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+
diff --git a/src/other/cJSON.h b/src/other/cJSON.h
new file mode 100644
index 0000000000000000000000000000000000000000..15755991d0303e338dd245b5a20032bd3958cb2c
--- /dev/null
+++ b/src/other/cJSON.h
@@ -0,0 +1,50 @@
+#ifndef cJSON__h
+#define cJSON__h
+
+#include "common_include.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+#define cJSON_IsReference 256
+
+/* The cJSON structure: */
+typedef struct cJSON {
+ struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+ int type; /* The type of the item, as above. */
+ char *valuestring; /* The item's string, if type==cJSON_String */
+ int valueint; /* The item's number, if type==cJSON_Number */
+ double valuedouble; /* The item's number, if type==cJSON_Number */
+
+ char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Delete a cJSON entity and all subentities. */
+extern void cJSON_Delete(cJSON *c);
+
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif