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