添加gs21 sdk源码 GS21_1.10.100 1521/2 1521/head 1527/target/1
authorSnickerSun <snickersun@163.com>
Mon, 16 Dec 2024 09:12:36 +0000 (17:12 +0800)
committerSnickerSun <snickersun@163.com>
Mon, 16 Dec 2024 09:12:36 +0000 (17:12 +0800)
218 files changed:
code/sdk/zhihui/GS21_1.10.100/agnss/server_agnss_download_demo/server_agnss_download_demo.py [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/Makefile [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller_helper.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_device_info.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware_utils.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_log.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/gnss_board_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_misc_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_pin_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_uart_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/osal_porting/tiot_osal.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface_ext.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securec.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securectype.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/Makefile [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fwscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/gets_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/input.inl [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memcpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memmove_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memset_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/output.inl [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/scanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secinput.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_a.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_w.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_a.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_w.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/snprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcat_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncat_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strtok_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfwscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsnprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswprintf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vwscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscat_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncat_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcstok_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemcpy_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemmove_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wscanf_s.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_slave_handle.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_types.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_buf/tiot_circ_buf.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/list/tiot_list.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/tiot_types.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/Makefile [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/Makefile [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/readme.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_autoconfig.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_defconfig [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/readme.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_autoconfig.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_defconfig [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/readme.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_autoconfig.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_defconfig [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/readme.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_autoconfig.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_defconfig [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/readme.md [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/gnss_board_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/porting.mk [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_log_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_misc_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_pin_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_uart_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_osal_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_board_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_misc_device.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/porting.mk [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_log_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_misc_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_uart_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_dts_node.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_osal_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/gnss_board_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_log_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_misc_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_pin_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_uart_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_freertos_demo.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_nonos_demo.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_rtos_demo.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/gnss_board_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_log_port.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_misc_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_pin_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_uart_port.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_autoconfig.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_defconfig [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_cfg.bin [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/gnss_config.bin [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format2/gnss_config_array.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pdr/include/pdr_interface.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pdr/libpdr_fusion.a [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/libpgnss_decoder.so [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/pgnss_decoder_interface.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/build_and_run.sh [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/clean.sh [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/demo_data/EE_7days.dat [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/server_pgnss_decode_demo.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_download_demo/server_pgnss_download_demo.py [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/gnss_datatypes.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/gnss_datatypes.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/gnss_datatypes.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_acc.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_gyro.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.h [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.c [new file with mode: 0644]
code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.h [new file with mode: 0644]

diff --git a/code/sdk/zhihui/GS21_1.10.100/agnss/server_agnss_download_demo/server_agnss_download_demo.py b/code/sdk/zhihui/GS21_1.10.100/agnss/server_agnss_download_demo/server_agnss_download_demo.py
new file mode 100644 (file)
index 0000000..e4f959e
--- /dev/null
@@ -0,0 +1,146 @@
+#!/usr/bin/env python\r
+# coding:utf-8\r
+# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
+import requests\r
+import time\r
+import calendar\r
+import hmac\r
+import base64\r
+import binascii\r
+\r
+\r
+# 网络连接相关\r
+HOST = r'geo-drcn.platform.dbankcloud.cn'  # 域名\r
+PORT = 443  # 端口号\r
+URI = r'/higeo/v1/xgnss/agnss'  # uri路径\r
+\r
+# 鉴权认证相关\r
+APP_ID = r''  # 账号,请联系销售代表获取\r
+APP_SECRET = b''  # 密钥,请联系销售代表获取\r
+UUID = r''  # 每台设备的唯一标识码,请根据产品进行适配\r
+\r
+# 请求参数\r
+CONSTELLATION = r''  # 掩码表示卫星模式,0x1=GPS,0x2=GLONASS,0x4=BEIDOU,0x8=GALILEO,默认15表示全模\r
+DATATYPE = r''  # 掩码表示请求的数据类型,0x1=星历,0x2=UTC模型,0x4=电离层参数,0x8=实时完好性信息,0x10=频点对应关系,默认31表示全部数据\r
+\r
+\r
+class AgnssRequest:\r
+    def __init__(self):\r
+        self.ts = 0\r
+        self.qry_str = ''\r
+        self.signature = ''\r
+        self.url = ''\r
+        self.session = requests.session()\r
+\r
+    def format_req_str(self):\r
+        qry_str = ''\r
+        if CONSTELLATION and CONSTELLATION != '15':\r
+            # constellation默认值15,则无需填写\r
+            qry_str += f'constellation={CONSTELLATION}'\r
+        if DATATYPE and DATATYPE != '31':\r
+            # datatype默认值31,则无需填写\r
+            qry_str += f'&datatype={DATATYPE}' if qry_str else f'datatype={DATATYPE}'\r
+        self.qry_str = qry_str\r
+\r
+    def gen_auth_str(self):\r
+        # 构造待签名字符串\r
+        str_to_sign = f'GET&{URI}&{self.qry_str}&&appid={APP_ID}&timestamp={self.ts}'\r
+        # 计算签名HMAC值\r
+        h1 = hmac.new(key=APP_SECRET, digestmod='sha256')\r
+        h1.update(str_to_sign.encode('utf-8'))\r
+        b1 = base64.b64encode(h1.digest())\r
+        signature = b1.decode('utf-8')\r
+        self.signature = signature\r
+\r
+    def update_session(self):\r
+        # 填充完整url\r
+        self.url = r'https://{}:{}{}{}{}'.format(HOST, PORT, URI, '?' if self.qry_str else '', self.qry_str)\r
+        # 组装请求消息头\r
+        self.session.headers.update(\r
+            {\r
+                'X-Request-ID': f'{UUID}',\r
+                'Authorization': f'HMAC-SHA256 appid={APP_ID},timestamp={self.ts},signature={self.signature}'\r
+            }\r
+        )\r
+\r
+    def connect_session(self):\r
+        try:\r
+            print(f'正在连接服务器...')\r
+            rsp = self.session.get(url=self.url, verify=False, timeout=(3, 27))\r
+            print(f'Agnss请求结果:{rsp.status_code},结果码:{rsp.reason}, 响应长度:{len(rsp.content)}')\r
+\r
+            # 处理响应值\r
+            if rsp.status_code == 200:\r
+                # 响应200表示请求成功\r
+                print(r'响应内容:')\r
+                # 响应内容的Agnss辅助数据是二进制码流,转换成16进制打印\r
+                print(binascii.hexlify(rsp.content))\r
+                print(f'Agnss辅助数据请求成功')\r
+                with open(r'.\AGNSS.dat', 'wb') as f:\r
+                    f.write(rsp.content)\r
+            elif rsp.status_code == 401:\r
+                if rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'unix时间戳异常,请检查服务器下发的响应消息头中“X-Auth-Timestamp”与请求消息头的'\r
+                          r'“Authorization”中的“timestamp”是否相差很大')\r
+                    print(r'请检查“timestamp”是否取用正确的UNIX时间戳,单位是毫秒')\r
+                    # 如设备本身无时间系统,可在此处取用服务器下发的“X-Auth-Timestamp”进行重新请求\r
+                    print(f'响应消息头:{rsp.headers}')\r
+                    server_ts = rsp.headers.get('X-Auth-Timestamp', 0)\r
+                    self.ts = server_ts\r
+                    # 签名认证\r
+                    self.gen_auth_str()\r
+                    # 更新请求消息头\r
+                    self.update_session()\r
+                    # 重新请求\r
+                    rsp2 = self.session.get(url=self.url, verify=False, timeout=(3, 27), proxies=PROXIES)\r
+                    print(f'Agnss重新请求结果:{rsp2.status_code},结果码:{rsp2.reason}, 响应长度:{len(rsp2.content)}')\r
+\r
+                elif rsp.reason == 'authorization is missed':\r
+                    print(r'“Authorization”字段异常,请检查请求消息头是否正确填写“Authorization”字段')\r
+                elif rsp.reason == 'appid is missed':\r
+                    print(r'“appid”字段异常,请检查请求消息头的“Authorization”中是否正确填写“appid”字段')\r
+                elif rsp.reason == 'timestamp is invalid':\r
+                    print(r'“timestamp”字段异常,请检查请求消息头的“Authorization”中是否正确填写“timestamp”字段')\r
+                elif rsp.reason == 'signature is invalid':\r
+                    print(r'“signature”字段异常,请检查请求消息头的“Authorization”中已填写“signature”字段')\r
+                elif rsp.reason == "Can't get the keys of appid":\r
+                    print(r'“appid”无效,请检查请求消息头的“Authorization”中的“appid”的合法性')\r
+                elif rsp.reason == 'SignatureInvalid':\r
+                    print(r'“signature”异常,请检查请求消息头的“Authorization”中的“signature”正确性,'\r
+                          r'检查appid和app_secret是否匹配')\r
+                elif rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'异常,请检查')\r
+                elif rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'异常,请检查')\r
+            self.session.close()\r
+        except requests.exceptions.SSLError as e:\r
+            print(e)\r
+            print('请检查网络是否通畅')\r
+        except requests.exceptions.ProxyError as e:\r
+            print(e)\r
+            print('请检查网络是否通畅')\r
+        except Exception as e:\r
+            print(e)\r
+\r
+    def request(self, ts=0):\r
+        self.ts = ts\r
+\r
+        # step1. 构造规范化请求字符串\r
+        self.format_req_str()\r
+\r
+        # step2. 构造鉴权信息字符串\r
+        self.gen_auth_str()\r
+\r
+        # step3. 构造HTTP GET请求\r
+        self.update_session()\r
+        print(f'请求URL:{self.url}')\r
+\r
+        # step4. 发送请求\r
+        self.connect_session()\r
+\r
+\r
+if __name__ == '__main__':\r
+    # 获取当前UNIX时间,单位毫秒\r
+    now = calendar.timegm(time.gmtime()) * 1000\r
+    agnss = AgnssRequest()\r
+    agnss.request(now)\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6958bd1
--- /dev/null
@@ -0,0 +1,75 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+# 此处为TIoT驱动顶层CMake
+
+# CMake读取Kconfig配置
+function(KCONFIG_GET_PARAMS KCONFIG_PATH)
+    file(STRINGS ${KCONFIG_PATH} TIOT_CONFIG_LIST ENCODING "UTF-8")
+
+    foreach (CONFIG ${TIOT_CONFIG_LIST})
+        # CONFIG maybe: CONFIG_CC_STACKPROTECTOR_STRONG=y
+
+        # The first: variable name
+        string(REGEX MATCH "[^=]+" CONFIG_VAR_NAME ${CONFIG})
+
+        # The second: variable value
+        string(REGEX MATCH "=(.+$)" CONFIG_VAR_VAL ${CONFIG})
+        set(CONFIG_VAR_VAL ${CMAKE_MATCH_1})
+        if(CONFIG_VAR_VAL MATCHES "^y$")
+            set(${CONFIG_VAR_NAME} ${CONFIG_VAR_VAL} PARENT_SCOPE)
+        endif()
+    endforeach()
+endfunction()
+
+macro(add_subdirectory_if_exist _path)
+    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_path}/CMakeLists.txt)
+        add_subdirectory(${_path})
+    endif()
+endmacro()
+
+macro(list_sub_dirs result curdir)
+  file(GLOB children RELATIVE ${curdir} ${curdir}/*)
+  set(dirlist "")
+  foreach(child ${children})
+    if(IS_DIRECTORY ${curdir}/${child})
+      list(APPEND dirlist ${child})
+    endif()
+  endforeach()
+  set(${result} ${dirlist})
+endmacro()
+
+if(NOT DEFINED TIOT_COMMON_DIR)
+    set(TIOT_COMMON_DIR "${CMAKE_CURRENT_SOURCE_DIR}/common")
+endif()
+
+if(NOT DEFINED TIOT_PORTING_DIR)
+    set(TIOT_PORTING_DIR "${CMAKE_CURRENT_SOURCE_DIR}/product_porting")
+endif()
+
+if(NOT DEFINED TIOT_PORTING_CONFIG_DIR)
+    set(TIOT_PORTING_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/product_porting")
+endif()
+
+if(NOT DEFINED TIOT_DEVICE_LIST)
+    list_sub_dirs(TIOT_DEVICE_LIST ${CMAKE_CURRENT_SOURCE_DIR}/device)
+endif()
+
+# 初始化CMake全局变量
+set(TIOT_CFLAGS "SHELL:-include ${TIOT_PORTING_CONFIG_DIR}/tiot_autoconfig.h" CACHE INTERNAL "tiot c flags" FORCE)
+# all header and files listed here
+set(TIOT_HEADER_LIST "" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "" CACHE INTERNAL "tiot src list" FORCE)
+
+# 获取Kconfig配置
+KCONFIG_GET_PARAMS(${TIOT_PORTING_CONFIG_DIR}/tiot_defconfig)
+
+# devices
+foreach(tiot_device ${TIOT_DEVICE_LIST})
+    add_subdirectory_if_exist(device/${tiot_device})
+endforeach()
+# common
+add_subdirectory("${TIOT_COMMON_DIR}" common.out)
+# porting
+add_subdirectory("${TIOT_PORTING_DIR}" porting.out)
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/Makefile b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/Makefile
new file mode 100644 (file)
index 0000000..bf18c6f
--- /dev/null
@@ -0,0 +1,194 @@
+# This is the top of TIoT driver core Makefile.
+# 编译形态,builts-in, module, 不编译
+CONFIG_TIOT_DRIVER ?= m
+TIOT_PORTING_DIR ?= product_porting
+TIOT_PORTING_CONFIG_DIR ?= product_porting
+KERNEL_DIR ?=
+MODULE_PARAM ?=
+TIOT_OUT_OF_TREE_BUILD=n
+
+# 当前目录
+PWD := $(abspath $(lastword $(MAKEFILE_LIST)))
+# 指定TIoT驱动目录,用于Out of tree编译
+TIOT_DRIVER_PATH ?= $(dir $(PWD))
+$(warning pwd = $(PWD))
+
+# 寻找所有可用devices
+TIOT_TARGET_DEVICES := $(patsubst $(TIOT_DRIVER_PATH)/device/%,%,$(wildcard $(TIOT_DRIVER_PATH)/device/*))
+$(warning device lists = $(TIOT_TARGET_DEVICES))
+
+ifneq ($(KERNEL_DIR),)
+ifeq ($(KERNELRELEASE),)
+ifeq ($(CONFIG_TIOT_DRIVER),m)
+TIOT_OUT_OF_TREE_BUILD=y
+endif
+endif
+endif
+
+# 对于ko编译,首先进入内核源码,再通过kbuild系统进入此Makefile
+ifeq ($(TIOT_OUT_OF_TREE_BUILD),y)
+# 进入内核目录,之后再回到当前目录
+$(warning Module param $(MODULE_PARAM))
+default:
+       $(MAKE) -C $(KERNEL_DIR) $(MODULE_PARAM) M=$(TIOT_DRIVER_PATH) modules
+
+clean:
+       $(MAKE) -C $(KERNEL_DIR) M=$(TIOT_DRIVER_PATH) clean
+       -find device/ -type f -name "*.o" -exec rm -f {} \;
+       -find device/ -type f -name "*.o.cmd" -exec rm -f {} \;
+       -find device/ -type f -name "*.o.d" -exec rm -f {} \;
+       -find device/ -type f -name "*.o.symversions" -exec rm -f {} \;
+       -find common/ -type f -name "*.o" -exec rm -f {} \;
+       -find common/ -type f -name "*.o.cmd" -exec rm -f {} \;
+       -find common/ -type f -name "*.o.d" -exec rm -f {} \;
+       -find common/ -type f -name "*.o.symversions" -exec rm -f {} \;
+else
+# 此处为第二次进入
+$(warning twice enter)
+include $(TIOT_DRIVER_PATH)/$(TIOT_PORTING_CONFIG_DIR)/tiot_defconfig
+
+# Devices
+$(foreach dev,$(TIOT_TARGET_DEVICES),$(eval -include $(TIOT_DRIVER_PATH)/device/$(dev)/Makefile))
+
+# Common
+tiot-controller-objs += tiot_controller.o
+tiot-controller-objs := $(addprefix common/controller/,$(tiot-controller-objs))
+
+tiot-interface-objs += board_interface/board_internal/tiot_board_xmit_ops.o
+tiot-interface-objs += device_interface/tiot_service_interface.o
+tiot-interface-objs := $(addprefix common/interface/,$(tiot-interface-objs))
+
+tiot-fw-objs += tiot_firmware.o
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_PRIV), y)
+tiot-fw-priv-objs += tiot_cfg_handle_priv.o
+tiot-fw-priv-objs := $(addprefix cfg_handle_priv/,$(tiot-fw-priv-objs))
+tiot-fw-objs += ${tiot-fw-priv-objs}
+endif
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_XCI), y)
+tiot-fw-xci-objs += tiot_cfg_handle_xci.o
+tiot-fw-xci-objs := $(addprefix cfg_handle_xci/,$(tiot-fw-xci-objs))
+tiot-fw-objs += ${tiot-fw-xci-objs}
+endif
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_HIBURN), y)
+tiot-fw-hiburn-objs += cfg_handle_hiburn/tiot_cfg_handle_hiburn.o
+tiot-fw-objs += ${tiot-fw-hiburn-objs}
+endif
+tiot-fw-objs := $(addprefix common/fw_load/,$(tiot-fw-objs))
+
+tiot-pm-objs += tiot_pm.o tiot_pm_wakelock.o
+tiot-pm-objs += pm_default/tiot_pm_default.o
+ifeq ($(CONFIG_DEV_TIOT_SLAVE), y)
+tiot-pm-objs += pm_slave/tiot_pm_slave.o
+endif
+tiot-pm-objs := $(addprefix common/pm/,$(tiot-pm-objs))
+
+tiot-transfer-objs += tiot_xfer.o tiot_xfer_utils.o
+ifeq ($(CONFIG_XFER_PACKET_TIOT), y)
+tiot-packet-objs += tiot_packet.o tiot_packet_manager.o
+tiot-packet-objs := $(addprefix packet_handle/tiot_packet/,$(tiot-packet-objs))
+tiot-transfer-objs += $(tiot-packet-objs)
+endif
+ifeq ($(CONFIG_XFER_PACKET_NCI), y)
+tiot-nci-packet-objs += tiot_nci_packet.o
+tiot-nci-packet-objs := $(addprefix packet_handle/nci_packet/,$(tiot-nci-packet-objs))
+tiot-transfer-objs += $(tiot-nci-packet-objs)
+endif
+tiot-transfer-objs := $(addprefix common/transfer/,$(tiot-transfer-objs))
+
+tiot-sys-msg-handler-objs += tiot_sys_msg_handle.o
+ifeq ($(CONFIG_DEV_TIOT_SLAVE), y)
+tiot-sys-msg-handler-objs += tiot_sys_msg_slave_handle.o
+endif
+tiot-sys-msg-handler-objs := $(addprefix common/sys_msg_handler/,$(tiot-sys-msg-handler-objs))
+
+# Utils
+tiot-circ-queue-objs += circ_queue/tiot_circ_queue.o
+tiot-fileops-objs += fileops/tiot_fileops.o
+tiot-misc-objs += misc/tiot_misc.o
+
+tiot-utils-objs += $(tiot-circ-queue-objs)
+tiot-utils-objs += $(tiot-fileops-objs)
+tiot-utils-objs += $(tiot-misc-objs)
+tiot-utils-objs := $(addprefix common/utils/,$(tiot-utils-objs))
+
+ifneq ($(CONFIG_LIBBOUNDSCHECK_IMPLEMENTED), y)
+# libboundscheck
+tiot-boundscheck-objs += memcpy_s.o memmove_s.o memset_s.o securecutil.o secureprintoutput_a.o \
+                                                snprintf_s.o sprintf_s.o strcat_s.o strcpy_s.o strncat_s.o strncpy_s.o \
+                                                vsnprintf_s.o vsprintf_s.o strtok_s.o sscanf_s.o vsscanf_s.o secureinput_a.o
+tiot-boundscheck-objs := $(addprefix common/libboundscheck/src/,$(tiot-boundscheck-objs))
+endif
+
+# Porting
+include $(TIOT_DRIVER_PATH)/$(TIOT_PORTING_DIR)/Makefile
+
+# All
+tiot_driver-objs += $(tiot-controller-objs)
+
+tiot_driver-objs += $(tiot-interface-objs)
+
+tiot_driver-objs += $(tiot-fw-objs)
+
+tiot_driver-objs += $(tiot-pm-objs)
+
+tiot_driver-objs += $(tiot-transfer-objs)
+
+tiot_driver-objs += $(tiot-sys-msg-handler-objs)
+
+tiot_driver-objs += $(tiot-utils-objs)
+
+tiot_driver-objs += $(tiot-porting-objs)
+
+ifneq ($(CONFIG_LIBBOUNDSCHECK_IMPLEMENTED), y)
+tiot_driver-objs += $(tiot-boundscheck-objs)
+endif
+
+obj-$(CONFIG_TIOT_DRIVER) += tiot_driver.o
+
+TIOT_SRC_LIST := $(tiot_driver-objs)
+
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/controller
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/fw_load
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_PRIV), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/fw_load/cfg_handle_priv
+endif
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_XCI), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/fw_load/cfg_handle_xci
+endif
+ifeq ($(CONFIG_FIRMWARE_CFG_HANDLE_HIBURN), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/fw_load/cfg_handle_hiburn
+endif
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/interface/board_interface/board_internal
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/interface/board_interface/board_porting
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/interface/board_interface/osal_porting
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/interface/device_interface
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/pm
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/pm/pm_default
+ifeq ($(CONFIG_DEV_TIOT_SLAVE), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/pm/pm_slave
+endif
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/transfer
+ifeq ($(CONFIG_XFER_PACKET_TIOT), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/transfer/packet_handle/tiot_packet
+endif
+ifeq ($(CONFIG_XFER_PACKET_NCI), y)
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/transfer/packet_handle/nci_packet
+endif
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/sys_msg_handler
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils/list
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils/circ_buf
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils/circ_queue
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils/fileops
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/utils/misc
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/common/libboundscheck/include
+
+TIOT_CFLAGS += -include $(TIOT_DRIVER_PATH)/$(TIOT_PORTING_CONFIG_DIR)/tiot_autoconfig.h
+TIOT_CFLAGS += $(TIOT_HEADER_LIST)
+
+# We use c99, suppress some warning for kernel c89.
+subdir-ccflags-y := $(TIOT_CFLAGS) -Wno-error=declaration-after-statement
+
+$(warning TIOT_SRC_LIST: $(TIOT_SRC_LIST))
+
+endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/CMakeLists.txt
new file mode 100644 (file)
index 0000000..08498a6
--- /dev/null
@@ -0,0 +1,20 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+add_subdirectory(controller)
+add_subdirectory(fw_load)
+add_subdirectory(interface)
+add_subdirectory(libboundscheck)
+add_subdirectory(pm)
+add_subdirectory(transfer)
+add_subdirectory(sys_msg_handler)
+add_subdirectory(utils)
+
+if(DEFINED CONFIG_COMMON_SUPPORT_DEBUG)
+add_subdirectory_if_exist(debug)
+endif()
+
+if(DEFINED CONFIG_COMMON_SUPPORT_DFR)
+add_subdirectory_if_exist(dfr)
+endif()
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/CMakeLists.txt
new file mode 100644 (file)
index 0000000..89ea3c5
--- /dev/null
@@ -0,0 +1,11 @@
+#===============================================================================\r
+# @brief    cmake make file\r
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+#===============================================================================\r
+set(\r
+    tiot_controller_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_controller.c\r
+)\r
+\r
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)\r
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_controller_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.c
new file mode 100644 (file)
index 0000000..3fe85a0
--- /dev/null
@@ -0,0 +1,157 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: TIoT device controller. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-17, Create file. \n\r
+ */\r
+\r
+#include <stddef.h>\r
+#include "tiot_device_info.h"\r
+#include "tiot_controller.h"\r
+#include "tiot_board_log.h"\r
+\r
+#define CTRL_OPEN_COUNT_MAX  0xFFFFFFFFU\r
+\r
+int32_t tiot_controller_init(tiot_controller *ctrl, tiot_controller_info *info)\r
+{\r
+    int32_t ret;\r
+    tiot_board_info *board_info = info->board_info;\r
+    const tiot_device_info *device_info = info->dev_info;\r
+\r
+    if ((ctrl == NULL) || (ctrl->state == TIOT_CONTROLLER_INIT)) {\r
+        return -1;\r
+    }\r
+\r
+    /***** 软件初始化 *****/\r
+    /* 初始化open状态互斥锁. */\r
+    ret = osal_mutex_init(&ctrl->open_mutex);\r
+    if (ret != 0) {\r
+        goto mutex_init_fail;\r
+    }\r
+\r
+    /* 注册:1) PM状态机,如为NULL则使用默认状态机.\r
+             2)板级PM管脚信息,依据产品不同而不同. */\r
+    ret = tiot_pm_init(&ctrl->pm, board_info->hw_info.pm_info,\r
+                       device_info->pm_event_map, device_info->pm_event_map_size);\r
+    if (ret != 0) {\r
+        goto pm_init_fail;\r
+    }\r
+\r
+    /* 注册:1)固件加载回调,加载前 + 加载后,用于注册不同加载协议或设置波特率等,依据芯片不同而不同. */\r
+    ret = tiot_firmware_init(&ctrl->firmware, &device_info->exec_cbs);\r
+    if (ret != 0) {\r
+        goto fw_init_fail;\r
+    }\r
+\r
+    /* 注册:1) 接收回调 */\r
+    ret = tiot_xfer_init(&ctrl->transfer, board_info->hw_info.xmit_id, &device_info->xfer_info);\r
+    if (ret != 0) {\r
+        goto xfer_init_fail;\r
+    }\r
+\r
+    /* device info必须为静态分配变量. */\r
+    ctrl->dev_info = device_info;\r
+    ctrl->state = TIOT_CONTROLLER_INIT;\r
+    ctrl->dev_cus = (uintptr_t)info->dev_cus;\r
+\r
+    return 0;\r
+\r
+xfer_init_fail:\r
+    tiot_xfer_deinit(&ctrl->transfer);\r
+    memset_s((void *)&ctrl->transfer, sizeof(tiot_xfer_manager), 0, sizeof(tiot_xfer_manager));\r
+fw_init_fail:\r
+    memset_s((void *)&ctrl->firmware, sizeof(tiot_fw), 0, sizeof(tiot_fw));\r
+pm_init_fail:\r
+    memset_s((void *)&ctrl->pm, sizeof(tiot_pm), 0, sizeof(tiot_pm));\r
+    osal_mutex_destroy(&ctrl->open_mutex);\r
+mutex_init_fail:\r
+    return ret;\r
+}\r
+\r
+int32_t tiot_controller_open(tiot_controller *ctrl, void *param)\r
+{\r
+    int32_t ret = 0;\r
+    if (ctrl == NULL) {\r
+        tiot_print_dbg("[TIoT]device is null.\n");\r
+        return -1;\r
+    }\r
+    osal_mutex_lock(&ctrl->open_mutex);\r
+    if (ctrl->state == TIOT_CONTROLLER_UNINIT) {\r
+        tiot_print_err("[TIoT]dev state wrong %d.\r\n", ctrl->state);\r
+        ret = -1;\r
+        goto out;\r
+    }\r
+    if (ctrl->open_count == CTRL_OPEN_COUNT_MAX) {\r
+        tiot_print_err("[TIoT]reach max open count.\r\n");\r
+        ret = -1;\r
+        goto out;\r
+    }\r
+    ctrl->open_count++;\r
+    if (ctrl->state == TIOT_CONTROLLER_OPEN) {\r
+        /* 重复调用open仅添加计数. */\r
+        goto out;\r
+    }\r
+    ctrl->state = TIOT_CONTROLLER_OPENING; /* 中间状态,受mutex锁保护,不需要在open内判断. */\r
+    if (ctrl->ops.open(ctrl, param) != 0) {\r
+        ctrl->open_count--;\r
+        ctrl->state = TIOT_CONTROLLER_INIT;\r
+        ret = -1;\r
+        goto out;\r
+    }\r
+    ctrl->state = TIOT_CONTROLLER_OPEN;\r
+out:\r
+    osal_mutex_unlock(&ctrl->open_mutex);\r
+    return ret;\r
+}\r
+\r
+bool tiot_controller_check_opened(tiot_controller *ctrl)\r
+{\r
+    bool ret = true;\r
+    if (ctrl == NULL) {\r
+        tiot_print_dbg("[TIoT]device is null.\n");\r
+        return false;\r
+    }\r
+    osal_mutex_lock(&ctrl->open_mutex);\r
+    if (ctrl->state != TIOT_CONTROLLER_OPEN) {\r
+        tiot_print_dbg("[TIoT]device not opened.\n");\r
+        ret = false;\r
+    }\r
+    osal_mutex_unlock(&ctrl->open_mutex);\r
+    return ret;\r
+}\r
+\r
+void tiot_controller_close(tiot_controller *ctrl)\r
+{\r
+    if (ctrl == NULL) {\r
+        tiot_print_dbg("[TIoT]device is null.\n");\r
+        return;\r
+    }\r
+    osal_mutex_lock(&ctrl->open_mutex);\r
+    if ((ctrl->state != TIOT_CONTROLLER_OPEN) && (ctrl->state != TIOT_CONTROLLER_OPENING)) {\r
+        tiot_print_dbg("[TIoT]device is not opening or not opened.\n");\r
+        osal_mutex_unlock(&ctrl->open_mutex);\r
+        return;\r
+    }\r
+    /* 打开状态且open_count >=1时,减少open_count计数; 当open_count减少后变为0时,实际调用close操作. */\r
+    ctrl->open_count--;\r
+    if (ctrl->open_count == 0) {\r
+        ctrl->ops.close(ctrl);\r
+        ctrl->state = TIOT_CONTROLLER_INIT;\r
+    }\r
+    osal_mutex_unlock(&ctrl->open_mutex);\r
+}\r
+\r
+void tiot_controller_deinit(tiot_controller *ctrl)\r
+{\r
+    if ((ctrl == NULL) || (ctrl->state == TIOT_CONTROLLER_UNINIT)) {\r
+        return;\r
+    }\r
+\r
+    tiot_xfer_deinit(&ctrl->transfer);\r
+    tiot_pm_deinit(&ctrl->pm);\r
+    osal_mutex_destroy(&ctrl->open_mutex);\r
+    (void)memset_s((void *)ctrl, sizeof(tiot_controller), 0, sizeof(tiot_controller));\r
+    ctrl->state = TIOT_CONTROLLER_UNINIT;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.h
new file mode 100644 (file)
index 0000000..64a0dd3
--- /dev/null
@@ -0,0 +1,152 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: TIoT device controller header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-17, Create file. \n\r
+ */\r
+\r
+#ifndef TIOT_CONTROLLER_H\r
+#define TIOT_CONTROLLER_H\r
+\r
+#ifndef __KERNEL__\r
+#include <stdbool.h>\r
+#endif\r
+#include "tiot_board.h"\r
+#include "tiot_pm.h"\r
+#include "tiot_firmware.h"\r
+#include "tiot_xfer.h"\r
+#include "tiot_device_info.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_controller Controller\r
+ * @ingroup  tiot_common\r
+ * @{\r
+ */\r
+\r
+/**\r
+ * @brief TIoT controller state.\r
+ */\r
+typedef enum {\r
+    TIOT_CONTROLLER_UNINIT,\r
+    TIOT_CONTROLLER_INIT,\r
+    TIOT_CONTROLLER_OPENING,\r
+    TIOT_CONTROLLER_OPEN,\r
+} tiot_controller_state;\r
+\r
+/**\r
+ * @brief TIoT controller info provided outside.\r
+ */\r
+typedef struct {\r
+    tiot_board_info *board_info;       /*!< Board infomations. */\r
+    const tiot_device_info *dev_info;  /*!< Reserved device info, must be allocated staticly. */\r
+    const tiot_dev_customize *dev_cus; /*!< Reserved device customize. */\r
+} tiot_controller_info;\r
+\r
+struct _tiot_controller;\r
+\r
+/**\r
+ * @brief  TIoT controller ops.\r
+ */\r
+typedef struct {\r
+    int32_t (* open)(struct _tiot_controller *ctrl, void *param);\r
+    void (* close)(struct _tiot_controller *ctrl);\r
+    int32_t (* write)(struct _tiot_controller *ctrl, const uint8_t *data,\r
+                      uint32_t len, const tiot_xfer_tx_param *param);\r
+    int32_t (* read)(struct _tiot_controller *ctrl, uint8_t *buff, uint32_t buff_len, const tiot_xfer_rx_param *param);\r
+    int32_t (* pm_ctrl)(struct _tiot_controller *ctrl, uint8_t cmd);\r
+} tiot_controller_ops;\r
+\r
+/**\r
+ * @brief TIoT device controller.\r
+ */\r
+typedef struct _tiot_controller {\r
+    uint32_t state;                    /*!< Current state. */\r
+    tiot_pm pm;                        /*!< Power Manangement module. */\r
+    tiot_fw firmware;                  /*!< Firmware module. */\r
+    tiot_xfer_manager transfer;        /*!< Transfer manager modele. */\r
+    const tiot_device_info *dev_info;  /*!< Reserved device info, must be allocated staticly. */\r
+    tiot_controller_ops ops;           /*!< Controller ops, open, close, write, read. */\r
+    volatile uint32_t open_count;      /*!< open count. */\r
+    osal_mutex open_mutex;             /*!< open state mutex. */\r
+    uintptr_t dev_cus;                  /*!< device customize. */\r
+} tiot_controller;\r
+\r
+/**\r
+ * @brief  TIoT find controller by pin from controllers.\r
+ * @param  [in]  ctrls TIoT controller instances array.\r
+ * @param  [in]  ctrl_num TIoT controller instances num.\r
+ * @param  [in]  pin Pin number.\r
+ * @param  [in]  pin_type Pin type.\r
+ * @return if found controller, return controller pointer, else return NULL.\r
+ */\r
+static inline tiot_controller *tiot_find_controller_by_pin(tiot_controller *ctrls, uint8_t ctrl_num,\r
+                                                           uint32_t pin, uint32_t pin_type)\r
+{\r
+    const uint32_t *pm_info;\r
+    uint8_t i;\r
+    for (i = 0; i < ctrl_num; i++) {\r
+        pm_info = ctrls[i].pm.pm_info;\r
+        if (pm_info[pin_type] == pin) {\r
+            return &ctrls[i];\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+/**\r
+ * @brief  TIoT controller init.\r
+ * @param  [in]  ctrl TIoT controller instance.\r
+ * @param  [in]  info TIoT controller information.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_controller_init(tiot_controller *ctrl, tiot_controller_info *info);\r
+\r
+/**\r
+ * @brief  TIoT controller open, if already opened, add open count only.\r
+ * @param  [in]  ctrl TIoT controller instance.\r
+ * @param  [in]  param TIoT controller open param.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_controller_open(tiot_controller *ctrl, void *param);\r
+\r
+/**\r
+ * @brief  TIoT controller check opened or not, must be used after init.\r
+ * @param  [in]  ctrl TIoT controller instance.\r
+ * @return true if Opened;\r
+ *         false if not opened.\r
+ */\r
+bool tiot_controller_check_opened(tiot_controller *ctrl);\r
+\r
+/**\r
+ * @brief  TIoT controller close, if opened multiple times, only remove open count.\r
+ * @param  [in]  ctrl TIoT controller instance.\r
+ */\r
+void tiot_controller_close(tiot_controller *ctrl);\r
+\r
+/**\r
+ * @brief  TIoT controller deinit.\r
+ * @param  [in]  ctrl TIoT controller instance.\r
+ */\r
+void tiot_controller_deinit(tiot_controller *ctrl);\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller_helper.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller_helper.h
new file mode 100644 (file)
index 0000000..e0e02e1
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: TIoT Controllrt helper. \n
+ *
+ * History: \n
+ * 2024-03-05, Create file. \n
+ */
+#ifndef TIOT_CONTROLLER_HELPER_H
+#define TIOT_CONTROLLER_HELPER_H
+
+#include "tiot_board_pin_port.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_controller_helper Controller Helper
+ * @ingroup  tiot_common_controllrt
+ * @{
+ */
+
+static inline void tiot_pin_int_request(uint32_t pin, tiot_pin_int_callback cb)
+{
+    if (pin != TIOT_PIN_NONE) {
+        (void)tiot_board_pin_register_int_callback(pin, cb);
+        (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_ENABLE);
+    }
+}
+
+static inline void tiot_pin_int_release(uint32_t pin)
+{
+    if (pin != TIOT_PIN_NONE) {
+        (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_DISABLE);
+        (void)tiot_board_pin_register_int_callback(pin, NULL);
+    }
+}
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_device_info.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_device_info.h
new file mode 100644 (file)
index 0000000..cd4f54f
--- /dev/null
@@ -0,0 +1,78 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Device info header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#ifndef TIOT_DEVICE_INFO_H\r
+#define TIOT_DEVICE_INFO_H\r
+\r
+#include "tiot_pm.h"\r
+#include "tiot_firmware.h"\r
+#include "tiot_xfer.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_device Device Interface\r
+ * @ingroup  tiot_common_interface\r
+ * @{\r
+ */\r
+\r
+/**\r
+ * @brief  Device common timing specs.\r
+ */\r
+typedef struct {\r
+    const uint32_t power_on_wait_ms;       /*!< Before power on wait time. */\r
+    const uint32_t boot_time_ms;           /*!< Boot wait time. */\r
+    const uint32_t init_time_ms;           /*!< Init time wait time. */\r
+    const uint32_t wakeup_pulse_ms;        /*!< Wakeup pin pulse time. */\r
+    const uint32_t wakeup_wait_ms;         /*!< Wakeup wait time. */\r
+    const uint32_t baud_change_wait_us;    /*!< Baudrate change wait time. */\r
+} tiot_device_timings;\r
+\r
+struct _tiot_controller;\r
+\r
+/**\r
+ * @brief  Device infomations to be registed in driver.\r
+ */\r
+typedef struct {\r
+    /*!< Power management event map, set NULL if use default event map. */\r
+    tiot_pm_event_entry *pm_event_map;\r
+    uint8_t pm_event_map_size;\r
+    /*!< Firmware callback called before and after commands execute. */\r
+    const tiot_fw_ops exec_cbs;\r
+\r
+    /*!< Transfer */\r
+    tiot_xfer_device_info xfer_info;\r
+\r
+    /*!< Tiot packet sys msg handle. */\r
+    void (*pkt_sys_msg_handle)(struct _tiot_controller *ctrl, uint8_t code);\r
+\r
+    tiot_device_timings timings;\r
+} tiot_device_info;\r
+\r
+typedef struct {\r
+    uintptr_t start_data;\r
+    uintptr_t curr_data;\r
+    uintptr_t end_data;\r
+    uint32_t unit_data_len;\r
+} tiot_dev_customize;\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4f6793e
--- /dev/null
@@ -0,0 +1,46 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    tiot_firmware_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_firmware.c
+)
+
+set(
+    tiot_firmware_header_list
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+if(CONFIG_FIRMWARE_CFG_HANDLE_PRIV)
+list(APPEND
+     tiot_firmware_src_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_priv/tiot_cfg_handle_priv.c)
+
+list(APPEND
+     tiot_firmware_header_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_priv)
+endif()
+
+if(CONFIG_FIRMWARE_CFG_HANDLE_XCI)
+list(APPEND
+     tiot_firmware_src_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_xci/tiot_cfg_handle_xci.c)
+
+list(APPEND
+     tiot_firmware_header_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_xci)
+endif()
+
+if(CONFIG_FIRMWARE_CFG_HANDLE_HIBURN)
+list(APPEND
+     tiot_firmware_src_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_hiburn/tiot_cfg_handle_hiburn.c)
+
+list(APPEND
+     tiot_firmware_header_list
+     ${CMAKE_CURRENT_SOURCE_DIR}/cfg_handle_hiburn)
+endif()
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${tiot_firmware_header_list}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_firmware_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.c
new file mode 100644 (file)
index 0000000..b69bf1d
--- /dev/null
@@ -0,0 +1,170 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-12-05, Create file. \n
+ */
+
+#include "tiot_misc.h"
+#include "tiot_firmware.h"
+#include "tiot_firmware_utils.h"
+#include "tiot_board_log.h"
+#include "tiot_cfg_handle_priv.h"
+
+#define TIOT_FW_FILE_STA        0x43
+#define TIOT_FW_FILE_ACK        0x06
+#define TIOT_FW_FILE_NAK        0x15
+#define TIOT_FW_PRIV_CMD_OK     'G'
+
+#define TIOT_FW_PRIV_ACK_MAX    128
+#define TIOT_FW_CUS_STR_LEN     12
+
+typedef enum {
+    TIOT_FW_EXTCMD_ACK = 0x0,
+    TIOT_FW_EXTCMD_ACK_EXT = 0x1,
+    TIOT_FW_EXTCMD_CUSTOMIZE = 0x2,
+    TIOT_FW_EXTCMD_NUM
+} tiot_fw_ext_cmd_priv;
+
+typedef int32_t (*priv_ext_cmd_handle_func)(tiot_fw *fw, const uint8_t *cmd, uint16_t len);
+typedef int32_t (*pre_priv_ext_cmd_handle_func)(tiot_fw *fw, uint8_t *cmd, uint16_t *len);
+
+static int32_t tiot_fw_ack_handle_priv(tiot_fw *fw, const uint8_t *cmd, uint16_t len);
+static int32_t tiot_fw_ack_ext_handle_priv(tiot_fw *fw, const uint8_t *cmd, uint16_t len);
+static int32_t tiot_fw_customize_ext_cmd_handle_priv(tiot_fw *fw, uint8_t *cmd, uint16_t *len);
+
+static const priv_ext_cmd_handle_func tiot_fw_priv_ext_cmd_table[TIOT_FW_EXTCMD_NUM] = {
+    tiot_fw_ack_handle_priv,
+    tiot_fw_ack_ext_handle_priv,
+    tiot_fw_ack_handle_priv,
+};
+
+static const pre_priv_ext_cmd_handle_func tiot_fw_pre_priv_ext_cmd_table[TIOT_FW_EXTCMD_NUM] = {
+    NULL,
+    NULL,
+    tiot_fw_customize_ext_cmd_handle_priv,
+};
+
+static int32_t tiot_fw_customize_para_replace(uint8_t *cmd, uint16_t *len, uint32_t cus_data)
+{
+    char *tmp = NULL;
+    size_t str_len;
+    char cus_data_str[TIOT_FW_CUS_STR_LEN] = { 0 };
+
+    if (*len == 0 || (cmd[*len - 1] != ' ')) {
+        tiot_print_err("[TIoT:priv] customize cmd not space-terminated.\r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    if (tiot_num_to_hex(cus_data, cus_data_str, TIOT_FW_CUS_STR_LEN) != TIOT_FW_LOAD_RET_OK) {
+        tiot_print_err("[TIoT:priv] tiot_num_to_hex failed.\r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    // cmd如下格式"WRITEM 4 0x3ff08 0x1e8480 "; tmp指向子串"0x1e8480"的起始地址.
+    cmd[*len - 1] = '\0';
+    tmp = strrchr((const char *)cmd, ' ');
+    if (tmp == NULL) {
+        tiot_print_err("[TIoT:priv] customize cmd string does not have space.\r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+    tmp++;
+
+    // 把tmp指向的字符串替换为tiot驱动配置的参数
+    int ret = strcpy_s((char *)tmp, strlen(tmp) + 1, cus_data_str);
+    if (ret != 0) {
+        tiot_print_err("[TIoT:priv] customize para replace failed. \r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    // cmd最后的'\0'替换为空格
+    str_len = strlen((const char *)cmd);
+    cmd[str_len] = ' ';
+
+    // 更新cmd的长度
+    *len = str_len + 1;
+    return TIOT_FW_LOAD_RET_OK;
+}
+
+static int32_t tiot_fw_ack_handle_priv(tiot_fw *fw, const uint8_t *cmd, uint16_t len)
+{
+    int32_t ret = 0;
+    uint8_t ack = 0;
+    const uint8_t quit_cmd[] = "QUIT ";
+    // QUIT命令特殊处理
+    if ((len == (sizeof(quit_cmd) - 1)) && (memcmp(quit_cmd, cmd, len) == 0)) {
+        return 0;
+    }
+    ret = tiot_firmware_read(fw, &ack, sizeof(uint8_t));
+    if (ret != sizeof(uint8_t)) {
+        return -1;
+    }
+
+    tiot_print_dbg("[TIoT:priv]ack 0x%x\r\n", ack);
+    if ((ack == TIOT_FW_PRIV_CMD_OK) || (ack == TIOT_FW_FILE_STA) || (ack == TIOT_FW_FILE_ACK)) {
+        return TIOT_FW_LOAD_RET_OK;
+    } else if (ack == TIOT_FW_FILE_NAK) {
+        return TIOT_FW_LOAD_RET_RETRY;
+    }
+    return TIOT_FW_LOAD_RET_ERR;
+}
+
+static int32_t tiot_fw_ack_ext_handle_priv(tiot_fw *fw, const uint8_t *cmd, uint16_t len)
+{
+    tiot_unused(cmd);
+    tiot_unused(len);
+    int32_t ret = 0;
+    uint8_t ack_buff[TIOT_FW_PRIV_ACK_MAX] = { 0 };
+    ret = tiot_firmware_read(fw, ack_buff, sizeof(ack_buff));
+    if ((ret <= 0) || ((uint32_t)ret > sizeof(ack_buff))) {
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+    tiot_print_info("[TIoT:fw]ack ext: ");
+    for (uint32_t i = 0; i < (uint32_t)ret; i++) {
+        tiot_print_info("0x%x ", ack_buff[i]);
+    }
+    tiot_print_info("\r\n");
+    return TIOT_FW_LOAD_RET_OK;
+}
+
+static int32_t tiot_fw_customize_ext_cmd_handle_priv(tiot_fw *fw, uint8_t *cmd, uint16_t *len)
+{
+    uint32_t cus_data;
+
+    tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware);
+    if (ctrl->dev_cus == 0) {
+        tiot_print_info("[TIoT:priv] customize is NULL.\r\n");
+        return TIOT_FW_LOAD_RET_OK;
+    }
+
+    if (tiot_firmware_customize_value_get(fw, &cus_data) != TIOT_FW_LOAD_RET_OK) {
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    return tiot_fw_customize_para_replace(cmd, len, cus_data);
+}
+
+int32_t tiot_fw_ext_cmd_handle_priv(tiot_fw *fw, uint16_t ext_cmd, const uint8_t *cmd, uint16_t len)
+{
+    if (ext_cmd >= TIOT_FW_EXTCMD_NUM) {
+        tiot_print_err("[TIoT:fw]priv ext cmd exceed max!\r\n");
+        return -1;
+    }
+    return tiot_fw_priv_ext_cmd_table[ext_cmd](fw, cmd, len);
+}
+
+int32_t tiot_fw_pre_ext_cmd_handle_priv(tiot_fw *fw, uint16_t ext_cmd, uint8_t *cmd, uint16_t *len)
+{
+    if (ext_cmd >= TIOT_FW_EXTCMD_NUM) {
+        tiot_print_err("[TIoT:fw]pre priv ext cmd exceed max!\r\n");
+        return -1;
+    }
+
+    if (tiot_fw_pre_priv_ext_cmd_table[ext_cmd] == NULL) {
+        return TIOT_FW_LOAD_RET_OK;
+    }
+
+    return tiot_fw_pre_priv_ext_cmd_table[ext_cmd](fw, cmd, len);
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.h
new file mode 100644 (file)
index 0000000..23a4069
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT firmware load module private cfg handle. \n
+ *
+ * History: \n
+ * 2023-12-05, Create file. \n
+ */
+#ifndef TIOT_CFG_HANDLE_PRIV_H
+#define TIOT_CFG_HANDLE_PRIV_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_firmware_cfg_handle_priv CFG HANDLE PRIVATE
+ * @ingroup  tiot_common_firmware
+ * @{
+ */
+
+/**
+ * @brief  TIoT firmware private extend command handle.
+ * @param  [in]  fw TIoT firmware object.
+ * @param  [in]  ext_cmd Extend command.
+ * @param  [in]  cmd Firmware Command.
+ * @param  [in]  len Firmware Command length.
+ * @return if OK, return 0, if need retry ,return 1, else return -1.
+ */
+int32_t tiot_fw_ext_cmd_handle_priv(tiot_fw *fw, uint16_t ext_cmd, const uint8_t *cmd, uint16_t len);
+
+/**
+ * @brief  TIoT firmware before private extend command handle.
+ * @param  [in]  fw TIoT firmware object.
+ * @param  [in]  ext_cmd Extend command.
+ * @param  [in]  cmd Firmware Command.
+ * @param  [in]  len Firmware Command length.
+ * @return if OK, return 0, if need retry ,return 1, else return -1.
+ */
+int32_t tiot_fw_pre_ext_cmd_handle_priv(tiot_fw *fw, uint16_t ext_cmd, uint8_t *cmd, uint16_t *len);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.c
new file mode 100644 (file)
index 0000000..0219376
--- /dev/null
@@ -0,0 +1,277 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT firmware load module. \n
+ *
+ * History: \n
+ * 2023-03-30, Create file. \n
+ */
+#include "tiot_firmware.h"
+#include <stdbool.h>
+#include "tiot_firmware_utils.h"
+#include "securec.h"
+#include "tiot_board_log.h"
+
+#define FW_LEN_PER_SEND   64
+
+#define TIOT_FW_LOAD_FINISH    0
+#define TIOT_FW_LOAD_NEXT      1
+
+#define TIOT_FW_LOAD_RETRY_CNT 3
+
+#define TIOT_FW_EXT_VERSION1 0x1
+
+static inline uint32_t little_endian_to_u32(const uint8_t *data)
+{
+    uint32_t val;
+    val = data[0x3];
+    val <<= 0x8;
+    val |= data[0x2];
+    val <<= 0x8;
+    val |= data[0x1];
+    val <<= 0x8;
+    val |= data[0x0];
+    return val;
+}
+
+int32_t tiot_firmware_init(tiot_fw *fw, const tiot_fw_ops *ops)
+{
+    if ((fw == NULL) || (ops == NULL) || (ops->ext_cmd_handle == NULL)) {
+        tiot_print_dbg("[TIoT][fw]param invalid!\n");
+        return -1;
+    }
+    fw->ops = ops;
+    fw->fw_file = NULL;
+    return 0;
+}
+
+static int32_t tiot_firmware_pre_ext_cmd_write(tiot_fw *fw, uint16_t ext_cmd, uint8_t *cmd, uint16_t *cmd_len)
+{
+    int32_t ret = 0;
+
+    if (fw->ops->pre_ext_cmd_handle != NULL) {
+        ret = fw->ops->pre_ext_cmd_handle(fw, ext_cmd, cmd, cmd_len);
+    }
+    return ret;
+}
+
+static int32_t firmware_send_cmd(tiot_fw *fw, uint16_t ext_cmd, uint16_t cmd_len)
+{
+    uint16_t send_len;
+    uint16_t tmp_len;
+    // 加载时uart等接口每次最多发送64字节数据, 避免资源受限的场景申请大块内存
+    uint8_t cmd[FW_LEN_PER_SEND] = { 0 };
+    int32_t ret = 0;
+    uint16_t remain_len = cmd_len;
+
+    // 一个完整的命令分多次发送,每次发送FW_LEN_PER_SEND字节
+    do {
+        // 1, Get cmd data from file, maximum of 64 bytes each time.
+        send_len = (remain_len > FW_LEN_PER_SEND) ? FW_LEN_PER_SEND : remain_len;
+        ret = tiot_file_read(fw->fw_file, (char *)cmd, send_len, fw->cur_offset);
+        if (ret != send_len) {
+            tiot_print_err("[TIoT:fw]cmd content read fail\r\n");
+            return TIOT_FW_LOAD_RET_ERR;
+        }
+        fw->cur_offset += send_len;
+
+        // 2, Callback function before sending data.
+        tmp_len = send_len;
+        // 要确保需要处理的扩展命令长度都小于FW_LEN_PER_SEND字节(customize当前已保证),否则需要调整当前的分包发送逻辑
+        if (tiot_firmware_pre_ext_cmd_write(fw, ext_cmd, cmd, &tmp_len) != TIOT_FW_LOAD_RET_OK) {
+            tiot_print_err("[TIoT:fw]pre ext cmd handle failed.\r\n");
+            return TIOT_FW_LOAD_RET_ERR;
+        }
+
+        // 3, send data
+        ret = tiot_firmware_write(fw, cmd, tmp_len);
+        if (ret != tmp_len) {
+            tiot_print_err("[TIoT:fw]cmd content send fail\r\n");
+            return TIOT_FW_LOAD_RET_ERR;
+        }
+
+        remain_len -= send_len;
+    } while (remain_len > 0);
+
+    // 4, after the whole cmd data send, handle the cmd ack (注意: ext_cmd_handle只能使用最后一包cmd)
+    ret = fw->ops->ext_cmd_handle(fw, ext_cmd, cmd, tmp_len);
+    if (ret == TIOT_FW_LOAD_RET_RETRY) {
+        // 如果命令要重试,需复位文件指针, 以及customize数据指针(当前不实现,customize对应的命令不会返回RETRY)
+        fw->cur_offset -= cmd_len;
+    }
+
+    return ret;
+}
+
+static int32_t tiot_firmware_send_cmd_retry(tiot_fw *fw, uint16_t ext_cmd, uint16_t cmd_len)
+{
+    uint8_t retry_cnt;
+    int32_t ret = -1;
+
+    for (retry_cnt = 0; retry_cnt < TIOT_FW_LOAD_RETRY_CNT; retry_cnt++) {
+        ret = firmware_send_cmd(fw, ext_cmd, cmd_len);
+        if (ret != TIOT_FW_LOAD_RET_RETRY) {
+            break;
+        }
+        tiot_print_warning("[TIoT:fw]single cmd retry %d\r\n", retry_cnt);
+    }
+
+    if (ret == TIOT_FW_LOAD_RET_QUIT) {
+        tiot_print_info("[TIoT:fw]version matches, no need to upgrade firmware.\r\n");
+    } else if ((ret != TIOT_FW_LOAD_RET_OK) || (retry_cnt == TIOT_FW_LOAD_RETRY_CNT)) {
+        tiot_print_err("[TIoT:fw]cmd handle retry fail.\r\n");
+        ret = -1;
+    }
+
+    return ret;
+}
+
+static int32_t tiot_firmware_customize_index_init(tiot_fw *fw)
+{
+    tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware);
+    if (ctrl->dev_cus == 0) {
+        tiot_print_info("[TIoT:fw]tiot firmware no customize. \r\n");
+        return TIOT_FW_LOAD_RET_OK;
+    }
+
+    tiot_dev_customize *cus_ptr = (tiot_dev_customize *)ctrl->dev_cus;
+    cus_ptr->curr_data = cus_ptr->start_data;
+
+    return TIOT_FW_LOAD_RET_OK;
+}
+
+static int32_t tiot_firmware_load_cmds(tiot_fw *fw)
+{
+    int32_t ret;
+    uint16_t cmd_len, ext_cmd;
+
+    if (tiot_firmware_customize_index_init(fw) != TIOT_FW_LOAD_RET_OK) {
+        return -1;
+    }
+
+    do {
+        ret = tiot_file_read(fw->fw_file, (char *)&cmd_len, sizeof(uint16_t), fw->cur_offset);
+        // 处于文件末尾,读文件结束
+        if (ret == 0) {
+            break;
+        }
+        if (ret != sizeof(uint16_t)) {
+            tiot_print_err("[TIoT:fw]cmd len read fail\r\n");
+            ret = -1;
+            break;
+        }
+        ext_cmd = cmd_len >> 12;   // 拓展命令高4位, 右移12位
+        cmd_len = cmd_len & 0xFFF; // 长度为低12位
+
+        // 更新offset
+        fw->cur_offset += sizeof(uint16_t);
+
+        ret = tiot_firmware_send_cmd_retry(fw, ext_cmd, cmd_len);
+        if (ret != 0) {
+            break;
+        }
+    } while (true);
+
+    return ret == TIOT_FW_LOAD_RET_QUIT ? 0 : ret;
+}
+
+static inline int32_t firmware_read_u32(tiot_fw *fw, uint32_t *val)
+{
+    uint8_t data[4];
+    int32_t ret = tiot_file_read(fw->fw_file, (char *)data, sizeof(uint32_t), fw->cur_offset);
+    if (ret != sizeof(uint32_t)) {
+        return -1;
+    }
+    fw->cur_offset += sizeof(uint32_t);
+    *val = little_endian_to_u32(data);
+    return 0;
+}
+
+static int32_t firmware_load_ext_version1(tiot_fw *fw, tiot_fw_ext_version1 *ext)
+{
+    if (firmware_read_u32(fw, &ext->file_len) != 0) {
+        tiot_print_err("[TIoT:fw]read img file size fail.\n");
+        return -1;
+    }
+    tiot_print_info("[TIoT:fw]img file size = %d\n", ext->file_len);
+    return 0;
+}
+
+static int32_t tiot_firmware_load_file(tiot_fw *fw, const tiot_file_path *file_path, const char *file_name)
+{
+    uint32_t version;
+    int32_t ret = -1;
+    tiot_fw_ext_version1 ext = { 0 };
+
+    /* 初始化时保证cfg_path不为null */
+    fw->fw_file = tiot_file_open(file_path, file_name, OSAL_O_RDONLY, 0);
+    if (fw->fw_file == NULL) {
+        tiot_print_err("open file %s fail\n", file_name);
+        return ret;
+    }
+    /* 读取镜像格式版本号 */
+    fw->cur_offset = 0;  /* 从偏移量为0开始读取镜像格式版本号 */
+    if (firmware_read_u32(fw, &version) != 0) {
+        goto file_close;
+    }
+    tiot_print_info("[TIoT:fw]cfg img version: 0x%x\n", version);
+    if (version == TIOT_FW_EXT_VERSION1) { /* 存在拓展区 */
+        if (firmware_load_ext_version1(fw, &ext) != 0) {
+            goto file_close;
+        }
+#ifdef CONFIG_FILE_BY_ARRAY
+        fw->fw_file->len = ext.file_len;
+#else
+        tiot_print_warning("[TIoT:fw]non file-array should not use ext version1.\n");
+#endif
+    }
+    // 读取发送命令
+    ret = tiot_firmware_load_cmds(fw);
+file_close:
+    tiot_file_close(fw->fw_file);
+    fw->fw_file = NULL;
+    return ret;
+}
+
+int32_t tiot_firmware_load(tiot_fw *fw, const tiot_file_path *file_path, const char *file_name)
+{
+    if (fw == NULL || file_name == NULL) {
+        tiot_print_dbg("[TIoT][fw]fw object or file_name is NULL.\n");
+        return -1;
+    }
+    if (fw->ops->pre_cmd_execute != NULL) {
+        tiot_print_info("[TIoT][fw]Pre command execute\n");
+        fw->ops->pre_cmd_execute(fw);
+    }
+    /* 执行cfg镜像内命令 */
+    if (tiot_firmware_load_file(fw, file_path, file_name) != 0) {
+        tiot_print_err("[TIoT][fw]command execute err!\n");
+        return -1;
+    }
+    if (fw->ops->after_cmd_execute != NULL) {
+        tiot_print_info("[TIoT][fw]After command execute\n");
+        fw->ops->after_cmd_execute(fw);
+    }
+    return 0;
+}
+
+int32_t tiot_firmware_customize_value_get(tiot_fw *fw, uint32_t *cus_data)
+{
+    tiot_dev_customize *cus_ptr;
+
+    tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware);
+    if (ctrl->dev_cus == 0) {
+        tiot_print_err("[TIoT:fw]customize dev_cus is NULL.\r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    cus_ptr = (tiot_dev_customize *)ctrl->dev_cus;
+    if (cus_ptr->curr_data > cus_ptr->end_data) {
+        tiot_print_err("[TIoT:fw] firmware customize get overflow.\r\n");
+        return TIOT_FW_LOAD_RET_ERR;
+    }
+
+    *cus_data = *(uint32_t *)(cus_ptr->curr_data);
+    cus_ptr->curr_data += cus_ptr->unit_data_len;
+    return TIOT_FW_LOAD_RET_OK;
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.h
new file mode 100644 (file)
index 0000000..37d184d
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT firmware load module. \n
+ *
+ * History: \n
+ * 2023-12-05, Create file. \n
+ */
+#ifndef TIOT_FIRMWARE_H
+#define TIOT_FIRMWARE_H
+
+#include "tiot_types.h"
+#include "tiot_board.h"
+#include "tiot_fileops.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_firmware_load Firmware Load
+ * @ingroup  tiot_common
+ * @{
+ */
+
+#ifdef CONFIG_FILE_BY_ARRAY
+#define TIOT_FW_FILE_ARRAY_CFG_NAME   "cfg"
+#endif
+
+typedef enum {
+    TIOT_FW_LOAD_RET_ERR = -1,
+    TIOT_FW_LOAD_RET_OK = 0,
+    TIOT_FW_LOAD_RET_RETRY = 1,
+    TIOT_FW_LOAD_RET_QUIT = 2,
+} tiot_fw_ret;
+
+/*
+    固件文件格式:
+        | Version | Extended Info | Command1 | Command2 | ... | CommandN |
+        |---------|---------------|----------|----------|-----|----------|
+        | 4bytes  |      --       |     -    |     -    |     |     -    |
+    单条命令格式:
+        | ext_cmd | cmd_len |  cmd   |
+        |---------|---------|--------|
+        |       2bytes      | Nbytes |
+        | [12:15] | [0:11]  |        |
+*/
+
+/**
+ * @brief  TIoT firmware extended infos.
+ */
+typedef struct {
+    uint32_t file_len; /*!< img file size */
+} tiot_fw_ext_version1;
+
+struct _tiot_fw;
+
+/**
+ * @brief  TIoT firmware command execute callbacks.
+ */
+typedef struct {
+    void (* pre_cmd_execute)(struct _tiot_fw *fw);   /*!< Before command execute. */
+    void (* after_cmd_execute)(struct _tiot_fw *fw); /*!< After command execute. */
+     /*!< After single command execute. */
+    int32_t (* ext_cmd_handle)(struct _tiot_fw *fw, uint16_t ext_cmd, const uint8_t *cmd, uint16_t cmd_len);
+    /*!< Before single command execute. */
+    int32_t (* pre_ext_cmd_handle)(struct _tiot_fw *fw, uint16_t ext_cmd, uint8_t *cmd, uint16_t *cmd_len);
+} tiot_fw_ops;
+
+/**
+ * @brief  TIoT firmware object.
+ */
+typedef struct _tiot_fw {
+    const tiot_fw_ops *ops;        /*!< Firmware ops. */
+    tiot_file *fw_file;            /*!< Firmware file pointer. */
+    uint32_t cur_offset;           /*!< Firmware file offset. */
+} tiot_fw;
+
+/**
+ * @brief  TIoT firmware object init.
+ * @param  [in]  fw           TIoT firmware object.
+ * @param  [in]  ops     Firmware command execute callbacks.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_firmware_init(tiot_fw *fw, const tiot_fw_ops *ops);
+
+/**
+ * @brief  TIoT firmware start load process.
+ * @param  [in]  fw TIoT firmware object.
+ * @param  [in]  file_path TIoT firmware load file path.
+ * @param  [in]  file_name TIoT firmware load file name.
+ * @param  [in/out] fw_cmd_info TIoT firmware load command info.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_firmware_load(tiot_fw *fw, const tiot_file_path *file_path, const char *file_name);
+
+
+/**
+ * @brief  TIoT firmware obtaining customized parameters.
+ * @param  [in]  fw TIoT firmware object.
+ * @param  [out] cus_data customized parameter.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_firmware_customize_value_get(tiot_fw *fw, uint32_t *cus_data);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware_utils.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware_utils.h
new file mode 100644 (file)
index 0000000..a4b7e0f
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT firmware load module utils. \n
+ *
+ * History: \n
+ * 2023-12-05, Create file. \n
+ */
+#ifndef TIOT_FIRMWARE_UTILS_H
+#define TIOT_FIRMWARE_UTILS_H
+
+#include "tiot_firmware.h"
+#include "tiot_controller.h"
+#include "tiot_xfer.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_firmware_utils Firmware Utils
+ * @ingroup  tiot_common_firmware
+ * @{
+ */
+
+static inline int32_t tiot_firmware_write(tiot_fw *fw, const uint8_t *data, uint32_t len)
+{
+    tiot_controller *controller = tiot_container_of(fw, tiot_controller, firmware);
+    return tiot_xfer_send(&controller->transfer, data, len, NULL);
+}
+
+static inline int32_t tiot_firmware_read_timeout(tiot_fw *fw, uint8_t *data, uint32_t len, uint32_t timeout_ms)
+{
+    tiot_xfer_rx_param rx_param = { 0 };
+    tiot_controller *controller = tiot_container_of(fw, tiot_controller, firmware);
+    rx_param.timeout = timeout_ms;
+    rx_param.subsys  = 0;
+    return tiot_xfer_recv(&controller->transfer, data, len, &rx_param);
+}
+
+static inline int32_t tiot_firmware_read(tiot_fw *fw, uint8_t *data, uint32_t len)
+{
+    return tiot_firmware_read_timeout(fw, data, len, TIOT_XFER_RECV_WAIT_FOREVER);
+}
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fc47d89
--- /dev/null
@@ -0,0 +1,20 @@
+#===============================================================================\r
+# @brief    cmake make file\r
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+#===============================================================================\r
+set(\r
+    tiot_interface_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_internal/tiot_board_xmit_ops.c\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/device_interface/tiot_service_interface.c\r
+)\r
+\r
+set(\r
+    interface_header_lists\r
+    "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_internal"\r
+    "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_porting"\r
+    "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/osal_porting"\r
+    "${CMAKE_CURRENT_SOURCE_DIR}/device_interface"\r
+)\r
+\r
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${interface_header_lists}" CACHE INTERNAL "tiot header list" FORCE)\r
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_interface_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board.h
new file mode 100644 (file)
index 0000000..cae119b
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-07-04, Create file. \n
+ */
+#ifndef TIOT_BOARD_H
+#define TIOT_BOARD_H
+
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_board_internal_base Board
+ * @ingroup  tiot_common_interface_board_internal
+ * @{
+ */
+
+/**
+ * @brief  TIoT common board pins.
+ */
+typedef enum {
+    TIOT_PIN_POWER_CTRL,
+    TIOT_PIN_HOST_WAKEUP_DEVICE,
+    TIOT_PIN_DEVICE_WAKEUP_HOST,
+    TIOT_PIN_MAX
+} tiot_board_pin;
+
+/**
+ * @brief  Board hardware infomations.
+ */
+typedef struct {
+    uintptr_t xmit_id;         /*!< Transmit(UART/I2C/SPI/...) port index. */
+    const uint32_t *pm_info;   /*!< Power manager related infomations. */
+} tiot_board_hw_info;
+
+/**
+ * @brief  Board infomations, includes hardware infos and firmware info.
+ */
+typedef struct {
+    tiot_board_hw_info hw_info;       /*!< Power manager related infomations. */
+} tiot_board_info;
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_log.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_log.h
new file mode 100644 (file)
index 0000000..9de1f1f
--- /dev/null
@@ -0,0 +1,81 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board log header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-24, Create file. \n\r
+ */\r
+#ifndef TIOT_BOARD_LOG_H\r
+#define TIOT_BOARD_LOG_H\r
+\r
+#include "tiot_board_log_port.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_board_internal_log Board Log\r
+ * @ingroup  tiot_common_interface_board_internal\r
+ * @{\r
+ */\r
+\r
+#define TIOT_LOG_ALERT    0   /*!< Log level alert. */\r
+#define TIOT_LOG_ERR      1   /*!< Log level error. */\r
+#define TIOT_LOG_WARNING  2   /*!< Log level warning. */\r
+#define TIOT_LOG_INFO     3   /*!< Log level info. */\r
+#define TIOT_LOG_DEBUG    4   /*!< Log level debug. */\r
+\r
+#ifndef TIOT_BOARD_LOG_LEVEL\r
+#define TIOT_BOARD_LOG_LEVEL  TIOT_LOG_INFO\r
+#endif\r
+\r
+/* 宏定义 */\r
+#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_DEBUG\r
+#define TIOT_PRINT_FUNCTION_NAME    BOARD_PRINT_FUNCTION_NAME\r
+#define tiot_print_dbg(s, ...)  board_print_dbg(s, ##__VA_ARGS__)\r
+#else\r
+#define TIOT_PRINT_FUNCTION_NAME\r
+#define tiot_print_dbg(s, ...)\r
+#endif\r
+\r
+#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_INFO\r
+#define tiot_print_info(s, ...)  board_print_info(s, ##__VA_ARGS__)\r
+#define tiot_print_suc(s, ...)   board_print_suc(s, ##__VA_ARGS__)\r
+#else\r
+#define tiot_print_info(s, ...)\r
+#define tiot_print_suc(s, ...)\r
+#endif\r
+\r
+#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_WARNING\r
+#define tiot_print_warning(s, ...)  board_print_warning(s, ##__VA_ARGS__)\r
+#else\r
+#define tiot_print_warning(s, ...)\r
+#endif\r
+\r
+#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_ERR\r
+#define tiot_print_err(s, ...)      board_print_err(s, ##__VA_ARGS__)\r
+#else\r
+#define tiot_print_err(s, ...)\r
+#endif\r
+\r
+#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_ALERT\r
+#define tiot_print_alert(s, ...)      board_print_alter(s, ##__VA_ARGS__)\r
+#else\r
+#define tiot_print_alert(s, ...)\r
+#endif\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit.h
new file mode 100644 (file)
index 0000000..6a23acb
--- /dev/null
@@ -0,0 +1,64 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board transmit io common header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#ifndef TIOT_BOARD_XMIT_H\r
+#define TIOT_BOARD_XMIT_H\r
+\r
+#include "tiot_types.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_board_internal_xmit Board Transmit\r
+ * @ingroup  tiot_common_interface_board_internal\r
+ * @{\r
+ */\r
+\r
+/**\r
+ * @brief  Transmit handle, compatible for board transmit handle.\r
+ */\r
+typedef void *tiot_xmit_handle;\r
+\r
+/**\r
+ * @brief  Universal transmit config, compatible for all types of transmit io.\r
+ */\r
+struct tiot_xmit_config;\r
+\r
+/**\r
+ * @brief  Transmit object.\r
+ */\r
+typedef struct {\r
+    uintptr_t id;               /*!< Transmit io id.\r
+                                     If board io operations use index, set this id in port open interface. */\r
+    tiot_xmit_handle handle;    /*!< Transmit handle compatible for board io handle.\r
+                                     If board io operations use handle, set this handle in port open interface. */\r
+} tiot_xmit;\r
+\r
+/**\r
+ * @brief  Transmit callbacks, registed in port open interface.\r
+ */\r
+typedef struct {\r
+    /*!< Rx data receive notify callback when use asynchronous board interface to read data. */\r
+    void (*rx_notify)(tiot_xmit *xmit, uint8_t *data, uint32_t len);\r
+} tiot_xmit_callbacks;\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.c
new file mode 100644 (file)
index 0000000..32741b1
--- /dev/null
@@ -0,0 +1,62 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board Transmit select. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-27, Create file. \n\r
+ */\r
+#include "tiot_board_xmit_ops.h"\r
+\r
+const tiot_xmit_ops g_tiot_xmit_ops_map[TIOT_XMIT_TYPE_BUTT] = {\r
+#ifdef CONFIG_XMIT_WITH_UART\r
+    {\r
+        .open = tiot_board_uart_open,\r
+        .close = tiot_board_uart_close,\r
+        .write = tiot_board_uart_write,\r
+        .read = tiot_board_uart_read,\r
+        .set_config = tiot_board_uart_set_config,\r
+#ifdef CONFIG_UART_RX_MODE_BUFFED\r
+        .rx_mode = TIOT_XMIT_RX_MODE_BUFFED,\r
+#else\r
+        .rx_mode = TIOT_XMIT_RX_MODE_POLL,\r
+#endif\r
+    },\r
+#endif\r
+#ifdef CONFIG_XMIT_WITH_SPI\r
+    {\r
+        .open = tiot_board_spi_open,\r
+        .close = tiot_board_spi_close,\r
+        .write = tiot_board_spi_write,\r
+        .read = tiot_board_spi_read,\r
+        .set_config = tiot_board_spi_set_config,\r
+#ifdef CONFIG_SPI_RX_MODE_BUFFED\r
+        .rx_mode = TIOT_XMIT_RX_MODE_BUFFED,\r
+#else\r
+        .rx_mode = TIOT_XMIT_RX_MODE_POLL,\r
+#endif\r
+    },\r
+#endif\r
+#ifdef CONFIG_XMIT_WITH_I2C\r
+    {\r
+        .open = tiot_board_i2c_open,\r
+        .close = tiot_board_i2c_close,\r
+        .write = tiot_board_i2c_write,\r
+        .read = tiot_board_i2c_read,\r
+        .set_config = tiot_board_i2c_set_config,\r
+#ifdef CONFIG_I2C_RX_MODE_BUFFED\r
+        .rx_mode = TIOT_XMIT_RX_MODE_BUFFED,\r
+#else\r
+        .rx_mode = TIOT_XMIT_RX_MODE_POLL,\r
+#endif\r
+    },\r
+#endif\r
+};\r
+\r
+const tiot_xmit_ops *tiot_xmit_get_ops(tiot_xmit_type type)\r
+{\r
+    if (type >= TIOT_XMIT_TYPE_BUTT) {\r
+        return NULL;\r
+    }\r
+    return &g_tiot_xmit_ops_map[type];\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.h
new file mode 100644 (file)
index 0000000..fa8bca9
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Board transmit io common ops. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+#ifndef TIOT_BOARD_XMIT_OPS_H
+#define TIOT_BOARD_XMIT_OPS_H
+
+#include "tiot_board_xmit.h"
+#ifdef CONFIG_XMIT_WITH_UART
+#include "tiot_board_uart_port.h"
+#endif
+#ifdef CONFIG_XMIT_WITH_SPI
+#include "tiot_board_spi_port.h"
+#endif
+#ifdef CONFIG_XMIT_WITH_I2C
+#include "tiot_board_i2c_port.h"
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_board_internal_xmit Board Transmit Ops
+ * @ingroup  tiot_common_interface_board_internal
+ * @{
+ */
+
+/**
+ * @brief  TIoT support transmit type.
+ */
+typedef enum {
+#ifdef CONFIG_XMIT_WITH_UART
+    TIOT_XMIT_TYPE_UART,
+#endif
+#ifdef CONFIG_XMIT_WITH_SPI
+    TIOT_XMIT_TYPE_SPI,
+#endif
+#ifdef CONFIG_XMIT_WITH_I2C
+    TIOT_XMIT_TYPE_I2C,
+#endif
+    TIOT_XMIT_TYPE_BUTT
+} tiot_xmit_type;
+
+/**
+ * @brief  TIoT Transmit rx mode.
+ */
+typedef enum {
+    TIOT_XMIT_RX_MODE_BUFFED,  /* TIoT Transmit rx mode with circular buffer. */
+    TIOT_XMIT_RX_MODE_POLL,    /* TIoT Transmit rx mode without buffer, read data direct from io. */
+} tiot_xmit_rx_mode;
+
+/**
+ * @brief  Transmit operations.
+ */
+typedef struct {
+    int32_t (*open)(tiot_xmit *xmit, tiot_xmit_callbacks *cbs);                 /*!< Port open interface. */
+    void (*close)(tiot_xmit *xmit);                                             /*!< Port close interface. */
+    int32_t (*write)(tiot_xmit *xmit, const uint8_t *buff, uint32_t len);       /*!< Port write interface. */
+    int32_t (*read)(tiot_xmit *xmit, uint8_t *buff, uint32_t len);              /*!< Port read interface. */
+    int32_t (*set_config)(tiot_xmit *xmit, struct tiot_xmit_config *config);    /*!< Port config interface. */
+    const uint16_t rx_mode;
+} tiot_xmit_ops;
+
+/**
+ * @brief  Get selected transmit operations.
+ * @return const tiot_xmit_ops* Selected transmit operations.
+ */
+const tiot_xmit_ops *tiot_xmit_get_ops(tiot_xmit_type type);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/gnss_board_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/gnss_board_port.h
new file mode 100644 (file)
index 0000000..3667f94
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: GNSS board port head. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+#ifndef GNSS_BOARD_PORT_H
+#define GNSS_BOARD_PORT_H
+
+#include "tiot_types.h"
+#include "tiot_board_pin_port.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_device_gnss_board_port  GNSS Board Port
+ * @ingroup  tiot_device_gnss
+ * @{
+ */
+
+/**
+ * @brief  GNSS pm pins.
+ */
+typedef enum {
+    GNSS_PIN_POWER_CTRL,            /*!< GNSS power control pin. */
+    GNSS_PIN_HOST_WAKEUP_DEVICE,    /*!< GNSS host wakeup device pin. */
+    GNSS_PIN_DEVICE_WAKEUP_HOST,    /*!< GNSS device wakeup host pin. */
+    GNSS_PIN_NUM,                   /*!< GNSS pin max. */
+    GNSS_PIN_NONE = TIOT_PIN_NONE   /*!< GNSS pin none. */
+} gnss_pm_pins;
+
+/**
+ * @brief  GNSS board hardware info.
+ */
+typedef struct {
+    uintptr_t xmit_id;
+    uint32_t pm_info[GNSS_PIN_NUM];
+} gnss_board_hw_info;
+
+/**
+ * @brief  GNSS board info.
+ */
+typedef struct {
+    const char *cfg_path;            /*!< cfg file path, NULL for file array. */
+    gnss_board_hw_info *hw_infos;    /*!< Pointer to array of GNSS hardware infos. */
+} gnss_board_info;
+
+/**
+ * @brief  Board provides resource informations, including pin indexs, ids, file paths, etc.
+ * @return Provided resource information.
+ */
+const gnss_board_info *gnss_board_get_info(void);
+
+/**
+ * @brief  Board porting init, request board resources, including hardware io, interrupt,etc.
+ * @param  param user customsize parameters, like device num.
+ * @return zero if OK;
+ *         non-zero if FAIL.
+ */
+int32_t gnss_board_init(void *param);
+
+/**
+ * @brief  Board porting deinit, release board resources, including hardware io, interrupt,etc.
+ * @param  param user customsize parameters, like device num.
+ */
+void gnss_board_deinit(void *param);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_misc_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_misc_port.h
new file mode 100644 (file)
index 0000000..55f976c
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Board misc porting header. \n
+ *
+ * History: \n
+ * 2023-03-24, Create file. \n
+ */
+#ifndef TIOT_BOARD_MISC_PORT_H
+#define TIOT_BOARD_MISC_PORT_H
+
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_board_porting_misc Board Misc Port
+ * @ingroup  tiot_common_interface_board_porting
+ * @{
+ */
+
+/**
+ * @if Eng
+ * @brief Board wake lock struct.
+ * @else
+ * @brief 板级唤醒锁结构体。
+ * @endif
+ */
+typedef struct {
+    void *lock;
+} tiot_board_wakelock;
+
+/**
+ * @if Eng
+ * @brief Board wake lock initialization interface.
+ * @param  [out] lock wake lock to be initialized.
+ * @return if OK return 0, else return -1.
+ * @note if board has no sleep or just enter wfi, implement as empty function.
+ * @else
+ * @brief 板级唤醒锁初始化接口。
+ * @param  [out] lock 待初始化的唤醒锁。
+ * @return 初始化成功返回0,否则返回-1。
+ * @note 如果板级不睡眠或仅进入wfi,实现为空函数即可。
+ * @endif
+ */
+int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock);
+
+/**
+ * @if Eng
+ * @brief Board wake lock interface.
+ * @param  [in] lock wake lock to be locked.
+ * @note if board has no sleep or just enter wfi, implement as empty function.
+ * @else
+ * @brief 板级唤醒锁接口。
+ * @param  [in] lock 待上锁的唤醒锁。
+ * @note 如果板级不睡眠或仅进入wfi,实现为空函数即可。
+ * @endif
+ */
+void tiot_board_wake_lock(tiot_board_wakelock *lock);
+
+/**
+ * @if Eng
+ * @brief Board wake unlock interface.
+ * @param  [in]  lock wake lock to be unlocked.
+ * @note if board has no sleep or just enter wfi, implement as empty function.
+ * @else
+ * @brief 板级唤醒解锁接口。
+ * @param  [in]  lock 待解锁的唤醒锁。
+ * @note 如果板级不睡眠或仅进入wfi,实现为空函数即可。
+ * @endif
+ */
+void tiot_board_wake_unlock(tiot_board_wakelock *lock);
+
+/**
+ * @if Eng
+ * @brief Board wake lock destroy interface.
+ * @param  [in]  lock wake lock to be destroyed.
+ * @note if board has no sleep or just enter wfi, implement as empty function.
+ * @else
+ * @brief 板级唤醒锁销毁接口。
+ * @param  [in]  lock 待销毁的唤醒锁.
+ * @note 如果板级不睡眠或仅进入wfi,实现为空函数即可。
+ * @endif
+ */
+void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock);
+
+/**
+ * @if Eng
+ * @brief  Board μs level delay.
+ * @param  [in]  us μs count.
+ * @else
+ * @brief  板级微秒级delay接口。
+ * @param  [in]  us 微秒。
+ * @endif
+ */
+void tiot_board_udelay(uint32_t us);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_pin_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_pin_port.h
new file mode 100644 (file)
index 0000000..e2a88b2
--- /dev/null
@@ -0,0 +1,100 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board pin porting header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-24, Create file. \n\r
+ */\r
+#ifndef TIOT_BOARD_PIN_PORT_H\r
+#define TIOT_BOARD_PIN_PORT_H\r
+\r
+#include "tiot_types.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_board_porting_pin Board Pin Port\r
+ * @ingroup  tiot_common_interface_board_porting\r
+ * @{\r
+ */\r
+\r
+/**\r
+ * @brief  Pin none, board port should use this macro if pin is not connected.\r
+ */\r
+#define TIOT_PIN_NONE        0xFFFFFFFFU\r
+#define TIOT_PIN_UART_WAKEUP_NUM    0x80000000U    /* 用于uart rx唤醒. */\r
+\r
+/**\r
+ * @brief  Pin level enum.\r
+ */\r
+typedef enum {\r
+    TIOT_PIN_LEVEL_LOW,     /*!< 0: Pin level low. */\r
+    TIOT_PIN_LEVEL_HIGH     /*!< 1: Pin level high. */\r
+} tiot_pin_level;\r
+\r
+/**\r
+ * @brief  Pin interrupt enable enum.\r
+ */\r
+typedef enum {\r
+    TIOT_PIN_INT_DISABLE,   /*!< 0: Pin interrupt disable. */\r
+    TIOT_PIN_INT_ENABLE     /*!< 1: Pin interrupt enable. */\r
+} tiot_pin_int_enable;\r
+\r
+/**\r
+ * @brief  Pin interrupt callback type, need input corresponding pin.\r
+ */\r
+typedef void (* tiot_pin_int_callback)(uint32_t pin);\r
+\r
+/**\r
+ * @brief  Board set pin level interface.\r
+ * @param  [in] pin   Pin id.\r
+ * @param  [in] level Pin level, see @ref tiot_pin_level.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level);\r
+\r
+/**\r
+ * @brief  Board get current pin level interface.\r
+ * @param  [in]  pin   Pin id.\r
+ * @param  [out] level Current pin level, see @ref tiot_pin_level.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level);\r
+\r
+/**\r
+ * @brief  Board pin interrupt enable interface.\r
+ * @param  [in] pin         Pin id.\r
+ * @param  [in] int_enable  Interrupt enable or disable, see @ref tiot_pin_int_enable.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable);\r
+\r
+/**\r
+ * @brief  Board pin interrupt callback register interface.\r
+ * @note   Porting should ensure this callback is called when enters pin irq if interrupt enabled.\r
+ * @param  [in] pin     Pin id.\r
+ * @param  [in] int_cb  Registed interrupt callback, see @ref tiot_pin_int_callback.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb);\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_uart_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_uart_port.h
new file mode 100644 (file)
index 0000000..406cb48
--- /dev/null
@@ -0,0 +1,122 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board UART porting header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-24, Create file. \n\r
+ */\r
+#ifndef TIOT_BOARD_UART_PORT_H\r
+#define TIOT_BOARD_UART_PORT_H\r
+\r
+#include "tiot_board_xmit.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_board_porting_uart Board UART Port\r
+ * @ingroup  tiot_common_interface_board_porting\r
+ * @{\r
+ */\r
+\r
+#define TIOT_UART_ATTR_DATABIT_8    0 /*!< UART word length is 8 data bits per frame. */\r
+#define TIOT_UART_ATTR_DATABIT_7    1 /*!< UART word length is 7 data bits per frame. */\r
+#define TIOT_UART_ATTR_DATABIT_6    2 /*!< UART word length is 6 data bits per frame. */\r
+#define TIOT_UART_ATTR_DATABIT_5    3 /*!< UART word length is 5 data bits per frame. */\r
+#define TIOT_UART_ATTR_DATABIT_BUTT 4 /*!< UART word length butt. */\r
+\r
+#define TIOT_UART_ATTR_PARITY_NONE  0 /*!< no UART parity bit. */\r
+#define TIOT_UART_ATTR_PARITY_ODD   1 /*!< odd UART parity bit. */\r
+#define TIOT_UART_ATTR_PARITY_EVEN  2 /*!< even UART parity bit. */\r
+#define TIOT_UART_ATTR_PARITY_MARK  3 /*!< UART parity bit is always 1. */\r
+#define TIOT_UART_ATTR_PARITY_SPACE 4 /*!< UART parity bit is always 0. */\r
+#define TIOT_UART_ATTR_PARITY_BUTT  5 /*!< UART parity bit butt. */\r
+\r
+#define TIOT_UART_ATTR_STOPBIT_1    0 /*!< UART has 1 stop bit. */\r
+#define TIOT_UART_ATTR_STOPBIT_1P5  1 /*!< UART has 1.5 stop bits. */\r
+#define TIOT_UART_ATTR_STOPBIT_2    2 /*!< UART has 2 stop bits. */\r
+#define TIOT_UART_ATTR_STOPBIT_BUTT 3 /*!< UART stop bits butt. */\r
+\r
+#define TIOT_UART_ATTR_FLOW_CTRL_DISABLE  0 /*!< UART flow control is disabled. */\r
+#define TIOT_UART_ATTR_FLOW_CTRL_ENABLE   1 /*!< UART flow control enabled. */\r
+\r
+/**\r
+ * @brief Uart attribute.\r
+ *\r
+ */\r
+typedef struct {\r
+    uint16_t data_bits : 4;\r
+    uint16_t parity    : 4;\r
+    uint16_t stop_bits : 4;\r
+    uint16_t flow_ctrl : 4;\r
+    uint16_t reserved  : 16;\r
+} tiot_uart_attr;\r
+\r
+/**\r
+ * @brief Uart config.\r
+ *\r
+ */\r
+typedef struct tiot_xmit_config {\r
+    uint32_t baudrate;   /*!< UART baudrate. */\r
+    tiot_uart_attr attr; /*!< UART attribute. */\r
+} tiot_uart_config;\r
+\r
+/**\r
+ * @brief  Board UART open interface.\r
+ * @param  [in]  xmit Transmit object.\r
+ * @param  [in]  cb   Transmit callbacks.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cb);\r
+\r
+/**\r
+ * @brief  Board UART close interface.\r
+ * @param  [in]  xmit Transmit object.\r
+ */\r
+void    tiot_board_uart_close(tiot_xmit *xmit);\r
+\r
+/**\r
+ * @brief  Board UART write interface.\r
+ * @param  [in] xmit Transmit object.\r
+ * @param  [in] buff Data buff.\r
+ * @param  [in] len  Data length.\r
+ * @return zero or postive for writen OK length;\r
+ *         negtive if write FAIL.\r
+ */\r
+int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len);\r
+\r
+/**\r
+ * @brief  Board UART blocking read interface.\r
+ * @param  [in] xmit Transmit object.\r
+ * @param  [in] buff Read buff.\r
+ * @param  [in] len  Expected read length.\r
+ * @return zero or postive for read OK length;\r
+ *         negtive if read FAIL or cannot implemented.\r
+ */\r
+int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len);\r
+\r
+/**\r
+ * @brief  Board UART config interface.\r
+ * @param  [in] xmit   Transmit object.\r
+ * @param  [in] config UART config, see @ref tiot_uart_config.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config);\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/osal_porting/tiot_osal.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/osal_porting/tiot_osal.h
new file mode 100644 (file)
index 0000000..0a78cb1
--- /dev/null
@@ -0,0 +1,436 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT osal interface. \n
+ *
+ * History: \n
+ * 2023-05-31, Create file. \n
+ */
+#ifndef TIOT_OSAL_H
+#define TIOT_OSAL_H
+
+#ifdef CONFIG_OSAL_DEFINED
+#include "soc_osal.h"
+#else
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_osal TIoT Osal Interface
+ * @ingroup  tiot_common_interface
+ * @{
+ */
+
+#define OSAL_SUCCESS 0
+#define OSAL_FAILURE (-1)
+#define OSAL_EOVERFLOW (-75)
+
+#define OSAL_WAIT_FOREVER 0xFFFFFFFF
+#define OSAL_WAIT_CONDITION_TRUE 1
+
+#define OSAL_GFP_ZERO (0x1)
+#define OSAL_GFP_ATOMIC (0x1 << 1)
+#define OSAL_GFP_DMA (0x1 << 2)
+#define OSAL_GFP_KERNEL (0x1 << 3)
+
+#define OSAL_O_RDONLY 00000000
+#define OSAL_O_WRONLY 00000001
+#define OSAL_O_RDWR 00000002
+#define OSAL_O_ACCMODE 00000003
+
+#define OSAL_O_CREAT 00000100
+#define OSAL_O_EXCL 00000200
+#define OSAL_O_TRUNC 00001000
+#define OSAL_O_APPEND 00002000
+#define OSAL_O_CLOEXEC 02000000
+
+#define OSAL_SEEK_SET 0
+#define OSAL_SEEK_CUR 1
+#define OSAL_SEEK_END 2
+
+/* Osal string. */
+#ifdef __KERNEL__
+#define osal_strtol(cp, endp, base)    simple_strtol(cp, endp, base)
+#else
+#define osal_strtol(cp, endp, base)    strtol(cp, endp, base)
+#endif
+
+typedef struct {
+    void *lock;
+} osal_spinlock;
+
+typedef struct {
+    void *mutex;
+} osal_mutex;
+
+typedef struct {
+    void *wait;
+} osal_wait;
+
+typedef struct {
+    void *task;
+} osal_task;
+
+typedef int (*osal_kthread_handler)(void *data);
+
+/* return value is a bool type */
+typedef int (*osal_wait_condition_func)(const void *param);
+
+/**
+ * @ingroup osal_timer
+ * @brief sleep waiting for signals.
+ *
+ * @par Description:
+ * sleep waiting for signals.
+ *
+ * @param msecs [in] Time in milliseconds to sleep for.
+ *
+ * @return Returns 0 when the timer has expired otherwise the remaining time in ms will be returned.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+unsigned long osal_msleep(unsigned int msecs);
+
+/**
+ * @ingroup osal_addr
+ * @brief Alloc dynamic memory.
+ *
+ * @par Description:
+ * This API is used to alloc a memory block of which the size is specified.
+ *
+ * @param size [in] How many bytes of memory are required.
+ * @param osal_gfp_flag [in] The type of memory to alloc. This parameter is not used in liteos and freertos.
+ * In linux, it must include one of the following access modes: OSAL_GFP_ATOMIC, OSAL_GFP_DMA, OSAL_GFP_KERNEL.
+ * OSAL_GFP_ZERO can be bitwise-or'd in flags, Then, the memory is set to zero.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag);
+
+/**
+ * @ingroup osal_addr
+ * @brief Free dynamic memory.
+ *
+ * @par Description:
+ * This API is used to free specified dynamic memory that has been allocd and update module mem used.
+ *
+ * @param addr [in] Starting address of the memory block to be freed.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_kfree(void *addr);
+
+/**
+ * @ingroup osal_spinlock
+ * @brief Initialize a spin lock.
+ *
+ * @par Description:
+ * This API is used to initialization of spin_lock.
+ *
+ * @param lock [out] the lock to be initialized.
+ *
+ * @attention
+ * must be free with osal_spin_lock_destroy, other wise will lead to memory leak;
+ *
+ * @return OSAL_SUCCESS/OSAL_FAILURE
+ *
+ * @par Support System:
+ * linux liteos.
+ */
+int osal_spin_lock_init(osal_spinlock *lock);
+
+/**
+ * @ingroup osal_spinlock
+ * @brief acquire the spin_lock.
+ *
+ * @par Description:
+ * Saves the current IRQ status of the CPU, obtains the specified spin_lock, and disables the interrupts of the CPU.
+ *
+ * @param lock [in] the lock to be acquired.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags);
+
+/**
+ * @ingroup osal_spinlock
+ * @brief release the spin_lock.
+ *
+ * @par Description:
+ * Releases the specified spin_lock and restores the interrupt status of the CPU, and enables the interrupts of the CPU.
+ *
+ * @param lock [in] the lock to be released.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags);
+
+/**
+ * @ingroup osal_spinlock
+ * @brief Destroy the spin_lock.
+ *
+ * @par Description:
+ * Destroy the spin_lock.
+ *
+ * @param lock [in] The lock to be destroyed.
+ *
+ * @attention
+ * must be called when kmod exit, other wise will lead to memory leak;
+ * this API will free memory, lock must be from osal_spin_lock_init returns
+ *
+ * @par Support System:
+ * linux liteos.
+ */
+void osal_spin_lock_destroy(osal_spinlock *lock);
+
+/**
+ * @ingroup osal_mutex
+ * @brief Initialize the mutex.
+ *
+ * @par Description:
+ * This API is used to initialize the mutex.
+ *
+ * @param mutex [in] the mutex to be initialized.
+ *
+ * @return OSAL_FAILURE/OSAL_SUCCESS
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+int osal_mutex_init(osal_mutex *mutex);
+
+/**
+ * @ingroup osal_mutex
+ * @brief Acquire the mutex.
+ *
+ * @par Description:
+ * Acquire the mutex. Lock the mutex exclusively for this task.
+ * If the mutex is not available right now, it will sleep until it can get it.
+ *
+ * @param mutex [in] the mutex to be initialized.
+ *
+ * @return OSAL_FAILURE/OSAL_SUCCESS
+ *
+ * @note
+ * The mutex must later on be released by the same task that acquired it. Recursive locking is not allowed.
+ * The task may not exit without first unlocking the mutex.
+ * Also, kernel memory where the mutex resides must not be freed with the mutex still locked.
+ * The mutex must first be initialized (or statically defined) before it can be locked.
+ * memset()-ing the mutex to 0 is not allowed.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ * @par System Differ: Only LiteOS supports the nested lock feature.
+ */
+int osal_mutex_lock(osal_mutex *mutex);
+
+/**
+ * @ingroup osal_mutex
+ * @brief Release the mutex.
+ *
+ * @par Description:
+ * Release the mutex. Unlock a mutex that has been locked by this task previously.
+ * This function must not be used in interrupt context. Unlocking of a not locked mutex is not allowed.
+ *
+ * @param mutex [in] the mutex to be released.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_mutex_unlock(osal_mutex *mutex);
+
+/**
+ * @ingroup osal_mutex
+ * @brief Destroy the mutex.
+ *
+ * @par Description:
+ * This API is used to destroy the mutex.
+ *
+ * @param mutex [in] The mutex to be destroyed.
+ *
+ * @attention
+ * must be called when kmod exit, otherwise will lead to memory leak; osal_mutex_destroy will free memory,
+ * caller should clear pointer to be NULL after called.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_mutex_destroy(osal_mutex *mutex);
+
+/**
+ * @ingroup osal_wait
+ * @brief Initialize a waiting queue.
+ *
+ * @par Description:
+ * This API is used to Initialize a waiting queue.
+ *
+ * @param wait [out] The wait queue to be initialized.
+ *
+ * @par Support System:
+ * linux liteos.
+ */
+int osal_wait_init(osal_wait *wait);
+
+/**
+ * @ingroup osal_wait
+ * @brief sleep until a condition gets true or a timeout elapses.
+ *
+ * @par Description:
+ * sleep until a condition gets true or a timeout elapses.
+ * The process is put to sleep (TASK_INTERRUPTIBLE) until the @func returned true or a signal is received.
+ * Return value of the @func is checked each time the waitqueue @wait is woken up.
+ *
+ * @param wait [in] the waitqueue to wait on.
+ * @param wait [in] a C expression for the event to wait for.
+ * @param wait [in] timeout, in ms.
+ *
+ * @par Support System:
+ * linux liteos.
+ */
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,
+    unsigned long ms);
+
+/**
+ * @ingroup osal_wait
+ * @brief wake up threads blocked on a waitqueue.
+ *
+ * @par Description:
+ * Wake-up wait queue,pair to @wait_event_interruptible.
+ *
+ * @param wait [in] The wait to be wake up.
+ *
+ * @par Support System:
+ * linux liteos.
+ */
+void osal_wait_wakeup_interruptible(osal_wait *wait); // same as osal_wait_wakeup on liteos
+
+/**
+ * @ingroup osal_wait
+ * @brief to destroy the wait.
+ *
+ * @par Description:
+ * This API is used to destroy the wait.
+ *
+ * @param wait [in] The wait to be destroyed.
+ *
+ * @attention this api may free memory, wait should be from osal_complete_init.
+ * @par Support System:
+ * linux liteos.
+ */
+void osal_wait_destroy(osal_wait *wait);
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+/**
+ * @ingroup osal_task
+ *
+ * @brief Provides an interface for creating a thread and invokes kthread_run for creating a kernel thread.
+ *
+ * @par Description:
+ * Provides an interface for creating a thread and invokes kthread_run for creating a kernel thread.
+ *
+ * @param stack_size [in] Size of the stack space of the thread. 0 means default.
+ * @param handler [in] Functions to be processed by the thread
+ * @param data [in] Function handler data.
+ * @param name [in] Thread name displayed.
+ *
+ * @retval   osal_task*  If the thread is successfully created, the pointer of the thread is returned.
+ * @retval   NULL        If the thread fails to be created, NULL is returned.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+osal_task *osal_kthread_create(osal_kthread_handler handler, void *data, const char *name, unsigned int stack_size);
+
+/**
+ * @ingroup osal_task
+ *
+ * @brief Used to destroy the threads you created.
+ *
+ * @par Description:
+ * Stops a specified kernel thread.
+ *
+ * @attention osal_kthread_destroy will free memory of task, caller should clear pointer to be NULL.
+ * Note that if you want to destroy a thread, the thread cannot end before calling this function,
+ * Or something terrible will happen.
+ * When you call the Kthread_stop function, the thread function cannot be finished, otherwise it will oops.
+ * @task may be free in api, @task should be from osal_kthread_create.
+ *
+ * @param task  [in] Threads you want to destroy.
+ * @param stop_flag [in] Indicates whether the current thread exits. If the value of stop_flag is 0,
+ * The current thread does not exit. The stop flag is not 0.
+ *
+ * @par Support System:
+ * linux liteos freertos.
+ */
+void osal_kthread_destroy(osal_task *task, unsigned int stop_flag);
+#endif
+
+#ifndef CONFIG_FILE_BY_ARRAY
+/**
+ * @ingroup osal_fileops
+ * @brief open file and return file pointer.
+ * @param file [in] the filename of file
+ * @param flag [in] the opreation flag example: OSAL_O_CREAT
+ * @param mode [in] the mode example: OSAL_O_RDONLY
+ * @return void* / null
+ *
+ * @par Support System:
+ * linux liteos seliteos freertos.
+ */
+void *osal_klib_fopen(const char *file, int flags, int mode);
+
+/**
+ * @ingroup osal_fileops
+ * @brief close file.
+ * @param filp [in] the result of osal_klib_fopen
+ * @par Support System:
+ * linux liteos seliteos freertos.
+ */
+void osal_klib_fclose(void *filp);
+
+/**
+ * @ingroup osal_fileops
+ * @brief Kernel read function.
+ * @param buf [out] the buffer you want to read in
+ * @param size [in] the size of buffer
+ * @param filp [in] the result of osal_klib_fopen
+ * @return The length that has been read.
+ *
+ * @par Support System:
+ * linux liteos seliteos freertos.
+ */
+int osal_klib_fread(char *buf, unsigned long size, void *filp);
+
+/**
+ * @ingroup osal_fileops
+ * @brief Kernel file seek function.
+ * @param offset [in] the new position of file
+ * @param whence [in] the method of lseek,example:OSAL_SEEK_SET
+ * @param filp [in] the result of osal_klib_fopen
+ * @par Support System:
+ * linux liteos seliteos.
+ */
+int osal_klib_fseek(long long offset, int whence, void *filp);
+#endif
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* CONFIG_OSAL_DEFINED */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.c
new file mode 100644 (file)
index 0000000..643b39a
--- /dev/null
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-10-28, Create file. \n
+ */
+
+#include "tiot_service_interface.h"
+#include "tiot_service_interface_ext.h"
+#include "tiot_controller.h"
+#include "tiot_pm_wakelock.h"
+#include "tiot_board_log.h"
+#ifdef CONFIG_DEV_GNSS
+#include "gnss_service.h"
+#endif
+#ifdef CONFIG_DEV_W33
+#include "w33_service.h"
+#endif
+#ifdef CONFIG_DEV_CAXX
+#include "caxx_service.h"
+#endif
+#ifdef CONFIG_DEV_BSXX
+#include "bsxx_service.h"
+#endif
+#ifdef CONFIG_DEV_TIOT_SLAVE
+#include "tiot_slave_service.h"
+#endif
+
+typedef struct {
+    int32_t (* init)(void);
+    void (* deinit)(void);
+} tiot_service_entry;
+
+typedef struct {
+    const char *name;
+    uint8_t dev_max;
+    uintptr_t (* get_ctrl)(uint8_t dev_id);
+} tiot_service_desc;
+
+static const tiot_service_entry tiot_service_list[] = {
+#ifdef CONFIG_DEV_GNSS
+    { gnss_service_init, gnss_service_deinit },
+#endif
+#ifdef CONFIG_DEV_W33
+    { w33_service_init, w33_service_deinit },
+#endif
+#ifdef CONFIG_DEV_CAXX
+    { caxx_service_init, caxx_service_deinit },
+#endif
+#ifdef CONFIG_DEV_BSXX
+    { bsxx_service_init, bsxx_service_deinit },
+#endif
+#ifdef CONFIG_DEV_TIOT_SLAVE
+    { tiot_slave_service_init, tiot_slave_service_deinit },
+#endif
+};
+
+static const tiot_service_desc tiot_service_desc_list[] = {
+#ifdef CONFIG_DEV_GNSS
+    { "gn71", CONFIG_GNSS_DEV_NUM, gnss_service_get_ctrl },
+    { "gnss01", CONFIG_GNSS_DEV_NUM, gnss_service_get_ctrl },
+#endif
+#ifdef CONFIG_DEV_W33
+    { "w33", CONFIG_W33_DEV_NUM, w33_service_get_ctrl },
+#endif
+#ifdef CONFIG_DEV_CAXX
+    { "ca01", CONFIG_CAXX_DEV_NUM, caxx_service_get_ctrl },
+#endif
+#ifdef CONFIG_DEV_BSXX
+    { "bs21", CONFIG_BSXX_DEV_NUM, bsxx_service_get_ctrl },
+    { "bs25", CONFIG_BSXX_DEV_NUM, bsxx_service_get_ctrl },
+#endif
+#ifdef CONFIG_DEV_TIOT_SLAVE
+    { "tiot_slave", CONFIG_TIOT_SLAVE_DEV_NUM, tiot_slave_service_get_ctrl },
+#endif
+};
+
+static const tiot_service_desc *tiot_service_get_description(const char *device_name, uint8_t *dev_id)
+{
+    uint32_t i;
+    uint32_t len = strlen(device_name);
+    uint32_t name_len = 0;
+    for (i = 0; i < (sizeof(tiot_service_desc_list) / sizeof(tiot_service_desc)); i++) {
+        name_len = strlen(tiot_service_desc_list[i].name);
+        /* devcie_name长度小于描述名时不可能匹配,避免memcmp对device_name访问溢出. */
+        if (len < name_len) {
+            continue;
+        }
+        if (memcmp(device_name, tiot_service_desc_list[i].name, name_len) == 0) {
+            break;
+        }
+    }
+    if (i == (sizeof(tiot_service_desc_list) / sizeof(tiot_service_desc))) {
+        tiot_print_err("[TIoT]invalid device_name string %s.\r\n", device_name);
+        return NULL;
+    }
+    /* device_name格式 */
+    /* "xxxx" 其中xxxx为对应device名字, dev_id默认为0 */
+    /* "xxxx,n" 其中n为单个数字字符,n < 10,dev_id设为n */
+    if (len > name_len) {
+        if (len - name_len != 2) { // n为单个字符,加上分隔符,长度固定为2
+            tiot_print_err("[TIoT]device_name length %d invalid.\r\n", len);
+            return NULL;
+        }
+        if (device_name[name_len] != ',') {
+            tiot_print_err("[TIoT]device_name seprator invalid %c.\r\n", device_name[name_len]);
+            return NULL;
+        }
+        if ((device_name[name_len + 1] < '0') || (device_name[name_len + 1] > '9')) {
+            tiot_print_err("[TIoT]dev id invalid %c.\r\n", device_name[name_len + 1]);
+            return NULL;
+        }
+        *dev_id = device_name[name_len + 1] - '0';
+    }
+    if (*dev_id >= tiot_service_desc_list[i].dev_max) {
+        tiot_print_err("[TIoT]device_name dev id exceed max %c.\r\n", device_name[name_len + 1]);
+        return NULL;
+    }
+    return &tiot_service_desc_list[i];
+}
+
+int32_t tiot_service_init(void)
+{
+    int32_t ret;
+    uint32_t i;
+    uint32_t j;
+    if (tiot_pm_wake_lock_init() != 0) {
+        return -1;
+    }
+    for (i = 0; i < (sizeof(tiot_service_list) / sizeof(tiot_service_entry)); i++) {
+        ret = tiot_service_list[i].init();
+        if (ret != 0) {
+            tiot_print_err("[TIoT]service init fail @%d\n", i);
+            goto fail;
+        }
+    }
+    return 0;
+fail:
+    for (j = 0; j < i; j++) {
+        tiot_service_list[j].deinit();
+    }
+    tiot_pm_wake_lock_destroy();
+    return ret;
+}
+
+void tiot_service_deinit(void)
+{
+    uint32_t i;
+    for (i = 0; i < (sizeof(tiot_service_list) / sizeof(tiot_service_entry)); i++) {
+        tiot_service_list[i].deinit();
+    }
+    tiot_pm_wake_lock_destroy();
+}
+
+tiot_handle tiot_service_open(const char *device_name, void *param)
+{
+    tiot_controller *ctrl = NULL;
+    uint8_t dev_id = 0;
+    const tiot_service_desc *desc;
+    if (device_name == NULL) {
+        tiot_print_err("[TIoT]device_name is NULL.\r\n");
+        return 0;
+    }
+    desc = tiot_service_get_description(device_name, &dev_id);
+    if (desc == NULL) {
+        return 0;
+    }
+    ctrl = (tiot_controller *)desc->get_ctrl(dev_id);
+    if (tiot_controller_open(ctrl, param) != 0) {
+        ctrl = NULL;
+    }
+    return (tiot_handle)ctrl;
+}
+
+void tiot_service_close(tiot_handle handle)
+{
+    tiot_controller *ctrl = (tiot_controller *)handle;
+    tiot_controller_close(ctrl);
+}
+
+int32_t tiot_service_write_ext(tiot_handle handle, const uint8_t *data,
+                               uint32_t len, const tiot_service_tx_param *param)
+{
+    tiot_controller *ctrl = (tiot_controller *)handle;
+    if ((data == NULL) || (len == 0)) {
+        tiot_print_dbg("[TIoT]send data invalid.\n");
+        return -1;
+    }
+    if (tiot_controller_check_opened(ctrl) != true) {
+        return -1;
+    }
+    return ctrl->ops.write(ctrl, data, len, (const tiot_xfer_tx_param *)param);
+}
+
+int32_t tiot_service_write(tiot_handle handle, const uint8_t *data, uint32_t len)
+{
+    /* 默认发送subsys为0的数据 */
+    const tiot_service_tx_param param = { 0 };
+    return tiot_service_write_ext(handle, data, len, &param);
+}
+
+int32_t tiot_service_read_ext(tiot_handle handle, uint8_t *buff, uint32_t buff_len, const tiot_service_rx_param *param)
+{
+    int32_t buff_invalid;
+    tiot_controller *ctrl = (tiot_controller *)handle;
+    if (param == NULL) {
+        tiot_print_dbg("[TIoT]rx param invalid.\n");
+        return -1;
+    }
+    buff_invalid = (buff == NULL) || (buff_len == 0);
+#ifdef __KERNEL__
+    /* 用作poll接口时,buff & buff_len可以为空. */
+    if (((param->filp == NULL) || (param->poll_wait == NULL)) && (buff_invalid != 0)) {
+#else
+    if (buff_invalid != 0) {
+#endif
+        tiot_print_dbg("[TIoT]read buff invalid.\n");
+        return -1;
+    }
+    if (tiot_controller_check_opened(ctrl) != true) {
+        return -1;
+    }
+    return ctrl->ops.read(ctrl, buff, buff_len, (const tiot_xfer_rx_param *)param);
+}
+
+int32_t tiot_service_read(tiot_handle handle, uint8_t *buff, uint32_t buff_len, uint32_t timeout_ms)
+{
+    /* 默认接收queueID为0的数据 */
+    /* tiot_service_rx_para结构体有kernel编译宏区分, 不能列表初始化, 否则参数未知. */
+    tiot_service_rx_param param = { 0 };
+    param.timeout_ms = timeout_ms;
+    return tiot_service_read_ext(handle, buff, buff_len, &param);
+}
+
+int32_t tiot_service_pm_ctrl(tiot_handle handle, tiot_service_pm_ctrl_cmd cmd)
+{
+    tiot_controller *ctrl = (tiot_controller *)handle;
+    if (tiot_controller_check_opened(ctrl) != true) {
+        return -1;
+    }
+    if (ctrl->ops.pm_ctrl == NULL) {
+        tiot_print_err("[TIoT]not support pm_ctrl.\n");
+        return -1;
+    }
+    return ctrl->ops.pm_ctrl(ctrl, (uint8_t)cmd);
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.h
new file mode 100644 (file)
index 0000000..506a0f5
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-10-24, Create file. \n
+ */
+#ifndef TIOT_SERVICE_INTERFACE_H
+#define TIOT_SERVICE_INTERFACE_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#else
+#include <stdint.h>
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_service Service Interface
+ * @ingroup  tiot_common_interface
+ * @{
+ */
+
+#define TIOT_READ_TIMEOUT_FOREVER  0xFFFFFFFU  /*!< Read wait timeout forever. */
+
+typedef uintptr_t tiot_handle;
+
+typedef struct {
+    uint8_t *buff; /* 用户需要创建静态buff */
+    uint32_t buff_len;
+    void (*rx_callback)(const uint8_t *buff, uint32_t len);
+    uint32_t flags;
+} tiot_service_open_param;
+
+/**
+ * @brief  TIoT Service Init interface.
+ * @return zero if OK;
+ *         -1 if FAIL.
+ * @note Init for all driver and board.
+ */
+int32_t tiot_service_init(void);
+
+/**
+ * @brief  TIoT Service Deinit interface.
+ * @note Deinit for all driver and board.
+ */
+void tiot_service_deinit(void);
+
+/**
+ * @brief  TIoT Service Open interface.
+ * @param  [in]  device_name TIoT device compatible string.
+ * @param  [in]  param User/Service defined params.
+ * @return valid handle if OK;
+ *         zero if FAIL.
+ * @note   Must write/read after open.
+ */
+tiot_handle tiot_service_open(const char *device_name, void *param);
+
+/**
+ * @brief  TIoT Service Close interface.
+ * @note   Meaningless to return error.
+ */
+void tiot_service_close(tiot_handle handle);
+
+/**
+ * @brief  TIoT Service Write Message interface.
+ * @param  [in]  data Data need to send.
+ * @param  [in]  len Data length.
+ * @return zero or postive for writen OK length;
+ *         negtive if write FAIL.
+ * @note   Will return after data is sent to board uart interface.
+ */
+int32_t tiot_service_write(tiot_handle handle, const uint8_t *data, uint32_t len);
+
+/**
+ * @brief  TIoT Service Read Message interface.
+ * @param  [in/out] buff User read buff.
+ * @param  [in]  buff_len User read buff size.
+ * @param  [in]  timeout_ms Wait timeout ms.
+ * @return if read wait timeout(nothing to read), return 0.
+ *         if read fail, return -1.
+ *         if support ASCII message, message type(2 bytes, ASCII or BINARY) and message will be copied to buff,
+ *         else only message will be copied to buff,
+ *         return read length.
+ * @note   This interface will return only single complete message once,
+ *         for continous message read, call this interface repeatly.
+ */
+int32_t tiot_service_read(tiot_handle handle, uint8_t *buff, uint32_t buff_len, uint32_t timeout_ms);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface_ext.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface_ext.h
new file mode 100644 (file)
index 0000000..37bcd41
--- /dev/null
@@ -0,0 +1,98 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2024-01-29, Create file. \n\r
+ */\r
+#ifndef TIOT_SERVICE_INTERFACE_EXT_H\r
+#define TIOT_SERVICE_INTERFACE_EXT_H\r
+\r
+#include "tiot_service_interface.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_service_ext Service Interface Ext\r
+ * @ingroup  tiot_common_interface\r
+ * @{\r
+ */\r
+\r
+/**\r
+ * @brief  TIoT Tx param, for tiot_service_write_ext.\r
+ */\r
+typedef struct {\r
+    uint32_t subsys;     /*!< Write for which sub system, varies for different device. */\r
+} tiot_service_tx_param;\r
+\r
+/**\r
+ * @brief  TIoT Rx param, for tiot_service_read_ext.\r
+ */\r
+typedef struct {\r
+    uint32_t timeout_ms; /*!< Wait timeout ms. */\r
+    uint32_t subsys;     /*!< Read for which sub system, varies for different device. */\r
+#ifdef __KERNEL__\r
+    struct file *filp;     /*!< for poll */\r
+    poll_table *poll_wait; /*!< for poll */\r
+#endif\r
+} tiot_service_rx_param;\r
+\r
+typedef enum {\r
+    TIOT_PM_CTRL_SUSPEND_PREPARE,\r
+    TIOT_PM_CTRL_SUSPEND,\r
+    TIOT_PM_CTRL_RESUME_PREPARE,\r
+    TIOT_PM_CTRL_RESUME,\r
+    TIOT_PM_CTRL_BUTT\r
+} tiot_service_pm_ctrl_cmd;\r
+\r
+/**\r
+ * @brief  TIoT Service Write Message extende interface.\r
+ * @param  [in]  data Data need to send.\r
+ * @param  [in]  len Data length.\r
+ * @param  [in]  param Write Param, see @ref tiot_service_tx_param.\r
+ * @return zero or postive for writen OK length;\r
+ *         negtive if write FAIL.\r
+ * @note   Will return after data is sent to board uart interface.\r
+ */\r
+int32_t tiot_service_write_ext(tiot_handle handle, const uint8_t *data,\r
+                               uint32_t len, const tiot_service_tx_param *param);\r
+\r
+/**\r
+ * @brief  TIoT Service Read Message extended interface.\r
+ * @param  [in/out] buff User read buff.\r
+ * @param  [in]  buff_len User read buff size.\r
+ * @param  [in]  param Read Param, see @ref tiot_service_rx_param.\r
+ * @return if read wait timeout(nothing to read), return 0.\r
+ *         if read fail, return -1.\r
+ *         if support ASCII message, message type(2 bytes, ASCII or BINARY) and message will be copied to buff,\r
+ *         else only message will be copied to buff,\r
+ *         return read length.\r
+ * @note   This interface will return only single complete message once,\r
+ *         for continous message read, call this interface repeatly.\r
+ */\r
+int32_t tiot_service_read_ext(tiot_handle handle, uint8_t *buff, uint32_t buff_len, const tiot_service_rx_param *param);\r
+\r
+/**\r
+ * @brief  TIoT Service Pm Control interface.\r
+ * @param  [in]  handle Service instance handle, should be return by tiot_service_open.\r
+ * @param  [in]  cmd Service pm ctrl cmd.\r
+ * @return return 0 if success else return -1.\r
+ */\r
+int32_t tiot_service_pm_ctrl(tiot_handle handle, tiot_service_pm_ctrl_cmd cmd);\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt
new file mode 100644 (file)
index 0000000..39d8819
--- /dev/null
@@ -0,0 +1,28 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
+#===============================================================================
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE INTERNAL "tiot header list" FORCE)
+if(DEFINED CONFIG_LIBBOUNDSCHECK_IMPLEMENTED)
+else()
+set(libboundscheck_src
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/memcpy_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/memmove_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/memset_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/securecutil.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/secureprintoutput_a.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/snprintf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/sprintf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/strcat_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/strcpy_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/strncat_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/strncpy_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/vsnprintf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/vsprintf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/strtok_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/sscanf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/vsscanf_s.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/secureinput_a.c
+)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${libboundscheck_src}" CACHE INTERNAL "tiot src list" FORCE)
+endif()
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securec.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securec.h
new file mode 100644 (file)
index 0000000..d933056
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: The user of this secure c library should include this header file in you source code.
+ *              This header file declare all supported API prototype of the library,
+ *              such as memcpy_s, strcpy_s, wcscpy_s,strcat_s, strncat_s, sprintf_s, scanf_s, and so on.
+ * Create: 2014-02-25
+ * Notes: Do not modify this file by yourself.
+ */
+
+#ifndef SECUREC_H_5D13A042_DC3F_4ED9_A8D1_882811274C27
+#define SECUREC_H_5D13A042_DC3F_4ED9_A8D1_882811274C27
+
+#include "securectype.h"
+#ifndef SECUREC_HAVE_STDARG_H
+#define SECUREC_HAVE_STDARG_H 1
+#endif
+
+#if SECUREC_HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifndef SECUREC_HAVE_ERRNO_H
+#define SECUREC_HAVE_ERRNO_H 1
+#endif
+
+/* EINVAL ERANGE may defined in errno.h */
+#if SECUREC_HAVE_ERRNO_H
+#if SECUREC_IN_KERNEL
+#include <linux/errno.h>
+#else
+#include <errno.h>
+#endif
+#endif
+
+/* Define error code */
+#if defined(SECUREC_NEED_ERRNO_TYPE) || !defined(__STDC_WANT_LIB_EXT1__) || \
+    (defined(__STDC_WANT_LIB_EXT1__) && (!__STDC_WANT_LIB_EXT1__))
+#ifndef SECUREC_DEFINED_ERRNO_TYPE
+#define SECUREC_DEFINED_ERRNO_TYPE
+/* Just check whether macrodefinition exists. */
+#ifndef errno_t
+typedef int errno_t;
+#endif
+#endif
+#endif
+
+/* Success */
+#ifndef EOK
+#define EOK 0
+#endif
+
+#ifndef EINVAL
+/* The src buffer is not correct and destination buffer can not be reset */
+#define EINVAL 22
+#endif
+
+#ifndef EINVAL_AND_RESET
+/* Once the error is detected, the dest buffer must be reset! Value is 22 or 128 */
+#define EINVAL_AND_RESET 150
+#endif
+
+#ifndef ERANGE
+/* The destination buffer is not long enough and destination buffer can not be reset */
+#define ERANGE 34
+#endif
+
+#ifndef ERANGE_AND_RESET
+/* Once the error is detected, the dest buffer must be reset! Value is 34 or 128 */
+#define ERANGE_AND_RESET  162
+#endif
+
+#ifndef EOVERLAP_AND_RESET
+/* Once the buffer overlap is detected, the dest buffer must be reset! Value is 54 or 128 */
+#define EOVERLAP_AND_RESET 182
+#endif
+
+/* If you need export the function of this library in Win32 dll, use __declspec(dllexport) */
+#ifndef SECUREC_API
+#if defined(SECUREC_DLL_EXPORT)
+#define SECUREC_API __declspec(dllexport)
+#elif defined(SECUREC_DLL_IMPORT)
+#define SECUREC_API __declspec(dllimport)
+#else
+/*
+ * Standardized function declaration. If a security function is declared in the your code,
+ * it may cause a compilation alarm,Please delete the security function you declared.
+ * Adding extern under windows will cause the system to have inline functions to expand,
+ * so do not add the extern in default
+ */
+#if defined(_MSC_VER)
+#define SECUREC_API
+#else
+#define SECUREC_API extern
+#endif
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Description: The GetHwSecureCVersion function get SecureC Version string and version number.
+ * Parameter: verNumber - to store version number (for example value is 0x500 | 0xa)
+ * Return:   version string
+ */
+SECUREC_API const char *GetHwSecureCVersion(unsigned short *verNumber);
+
+#if SECUREC_ENABLE_MEMSET
+/*
+ * Description: The memset_s function copies the value of c (converted to an unsigned char) into each of
+ * the first count characters of the object pointed to by dest.
+ * Parameter: dest - destination address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: c - the value to be copied
+ * Parameter: count - copies count bytes of value to dest
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t memset_s(void *dest, size_t destMax, int c, size_t count);
+#endif
+
+#ifndef SECUREC_ONLY_DECLARE_MEMSET
+#define SECUREC_ONLY_DECLARE_MEMSET     0
+#endif
+
+#if !SECUREC_ONLY_DECLARE_MEMSET
+
+#if SECUREC_ENABLE_MEMMOVE
+/*
+ * Description: The memmove_s function copies n characters from the object pointed to by src
+ * into the object pointed to by dest.
+ * Parameter: dest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: src - source address
+ * Parameter: count - copies count bytes from the src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count);
+#endif
+
+#if SECUREC_ENABLE_MEMCPY
+/*
+ * Description: The memcpy_s function copies n characters from the object pointed to
+ * by src into the object pointed to by dest.
+ * Parameter: dest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: src - source address
+ * Parameter: count - copies count bytes from the  src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count);
+#endif
+
+#if SECUREC_ENABLE_STRCPY
+/*
+ * Description: The strcpy_s function copies the string pointed to by strSrc (including
+ * the terminating null character) into the array pointed to by strDest
+ * Parameter: strDest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null character)
+ * Parameter: strSrc - source address
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc);
+#endif
+
+#if SECUREC_ENABLE_STRNCPY
+/*
+ * Description: The strncpy_s function copies not more than n successive characters (not including
+ * the terminating null character) from the array pointed to by strSrc to the array pointed to by strDest.
+ * Parameter: strDest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null character)
+ * Parameter: strSrc - source  address
+ * Parameter: count - copies count characters from the src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count);
+#endif
+
+#if SECUREC_ENABLE_STRCAT
+/*
+ * Description: The strcat_s function appends a copy of the string pointed to by strSrc (including
+ * the terminating null character) to the end of the string pointed to by strDest.
+ * Parameter: strDest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide character)
+ * Parameter: strSrc - source address
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc);
+#endif
+
+#if SECUREC_ENABLE_STRNCAT
+/*
+ * Description: The strncat_s function appends not more than n successive characters (not including
+ * the terminating null character)
+ * from the array pointed to by strSrc to the end of the string pointed to by strDest.
+ * Parameter: strDest - destination address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null character)
+ * Parameter: strSrc - source address
+ * Parameter: count - copies count characters from the src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count);
+#endif
+
+#if SECUREC_ENABLE_VSPRINTF
+/*
+ * Description: The vsprintf_s function is equivalent to the vsprintf function except for the parameter destMax
+ * and the explicit runtime-constraints violation
+ * Parameter: strDest -  produce output according to a format,write to the character string strDest.
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide character)
+ * Parameter: format - format string
+ * Parameter: argList - instead of a variable number of arguments
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.
+ */
+SECUREC_API int vsprintf_s(char *strDest, size_t destMax, const char *format,
+                           va_list argList) SECUREC_ATTRIBUTE(3, 0);
+#endif
+
+#if SECUREC_ENABLE_SPRINTF
+/*
+ * Description: The sprintf_s function is equivalent to the sprintf function except for the parameter destMax
+ * and the explicit runtime-constraints violation
+ * Parameter: strDest -  produce output according to a format ,write to the character string strDest.
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0')
+ * Parameter: format - format string
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.
+*/
+SECUREC_API int sprintf_s(char *strDest, size_t destMax, const char *format, ...) SECUREC_ATTRIBUTE(3, 4);
+#endif
+
+#if SECUREC_ENABLE_VSNPRINTF
+/*
+ * Description: The vsnprintf_s function is equivalent to the vsnprintf function except for
+ * the parameter destMax/count and the explicit runtime-constraints violation
+ * Parameter: strDest -  produce output according to a format ,write to the character string strDest.
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null  byte '\0')
+ * Parameter: count - do not write more than count bytes to strDest(not including the terminating null  byte '\0')
+ * Parameter: format - format string
+ * Parameter: argList - instead of  a variable number of arguments
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs.
+ */
+SECUREC_API int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format,
+                            va_list argList) SECUREC_ATTRIBUTE(4, 0);
+#endif
+
+#if SECUREC_ENABLE_SNPRINTF
+/*
+ * Description: The snprintf_s function is equivalent to the snprintf function except for
+ * the parameter destMax/count and the explicit runtime-constraints violation
+ * Parameter: strDest - produce output according to a format ,write to the character string strDest.
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null  byte '\0')
+ * Parameter: count - do not write more than count bytes to strDest(not including the terminating null  byte '\0')
+ * Parameter: format - format string
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs.
+ */
+SECUREC_API int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format,
+                           ...) SECUREC_ATTRIBUTE(4, 5);
+#endif
+
+#if SECUREC_SNPRINTF_TRUNCATED
+/*
+ * Description: The vsnprintf_truncated_s function is equivalent to the vsnprintf_s function except
+ * no count parameter and return value
+ * Parameter: strDest -  produce output according to a format ,write to the character string strDest
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null  byte '\0')
+ * Parameter: format - format string
+ * Parameter: argList - instead of  a variable  number of arguments
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs
+*/
+SECUREC_API int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format,
+                                      va_list argList) SECUREC_ATTRIBUTE(3, 0);
+
+/*
+ * Description: The snprintf_truncated_s function is equivalent to the snprintf_s function except
+ * no count parameter and return value
+ * Parameter: strDest - produce output according to a format,write to the character string strDest.
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0')
+ * Parameter: format - format string
+ * Return:    the number of characters printed(not including the terminating null byte '\0'),
+ * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs.
+ */
+SECUREC_API int snprintf_truncated_s(char *strDest, size_t destMax,
+                                     const char *format, ...) SECUREC_ATTRIBUTE(3, 4);
+#endif
+
+#if SECUREC_ENABLE_SCANF
+/*
+ * Description: The scanf_s function is equivalent to fscanf_s with the argument stdin
+ * interposed before the arguments to scanf_s
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int scanf_s(const char *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VSCANF
+/*
+ * Description: The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList
+ * Parameter: format - format string
+ * Parameter: argList - instead of a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vscanf_s(const char *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_SSCANF
+/*
+ * Description: The sscanf_s function is equivalent to fscanf_s, except that input is obtained from a
+ * string (specified by the argument buffer) rather than from a stream
+ * Parameter: buffer - read character from buffer
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int sscanf_s(const char *buffer, const char *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VSSCANF
+/*
+ * Description: The vsscanf_s function is equivalent to sscanf_s, with the variable argument list
+ * replaced by argList
+ * Parameter: buffer -  read character from buffer
+ * Parameter: format - format string
+ * Parameter: argList - instead of a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vsscanf_s(const char *buffer, const char *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_FSCANF
+/*
+ * Description: The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion specifiers
+ * apply to a pair of arguments (unless assignment suppression is indicated by a *)
+ * Parameter: stream - stdio file stream
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int fscanf_s(FILE *stream, const char *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VFSCANF
+/*
+ * Description: The vfscanf_s function is equivalent to fscanf_s, with the variable argument list
+ * replaced by argList
+ * Parameter: stream - stdio file stream
+ * Parameter: format - format string
+ * Parameter: argList - instead of a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vfscanf_s(FILE *stream, const char *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_STRTOK
+/*
+ * Description: The strtok_s function parses a string into a sequence of strToken,
+ * replace all characters in strToken string that match to strDelimit set with 0.
+ * On the first call to strtok_s the string to be parsed should be specified in strToken.
+ * In each subsequent call that should parse the same string, strToken should be NULL
+ * Parameter: strToken - the string to be delimited
+ * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string
+ * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function
+ * Return:  On the first call returns the address of the first non \0 character, otherwise NULL is returned.
+ * In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call,
+ * return NULL if the *context string length is equal 0, otherwise return *context.
+ */
+SECUREC_API char *strtok_s(char *strToken, const char *strDelimit, char **context);
+#endif
+
+#if SECUREC_ENABLE_GETS && !SECUREC_IN_KERNEL
+/*
+ * Description: The gets_s function reads at most one less than the number of characters specified
+ * by destMax from the stream pointed to by stdin, into the array pointed to by buffer
+ * Parameter: buffer - destination address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null character)
+ * Return:    buffer if there was no runtime-constraint violation,If an error occurred Return: NULL.
+ */
+SECUREC_API char *gets_s(char *buffer, size_t destMax);
+#endif
+
+#if SECUREC_ENABLE_WCHAR_FUNC
+#if SECUREC_ENABLE_MEMCPY
+/*
+ * Description: The wmemcpy_s function copies n successive wide characters from the object pointed to
+ * by src into the object pointed to by dest.
+ * Parameter: dest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: src - source address
+ * Parameter: count - copies count wide characters from the  src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count);
+#endif
+
+#if SECUREC_ENABLE_MEMMOVE
+/*
+ * Description: The wmemmove_s function copies n successive wide characters from the object
+ * pointed to by src into the object pointed to by dest.
+ * Parameter: dest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: src - source address
+ * Parameter: count - copies count wide characters from the  src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count);
+#endif
+
+#if SECUREC_ENABLE_STRCPY
+/*
+ * Description: The wcscpy_s function copies the wide string pointed to by strSrc(including the terminating
+ * null wide character) into the array pointed to by strDest
+ * Parameter: strDest - destination address
+ * Parameter: destMax - The maximum length of destination buffer
+ * Parameter: strSrc - source address
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc);
+#endif
+
+#if SECUREC_ENABLE_STRNCPY
+/*
+ * Description: The wcsncpy_s function copies not more than n successive wide characters (not including the
+ * terminating null wide character) from the array pointed to by strSrc to the array pointed to by strDest
+ * Parameter: strDest - destination address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character)
+ * Parameter: strSrc - source address
+ * Parameter: count - copies count wide characters from the src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count);
+#endif
+
+#if SECUREC_ENABLE_STRCAT
+/*
+ * Description: The wcscat_s function appends a copy of the wide string pointed to by strSrc (including the
+ * terminating null wide character) to the end of the wide string pointed to by strDest
+ * Parameter: strDest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character)
+ * Parameter: strSrc - source address
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc);
+#endif
+
+#if SECUREC_ENABLE_STRNCAT
+/*
+ * Description: The wcsncat_s function appends not more than n successive wide characters (not including the
+ * terminating null wide character) from the array pointed to by strSrc to the end of the wide string pointed to
+ * by strDest.
+ * Parameter: strDest - destination  address
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character)
+ * Parameter: strSrc - source  address
+ * Parameter: count - copies count wide characters from the  src
+ * Return:    EOK if there was no runtime-constraint violation
+ */
+SECUREC_API errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count);
+#endif
+
+#if SECUREC_ENABLE_STRTOK
+/*
+ * Description: The wcstok_s function is the wide-character equivalent of the strtok_s function
+ * Parameter: strToken - the string to be delimited
+ * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string
+ * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function
+ * Return:    a pointer to the first character of a token, or a null pointer if there is no token
+ * or there is a runtime-constraint violation.
+ */
+SECUREC_API wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context);
+#endif
+
+#if SECUREC_ENABLE_VSPRINTF
+/*
+ * Description: The vswprintf_s function is the wide-character equivalent of the vsprintf_s function
+ * Parameter: strDest - produce output according to a format,write to the character string strDest
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null)
+ * Parameter: format - format string
+ * Parameter: argList - instead of a variable number of arguments
+ * Return:    the number of characters printed(not including the terminating null wide character),
+ * If an error occurred Return: -1.
+ */
+SECUREC_API int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_SPRINTF
+/*
+ * Description: The swprintf_s function is the wide-character equivalent of the sprintf_s function
+ * Parameter: strDest - produce output according to a format,write to the character string strDest
+ * Parameter: destMax - The maximum length of destination buffer(including the terminating null)
+ * Parameter: format - format string
+ * Return:    the number of characters printed(not including the terminating null wide character),
+ * If an error occurred Return: -1.
+ */
+SECUREC_API int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...);
+#endif
+
+#if SECUREC_ENABLE_FSCANF
+/*
+ * Description: The fwscanf_s function is the wide-character equivalent of the fscanf_s function
+ * Parameter: stream - stdio file stream
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int fwscanf_s(FILE *stream, const wchar_t *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VFSCANF
+/*
+ * Description: The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function
+ * Parameter: stream - stdio file stream
+ * Parameter: format - format string
+ * Parameter: argList - instead of  a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_SCANF
+/*
+ * Description: The wscanf_s function is the wide-character equivalent of the scanf_s function
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int wscanf_s(const wchar_t *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VSCANF
+/*
+ * Description: The vwscanf_s function is the wide-character equivalent of the vscanf_s function
+ * Parameter: format - format string
+ * Parameter: argList - instead of  a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vwscanf_s(const wchar_t *format, va_list argList);
+#endif
+
+#if SECUREC_ENABLE_SSCANF
+/*
+ * Description: The swscanf_s function is the wide-character equivalent of the sscanf_s function
+ * Parameter: buffer - read character from buffer
+ * Parameter: format - format string
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...);
+#endif
+
+#if SECUREC_ENABLE_VSSCANF
+/*
+ * Description: The vswscanf_s function is the wide-character equivalent of the vsscanf_s function
+ * Parameter: buffer -  read character from  buffer
+ * Parameter: format - format string
+ * Parameter: argList - instead of  a variable number of arguments
+ * Return:    the number of input items assigned, If an error occurred Return: -1.
+ */
+SECUREC_API int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList);
+#endif
+#endif /* SECUREC_ENABLE_WCHAR_FUNC */
+#endif
+
+/* Those functions are used by macro,must declare hare, also for without function declaration warning */
+extern errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count);
+extern errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc);
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+/* Those functions are used by macro */
+extern errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count);
+extern errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count);
+extern errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count);
+extern errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count);
+
+/* The strcpy_sp is a macro, not a function in performance optimization mode. */
+#define strcpy_sp(dest, destMax, src)  ((__builtin_constant_p((destMax)) && \
+    __builtin_constant_p((src))) ?  \
+    SECUREC_STRCPY_SM((dest), (destMax), (src)) : \
+    strcpy_s((dest), (destMax), (src)))
+
+/* The strncpy_sp is a macro, not a function in performance optimization mode. */
+#define strncpy_sp(dest, destMax, src, count)  ((__builtin_constant_p((count)) && \
+    __builtin_constant_p((destMax)) && \
+    __builtin_constant_p((src))) ?  \
+    SECUREC_STRNCPY_SM((dest), (destMax), (src), (count)) : \
+    strncpy_s((dest), (destMax), (src), (count)))
+
+/* The strcat_sp is a macro, not a function in performance optimization mode. */
+#define strcat_sp(dest, destMax, src) ((__builtin_constant_p((destMax)) && \
+    __builtin_constant_p((src))) ?  \
+    SECUREC_STRCAT_SM((dest), (destMax), (src)) : \
+    strcat_s((dest), (destMax), (src)))
+
+/* The strncat_sp is a macro, not a function in performance optimization mode. */
+#define strncat_sp(dest, destMax, src, count) ((__builtin_constant_p((count)) &&  \
+    __builtin_constant_p((destMax)) && \
+    __builtin_constant_p((src))) ?  \
+    SECUREC_STRNCAT_SM((dest), (destMax), (src), (count)) : \
+    strncat_s((dest), (destMax), (src), (count)))
+
+/* The memcpy_sp is a macro, not a function in performance optimization mode. */
+#define memcpy_sp(dest, destMax, src, count)  (__builtin_constant_p((count)) ? \
+    (SECUREC_MEMCPY_SM((dest), (destMax), (src), (count))) : \
+    (__builtin_constant_p((destMax)) ? \
+    (((size_t)(destMax) > 0 && \
+    (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \
+    memcpy_sOptTc((dest), (destMax), (src), (count)) : ERANGE) : \
+    memcpy_sOptAsm((dest), (destMax), (src), (count))))
+
+/* The memset_sp is a macro, not a function in performance optimization mode. */
+#define memset_sp(dest, destMax, c, count)  (__builtin_constant_p((count)) ? \
+    (SECUREC_MEMSET_SM((dest), (destMax), (c), (count))) : \
+    (__builtin_constant_p((destMax)) ? \
+    (((((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \
+    memset_sOptTc((dest), (destMax), (c), (count)) : ERANGE) : \
+    memset_sOptAsm((dest), (destMax), (c), (count))))
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securectype.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securectype.h
new file mode 100644 (file)
index 0000000..69e79c2
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Define internal used macro and data type. The marco of SECUREC_ON_64BITS
+ *              will be determined in this header file, which is a switch for part
+ *              of code. Some macro are used to suppress warning by MS compiler.
+ * Create: 2014-02-25
+ * Notes: User can change the value of SECUREC_STRING_MAX_LEN and SECUREC_MEM_MAX_LEN
+ *        macro to meet their special need, but The maximum value should not exceed 2G.
+ */
+/*
+ * [Standardize-exceptions]: Performance-sensitive
+ * [reason]: Strict parameter verification has been done before use
+ */
+
+#ifndef SECURECTYPE_H_A7BBB686_AADA_451B_B9F9_44DACDAE18A7
+#define SECURECTYPE_H_A7BBB686_AADA_451B_B9F9_44DACDAE18A7
+
+#ifndef SECUREC_USING_STD_SECURE_LIB
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#if defined(__STDC_WANT_SECURE_LIB__) && (!__STDC_WANT_SECURE_LIB__)
+/* Security functions have been provided since vs2005, default use of system library functions */
+#define SECUREC_USING_STD_SECURE_LIB    0
+#else
+#define SECUREC_USING_STD_SECURE_LIB    1
+#endif
+#else
+#define SECUREC_USING_STD_SECURE_LIB    0
+#endif
+#endif
+
+/* Compatibility with older Secure C versions, shielding VC symbol redefinition warning */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) && (!SECUREC_USING_STD_SECURE_LIB)
+#ifndef SECUREC_DISABLE_CRT_FUNC
+#define SECUREC_DISABLE_CRT_FUNC        1
+#endif
+#ifndef SECUREC_DISABLE_CRT_IMP
+#define SECUREC_DISABLE_CRT_IMP         1
+#endif
+#else /*  MSC VER */
+#ifndef SECUREC_DISABLE_CRT_FUNC
+#define SECUREC_DISABLE_CRT_FUNC        0
+#endif
+#ifndef SECUREC_DISABLE_CRT_IMP
+#define SECUREC_DISABLE_CRT_IMP         0
+#endif
+#endif
+
+#if SECUREC_DISABLE_CRT_FUNC
+#ifdef __STDC_WANT_SECURE_LIB__
+#undef __STDC_WANT_SECURE_LIB__
+#endif
+#define __STDC_WANT_SECURE_LIB__        0
+#endif
+
+#if SECUREC_DISABLE_CRT_IMP
+#ifdef _CRTIMP_ALTERNATIVE
+#undef _CRTIMP_ALTERNATIVE
+#endif
+#define _CRTIMP_ALTERNATIVE     /* Comment Microsoft *_s function */
+#endif
+
+/* Compile in kernel under macro control */
+#ifndef SECUREC_IN_KERNEL
+#ifdef __KERNEL__
+#define SECUREC_IN_KERNEL               1
+#else
+#define SECUREC_IN_KERNEL               0
+#endif
+#endif
+
+/* make kernel symbols of functions available to loadable modules */
+#ifndef SECUREC_EXPORT_KERNEL_SYMBOL
+#if SECUREC_IN_KERNEL
+#define SECUREC_EXPORT_KERNEL_SYMBOL    1
+#else
+#define SECUREC_EXPORT_KERNEL_SYMBOL    0
+#endif
+#endif
+
+#if SECUREC_IN_KERNEL
+#ifndef SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_SCANF_FILE       0
+#endif
+#ifndef SECUREC_ENABLE_WCHAR_FUNC
+#define SECUREC_ENABLE_WCHAR_FUNC       0
+#endif
+#else /* SECUREC_IN_KERNEL */
+#ifndef SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_SCANF_FILE       1
+#endif
+#ifndef SECUREC_ENABLE_WCHAR_FUNC
+#define SECUREC_ENABLE_WCHAR_FUNC       1
+#endif
+#endif
+
+/* Default secure function declaration, default declarations for non-standard functions */
+#ifndef SECUREC_SNPRINTF_TRUNCATED
+#define SECUREC_SNPRINTF_TRUNCATED      1
+#endif
+
+#if SECUREC_USING_STD_SECURE_LIB
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+/* Declare secure functions that are not available in the VS compiler */
+#ifndef SECUREC_ENABLE_MEMSET
+#define SECUREC_ENABLE_MEMSET           1
+#endif
+/* VS 2005 have vsnprintf_s function */
+#ifndef SECUREC_ENABLE_VSNPRINTF
+#define SECUREC_ENABLE_VSNPRINTF        0
+#endif
+#ifndef SECUREC_ENABLE_SNPRINTF
+/* VS 2005 have vsnprintf_s function Adapt the snprintf_s of the security function */
+#define snprintf_s _snprintf_s
+#define SECUREC_ENABLE_SNPRINTF         0
+#endif
+/* Before VS 2010 do not have v functions */
+#if _MSC_VER <= 1600 || defined(SECUREC_FOR_V_SCANFS)
+#ifndef SECUREC_ENABLE_VFSCANF
+#define SECUREC_ENABLE_VFSCANF          1
+#endif
+#ifndef SECUREC_ENABLE_VSCANF
+#define SECUREC_ENABLE_VSCANF           1
+#endif
+#ifndef SECUREC_ENABLE_VSSCANF
+#define SECUREC_ENABLE_VSSCANF          1
+#endif
+#endif
+
+#else /* MSC VER */
+#ifndef SECUREC_ENABLE_MEMSET
+#define SECUREC_ENABLE_MEMSET           0
+#endif
+#ifndef SECUREC_ENABLE_SNPRINTF
+#define SECUREC_ENABLE_SNPRINTF         0
+#endif
+#ifndef SECUREC_ENABLE_VSNPRINTF
+#define SECUREC_ENABLE_VSNPRINTF        0
+#endif
+#endif
+
+#ifndef SECUREC_ENABLE_MEMMOVE
+#define SECUREC_ENABLE_MEMMOVE          0
+#endif
+#ifndef SECUREC_ENABLE_MEMCPY
+#define SECUREC_ENABLE_MEMCPY           0
+#endif
+#ifndef SECUREC_ENABLE_STRCPY
+#define SECUREC_ENABLE_STRCPY           0
+#endif
+#ifndef SECUREC_ENABLE_STRNCPY
+#define SECUREC_ENABLE_STRNCPY          0
+#endif
+#ifndef SECUREC_ENABLE_STRCAT
+#define SECUREC_ENABLE_STRCAT           0
+#endif
+#ifndef SECUREC_ENABLE_STRNCAT
+#define SECUREC_ENABLE_STRNCAT          0
+#endif
+#ifndef SECUREC_ENABLE_SPRINTF
+#define SECUREC_ENABLE_SPRINTF          0
+#endif
+#ifndef SECUREC_ENABLE_VSPRINTF
+#define SECUREC_ENABLE_VSPRINTF          0
+#endif
+#ifndef SECUREC_ENABLE_SSCANF
+#define SECUREC_ENABLE_SSCANF           0
+#endif
+#ifndef SECUREC_ENABLE_VSSCANF
+#define SECUREC_ENABLE_VSSCANF          0
+#endif
+#ifndef SECUREC_ENABLE_SCANF
+#define SECUREC_ENABLE_SCANF            0
+#endif
+#ifndef SECUREC_ENABLE_VSCANF
+#define SECUREC_ENABLE_VSCANF           0
+#endif
+
+#ifndef SECUREC_ENABLE_FSCANF
+#define SECUREC_ENABLE_FSCANF           0
+#endif
+#ifndef SECUREC_ENABLE_VFSCANF
+#define SECUREC_ENABLE_VFSCANF          0
+#endif
+#ifndef SECUREC_ENABLE_STRTOK
+#define SECUREC_ENABLE_STRTOK           0
+#endif
+#ifndef SECUREC_ENABLE_GETS
+#define SECUREC_ENABLE_GETS             0
+#endif
+
+#else /* SECUREC USE STD SECURE LIB */
+
+#ifndef SECUREC_ENABLE_MEMSET
+#define SECUREC_ENABLE_MEMSET           1
+#endif
+#ifndef SECUREC_ENABLE_MEMMOVE
+#define SECUREC_ENABLE_MEMMOVE          1
+#endif
+#ifndef SECUREC_ENABLE_MEMCPY
+#define SECUREC_ENABLE_MEMCPY           1
+#endif
+#ifndef SECUREC_ENABLE_STRCPY
+#define SECUREC_ENABLE_STRCPY           1
+#endif
+#ifndef SECUREC_ENABLE_STRNCPY
+#define SECUREC_ENABLE_STRNCPY          1
+#endif
+#ifndef SECUREC_ENABLE_STRCAT
+#define SECUREC_ENABLE_STRCAT           1
+#endif
+#ifndef SECUREC_ENABLE_STRNCAT
+#define SECUREC_ENABLE_STRNCAT          1
+#endif
+#ifndef SECUREC_ENABLE_SPRINTF
+#define SECUREC_ENABLE_SPRINTF          1
+#endif
+#ifndef SECUREC_ENABLE_VSPRINTF
+#define SECUREC_ENABLE_VSPRINTF          1
+#endif
+#ifndef SECUREC_ENABLE_SNPRINTF
+#define SECUREC_ENABLE_SNPRINTF         1
+#endif
+#ifndef SECUREC_ENABLE_VSNPRINTF
+#define SECUREC_ENABLE_VSNPRINTF        1
+#endif
+#ifndef SECUREC_ENABLE_SSCANF
+#define SECUREC_ENABLE_SSCANF           1
+#endif
+#ifndef SECUREC_ENABLE_VSSCANF
+#define SECUREC_ENABLE_VSSCANF          1
+#endif
+#ifndef SECUREC_ENABLE_SCANF
+#if SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_SCANF            1
+#else
+#define SECUREC_ENABLE_SCANF            0
+#endif
+#endif
+#ifndef SECUREC_ENABLE_VSCANF
+#if SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_VSCANF           1
+#else
+#define SECUREC_ENABLE_VSCANF           0
+#endif
+#endif
+
+#ifndef SECUREC_ENABLE_FSCANF
+#if SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_FSCANF           1
+#else
+#define SECUREC_ENABLE_FSCANF           0
+#endif
+#endif
+#ifndef SECUREC_ENABLE_VFSCANF
+#if SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_VFSCANF          1
+#else
+#define SECUREC_ENABLE_VFSCANF          0
+#endif
+#endif
+
+#ifndef SECUREC_ENABLE_STRTOK
+#define SECUREC_ENABLE_STRTOK           1
+#endif
+#ifndef SECUREC_ENABLE_GETS
+#define SECUREC_ENABLE_GETS             1
+#endif
+#endif /* SECUREC_USE_STD_SECURE_LIB */
+
+#if !SECUREC_ENABLE_SCANF_FILE
+#if SECUREC_ENABLE_FSCANF
+#undef SECUREC_ENABLE_FSCANF
+#define SECUREC_ENABLE_FSCANF           0
+#endif
+#if SECUREC_ENABLE_VFSCANF
+#undef SECUREC_ENABLE_VFSCANF
+#define SECUREC_ENABLE_VFSCANF          0
+#endif
+#if SECUREC_ENABLE_SCANF
+#undef SECUREC_ENABLE_SCANF
+#define SECUREC_ENABLE_SCANF            0
+#endif
+#if SECUREC_ENABLE_FSCANF
+#undef SECUREC_ENABLE_FSCANF
+#define SECUREC_ENABLE_FSCANF           0
+#endif
+
+#endif
+
+#if SECUREC_IN_KERNEL
+#include <linux/kernel.h>
+#include <linux/module.h>
+#else
+#ifndef SECUREC_HAVE_STDIO_H
+#define SECUREC_HAVE_STDIO_H 1
+#endif
+#ifndef SECUREC_HAVE_STRING_H
+#define SECUREC_HAVE_STRING_H 1
+#endif
+#ifndef SECUREC_HAVE_STDLIB_H
+#define SECUREC_HAVE_STDLIB_H 1
+#endif
+#if SECUREC_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if SECUREC_HAVE_STRING_H
+#include <string.h>
+#endif
+#if SECUREC_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#endif
+
+/*
+ * If you need high performance, enable the SECUREC_WITH_PERFORMANCE_ADDONS macro, default is enable.
+ * The macro is automatically closed on the windows platform and linux kernel
+ */
+#ifndef SECUREC_WITH_PERFORMANCE_ADDONS
+#if SECUREC_IN_KERNEL
+#define SECUREC_WITH_PERFORMANCE_ADDONS 0
+#else
+#define SECUREC_WITH_PERFORMANCE_ADDONS 1
+#endif
+#endif
+
+/* If enable SECUREC_COMPATIBLE_WIN_FORMAT, the output format will be compatible to Windows. */
+#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)) && !defined(SECUREC_COMPATIBLE_LINUX_FORMAT)
+#ifndef SECUREC_COMPATIBLE_WIN_FORMAT
+#define SECUREC_COMPATIBLE_WIN_FORMAT
+#endif
+#endif
+
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+/* On windows platform, can't use optimized function for there is no __builtin_constant_p like function */
+/* If need optimized macro, can define this: define __builtin_constant_p(x) 0 */
+#ifdef SECUREC_WITH_PERFORMANCE_ADDONS
+#undef SECUREC_WITH_PERFORMANCE_ADDONS
+#define SECUREC_WITH_PERFORMANCE_ADDONS 0
+#endif
+#endif
+
+#if defined(__VXWORKS__) || defined(__vxworks) || defined(__VXWORKS) || defined(_VXWORKS_PLATFORM_)  || \
+    defined(SECUREC_VXWORKS_VERSION_5_4)
+#ifndef SECUREC_VXWORKS_PLATFORM
+#define SECUREC_VXWORKS_PLATFORM
+#endif
+#endif
+
+/* If enable SECUREC_COMPATIBLE_LINUX_FORMAT, the output format will be compatible to Linux. */
+#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) && !defined(SECUREC_VXWORKS_PLATFORM)
+#ifndef SECUREC_COMPATIBLE_LINUX_FORMAT
+#define SECUREC_COMPATIBLE_LINUX_FORMAT
+#endif
+#endif
+
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+#ifndef SECUREC_HAVE_STDDEF_H
+#define SECUREC_HAVE_STDDEF_H 1
+#endif
+/* Some system may no stddef.h */
+#if SECUREC_HAVE_STDDEF_H
+#if !SECUREC_IN_KERNEL
+#include <stddef.h>
+#endif
+#endif
+#endif
+
+/*
+ * Add  the -DSECUREC_SUPPORT_FORMAT_WARNING=1  compiler option to supoort  -Wformat=2.
+ * Default does not check the format is that the same data type in the actual code.
+ * In the product is different in the original data type definition of VxWorks and Linux.
+ */
+#ifndef SECUREC_SUPPORT_FORMAT_WARNING
+#define SECUREC_SUPPORT_FORMAT_WARNING 0
+#endif
+
+#if SECUREC_SUPPORT_FORMAT_WARNING
+#define SECUREC_ATTRIBUTE(x, y)  __attribute__((format(printf, (x), (y))))
+#else
+#define SECUREC_ATTRIBUTE(x, y)
+#endif
+
+/*
+ * Add the -DSECUREC_SUPPORT_BUILTIN_EXPECT=0 compiler option, if compiler can not support __builtin_expect.
+ */
+#ifndef SECUREC_SUPPORT_BUILTIN_EXPECT
+#define SECUREC_SUPPORT_BUILTIN_EXPECT 1
+#endif
+
+#if SECUREC_SUPPORT_BUILTIN_EXPECT && defined(__GNUC__) && ((__GNUC__ > 3) || \
+    (defined(__GNUC_MINOR__) && (__GNUC__ == 3 && __GNUC_MINOR__ > 3)))
+/*
+ * This is a built-in function that can be used without a declaration, if warning for declaration not found occurred,
+ * you can add -DSECUREC_NEED_BUILTIN_EXPECT_DECLARE to compiler options
+ */
+#ifdef SECUREC_NEED_BUILTIN_EXPECT_DECLARE
+long __builtin_expect(long exp, long c);
+#endif
+
+#define SECUREC_LIKELY(x) __builtin_expect(!!(x), 1)
+#define SECUREC_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define SECUREC_LIKELY(x) (x)
+#define SECUREC_UNLIKELY(x) (x)
+#endif
+
+/* Define the max length of the string */
+#ifndef SECUREC_STRING_MAX_LEN
+#define SECUREC_STRING_MAX_LEN 0x7fffffffUL
+#endif
+#define SECUREC_WCHAR_STRING_MAX_LEN (SECUREC_STRING_MAX_LEN / sizeof(wchar_t))
+
+/* Add SECUREC_MEM_MAX_LEN for memcpy and memmove */
+#ifndef SECUREC_MEM_MAX_LEN
+#define SECUREC_MEM_MAX_LEN 0x7fffffffUL
+#endif
+#define SECUREC_WCHAR_MEM_MAX_LEN (SECUREC_MEM_MAX_LEN / sizeof(wchar_t))
+
+#if SECUREC_STRING_MAX_LEN > 0x7fffffffUL
+#error "max string is 2G"
+#endif
+
+#if (defined(__GNUC__) && defined(__SIZEOF_POINTER__))
+#if (__SIZEOF_POINTER__ != 4) && (__SIZEOF_POINTER__ != 8)
+#error "unsupported system"
+#endif
+#endif
+
+#if defined(_WIN64) || defined(WIN64) || defined(__LP64__) || defined(_LP64)
+#define SECUREC_ON_64BITS
+#endif
+
+#if (!defined(SECUREC_ON_64BITS) && defined(__GNUC__) && defined(__SIZEOF_POINTER__))
+#if __SIZEOF_POINTER__ == 8
+#define SECUREC_ON_64BITS
+#endif
+#endif
+
+#if defined(__SVR4) || defined(__svr4__)
+#define SECUREC_ON_SOLARIS
+#endif
+
+#if (defined(__hpux) || defined(_AIX) || defined(SECUREC_ON_SOLARIS))
+#define SECUREC_ON_UNIX
+#endif
+
+/*
+ * Codes should run under the macro SECUREC_COMPATIBLE_LINUX_FORMAT in unknown system on default,
+ * and strtold.
+ * The function strtold is referenced first at ISO9899:1999(C99), and some old compilers can
+ * not support these functions. Here provides a macro to open these functions:
+ * SECUREC_SUPPORT_STRTOLD  -- If defined, strtold will be used
+ */
+#ifndef SECUREC_SUPPORT_STRTOLD
+#define SECUREC_SUPPORT_STRTOLD 0
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT))
+#if defined(__USE_ISOC99)  || \
+    (defined(_AIX) && defined(_ISOC99_SOURCE)) || \
+    (defined(__hpux) && defined(__ia64)) || \
+    (defined(SECUREC_ON_SOLARIS) && (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
+    defined(_STDC_C99) || defined(__EXTENSIONS__))
+#undef  SECUREC_SUPPORT_STRTOLD
+#define SECUREC_SUPPORT_STRTOLD 1
+#endif
+#endif
+#if ((defined(SECUREC_WRLINUX_BELOW4) || defined(_WRLINUX_BELOW4_)))
+#undef  SECUREC_SUPPORT_STRTOLD
+#define SECUREC_SUPPORT_STRTOLD 0
+#endif
+#endif
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+
+#ifndef SECUREC_TWO_MIN
+#define SECUREC_TWO_MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* For strncpy_s performance optimization */
+#define SECUREC_STRNCPY_SM(dest, destMax, src, count) \
+    (((void *)(dest) != NULL && (const void *)(src) != NULL && (size_t)(destMax) > 0 && \
+    (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \
+    (SECUREC_TWO_MIN((size_t)(count), strlen(src)) + 1) <= (size_t)(destMax)) ? \
+    (((size_t)(count) < strlen(src)) ? (memcpy((dest), (src), (count)), *((char *)(dest) + (count)) = '\0', EOK) : \
+    (memcpy((dest), (src), strlen(src) + 1), EOK)) : (strncpy_error((dest), (destMax), (src), (count))))
+
+#define SECUREC_STRCPY_SM(dest, destMax, src) \
+    (((void *)(dest) != NULL && (const void *)(src) != NULL && (size_t)(destMax) > 0 && \
+    (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \
+    (strlen(src) + 1) <= (size_t)(destMax)) ? (memcpy((dest), (src), strlen(src) + 1), EOK) : \
+    (strcpy_error((dest), (destMax), (src))))
+
+/* For strcat_s performance optimization */
+#if defined(__GNUC__)
+#define SECUREC_STRCAT_SM(dest, destMax, src) ({ \
+    int catRet_ = EOK; \
+    if ((void *)(dest) != NULL && (const void *)(src) != NULL && (size_t)(destMax) > 0 && \
+        (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \
+        char *catTmpDst_ = (char *)(dest); \
+        size_t catRestSize_ = (destMax); \
+        while (catRestSize_ > 0 && *catTmpDst_ != '\0') { \
+            ++catTmpDst_; \
+            --catRestSize_; \
+        } \
+        if (catRestSize_ == 0) { \
+            catRet_ = EINVAL; \
+        } else if ((strlen(src) + 1) <= catRestSize_) { \
+            memcpy(catTmpDst_, (src), strlen(src) + 1); \
+            catRet_ = EOK; \
+        } else { \
+            catRet_ = ERANGE; \
+        } \
+        if (catRet_ != EOK) { \
+            catRet_ = strcat_s((dest), (destMax), (src)); \
+        } \
+    } else { \
+        catRet_ = strcat_s((dest), (destMax), (src)); \
+    } \
+    catRet_; \
+})
+#else
+#define SECUREC_STRCAT_SM(dest, destMax, src) strcat_s((dest), (destMax), (src))
+#endif
+
+/* For strncat_s performance optimization */
+#if defined(__GNUC__)
+#define SECUREC_STRNCAT_SM(dest, destMax, src, count) ({ \
+    int ncatRet_ = EOK; \
+    if ((void *)(dest) != NULL && (const void *)(src) != NULL && (size_t)(destMax) > 0 && \
+        (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)  && \
+        (((unsigned long long)(count) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \
+        char *ncatTmpDest_ = (char *)(dest); \
+        size_t ncatRestSize_ = (size_t)(destMax); \
+        while (ncatRestSize_ > 0 && *ncatTmpDest_ != '\0') { \
+            ++ncatTmpDest_; \
+            --ncatRestSize_; \
+        } \
+        if (ncatRestSize_ == 0) { \
+            ncatRet_ = EINVAL; \
+        } else if ((SECUREC_TWO_MIN((count), strlen(src)) + 1) <= ncatRestSize_) { \
+            if ((size_t)(count) < strlen(src)) { \
+                memcpy(ncatTmpDest_, (src), (count)); \
+                *(ncatTmpDest_ + (count)) = '\0'; \
+            } else { \
+                memcpy(ncatTmpDest_, (src), strlen(src) + 1); \
+            } \
+        } else { \
+            ncatRet_ = ERANGE; \
+        } \
+        if (ncatRet_ != EOK) { \
+            ncatRet_ = strncat_s((dest), (destMax), (src), (count)); \
+        } \
+    } else { \
+        ncatRet_ = strncat_s((dest), (destMax), (src), (count)); \
+    } \
+    ncatRet_; \
+})
+#else
+#define SECUREC_STRNCAT_SM(dest, destMax, src, count) strncat_s((dest), (destMax), (src), (count))
+#endif
+
+/* This macro do not check buffer overlap by default */
+#define  SECUREC_MEMCPY_SM(dest, destMax, src, count) \
+    (!(((size_t)(destMax) == 0) || \
+        (((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \
+        ((size_t)(count) > (size_t)(destMax)) || ((void *)(dest)) == NULL || ((const void *)(src) == NULL)) ? \
+        (memcpy((dest), (src), (count)), EOK) : \
+        (memcpy_s((dest), (destMax), (src), (count))))
+
+#define  SECUREC_MEMSET_SM(dest, destMax, c, count) \
+    (!((((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \
+        ((void *)(dest) == NULL) || ((size_t)(count) > (size_t)(destMax))) ? \
+        (memset((dest), (c), (count)), EOK) : \
+        (memset_s((dest), (destMax), (c), (count))))
+
+#endif
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/Makefile b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/Makefile
new file mode 100644 (file)
index 0000000..6513bc4
--- /dev/null
@@ -0,0 +1,196 @@
+######
+###     This is a sample file for linux platform, please write the Makefile according to the actual situation of the product
+###     If you want to create a shared library, use the command:"make"
+###     If you want to create a static library, use the command:"make lib"
+###     If you want to create a .ko file, use the command:"make kernel"
+###     If you want to filter out unsupported compiler options, add the command:"CHECK_OPTION=check"
+######
+
+PROJECT=libsecurec.so
+#if you need a debug version library, use "-g" instead of "-s -DNDEBUG -O2".
+# If you compiler report a warning on "break strict-aliasing rules", there is no problem. If you need to clear all warnings, you can add "-fno-strict-aliasing" option to your compiler, but this will impact the performance a little.
+CC?=gcc
+
+#for linux secure compile options from stdandard 2018.8
+SECURE_CFLAG_FOR_SHARED_LIBRARY  = -fPIC
+SECURE_LDFLAG_FOR_SHARED_LIBRARY += -s
+SECURE_LDFLAG_FOR_SHARED_LIBRARY += -Wl,-z,relro,-z,now,-z,noexecstack
+#This option ensure forced links to functions in the library. If these functions are already contained in other libraries, cross-calls will occur
+#SECURE_LDFLAG_FOR_SHARED_LIBRARY += -Wl,-Bsymbolic
+
+
+GCC_HAVE_STRONG=$(shell $(CC) -fstack-protector-strong -E -dM - < /dev/null 2>&1 |grep -- "fstack-protector-strong" >/dev/null ;if [ $$? -ne 0 ] ;then echo yes;fi)
+ifeq ($(GCC_HAVE_STRONG),yes)
+SECURE_CFLAG_FOR_SHARED_LIBRARY  += -fstack-protector-strong
+else
+SECURE_CFLAG_FOR_SHARED_LIBRARY  += -fstack-protector-all
+endif
+
+
+#-fvisibility=hidden need modify source code
+#SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL += -fvisibility=hidden
+
+#-ftrapv -D_FORTIFY_SOURCE=2 -fstack-check May result in performance degradation after opening
+SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL += -D_FORTIFY_SOURCE=2 -O2
+#SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL += -ftrapv
+#SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL += -fstack-check
+
+
+SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL +=  -Wformat=2 -Wfloat-equal -Wshadow
+# about pie option , We compiled a dynamic library, so we did not use it. ,If you want to compile executable files, please open this option
+#SECURE_CFLAG_FOR_EXE = -fPIE -pie
+
+
+
+## code standard options
+SECUREC_CODE_STANDARD_OPTION = -Wconversion
+SECUREC_CODE_STANDARD_OPTION += -Wformat-security
+SECUREC_CODE_STANDARD_OPTION += -Wextra
+SECUREC_CODE_STANDARD_OPTION += --param ssp-buffer-size=4
+
+#repeat options
+#SECUREC_CODE_STANDARD_OPTION += -D_FORTIFY_SOURCE=2
+#SECUREC_CODE_STANDARD_OPTION += -Wl,-z,relro,-z,now
+#SECUREC_CODE_STANDARD_OPTION += -fstack-protector
+
+#from product options
+PRODUCT_OPTION_FOR_SELECTION  = -Warray-bounds
+PRODUCT_OPTION_FOR_SELECTION += -Wpointer-arith
+PRODUCT_OPTION_FOR_SELECTION += -Wcast-qual
+PRODUCT_OPTION_FOR_SELECTION += -Wstrict-prototypes
+PRODUCT_OPTION_FOR_SELECTION += -Wmissing-prototypes
+PRODUCT_OPTION_FOR_SELECTION += -Wstrict-overflow=1
+PRODUCT_OPTION_FOR_SELECTION += -Wstrict-aliasing=2
+PRODUCT_OPTION_FOR_SELECTION += -Wswitch -Wswitch-default
+PRODUCT_OPTION_FOR_SELECTION += -Wdate-time
+PRODUCT_OPTION_FOR_SELECTION += -Wdisabled-optimization
+PRODUCT_OPTION_FOR_SELECTION += -Wduplicated-branches
+PRODUCT_OPTION_FOR_SELECTION += -Wduplicated-cond
+PRODUCT_OPTION_FOR_SELECTION += -Wignored-qualifiers
+PRODUCT_OPTION_FOR_SELECTION += -Wimplicit-fallthrough=3
+PRODUCT_OPTION_FOR_SELECTION += -Wmissing-include-dirs
+PRODUCT_OPTION_FOR_SELECTION += -Wshift-negative-value
+PRODUCT_OPTION_FOR_SELECTION += -Wsign-compare
+PRODUCT_OPTION_FOR_SELECTION += -Wtrampolines
+PRODUCT_OPTION_FOR_SELECTION += -Wtype-limits
+PRODUCT_OPTION_FOR_SELECTION += -Wwrite-strings
+PRODUCT_OPTION_FOR_SELECTION += -Werror
+PRODUCT_OPTION_FOR_SELECTION += -Wunused-macros
+PRODUCT_OPTION_FOR_SELECTION += -Wshift-overflow=2
+PRODUCT_OPTION_FOR_SELECTION += -Wnested-externs
+PRODUCT_OPTION_FOR_SELECTION += -Wlogical-op
+PRODUCT_OPTION_FOR_SELECTION += -Wjump-misses-init
+PRODUCT_OPTION_FOR_SELECTION += -Wvla
+PRODUCT_OPTION_FOR_SELECTION += -Wframe-larger-than=4096
+PRODUCT_OPTION_FOR_SELECTION += -Wsuggest-attribute=format
+PRODUCT_OPTION_FOR_SELECTION += -Wmissing-format-attribute
+PRODUCT_OPTION_FOR_SELECTION += # -fno-inline-small-functions -fno-indirect-inlining -fno-inline-functions-called-once -fno-early-inlining -fno-inline
+PRODUCT_OPTION_FOR_SELECTION += # -ftrapv
+
+ifeq ($(CHECK_OPTION),check)
+PRODUCT_OPTION := $(shell touch tmp.c; echo "int main(void){return 0;}" > tmp.c; \
+        for loop in $(PRODUCT_OPTION_FOR_SELECTION); \
+        do err=$$({ `$(CC) $$loop -I../include -c tmp.c >/dev/null`; } 2>&1);\
+       echo $${err} | grep ^clang:.w.*ted\]$$ > /dev/null 2>&1;\
+       if [ $$? = 0 ] || [ "X$${err}" = "X" ];then echo "$$loop";fi;\
+        done;\
+        if [ -f tmp.o ];then rm tmp.o;fi;\
+        if [ -f tmp.c ];then rm tmp.c;fi;)
+else
+PRODUCT_OPTION := $(PRODUCT_OPTION_FOR_SELECTION)
+endif
+
+CFLAG   = -Wall -DNDEBUG -O2 $(SECURE_CFLAG_FOR_SHARED_LIBRARY) $(SECURE_CFLAG_FOR_EXE) $(SECURE_CFLAG_FOR_SHARED_LIBRARY_OPTIONAL) $(SECUREC_CODE_STANDARD_OPTION) $(PRODUCT_OPTION)
+#CFLAG += -DSECUREC_VXWORKS_PLATFORM
+#CFLAG += -DSECUREC_SUPPORT_STRTOLD
+#CFLAG += -DSECUREC_VXWORKS_VERSION_5_4
+#CFLAG += -D__STDC_WANT_LIB_EXT1__=0
+CFLAG  += $(CFLAG_EXT)
+
+ARCH:=$(shell getconf LONG_BIT)
+
+ifeq ($(MAKECMDGOALS),lib)
+#Set static library related options
+CFLAG :=$(filter-out "xxxxx",$(CFLAG))
+endif
+
+#SOURCES=$(wildcard *.c)
+SOURCES = fscanf_s.c gets_s.c memcpy_s.c memmove_s.c memset_s.c scanf_s.c securecutil.c secureinput_a.c secureprintoutput_a.c snprintf_s.c sprintf_s.c sscanf_s.c strcat_s.c strcpy_s.c strncat_s.c strncpy_s.c strtok_s.c vfscanf_s.c vscanf_s.c vsnprintf_s.c vsprintf_s.c vsscanf_s.c
+
+SOURCES += fwscanf_s.c secureinput_w.c secureprintoutput_w.c swprintf_s.c swscanf_s.c vfwscanf_s.c vswprintf_s.c vswscanf_s.c vwscanf_s.c wcscat_s.c wcscpy_s.c wcsncat_s.c wcsncpy_s.c wcstok_s.c wmemcpy_s.c wmemmove_s.c wscanf_s.c
+
+OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
+
+.PHONY:clean lib kernel
+
+ENABLE_SCANF_FILE=$(findstring SECUREC_ENABLE_SCANF_FILE=0,$(CFLAG))
+ifeq ($(ENABLE_SCANF_FILE),SECUREC_ENABLE_SCANF_FILE=0)
+OBJECTS:=$(filter-out fscanf_s.o vfscanf_s.o vscanf_s.o scanf_s.o vwscanf_s.o wscanf_s.o fwscanf_s.o vfwscanf_s.o,$(OBJECTS))
+endif
+
+
+ifneq ($(CFLAGS),)
+CFLAG :=$(CFLAGS)
+endif
+CFLAG += -I../include
+LD_FLAG ?= $(SECURE_LDFLAG_FOR_SHARED_LIBRARY) $(SECURE_CFLAG_FOR_SHARED_LIBRARY)
+AR ?=ar
+RANLIB ?=ranlib
+
+$(PROJECT): note_msg $(OBJECTS)
+       @mkdir -p ../obj
+       mkdir -p ../lib
+       $(CC)  -shared -o ../lib/$@ $(patsubst %.o,../obj/%.o,$(OBJECTS)) $(LD_FLAG)
+       @echo "finish $(PROJECT)"
+       #you may add you custom commands here
+
+lib: note_msg $(OBJECTS)
+       $(AR) crv libsecurec.a $(patsubst %.o,../obj/%.o,$(OBJECTS))
+       $(RANLIB) libsecurec.a
+       -mkdir -p ../lib
+       -cp libsecurec.a ../lib
+       @echo "finish libsecurec.a"
+       #you may add you custom commands here
+.c.o:
+       @mkdir -p ../obj
+       $(CC) -c $< $(CFLAG) -o ../obj/$(patsubst %.c,%.o,$<)
+
+EXTRA_CFLAGS += -I$(INCDIR) -fstack-protector $(CFLAG_EXT)
+
+# provide the default value to module name and ccflags-y
+ifeq ($(MODULE),)
+       MODULE := ksecurec
+endif
+ifeq ($(DEBUG),y)
+       ccflags-y += -DDEBUG
+endif
+
+ifneq ($(KERNELRELEASE),)
+    obj-m := ksecurec.o
+ifeq ($(SECUREC_KERNEL_ALL),)
+    #ksecurec-objs := memcpy_s.o memmove_s.o memset_s.o  securecutil.o  strcat_s.o strcpy_s.o strncat_s.o strncpy_s.o
+    ksecurec-objs := memcpy_s.o memmove_s.o memset_s.o  securecutil.o  strcat_s.o strcpy_s.o strncat_s.o strncpy_s.o sprintf_s.o vsprintf_s.o snprintf_s.o vsnprintf_s.o secureprintoutput_a.o sscanf_s.o vsscanf_s.o secureinput_a.o strtok_s.o
+else
+    ksecurec-objs := memcpy_s.o memmove_s.o memset_s.o  securecutil.o  strcat_s.o strcpy_s.o strncat_s.o strncpy_s.o sprintf_s.o vsprintf_s.o snprintf_s.o vsnprintf_s.o secureprintoutput_a.o sscanf_s.o vsscanf_s.o secureinput_a.o strtok_s.o
+endif
+else
+    KERNELDIR := /lib/modules/$(shell uname -r)/build
+    PWD := $(shell pwd)
+kernel: note_msg
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) INCDIR=$(PWD)/../include modules
+endif
+
+NOTE_MSG:='\n'
+NOTE_MSG+='---------------------------------------------------------\n'
+NOTE_MSG+='+ This Makefile is a sample file, do not use in product +\n'
+NOTE_MSG+='---------------------------------------------------------\n'
+
+note_msg:
+       -@echo  -e $(NOTE_MSG)
+
+clean:
+       @echo "cleaning ...."
+       -rm modules.order Module.symvers  $(MODULE).ko $(MODULE).mod.c  $(MODULE).mod.o $(MODULE).o *.o
+       -rm -rf ../obj ../lib
+       @echo "clean up"
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fscanf_s.c
new file mode 100644 (file)
index 0000000..d3c7f06
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: fscanf_s function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The fscanf_s function is equivalent to fscanf except that the c, s,
+ *    and [ conversion specifiers apply to a pair of arguments (unless assignment suppression is indicated by a*)
+ *    The fscanf function reads data from the current position of stream into
+ *    the locations given by argument (if any). Each argument must be a pointer
+ *    to a variable of a type that corresponds to a type specifier in format.
+ *    format controls the interpretation of the input fields and has the same
+ *    form and function as the format argument for scanf.
+ *
+ * <INPUT PARAMETERS>
+ *    stream              Pointer to FILE structure.
+ *    format              Format control string, see Format Specifications.
+ *    ...                 Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                 The converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int fscanf_s(FILE *stream, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vfscanf_s(stream, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fwscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fwscanf_s.c
new file mode 100644 (file)
index 0000000..bd0f12a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: fwscanf_s function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The fwscanf_s function  is  the  wide-character  equivalent  of the fscanf_s function
+ *    The fwscanf_s function reads data from the current position of stream into
+ *    the locations given by argument (if any). Each argument must be a pointer
+ *    to a variable of a type that corresponds to a type specifier in format.
+ *    format controls the interpretation of the input fields and has the same
+ *    form and function as the format argument for scanf.
+ *
+ * <INPUT PARAMETERS>
+ *    stream                   Pointer to FILE structure.
+ *    format                   Format control string, see Format Specifications.
+ *    ...                      Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                      The converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int fwscanf_s(FILE *stream, const wchar_t *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vfwscanf_s(stream, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/gets_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/gets_s.c
new file mode 100644 (file)
index 0000000..d12495a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: gets_s function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+/*
+ * The parameter size is buffer size in byte
+ */
+SECUREC_INLINE void SecTrimCRLF(char *buffer, size_t size)
+{
+    size_t len = strlen(buffer);
+    --len; /* Unsigned integer wrapping is accepted and is checked afterwards */
+    while (len < size && (buffer[len] == '\r' || buffer[len] == '\n')) {
+        buffer[len] = '\0';
+        --len; /* Unsigned integer wrapping is accepted and is checked next loop */
+    }
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The gets_s function reads at most one less than the number of characters
+ *    specified by destMax from the std input stream, into the array pointed to by buffer
+ *    The line consists of all characters up to and including
+ *    the first newline character ('\n'). gets_s then replaces the newline
+ *    character with a null character ('\0') before returning the line.
+ *    If the first character read is the end-of-file character, a null character
+ *    is stored at the beginning of buffer and NULL is returned.
+ *
+ * <INPUT PARAMETERS>
+ *    buffer                         Storage location for input string.
+ *    destMax                        The size of the buffer.
+ *
+ * <OUTPUT PARAMETERS>
+ *    buffer                         is updated
+ *
+ * <RETURN VALUE>
+ *    buffer                         Successful operation
+ *    NULL                           Improper parameter or read fail
+ */
+char *gets_s(char *buffer, size_t destMax)
+{
+#ifdef SECUREC_COMPATIBLE_WIN_FORMAT
+    size_t bufferSize = ((destMax == (size_t)(-1)) ? SECUREC_STRING_MAX_LEN : destMax);
+#else
+    size_t bufferSize = destMax;
+#endif
+
+    if (buffer == NULL || bufferSize == 0 || bufferSize > SECUREC_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_PARAMTER("gets_s");
+        return NULL;
+    }
+
+    if (fgets(buffer, (int)bufferSize, SECUREC_STREAM_STDIN) != NULL) {
+        SecTrimCRLF(buffer, bufferSize);
+        return buffer;
+    }
+
+    return NULL;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/input.inl b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/input.inl
new file mode 100644 (file)
index 0000000..9727d5e
--- /dev/null
@@ -0,0 +1,2229 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Used by secureinput_a.c and secureinput_w.c to include.
+ *              This file provides a template function for ANSI and UNICODE compiling by
+ *              different type definition. The functions of SecInputS or
+ *              SecInputSW provides internal implementation for scanf family API, such as sscanf_s, fscanf_s.
+ * Create: 2014-02-25
+ * Notes: The formatted input processing results of integers on different platforms are different.
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Performance-sensitive
+ * [reason] Always used in the performance critical path,
+ *          and sufficient input validation is performed before calling
+ */
+#ifndef INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27
+#define INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27
+
+#if SECUREC_IN_KERNEL
+#if !defined(SECUREC_CTYPE_MACRO_ADAPT)
+#include <linux/ctype.h>
+#endif
+#else
+#if !defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT)
+#include <ctype.h>
+#ifdef SECUREC_FOR_WCHAR
+#include <wctype.h>             /* For iswspace */
+#endif
+#endif
+#endif
+
+#ifndef EOF
+#define EOF  (-1)
+#endif
+
+#define SECUREC_NUM_WIDTH_SHORT                 0
+#define SECUREC_NUM_WIDTH_INT                   1
+#define SECUREC_NUM_WIDTH_LONG                  2
+#define SECUREC_NUM_WIDTH_LONG_LONG             3 /* Also long double */
+
+#define SECUREC_BUFFERED_BLOK_SIZE              1024U
+
+#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(va_copy) && !defined(__va_copy)
+/* The name is the same as system macro. */
+#define __va_copy(dest, src) do { \
+    size_t destSize_ = (size_t)sizeof(dest); \
+    size_t srcSize_ = (size_t)sizeof(src); \
+    if (destSize_ != srcSize_) { \
+        SECUREC_MEMCPY_WARP_OPT((dest), (src), sizeof(va_list)); \
+    } else { \
+        SECUREC_MEMCPY_WARP_OPT(&(dest), &(src), sizeof(va_list)); \
+    } \
+} SECUREC_WHILE_ZERO
+#endif
+
+#define SECUREC_MULTI_BYTE_MAX_LEN              6
+
+/* Compatibility macro name cannot be modifie */
+#ifndef UNALIGNED
+#if !(defined(_M_IA64)) && !(defined(_M_AMD64))
+#define UNALIGNED
+#else
+#define UNALIGNED __unaligned
+#endif
+#endif
+
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+/* Max 64bit value is 0xffffffffffffffff */
+#define SECUREC_MAX_64BITS_VALUE                18446744073709551615ULL
+#define SECUREC_MAX_64BITS_VALUE_DIV_TEN        1844674407370955161ULL
+#define SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT 18446744073709551610ULL
+#define SECUREC_MIN_64BITS_NEG_VALUE            9223372036854775808ULL
+#define SECUREC_MAX_64BITS_POS_VALUE            9223372036854775807ULL
+#define SECUREC_MIN_32BITS_NEG_VALUE            2147483648UL
+#define SECUREC_MAX_32BITS_POS_VALUE            2147483647UL
+#define SECUREC_MAX_32BITS_VALUE                4294967295UL
+#define SECUREC_MAX_32BITS_VALUE_INC            4294967296UL
+#define SECUREC_MAX_32BITS_VALUE_DIV_TEN        429496729UL
+#define SECUREC_LONG_BIT_NUM                    ((unsigned int)(sizeof(long) << 3U))
+/* Use ULL to clean up cl6x compilation alerts */
+#define SECUREC_MAX_LONG_POS_VALUE              ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1)) - 1)
+#define SECUREC_MIN_LONG_NEG_VALUE              ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1)))
+
+/* Covert to long long to clean up cl6x compilation alerts */
+#define SECUREC_LONG_HEX_BEYOND_MAX(number)     (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 4U)) > 0)
+#define SECUREC_LONG_OCTAL_BEYOND_MAX(number)   (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 3U)) > 0)
+
+#define SECUREC_QWORD_HEX_BEYOND_MAX(number)    (((number) >> (64U - 4U)) > 0)
+#define SECUREC_QWORD_OCTAL_BEYOND_MAX(number)  (((number) >> (64U - 3U)) > 0)
+
+#define SECUREC_LP64_BIT_WIDTH                  64
+#define SECUREC_LP32_BIT_WIDTH                  32
+
+#define SECUREC_CONVERT_IS_SIGNED(conv) ((conv) == 'd' || (conv) == 'i')
+#endif
+
+#define SECUREC_BRACE                           '{'     /* [ to { */
+#define SECUREC_FILED_WIDTH_ENOUGH(spec) ((spec)->widthSet == 0 || (spec)->width > 0)
+#define SECUREC_FILED_WIDTH_DEC(spec) do { \
+    if ((spec)->widthSet != 0) { \
+        --(spec)->width; \
+    } \
+} SECUREC_WHILE_ZERO
+
+#ifdef SECUREC_FOR_WCHAR
+/* Bits for all wchar, size is 65536/8, only supports wide characters with a maximum length of two bytes */
+#define SECUREC_BRACKET_TABLE_SIZE    8192
+#define SECUREC_EOF WEOF
+#define SECUREC_MB_LEN 16       /* Max. # bytes in multibyte char  ,see MB_LEN_MAX */
+#else
+/* Bits for all char, size is 256/8 */
+#define SECUREC_BRACKET_TABLE_SIZE    32
+#define SECUREC_EOF EOF
+#endif
+
+#if SECUREC_HAVE_WCHART
+#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || \
+    ((spec).isWCharOrLong <= 0 && (spec).arrayWidth > SECUREC_STRING_MAX_LEN) || \
+    ((spec).isWCharOrLong > 0 && (spec).arrayWidth > SECUREC_WCHAR_STRING_MAX_LEN))
+#else
+#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || (spec).arrayWidth > SECUREC_STRING_MAX_LEN)
+#endif
+
+#ifdef SECUREC_ON_64BITS
+/* Use 0xffffffffUL mask to pass integer as array length */
+#define SECUREC_GET_ARRAYWIDTH(argList) (((size_t)va_arg((argList), size_t)) & 0xffffffffUL)
+#else /* !SECUREC_ON_64BITS */
+#define SECUREC_GET_ARRAYWIDTH(argList) ((size_t)va_arg((argList), size_t))
+#endif
+
+typedef struct {
+#ifdef SECUREC_FOR_WCHAR
+    unsigned char *table; /* Default NULL */
+#else
+    unsigned char table[SECUREC_BRACKET_TABLE_SIZE]; /* Array length is large enough in application scenarios */
+#endif
+    unsigned char mask; /* Default 0 */
+} SecBracketTable;
+
+#ifdef SECUREC_FOR_WCHAR
+#define SECUREC_INIT_BRACKET_TABLE { NULL, 0 }
+#else
+#define SECUREC_INIT_BRACKET_TABLE { {0}, 0 }
+#endif
+
+#if SECUREC_ENABLE_SCANF_FLOAT
+typedef struct {
+    size_t floatStrTotalLen;       /* Initialization must be length of buffer in charater */
+    size_t floatStrUsedLen;        /* Store float string len */
+    SecChar *floatStr;             /* Initialization must point to buffer */
+    SecChar *allocatedFloatStr;    /* Initialization must be NULL  to store alloced point */
+    SecChar buffer[SECUREC_FLOAT_BUFSIZE + 1];
+} SecFloatSpec;
+#endif
+
+#define SECUREC_NUMBER_STATE_DEFAULT 0U
+#define SECUREC_NUMBER_STATE_STARTED 1U
+
+typedef struct {
+    SecInt ch;            /* Char read from input */
+    int charCount;        /* Number of characters processed */
+    void *argPtr;         /* Variable parameter pointer, point to the end of the string */
+    size_t arrayWidth;    /* Length of pointer Variable parameter, in charaters */
+    SecUnsignedInt64 number64; /* Store input number64 value */
+    unsigned long number; /* Store input number32 value */
+    int numberWidth;      /* 0 = SHORT, 1 = int, > 1  long or L_DOUBLE */
+    int numberArgType;       /* 1 for 64-bit integer, 0 otherwise. use it as decode function index */
+    unsigned int negative;         /* 0 is positive */
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    unsigned int beyondMax;        /* Non-zero means beyond */
+#endif
+    unsigned int numberState; /* Identifies whether to start processing numbers, 1 is can input number */
+    int width;            /* Width number in format */
+    int widthSet;         /* 0 is not set width in format */
+    int convChr;          /* Lowercase format conversion characters */
+    int oriConvChr;       /* Store  original format conversion, convChr may change when parsing integers */
+    signed char isWCharOrLong;  /* -1/0 not wchar or long, 1 for wchar or long */
+    unsigned char suppress;     /* 0 is not have %* in format */
+} SecScanSpec;
+
+#ifdef SECUREC_FOR_WCHAR
+#define SECUREC_GETC fgetwc
+#define SECUREC_UN_GETC ungetwc
+/* Only supports wide characters with a maximum length of two bytes in format string */
+#define SECUREC_BRACKET_CHAR_MASK 0xffffU
+#else
+#define SECUREC_GETC fgetc
+#define SECUREC_UN_GETC ungetc
+#define SECUREC_BRACKET_CHAR_MASK 0xffU
+#endif
+
+#define SECUREC_CHAR_SIZE ((unsigned int)(sizeof(SecChar)))
+/* To avoid 648, mask high bit: 0x00ffffff 0x0000ffff or 0x00000000 */
+#define SECUREC_CHAR_MASK_HIGH (((((((((unsigned int)(-1) >> SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \
+    SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \
+    SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \
+    SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE)
+
+/* For char is 0xff, wcahr_t is 0xffff or 0xffffffff. */
+#define SECUREC_CHAR_MASK (~((((((((((unsigned int)(-1) & SECUREC_CHAR_MASK_HIGH) << \
+    SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \
+    SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \
+    SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \
+    SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE))
+
+/* According wchar_t has multiple bytes, so use sizeof */
+#define SECUREC_GET_CHAR(stream, outCh) do { \
+    if ((stream)->count >= sizeof(SecChar)) { \
+        *(outCh) = (SecInt)(SECUREC_CHAR_MASK & \
+            (unsigned int)(int)(*((const SecChar *)(const void *)(stream)->cur))); \
+        (stream)->cur += sizeof(SecChar); \
+        (stream)->count -= sizeof(SecChar); \
+    } else { \
+        *(outCh) = SECUREC_EOF; \
+    } \
+} SECUREC_WHILE_ZERO
+
+#define SECUREC_UN_GET_CHAR(stream) do { \
+    if ((stream)->cur > (stream)->base) { \
+        (stream)->cur -= sizeof(SecChar); \
+        (stream)->count += sizeof(SecChar); \
+    } \
+} SECUREC_WHILE_ZERO
+
+/* Convert wchar_t to int and then to unsigned int  to keep data clearing warning */
+#define SECUREC_TO_LOWERCASE(chr) ((int)((unsigned int)(int)(chr) | (unsigned int)('a' - 'A')))
+
+/* Record a flag for each bit */
+#define SECUREC_BRACKET_INDEX(x)  ((unsigned int)(x) >> 3U)
+#define SECUREC_BRACKET_VALUE(x)  ((unsigned char)(1U << ((unsigned int)(x) & 7U)))
+#if SECUREC_IN_KERNEL
+#define SECUREC_CONVERT_IS_UNSIGNED(conv) ((conv) == 'x' || (conv) == 'o' || (conv) == 'u')
+#endif
+
+/*
+ * Set char in %[xxx] into table, only supports wide characters with a maximum length of two bytes
+ */
+SECUREC_INLINE void SecBracketSetBit(unsigned char *table, SecUnsignedChar ch)
+{
+    unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK));
+    unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK));
+    /* Do not use   |=   optimize this code, it will cause compiling warning */
+    table[tableIndex] = (unsigned char)(table[tableIndex] | tableValue);
+}
+
+SECUREC_INLINE void SecBracketSetBitRange(unsigned char *table, SecUnsignedChar startCh, SecUnsignedChar endCh)
+{
+    SecUnsignedChar expCh;
+    /* %[a-z] %[a-a] Format %[a-\xff] end is 0xFF, condition (expCh <= endChar) cause dead loop */
+    for (expCh = startCh; expCh < endCh; ++expCh) {
+        SecBracketSetBit(table, expCh);
+    }
+    SecBracketSetBit(table, endCh);
+}
+/*
+ * Determine whether the expression can be satisfied
+ */
+SECUREC_INLINE int SecCanInputForBracket(int convChr, SecInt ch, const SecBracketTable *bracketTable)
+{
+    unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK));
+    unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK));
+#ifdef SECUREC_FOR_WCHAR
+    if (((unsigned int)(int)ch & (~(SECUREC_BRACKET_CHAR_MASK))) != 0) {
+        /* The value of the wide character exceeds the size of two bytes */
+        return 0;
+    }
+    return (int)(convChr == SECUREC_BRACE &&
+        (((unsigned int)bracketTable->table[tableIndex] ^ (unsigned int)bracketTable->mask) & tableValue) != 0);
+#else
+    return (int)(convChr == SECUREC_BRACE &&
+        (((unsigned int)bracketTable->table[tableIndex] ^ (unsigned int)bracketTable->mask) & tableValue) != 0);
+#endif
+}
+
+/*
+ * String input ends when blank character is encountered
+ */
+SECUREC_INLINE int SecCanInputString(int convChr, SecInt ch)
+{
+    return (int)(convChr == 's' &&
+        (!(ch >= SECUREC_CHAR('\t') && ch <= SECUREC_CHAR('\r')) && ch != SECUREC_CHAR(' ')));
+}
+
+/*
+ * Can input a character when format is %c
+ */
+SECUREC_INLINE int SecCanInputCharacter(int convChr)
+{
+    return (int)(convChr == 'c');
+}
+
+/*
+ * Determine if it is a 64-bit pointer  function
+ * Return 0 is not ,1 is 64bit pointer
+ */
+SECUREC_INLINE int SecNumberArgType(size_t sizeOfVoidStar)
+{
+    /* Point size is 4 or 8 , Under the 64 bit system, the value not 0 */
+    /* To clear e778 */
+    if ((sizeOfVoidStar & sizeof(SecInt64)) != 0) {
+        return 1;
+    }
+    return 0;
+}
+SECUREC_INLINE int SecIsDigit(SecInt ch);
+SECUREC_INLINE int SecIsXdigit(SecInt ch);
+SECUREC_INLINE int SecIsSpace(SecInt ch);
+SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter);
+SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter);
+SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter);
+
+#if SECUREC_ENABLE_SCANF_FLOAT
+
+/*
+ * Convert a floating point string to a floating point number
+ */
+SECUREC_INLINE int SecAssignNarrowFloat(const char *floatStr, const SecScanSpec *spec)
+{
+    char *endPtr = NULL;
+    double d;
+#if SECUREC_SUPPORT_STRTOLD
+    if (spec->numberWidth == SECUREC_NUM_WIDTH_LONG_LONG) {
+        long double d2 = strtold(floatStr, &endPtr);
+        if (endPtr == floatStr) {
+            return -1;
+        }
+        *(long double UNALIGNED *)(spec->argPtr) = d2;
+        return 0;
+    }
+#endif
+    d = strtod(floatStr, &endPtr);
+    /* cannot detect if endPtr points to the end of floatStr,because strtod handles only two characters for 1.E */
+    if (endPtr == floatStr) {
+        return -1;
+    }
+    if (spec->numberWidth > SECUREC_NUM_WIDTH_INT) {
+        *(double UNALIGNED *)(spec->argPtr) = (double)d;
+    } else {
+        *(float UNALIGNED *)(spec->argPtr) = (float)d;
+    }
+    return 0;
+}
+
+#ifdef SECUREC_FOR_WCHAR
+/*
+ * Convert a floating point wchar string to a floating point number
+ * Success  ret 0
+ */
+SECUREC_INLINE int SecAssignWideFloat(const SecFloatSpec *floatSpec, const SecScanSpec *spec)
+{
+    int retVal;
+    /* Convert float string */
+    size_t mbsLen;
+    size_t tempFloatStrLen = (size_t)(floatSpec->floatStrUsedLen + 1) * sizeof(wchar_t);
+    char *tempFloatStr = (char *)SECUREC_MALLOC(tempFloatStrLen);
+    if (tempFloatStr == NULL) {
+        return -1;
+    }
+    tempFloatStr[0] = '\0';
+    SECUREC_MASK_MSVC_CRT_WARNING
+    mbsLen = wcstombs(tempFloatStr, floatSpec->floatStr, tempFloatStrLen - 1);
+    SECUREC_END_MASK_MSVC_CRT_WARNING
+    /* This condition must satisfy mbsLen is not -1 */
+    if (mbsLen >= tempFloatStrLen) {
+        SECUREC_FREE(tempFloatStr);
+        return -1;
+    }
+    tempFloatStr[mbsLen] = '\0';
+    retVal = SecAssignNarrowFloat(tempFloatStr, spec);
+    SECUREC_FREE(tempFloatStr);
+    return retVal;
+}
+#endif
+
+SECUREC_INLINE int SecAssignFloat(const SecFloatSpec *floatSpec, const SecScanSpec *spec)
+{
+#ifdef SECUREC_FOR_WCHAR
+    return SecAssignWideFloat(floatSpec, spec);
+#else
+    return SecAssignNarrowFloat(floatSpec->floatStr, spec);
+#endif
+}
+
+/*
+ * Init SecFloatSpec before parse format
+ */
+SECUREC_INLINE void SecInitFloatSpec(SecFloatSpec *floatSpec)
+{
+    floatSpec->floatStr = floatSpec->buffer;
+    floatSpec->allocatedFloatStr = NULL;
+    floatSpec->floatStrTotalLen = sizeof(floatSpec->buffer) / sizeof(floatSpec->buffer[0]);
+    floatSpec->floatStrUsedLen = 0;
+}
+
+SECUREC_INLINE void SecFreeFloatSpec(SecFloatSpec *floatSpec, int *doneCount)
+{
+    /* 2014.3.6 add, clear the stack data */
+    if (memset_s(floatSpec->buffer, sizeof(floatSpec->buffer), 0, sizeof(floatSpec->buffer)) != EOK) {
+        *doneCount = 0; /* This code just to meet the coding requirements */
+    }
+    /* The pFloatStr can be alloced in SecExtendFloatLen function, clear and free it */
+    if (floatSpec->allocatedFloatStr != NULL) {
+        size_t bufferSize = floatSpec->floatStrTotalLen * sizeof(SecChar);
+        if (memset_s(floatSpec->allocatedFloatStr, bufferSize, 0, bufferSize) != EOK) {
+            *doneCount = 0; /* This code just to meet the coding requirements */
+        }
+        SECUREC_FREE(floatSpec->allocatedFloatStr);
+        floatSpec->allocatedFloatStr = NULL;
+        floatSpec->floatStr = NULL;
+    }
+}
+
+/*
+ * Splice floating point string
+ * Return 0 OK
+ */
+SECUREC_INLINE int SecExtendFloatLen(SecFloatSpec *floatSpec)
+{
+    if (floatSpec->floatStrUsedLen >= floatSpec->floatStrTotalLen) {
+        /* Buffer size is len x sizeof(SecChar) */
+        size_t oriSize = floatSpec->floatStrTotalLen * sizeof(SecChar);
+        /* Add one character to clear tool warning */
+        size_t nextSize = (oriSize * 2) + sizeof(SecChar); /* Multiply 2 to extend buffer size */
+
+        /* Prevents integer overflow, the maximum length of SECUREC_MAX_WIDTH_LEN is enough */
+        if (nextSize <= (size_t)SECUREC_MAX_WIDTH_LEN) {
+            void *nextBuffer = (void *)SECUREC_MALLOC(nextSize);
+            if (nextBuffer == NULL) {
+                return -1;
+            }
+            if (memcpy_s(nextBuffer, nextSize, floatSpec->floatStr, oriSize) != EOK) {
+                SECUREC_FREE(nextBuffer);   /* This is a dead code, just to meet the coding requirements */
+                return -1;
+            }
+            /* Clear old buffer memory */
+            if (memset_s(floatSpec->floatStr, oriSize, 0, oriSize) != EOK) {
+                SECUREC_FREE(nextBuffer);   /* This is a dead code, just to meet the coding requirements */
+                return -1;
+            }
+            /* Free old allocated buffer */
+            if (floatSpec->allocatedFloatStr != NULL) {
+                SECUREC_FREE(floatSpec->allocatedFloatStr);
+            }
+            floatSpec->allocatedFloatStr = (SecChar *)(nextBuffer);    /* Use to clear free on stack warning */
+            floatSpec->floatStr = (SecChar *)(nextBuffer);
+            floatSpec->floatStrTotalLen = nextSize / sizeof(SecChar); /* Get buffer total len in character */
+            return 0;
+        }
+        return -1; /* Next size is beyond max */
+    }
+    return 0;
+}
+
+/* Do not use localeconv()->decimal_pointif  onlay support  '.' */
+SECUREC_INLINE int SecIsFloatDecimal(SecChar ch)
+{
+    return (int)(ch == SECUREC_CHAR('.'));
+}
+
+SECUREC_INLINE int SecInputFloatSign(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    if (!SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        return 0;
+    }
+    spec->ch = SecGetChar(stream, &(spec->charCount));
+    if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) {
+        SECUREC_FILED_WIDTH_DEC(spec); /* Make sure the count after un get char is correct */
+        if (spec->ch == SECUREC_CHAR('-')) {
+            floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('-');
+            ++floatSpec->floatStrUsedLen;
+            if (SecExtendFloatLen(floatSpec) != 0) {
+                return -1;
+            }
+        }
+    } else {
+        SecUnGetChar(spec->ch, stream, &(spec->charCount));
+    }
+    return 0;
+}
+
+SECUREC_INLINE int SecInputFloatDigit(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    /* Now get integral part */
+    while (SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        if (SecIsDigit(spec->ch) == 0) {
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            return 0;
+        }
+        SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */
+        spec->numberState = SECUREC_NUMBER_STATE_STARTED;
+        floatSpec->floatStr[floatSpec->floatStrUsedLen] = (SecChar)spec->ch;
+        ++floatSpec->floatStrUsedLen;
+        if (SecExtendFloatLen(floatSpec) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+* Scan value of exponent.
+* Return 0 OK
+*/
+SECUREC_INLINE int SecInputFloatE(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    if (SecInputFloatSign(stream, spec, floatSpec) == -1) {
+        return -1;
+    }
+    if (SecInputFloatDigit(stream, spec, floatSpec) != 0) {
+        return -1;
+    }
+    return 0;
+}
+
+SECUREC_INLINE int SecInputFloatFractional(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    if (SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        if (SecIsFloatDecimal((SecChar)spec->ch) == 0) {
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            return 0;
+        }
+        SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */
+        /* Now check for decimal */
+        floatSpec->floatStr[floatSpec->floatStrUsedLen] = (SecChar)spec->ch;
+        ++floatSpec->floatStrUsedLen;
+        if (SecExtendFloatLen(floatSpec) != 0) {
+            return -1;
+        }
+        if (SecInputFloatDigit(stream, spec, floatSpec) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+SECUREC_INLINE int SecInputFloatExponent(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    /* Now get exponent part */
+    if (spec->numberState == SECUREC_NUMBER_STATE_STARTED && SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        if (spec->ch != SECUREC_CHAR('e') && spec->ch != SECUREC_CHAR('E')) {
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            return 0;
+        }
+        SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */
+        floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('e');
+        ++floatSpec->floatStrUsedLen;
+        if (SecExtendFloatLen(floatSpec) != 0) {
+            return -1;
+        }
+        if (SecInputFloatE(stream, spec, floatSpec) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+* Scan %f.
+* Return 0 OK
+*/
+SECUREC_INLINE int SecInputFloat(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec)
+{
+    floatSpec->floatStrUsedLen = 0;
+
+    /* The following code sequence is strict */
+    if (SecInputFloatSign(stream, spec, floatSpec) != 0) {
+        return -1;
+    }
+    if (SecInputFloatDigit(stream, spec, floatSpec) != 0) {
+        return -1;
+    }
+    if (SecInputFloatFractional(stream, spec, floatSpec) != 0) {
+        return -1;
+    }
+    if (SecInputFloatExponent(stream, spec, floatSpec) != 0) {
+        return -1;
+    }
+
+    /* Make sure  have a string terminator, buffer is large enough */
+    floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('\0');
+    if (spec->numberState == SECUREC_NUMBER_STATE_STARTED) {
+        return 0;
+    }
+    return -1;
+}
+#endif
+
+#if (!defined(SECUREC_FOR_WCHAR) && SECUREC_HAVE_WCHART && SECUREC_HAVE_MBTOWC) || \
+    (!defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION))
+/* only multi-bytes string need isleadbyte() function */
+SECUREC_INLINE int SecIsLeadByte(SecInt ch)
+{
+    unsigned int c = (unsigned int)ch;
+#if !(defined(_MSC_VER) || defined(_INC_WCTYPE))
+    return (int)(c & 0x80U); /* Use bitwise operation to check if the most significant bit is 1 */
+#else
+    return (int)isleadbyte((int)(c & 0xffU)); /* Use bitwise operations to limit character values to valid ranges */
+#endif
+}
+#endif
+
+/*
+ * Parsing whether it is a wide character
+ */
+SECUREC_INLINE void SecUpdateWcharFlagByType(SecUnsignedChar ch, SecScanSpec *spec)
+{
+    if (spec->isWCharOrLong != 0) {
+        /* Wide character identifiers have been explicitly set by l or h flag */
+        return;
+    }
+
+    /* Set default flag */
+#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+    spec->isWCharOrLong = 1;  /* On windows wide char version %c %s %[ is wide char */
+#else
+    spec->isWCharOrLong = -1; /* On linux all version %c %s %[ is multi char */
+#endif
+
+    if (ch == SECUREC_CHAR('C') || ch == SECUREC_CHAR('S')) {
+#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+        spec->isWCharOrLong = -1; /* On windows wide char version %C %S is multi char */
+#else
+        spec->isWCharOrLong = 1;  /* On linux all version %C %S is wide char */
+#endif
+    }
+
+    return;
+}
+/*
+ * Decode  %l %ll
+ */
+SECUREC_INLINE void SecDecodeScanQualifierL(const SecUnsignedChar **format, SecScanSpec *spec)
+{
+    const SecUnsignedChar *fmt = *format;
+    if (*(fmt + 1) == SECUREC_CHAR('l')) {
+        spec->numberArgType = 1;
+        spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG;
+        ++fmt;
+    } else {
+        spec->numberWidth = SECUREC_NUM_WIDTH_LONG;
+#if defined(SECUREC_ON_64BITS) && !(defined(SECUREC_COMPATIBLE_WIN_FORMAT))
+        /* On window 64 system sizeof long is 32bit */
+        spec->numberArgType = 1;
+#endif
+        spec->isWCharOrLong = 1;
+    }
+    *format = fmt;
+}
+
+/*
+ * Decode  %I %I43 %I64 %Id %Ii %Io ...
+ * Set finishFlag to  1  finish Flag
+ */
+SECUREC_INLINE void SecDecodeScanQualifierI(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag)
+{
+    const SecUnsignedChar *fmt = *format;
+    if ((*(fmt + 1) == SECUREC_CHAR('6')) &&
+        (*(fmt + 2) == SECUREC_CHAR('4'))) { /* Offset 2 for I64 */
+        spec->numberArgType = 1;
+        *format = *format + 2; /* Add 2 to skip I64 point to '4' next loop will inc */
+    } else if ((*(fmt + 1) == SECUREC_CHAR('3')) &&
+                (*(fmt + 2) == SECUREC_CHAR('2'))) { /* Offset 2 for I32 */
+        *format = *format + 2; /* Add 2 to skip I32 point to '2' next loop will inc */
+    } else if ((*(fmt + 1) == SECUREC_CHAR('d')) ||
+                (*(fmt + 1) == SECUREC_CHAR('i')) ||
+                (*(fmt + 1) == SECUREC_CHAR('o')) ||
+                (*(fmt + 1) == SECUREC_CHAR('x')) ||
+                (*(fmt + 1) == SECUREC_CHAR('X'))) {
+        spec->numberArgType = SecNumberArgType(sizeof(void *));
+    } else {
+        /* For %I */
+        spec->numberArgType = SecNumberArgType(sizeof(void *));
+        *finishFlag = 1;
+    }
+}
+
+SECUREC_INLINE int SecDecodeScanWidth(const SecUnsignedChar **format, SecScanSpec *spec)
+{
+    const SecUnsignedChar *fmt = *format;
+    while (SecIsDigit((SecInt)(int)(*fmt)) != 0) {
+        spec->widthSet = 1;
+        if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(spec->width)) {
+            return -1;
+        }
+        spec->width = (int)SECUREC_MUL_TEN((unsigned int)spec->width) + (unsigned char)(*fmt - SECUREC_CHAR('0'));
+        ++fmt;
+    }
+    *format = fmt;
+    return 0;
+}
+
+/*
+ * Init default flags for each format. do not init ch this variable is context-dependent
+ */
+SECUREC_INLINE void SecSetDefaultScanSpec(SecScanSpec *spec)
+{
+    /* The ch and charCount member variables cannot be initialized here */
+    spec->argPtr = NULL;
+    spec->arrayWidth = 0;
+    spec->number64 = 0;
+    spec->number = 0;
+    spec->numberWidth = SECUREC_NUM_WIDTH_INT;    /* 0 = SHORT, 1 = int, > 1  long or L_DOUBLE */
+    spec->numberArgType = 0;                         /* 1 for 64-bit integer, 0 otherwise */
+    spec->width = 0;
+    spec->widthSet = 0;
+    spec->convChr = 0;
+    spec->oriConvChr = 0;
+    spec->isWCharOrLong = 0;
+    spec->suppress = 0;
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    spec->beyondMax = 0;
+#endif
+    spec->negative = 0;
+    spec->numberState = SECUREC_NUMBER_STATE_DEFAULT;
+}
+
+/*
+ * Decode qualifier %I %L %h ...
+ * Set finishFlag to  1  finish Flag
+ */
+SECUREC_INLINE void  SecDecodeScanQualifier(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag)
+{
+    switch (**format) {
+        case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('N'):
+            break;
+        case SECUREC_CHAR('h'):
+            --spec->numberWidth; /* The h for SHORT , hh for CHAR */
+            spec->isWCharOrLong = -1;
+            break;
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+        case SECUREC_CHAR('j'):
+            spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG;  /* For intmax_t or uintmax_t */
+            spec->numberArgType = 1;
+            break;
+        case SECUREC_CHAR('t'): /* fall-through */ /* FALLTHRU */
+#endif
+#if SECUREC_IN_KERNEL
+        case SECUREC_CHAR('Z'): /* fall-through */ /* FALLTHRU */
+#endif
+        case SECUREC_CHAR('z'):
+#ifdef SECUREC_ON_64BITS
+            spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG;
+            spec->numberArgType = 1;
+#else
+            spec->numberWidth = SECUREC_NUM_WIDTH_LONG;
+#endif
+            break;
+        case SECUREC_CHAR('L'):    /* For long double */ /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('q'):
+            spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG;
+            spec->numberArgType = 1;
+            break;
+        case SECUREC_CHAR('l'):
+            SecDecodeScanQualifierL(format, spec);
+            break;
+        case SECUREC_CHAR('w'):
+            spec->isWCharOrLong = 1;
+            break;
+        case SECUREC_CHAR('*'):
+            spec->suppress = 1;
+            break;
+        case SECUREC_CHAR('I'):
+            SecDecodeScanQualifierI(format, spec, finishFlag);
+            break;
+        default:
+            *finishFlag = 1;
+            break;
+    }
+}
+/*
+ * Decode width and qualifier in format
+ */
+SECUREC_INLINE int SecDecodeScanFlag(const SecUnsignedChar **format, SecScanSpec *spec)
+{
+    const SecUnsignedChar *fmt = *format;
+    int finishFlag = 0;
+
+    do {
+        ++fmt; /*  First skip % , next  seek fmt */
+        /* May %*6d , so put it inside the loop */
+        if (SecDecodeScanWidth(&fmt, spec) != 0) {
+            return -1;
+        }
+        SecDecodeScanQualifier(&fmt, spec, &finishFlag);
+    } while (finishFlag == 0);
+    *format = fmt;
+    return 0;
+}
+
+/*
+ * Judging whether a zeroing buffer is needed according to different formats
+ */
+SECUREC_INLINE int SecDecodeClearFormat(const SecUnsignedChar *format, int *convChr)
+{
+    const SecUnsignedChar *fmt = format;
+    /* To lowercase */
+    int ch = SECUREC_TO_LOWERCASE(*fmt);
+    if (!(ch == 'c' || ch == 's' || ch == SECUREC_BRACE)) {
+        return -1;     /* First argument is not a string type */
+    }
+    if (ch == SECUREC_BRACE) {
+#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT))
+        if (*fmt == SECUREC_CHAR('{')) {
+            return -1;
+        }
+#endif
+        ++fmt;
+        if (*fmt == SECUREC_CHAR('^')) {
+            ++fmt;
+        }
+        if (*fmt == SECUREC_CHAR(']')) {
+            ++fmt;
+        }
+        while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) {
+            ++fmt;
+        }
+        if (*fmt == SECUREC_CHAR('\0')) {
+            return -1; /* Trunc'd format string */
+        }
+    }
+    *convChr = ch;
+    return 0;
+}
+
+/*
+ * Add L'\0' for wchar string , add '\0' for char string
+ */
+SECUREC_INLINE void SecAddEndingZero(void *ptr, const SecScanSpec *spec)
+{
+    if (spec->suppress == 0) {
+        *(char *)ptr = '\0';
+#if SECUREC_HAVE_WCHART
+        if (spec->isWCharOrLong > 0) {
+            *(wchar_t UNALIGNED *)ptr = L'\0';
+        }
+#endif
+    }
+}
+
+SECUREC_INLINE void SecDecodeClearArg(SecScanSpec *spec, va_list argList)
+{
+    va_list argListSave; /* Backup for argList value, this variable don't need initialized */
+    (void)SECUREC_MEMSET_FUNC_OPT(&argListSave, 0, sizeof(va_list)); /* To clear e530 argListSave not initialized */
+#if defined(va_copy)
+    va_copy(argListSave, argList);
+#elif defined(__va_copy)        /* For vxworks */
+    __va_copy(argListSave, argList);
+#else
+    argListSave = argList;
+#endif
+    spec->argPtr = (void *)va_arg(argListSave, void *);
+    /* Get the next argument, size of the array in characters */
+    /* Use 0xffffffffUL mask to Support  pass integer as array length */
+    spec->arrayWidth = ((size_t)(va_arg(argListSave, size_t))) & 0xffffffffUL;
+    va_end(argListSave);
+    /* To clear e438 last value assigned not used , the compiler will optimize this code */
+    (void)argListSave;
+}
+
+#ifdef SECUREC_FOR_WCHAR
+/*
+ *  Clean up the first %s %c buffer to zero for wchar version
+ */
+void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList)
+#else
+/*
+ *  Clean up the first %s %c buffer to zero for char version
+ */
+void SecClearDestBuf(const char *buffer, const char *format, va_list argList)
+#endif
+{
+    SecScanSpec spec;
+    int convChr = 0;
+    const SecUnsignedChar *fmt = (const SecUnsignedChar *)format;
+
+    /* Find first % */
+    while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR('%')) {
+        ++fmt;
+    }
+    if (*fmt == SECUREC_CHAR('\0')) {
+        return;
+    }
+
+    SecSetDefaultScanSpec(&spec);
+    if (SecDecodeScanFlag(&fmt, &spec) != 0) {
+        return;
+    }
+
+    /* Update wchar flag for %S %C */
+    SecUpdateWcharFlagByType(*fmt, &spec);
+    if (spec.suppress != 0) {
+        return;
+    }
+
+    if (SecDecodeClearFormat(fmt, &convChr) != 0) {
+        return;
+    }
+
+    if (*buffer != SECUREC_CHAR('\0') && convChr != 's') {
+        /*
+         * When buffer not empty just clear %s.
+         * Example call sscanf by  argment of (" \n", "%s", s, sizeof(s))
+         */
+        return;
+    }
+
+    SecDecodeClearArg(&spec, argList);
+    /* There is no need to judge the upper limit */
+    if (spec.arrayWidth == 0 || spec.argPtr == NULL) {
+        return;
+    }
+    /* Clear one char */
+    SecAddEndingZero(spec.argPtr, &spec);
+    return;
+}
+
+/*
+ *  Assign number  to output buffer
+ */
+SECUREC_INLINE void SecAssignNumber(const SecScanSpec *spec)
+{
+    void *argPtr = spec->argPtr;
+    if (spec->numberArgType != 0) {
+#if defined(SECUREC_VXWORKS_PLATFORM)
+#if defined(SECUREC_VXWORKS_PLATFORM_COMP)
+        *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64);
+#else
+        /* Take number64 as unsigned number unsigned to int clear Compile warning */
+        *(SecInt64 UNALIGNED *)argPtr = *(SecUnsignedInt64 *)(&(spec->number64));
+#endif
+#else
+        /* Take number64 as unsigned number */
+        *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64);
+#endif
+        return;
+    }
+    if (spec->numberWidth > SECUREC_NUM_WIDTH_INT) {
+        /* Take number as unsigned number */
+        *(long UNALIGNED *)argPtr = (long)(spec->number);
+    } else if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) {
+        *(int UNALIGNED *)argPtr = (int)(spec->number);
+    } else if (spec->numberWidth == SECUREC_NUM_WIDTH_SHORT) {
+        /* Take number as unsigned number */
+        *(short UNALIGNED *)argPtr = (short)(spec->number);
+    } else {  /* < 0 for hh format modifier */
+        /* Take number as unsigned number */
+        *(char UNALIGNED *)argPtr = (char)(spec->number);
+    }
+}
+
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+/*
+ *  Judge the long bit width
+ */
+SECUREC_INLINE int SecIsLongBitEqual(int bitNum)
+{
+    return (int)((unsigned int)bitNum == SECUREC_LONG_BIT_NUM);
+}
+#endif
+
+/*
+ * Convert hexadecimal characters to decimal value
+ */
+SECUREC_INLINE int SecHexValueOfChar(SecInt ch)
+{
+    /* Use isdigt Causing tool false alarms */
+    return (int)((ch >= '0' && ch <= '9') ? ((unsigned char)ch - '0') :
+            ((((unsigned char)ch | (unsigned char)('a' - 'A')) - ('a')) + 10)); /* Adding 10 is to hex value */
+}
+
+/*
+ * Parse decimal character to integer for 32bit .
+ */
+static void SecDecodeNumberDecimal(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    unsigned long decimalEdge = SECUREC_MAX_32BITS_VALUE_DIV_TEN;
+#ifdef SECUREC_ON_64BITS
+    if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) {
+        decimalEdge = (unsigned long)SECUREC_MAX_64BITS_VALUE_DIV_TEN;
+    }
+#endif
+    if (spec->number > decimalEdge) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number = SECUREC_MUL_TEN(spec->number);
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (spec->number == SECUREC_MUL_TEN(decimalEdge)) {
+        /* This code is specially converted to unsigned long type for compatibility */
+        SecUnsignedInt64 number64As = (unsigned long)SECUREC_MAX_64BITS_VALUE - spec->number;
+        if (number64As < (SecUnsignedInt64)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0')) {
+            spec->beyondMax = 1;
+        }
+    }
+#endif
+    spec->number += ((unsigned long)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0'));
+}
+
+/*
+ * Parse Hex character to integer for 32bit .
+ */
+static void SecDecodeNumberHex(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (SECUREC_LONG_HEX_BEYOND_MAX(spec->number)) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number = SECUREC_MUL_SIXTEEN(spec->number);
+    spec->number += (unsigned long)(unsigned int)SecHexValueOfChar(spec->ch);
+}
+
+/*
+ * Parse Octal character to integer for 32bit .
+ */
+static void SecDecodeNumberOctal(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (SECUREC_LONG_OCTAL_BEYOND_MAX(spec->number)) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number = SECUREC_MUL_EIGHT(spec->number);
+    spec->number += ((unsigned long)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0'));
+}
+
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+/* Compatible with integer negative values other than int */
+SECUREC_INLINE void SecFinishNumberNegativeOther(SecScanSpec *spec)
+{
+    if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+        if (spec->number > SECUREC_MIN_LONG_NEG_VALUE) {
+            spec->number = SECUREC_MIN_LONG_NEG_VALUE;
+        } else {
+            spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */
+        }
+        if (spec->beyondMax != 0) {
+            if (spec->numberWidth < SECUREC_NUM_WIDTH_INT) {
+                spec->number = 0;
+            }
+            if (spec->numberWidth == SECUREC_NUM_WIDTH_LONG) {
+                spec->number = SECUREC_MIN_LONG_NEG_VALUE;
+            }
+        }
+    } else { /* For o, u, x, X, p */
+        spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */
+        if (spec->beyondMax != 0) {
+            spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+        }
+    }
+}
+/* Compatible processing of integer negative numbers */
+SECUREC_INLINE void SecFinishNumberNegativeInt(SecScanSpec *spec)
+{
+    if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+#ifdef SECUREC_ON_64BITS
+        if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) {
+            if ((spec->number > SECUREC_MIN_64BITS_NEG_VALUE)) {
+                spec->number = 0;
+            } else {
+                spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */
+            }
+        }
+#else
+        if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) {
+            if ((spec->number > SECUREC_MIN_32BITS_NEG_VALUE)) {
+                spec->number = SECUREC_MIN_32BITS_NEG_VALUE;
+            } else {
+                spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */
+            }
+        }
+#endif
+        if (spec->beyondMax != 0) {
+#ifdef SECUREC_ON_64BITS
+            if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) {
+                spec->number = 0;
+            }
+#else
+            if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) {
+                spec->number = SECUREC_MIN_32BITS_NEG_VALUE;
+            }
+#endif
+        }
+    } else {            /* For o, u, x, X ,p */
+#ifdef SECUREC_ON_64BITS
+        if (spec->number > SECUREC_MAX_32BITS_VALUE_INC) {
+            spec->number = SECUREC_MAX_32BITS_VALUE;
+        } else {
+            spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */
+        }
+#else
+        spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */
+#endif
+        if (spec->beyondMax != 0) {
+            spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+        }
+    }
+}
+
+/* Compatible with integer positive values other than int */
+SECUREC_INLINE void SecFinishNumberPositiveOther(SecScanSpec *spec)
+{
+    if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+        if (spec->number > SECUREC_MAX_LONG_POS_VALUE) {
+            spec->number = SECUREC_MAX_LONG_POS_VALUE;
+        }
+        if ((spec->beyondMax != 0 && spec->numberWidth < SECUREC_NUM_WIDTH_INT)) {
+            spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+        }
+        if (spec->beyondMax != 0 && spec->numberWidth == SECUREC_NUM_WIDTH_LONG) {
+            spec->number = SECUREC_MAX_LONG_POS_VALUE;
+        }
+    } else {
+        if (spec->beyondMax != 0) {
+            spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+        }
+    }
+}
+
+/* Compatible processing of integer positive numbers */
+SECUREC_INLINE void SecFinishNumberPositiveInt(SecScanSpec *spec)
+{
+    if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+#ifdef SECUREC_ON_64BITS
+        if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) {
+            if (spec->number > SECUREC_MAX_64BITS_POS_VALUE) {
+                spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+            }
+        }
+        if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) {
+            spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE;
+        }
+#else
+        if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) {
+            if (spec->number > SECUREC_MAX_32BITS_POS_VALUE) {
+                spec->number = SECUREC_MAX_32BITS_POS_VALUE;
+            }
+        }
+        if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) {
+            spec->number = SECUREC_MAX_32BITS_POS_VALUE;
+        }
+#endif
+    } else {            /* For o,u,x,X,p */
+        if (spec->beyondMax != 0) {
+            spec->number = SECUREC_MAX_32BITS_VALUE;
+        }
+    }
+}
+
+#endif
+
+/*
+ * Parse decimal character to integer for 64bit .
+ */
+static void SecDecodeNumber64Decimal(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (spec->number64 > SECUREC_MAX_64BITS_VALUE_DIV_TEN) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number64 = SECUREC_MUL_TEN(spec->number64);
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (spec->number64 == SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT) {
+        SecUnsignedInt64 number64As = (SecUnsignedInt64)SECUREC_MAX_64BITS_VALUE - spec->number64;
+        if (number64As < (SecUnsignedInt64)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0')) {
+            spec->beyondMax = 1;
+        }
+    }
+#endif
+    spec->number64 += ((SecUnsignedInt64)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0'));
+}
+
+/*
+ * Parse Hex character to integer for 64bit .
+ */
+static void SecDecodeNumber64Hex(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (SECUREC_QWORD_HEX_BEYOND_MAX(spec->number64)) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number64 = SECUREC_MUL_SIXTEEN(spec->number64);
+    spec->number64 += (SecUnsignedInt64)(unsigned int)SecHexValueOfChar(spec->ch);
+}
+
+/*
+ * Parse Octal character to integer for 64bit .
+ */
+static void SecDecodeNumber64Octal(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (SECUREC_QWORD_OCTAL_BEYOND_MAX(spec->number64)) {
+        spec->beyondMax = 1;
+    }
+#endif
+    spec->number64 = SECUREC_MUL_EIGHT(spec->number64);
+    spec->number64 += ((SecUnsignedInt64)(SecUnsignedInt)spec->ch - (SecUnsignedInt)SECUREC_CHAR('0'));
+}
+
+#define SECUREC_DECODE_NUMBER_FUNC_NUM 2
+
+/*
+ * Parse 64-bit integer formatted input, return 0 when ch is a number.
+ */
+SECUREC_INLINE int SecDecodeNumber(SecScanSpec *spec)
+{
+    /* Function name cannot add address symbol, causing 546 alarm */
+    static void (* const secDecodeNumberHex[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = {
+        SecDecodeNumberHex, SecDecodeNumber64Hex
+    };
+    static void (* const secDecodeNumberOctal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = {
+        SecDecodeNumberOctal, SecDecodeNumber64Octal
+    };
+    static void (* const secDecodeNumberDecimal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = {
+        SecDecodeNumberDecimal, SecDecodeNumber64Decimal
+    };
+    if (spec->convChr == 'x' || spec->convChr == 'p') {
+        if (SecIsXdigit(spec->ch) != 0) {
+            (*secDecodeNumberHex[spec->numberArgType])(spec);
+        } else {
+            return -1;
+        }
+        return 0;
+    }
+    if (SecIsDigit(spec->ch) == 0) {
+        return -1;
+    }
+    if (spec->convChr == 'o') {
+        if (spec->ch < SECUREC_CHAR('8')) { /* Octal maximum limit '8' */
+            (*secDecodeNumberOctal[spec->numberArgType])(spec);
+        } else {
+            return -1;
+        }
+    } else { /* The convChr is 'd' */
+        (*secDecodeNumberDecimal[spec->numberArgType])(spec);
+    }
+    return 0;
+}
+
+/*
+ * Complete the final 32-bit integer formatted input
+ */
+static void SecFinishNumber(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (spec->negative != 0) {
+        if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) {
+            SecFinishNumberNegativeInt(spec);
+        } else {
+            SecFinishNumberNegativeOther(spec);
+        }
+    } else {
+        if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) {
+            SecFinishNumberPositiveInt(spec);
+        } else {
+            SecFinishNumberPositiveOther(spec);
+        }
+    }
+#else
+    if (spec->negative != 0) {
+#if defined(__hpux)
+        if (spec->oriConvChr != 'p') {
+            spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */
+        }
+#else
+        spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */
+#endif
+    }
+#endif
+    return;
+}
+
+/*
+ * Complete the final 64-bit integer formatted input
+ */
+static void SecFinishNumber64(SecScanSpec *spec)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX)))
+    if (spec->negative != 0) {
+        if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+            if (spec->number64 > SECUREC_MIN_64BITS_NEG_VALUE) {
+                spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE;
+            } else {
+                spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */
+            }
+            if (spec->beyondMax != 0) {
+                spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE;
+            }
+        } else {                /* For o, u, x, X, p */
+            spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */
+            if (spec->beyondMax != 0) {
+                spec->number64 = SECUREC_MAX_64BITS_VALUE;
+            }
+        }
+    } else {
+        if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) {
+            if (spec->number64 > SECUREC_MAX_64BITS_POS_VALUE) {
+                spec->number64 = SECUREC_MAX_64BITS_POS_VALUE;
+            }
+            if (spec->beyondMax != 0) {
+                spec->number64 = SECUREC_MAX_64BITS_POS_VALUE;
+            }
+        } else {
+            if (spec->beyondMax != 0) {
+                spec->number64 = SECUREC_MAX_64BITS_VALUE;
+            }
+        }
+    }
+#else
+    if (spec->negative != 0) {
+#if defined(__hpux)
+        if (spec->oriConvChr != 'p') {
+            spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */
+        }
+#else
+        spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */
+#endif
+    }
+#endif
+    return;
+}
+
+#if SECUREC_ENABLE_SCANF_FILE
+
+/*
+ *  Adjust the pointer position of the file stream
+ */
+SECUREC_INLINE void SecSeekStream(SecFileStream *stream)
+{
+    if (stream->count == 0) {
+        if (feof(stream->pf) != 0) {
+            /* File pointer at the end of file, don't need to seek back */
+            stream->base[0] = '\0';
+            return;
+        }
+    }
+    /* Seek to original position, for file read, but nothing to input */
+    if (fseek(stream->pf, stream->oriFilePos, SEEK_SET) != 0) {
+        /* Seek failed, ignore it */
+        stream->oriFilePos = 0;
+        return;
+    }
+
+    if (stream->fileRealRead > 0) { /* Do not seek without input data */
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+        size_t residue = stream->fileRealRead % SECUREC_BUFFERED_BLOK_SIZE;
+        size_t loops;
+        for (loops = 0; loops < (stream->fileRealRead / SECUREC_BUFFERED_BLOK_SIZE); ++loops) {
+            if (fread(stream->base, (size_t)SECUREC_BUFFERED_BLOK_SIZE, (size_t)1, stream->pf) != (size_t)1) {
+                break;
+            }
+        }
+        if (residue != 0) {
+            long curFilePos;
+            if (fread(stream->base, residue, (size_t)1, stream->pf) != (size_t)1) {
+                return;
+            }
+            curFilePos = ftell(stream->pf);
+            if (curFilePos < stream->oriFilePos ||
+                (size_t)(unsigned long)(curFilePos - stream->oriFilePos) < stream->fileRealRead) {
+                /* Try to remedy the problem */
+                long adjustNum = (long)(stream->fileRealRead - (size_t)(unsigned long)(curFilePos - stream->oriFilePos));
+                (void)fseek(stream->pf, adjustNum, SEEK_CUR);
+            }
+        }
+#else
+        /* Seek from oriFilePos. Regardless of the integer sign problem, call scanf will not read very large data */
+        if (fseek(stream->pf, (long)stream->fileRealRead, SEEK_CUR) != 0) {
+            /* Seek failed, ignore it */
+            stream->oriFilePos = 0;
+            return;
+        }
+#endif
+    }
+    return;
+}
+
+/*
+ *  Adjust the pointer position of the file stream and free memory
+ */
+SECUREC_INLINE void SecAdjustStream(SecFileStream *stream)
+{
+    if ((stream->flag & SECUREC_FILE_STREAM_FLAG) != 0 && stream->base != NULL) {
+        SecSeekStream(stream);
+        SECUREC_FREE(stream->base);
+        stream->base = NULL;
+    }
+    return;
+}
+#endif
+
+SECUREC_INLINE void SecSkipSpaceFormat(const SecUnsignedChar **format)
+{
+    const SecUnsignedChar *fmt = *format;
+    while (SecIsSpace((SecInt)(int)(*fmt)) != 0) {
+        ++fmt;
+    }
+    *format = fmt;
+}
+
+#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION)
+/*
+ * Handling multi-character characters
+ */
+SECUREC_INLINE int SecDecodeLeadByte(SecScanSpec *spec, const SecUnsignedChar **format, SecFileStream *stream)
+{
+#if SECUREC_HAVE_MBTOWC
+    const SecUnsignedChar *fmt = *format;
+    int ch1 = (int)spec->ch;
+    int ch2 = SecGetChar(stream, &(spec->charCount));
+    spec->ch = (SecInt)ch2;
+    if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch2) {
+        /* in console mode, ungetc twice may cause problem */
+        SecUnGetChar(ch2, stream, &(spec->charCount));
+        SecUnGetChar(ch1, stream, &(spec->charCount));
+        return -1;
+    }
+    ++fmt;
+    if ((unsigned int)MB_CUR_MAX >= SECUREC_UTF8_BOM_HEADER_SIZE &&
+        (((unsigned char)ch1 & SECUREC_UTF8_LEAD_1ST) == SECUREC_UTF8_LEAD_1ST) &&
+        (((unsigned char)ch2 & SECUREC_UTF8_LEAD_2ND) == SECUREC_UTF8_LEAD_2ND)) {
+        /* This char is very likely to be a UTF-8 char */
+        wchar_t tempWChar;
+        char temp[SECUREC_MULTI_BYTE_MAX_LEN];
+        int ch3 = (int)SecGetChar(stream, &(spec->charCount));
+        spec->ch = (SecInt)ch3;
+        if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch3) {
+            SecUnGetChar(ch3, stream, &(spec->charCount));
+            return -1;
+        }
+        temp[0] = (char)ch1;
+        temp[1] = (char)ch2; /* 1 index of second character */
+        temp[2] = (char)ch3; /* 2 index of third character */
+        temp[3] = '\0';      /* 3 of string terminator position */
+        if (mbtowc(&tempWChar, temp, sizeof(temp)) > 0) {
+            /* Succeed */
+            ++fmt;
+            --spec->charCount;
+        } else {
+            SecUnGetChar(ch3, stream, &(spec->charCount));
+        }
+    }
+    --spec->charCount;    /* Only count as one character read */
+    *format = fmt;
+    return 0;
+#else
+    SecUnGetChar(spec->ch, stream, &(spec->charCount));
+    (void)format; /* To clear e438 last value assigned not used , the compiler will optimize this code */
+    return -1;
+#endif
+}
+
+SECUREC_INLINE int SecFilterWcharInFormat(SecScanSpec *spec, const SecUnsignedChar **format, SecFileStream *stream)
+{
+    if (SecIsLeadByte(spec->ch) != 0) {
+        if (SecDecodeLeadByte(spec, format, stream) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+#endif
+
+/*
+ *  Resolving sequence of characters from %[ format, format wile point to ']'
+ */
+SECUREC_INLINE int SecSetupBracketTable(const SecUnsignedChar **format, SecBracketTable *bracketTable)
+{
+    const SecUnsignedChar *fmt = *format;
+    SecUnsignedChar prevChar = 0;
+#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT))
+    if (*fmt == SECUREC_CHAR('{')) {
+        return -1;
+    }
+#endif
+    /* For building "table" data */
+    ++fmt; /* Skip [ */
+    bracketTable->mask = 0; /* Set all bits to 0 */
+    if (*fmt == SECUREC_CHAR('^')) {
+        ++fmt;
+        bracketTable->mask = (unsigned char)0xffU; /* Use 0xffU to set all bits to 1 */
+    }
+    if (*fmt == SECUREC_CHAR(']')) {
+        prevChar = SECUREC_CHAR(']');
+        ++fmt;
+        SecBracketSetBit(bracketTable->table, SECUREC_CHAR(']'));
+    }
+    while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) {
+        SecUnsignedChar expCh = *fmt;
+        ++fmt;
+        if (expCh != SECUREC_CHAR('-') || prevChar == 0 || *fmt == SECUREC_CHAR(']')) {
+            /* Normal character */
+            prevChar = expCh;
+            SecBracketSetBit(bracketTable->table, expCh);
+        } else {
+            /* For %[a-z] */
+            expCh = *fmt;   /* Get end of range */
+            ++fmt;
+            if (prevChar <= expCh) {  /* %[a-z] %[a-a] */
+                SecBracketSetBitRange(bracketTable->table, prevChar, expCh);
+            } else {
+                /* For %[z-a] */
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+                /* Swap start and end characters */
+                SecBracketSetBitRange(bracketTable->table, expCh, prevChar);
+#else
+                SecBracketSetBit(bracketTable->table, SECUREC_CHAR('-'));
+                SecBracketSetBit(bracketTable->table, expCh);
+#endif
+            }
+            prevChar = 0;
+        }
+    }
+    *format = fmt;
+    return 0;
+}
+
+#ifdef SECUREC_FOR_WCHAR
+SECUREC_INLINE int SecInputForWchar(SecScanSpec *spec)
+{
+    void *endPtr = spec->argPtr;
+    if (spec->isWCharOrLong > 0) {
+        *(wchar_t UNALIGNED *)endPtr = (wchar_t)spec->ch;
+        endPtr = (wchar_t *)endPtr + 1;
+        --spec->arrayWidth;
+    } else {
+#if SECUREC_HAVE_WCTOMB
+        int temp;
+        char tmpBuf[SECUREC_MB_LEN + 1];
+        SECUREC_MASK_MSVC_CRT_WARNING temp = wctomb(tmpBuf, (wchar_t)spec->ch);
+        SECUREC_END_MASK_MSVC_CRT_WARNING
+        if (temp <= 0 || (size_t)(unsigned int)temp > sizeof(tmpBuf)) {
+            /* If wctomb  error, then ignore character */
+            return 0;
+        }
+        if (((size_t)(unsigned int)temp) > spec->arrayWidth) {
+            return -1;
+        }
+        if (memcpy_s(endPtr, spec->arrayWidth, tmpBuf, (size_t)(unsigned int)temp) != EOK) {
+            return -1;
+        }
+        endPtr = (char *)endPtr + temp;
+        spec->arrayWidth -= (size_t)(unsigned int)temp;
+#else
+        return -1;
+#endif
+    }
+    spec->argPtr = endPtr;
+    return 0;
+}
+#endif
+
+#ifndef SECUREC_FOR_WCHAR
+#if SECUREC_HAVE_WCHART
+SECUREC_INLINE wchar_t SecConvertInputCharToWchar(SecScanSpec *spec, SecFileStream *stream)
+{
+    wchar_t tempWChar = L'?';   /* Set default char is ? */
+#if SECUREC_HAVE_MBTOWC
+    char temp[SECUREC_MULTI_BYTE_MAX_LEN + 1];
+    temp[0] = (char)spec->ch;
+    temp[1] = '\0';
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+    if (SecIsLeadByte(spec->ch) != 0) {
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        temp[1] = (char)spec->ch;
+        temp[2] = '\0'; /* 2 of string terminator position */
+    }
+    if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) {
+        /* No string termination error for tool */
+        tempWChar = L'?';
+    }
+#else
+    if (SecIsLeadByte(spec->ch) != 0) {
+        int convRes = 0;
+        int di = 1;
+        /* On Linux like system, the string is encoded in UTF-8 */
+        while (convRes <= 0 && di < (int)MB_CUR_MAX && di < SECUREC_MULTI_BYTE_MAX_LEN) {
+            spec->ch = SecGetChar(stream, &(spec->charCount));
+            temp[di] = (char)spec->ch;
+            ++di;
+            temp[di] = '\0';
+            convRes = mbtowc(&tempWChar, temp, sizeof(temp));
+        }
+        if (convRes <= 0) {
+            tempWChar = L'?';
+        }
+    } else {
+        if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) {
+            tempWChar = L'?';
+        }
+    }
+#endif
+#else
+    (void)spec;      /* To clear e438 last value assigned not used , the compiler will optimize this code */
+    (void)stream;    /* To clear e438 last value assigned not used , the compiler will optimize this code */
+#endif /* SECUREC_HAVE_MBTOWC */
+
+    return tempWChar;
+}
+#endif /* SECUREC_HAVE_WCHART */
+
+SECUREC_INLINE int SecInputForChar(SecScanSpec *spec, SecFileStream *stream)
+{
+    void *endPtr = spec->argPtr;
+    if (spec->isWCharOrLong > 0) {
+#if SECUREC_HAVE_WCHART
+        *(wchar_t UNALIGNED *)endPtr = SecConvertInputCharToWchar(spec, stream);
+        endPtr = (wchar_t *)endPtr + 1;
+        --spec->arrayWidth;
+#else
+    (void)stream;    /* To clear e438 last value assigned not used , the compiler will optimize this code */
+    return -1;
+#endif
+    } else {
+        *(char *)endPtr = (char)spec->ch;
+        endPtr = (char *)endPtr + 1;
+        --spec->arrayWidth;
+    }
+    spec->argPtr = endPtr;
+    return 0;
+}
+#endif
+
+/*
+ * Scan digital part of %d %i %o %u %x %p.
+ * Return 0 OK
+ */
+SECUREC_INLINE int SecInputNumberDigital(SecFileStream *stream, SecScanSpec *spec)
+{
+    static void (* const secFinishNumber[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = {
+        SecFinishNumber, SecFinishNumber64
+    };
+    while (SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        /* Decode ch to number */
+        if (SecDecodeNumber(spec) != 0) {
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            break;
+        }
+        SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */
+        spec->numberState = SECUREC_NUMBER_STATE_STARTED;
+    }
+    /* Handling integer negative numbers and beyond max */
+    (*secFinishNumber[spec->numberArgType])(spec);
+    if (spec->numberState == SECUREC_NUMBER_STATE_STARTED) {
+        return 0;
+    }
+    return -1;
+}
+
+/*
+ * Scan %d %i %o %u %x %p.
+ * Return 0 OK
+ */
+SECUREC_INLINE int SecInputNumber(SecFileStream *stream, SecScanSpec *spec)
+{
+    /* Character already read */
+    if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) {
+        if (spec->ch == SECUREC_CHAR('-')) {
+            spec->negative = 1;
+#if SECUREC_IN_KERNEL
+            /* In kernel Refuse to enter negative number */
+            if (SECUREC_CONVERT_IS_UNSIGNED(spec->oriConvChr)) {
+                return -1;
+            }
+#endif
+        }
+        SECUREC_FILED_WIDTH_DEC(spec); /* Do not need to check width here, must be greater than 0 */
+        spec->ch = SecGetChar(stream, &(spec->charCount)); /* Eat + or - */
+        spec->ch = SecGetChar(stream, &(spec->charCount)); /* Get next character, used for the '0' judgments */
+        SecUnGetChar(spec->ch, stream, &(spec->charCount)); /* Not sure if it was actually read, so push back */
+    }
+
+    if (spec->oriConvChr == 'i') {
+        spec->convChr = 'd'; /* The i could be d, o, or x, use d as default */
+    }
+
+    if (spec->ch == SECUREC_CHAR('0') && (spec->oriConvChr == 'x' || spec->oriConvChr == 'i') &&
+        SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        /* Input string begin with 0, may be 0x123  0X123  0123  0x  01  0yy  09  0  0ab 00 */
+        SECUREC_FILED_WIDTH_DEC(spec);
+        spec->ch = SecGetChar(stream, &(spec->charCount)); /* ch is '0' */
+
+        /* Read only '0' due to width limitation */
+        if (!SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+            /* The number or number64 in spec has been set 0 */
+            return 0;
+        }
+
+        spec->ch = SecGetChar(stream, &(spec->charCount)); /* Get next char to check x or X, do not dec width */
+        if ((SecChar)spec->ch == SECUREC_CHAR('x') || (SecChar)spec->ch == SECUREC_CHAR('X')) {
+            spec->convChr = 'x';
+            SECUREC_FILED_WIDTH_DEC(spec); /* Make incorrect width for x or X */
+        } else {
+            if (spec->oriConvChr == 'i') {
+                spec->convChr = 'o';
+            }
+            /* For "0y" "08" "01" "0a" ... ,push the 'y' '8' '1' 'a'  back */
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            /* Since 0 has been read, it indicates that a valid character has been read */
+            spec->numberState = SECUREC_NUMBER_STATE_STARTED;
+        }
+    }
+    return SecInputNumberDigital(stream, spec);
+}
+
+/*
+ * Scan %c %s %[
+ * Return 0 OK
+ */
+SECUREC_INLINE int SecInputString(SecFileStream *stream, SecScanSpec *spec,
+    const SecBracketTable *bracketTable, int *doneCount)
+{
+    void *startPtr = spec->argPtr;
+    int suppressed = 0;
+    int errNoMem = 0;
+
+    while (SECUREC_FILED_WIDTH_ENOUGH(spec)) {
+        SECUREC_FILED_WIDTH_DEC(spec);
+        spec->ch = SecGetChar(stream, &(spec->charCount));
+        /*
+         * The char condition or string condition and bracket condition.
+         * Only supports wide characters with a maximum length of two bytes
+         */
+        if (spec->ch != SECUREC_EOF && (SecCanInputCharacter(spec->convChr) != 0 ||
+            SecCanInputString(spec->convChr, spec->ch) != 0 ||
+            SecCanInputForBracket(spec->convChr, spec->ch, bracketTable) != 0)) {
+            if (spec->suppress != 0) {
+                /* Used to identify processed data for %*, use argPtr to identify will cause 613, so use suppressed */
+                suppressed = 1;
+                continue;
+            }
+            /* Now suppress is not set */
+            if (spec->arrayWidth == 0) {
+                errNoMem = 1; /* We have exhausted the user's buffer */
+                break;
+            }
+#ifdef SECUREC_FOR_WCHAR
+            errNoMem = SecInputForWchar(spec);
+#else
+            errNoMem = SecInputForChar(spec, stream);
+#endif
+            if (errNoMem != 0) {
+                break;
+            }
+        } else {
+            SecUnGetChar(spec->ch, stream, &(spec->charCount));
+            break;
+        }
+    }
+
+    if (errNoMem != 0) {
+        /* In case of error, blank out the input buffer */
+        SecAddEndingZero(startPtr, spec);
+        return -1;
+    }
+    if ((spec->suppress != 0 && suppressed == 0) ||
+        (spec->suppress == 0 && startPtr == spec->argPtr)) {
+        /* No input was scanned */
+        return -1;
+    }
+    if (spec->convChr != 'c') {
+        /* Add null-terminate for strings */
+        SecAddEndingZero(spec->argPtr, spec);
+    }
+    if (spec->suppress == 0) {
+        *doneCount = *doneCount + 1;
+    }
+    return 0;
+}
+
+#ifdef SECUREC_FOR_WCHAR
+/*
+ * Alloce buffer for wchar version of %[.
+ * Return 0 OK
+ */
+SECUREC_INLINE int SecAllocBracketTable(SecBracketTable *bracketTable)
+{
+    if (bracketTable->table == NULL) {
+        /* Table should be freed after use */
+        bracketTable->table = (unsigned char *)SECUREC_MALLOC(SECUREC_BRACKET_TABLE_SIZE);
+        if (bracketTable->table == NULL) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Free buffer for wchar version of %[
+ */
+SECUREC_INLINE void SecFreeBracketTable(SecBracketTable *bracketTable)
+{
+    if (bracketTable->table != NULL) {
+        SECUREC_FREE(bracketTable->table);
+        bracketTable->table = NULL;
+    }
+}
+#endif
+
+#ifdef SECUREC_FOR_WCHAR
+/*
+ *  Formatting input core functions for wchar version.Called by a function such as vswscanf_s
+ */
+int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList)
+#else
+/*
+ * Formatting input core functions for char version.Called by a function such as vsscanf_s
+ */
+int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList)
+#endif
+{
+    const SecUnsignedChar *format = (const SecUnsignedChar *)cFormat;
+    SecBracketTable bracketTable = SECUREC_INIT_BRACKET_TABLE;
+    SecScanSpec spec;
+    int doneCount = 0;
+    int formatError = 0;
+    int paraIsNull = 0;
+    int match = 0; /* When % is found , inc this value */
+    int errRet = 0;
+#if SECUREC_ENABLE_SCANF_FLOAT
+    SecFloatSpec floatSpec;
+    SecInitFloatSpec(&floatSpec);
+#endif
+    spec.ch = 0; /* Need to initialize to 0 */
+    spec.charCount = 0; /* Need to initialize to 0 */
+
+    /* Format must not NULL, use err < 1 to claer 845 */
+    while (errRet < 1 && *format != SECUREC_CHAR('\0')) {
+        /* Skip space in format and space in input */
+        if (SecIsSpace((SecInt)(int)(*format)) != 0) {
+            /* Read first no space char */
+            spec.ch = SecSkipSpaceChar(stream, &(spec.charCount));
+            /* Read the EOF cannot be returned directly here, because the case of " %n" needs to be handled */
+            /* Put fist no space char backup. put EOF back is also OK, and to modify the character count */
+            SecUnGetChar(spec.ch, stream, &(spec.charCount));
+            SecSkipSpaceFormat(&format);
+            continue;
+        }
+
+        if (*format != SECUREC_CHAR('%')) {
+            spec.ch = SecGetChar(stream, &(spec.charCount));
+            if ((int)(*format) != (int)(spec.ch)) {
+                SecUnGetChar(spec.ch, stream, &(spec.charCount));
+                break;
+            }
+            ++format;
+#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION)
+            if (SecFilterWcharInFormat(&spec, &format, stream) != 0) {
+                break;
+            }
+#endif
+            continue;
+        }
+
+        /* Now *format is % */
+        /* Set default value for each % */
+        SecSetDefaultScanSpec(&spec);
+        if (SecDecodeScanFlag(&format, &spec) != 0) {
+            formatError = 1;
+            ++errRet;
+            continue;
+        }
+        if (!SECUREC_FILED_WIDTH_ENOUGH(&spec)) {
+            /* 0 width in format */
+            ++errRet;
+            continue;
+        }
+
+        /* Update wchar flag for %S %C */
+        SecUpdateWcharFlagByType(*format, &spec);
+
+        spec.convChr = SECUREC_TO_LOWERCASE(*format);
+        spec.oriConvChr = spec.convChr; /* convChr may be modified to handle integer logic */
+        if (spec.convChr != 'n') {
+            if (spec.convChr != 'c' && spec.convChr != SECUREC_BRACE) {
+                spec.ch = SecSkipSpaceChar(stream, &(spec.charCount));
+            } else {
+                spec.ch = SecGetChar(stream, &(spec.charCount));
+            }
+            if (spec.ch == SECUREC_EOF) {
+                ++errRet;
+                continue;
+            }
+        }
+
+        /* Now no 0 width in format and get one char from input */
+        switch (spec.oriConvChr) {
+            case 'c': /* Also 'C' */
+                if (spec.widthSet == 0) {
+                    spec.widthSet = 1;
+                    spec.width = 1;
+                }
+                /* fall-through */ /* FALLTHRU */
+            case 's': /* Also 'S': */
+                /* fall-through */ /* FALLTHRU */
+            case SECUREC_BRACE:
+                /* Unset last char to stream */
+                SecUnGetChar(spec.ch, stream, &(spec.charCount));
+                /* Check dest buffer and size */
+                if (spec.suppress == 0) {
+                    spec.argPtr = (void *)va_arg(argList, void *);
+                    if (spec.argPtr == NULL) {
+                        paraIsNull = 1;
+                        ++errRet;
+                        continue;
+                    }
+                    /* Get the next argument, size of the array in characters */
+                    spec.arrayWidth = SECUREC_GET_ARRAYWIDTH(argList);
+                    if (SECUREC_ARRAY_WIDTH_IS_WRONG(spec)) {
+                        /* Do not clear buffer just go error */
+                        ++errRet;
+                        continue;
+                    }
+                    /* One element is needed for '\0' for %s and %[ */
+                    if (spec.convChr != 'c') {
+                        --spec.arrayWidth;
+                    }
+                } else {
+                    /* Set argPtr to  NULL  is necessary, in supress mode we don't use argPtr to store data */
+                    spec.argPtr = NULL;
+                }
+
+                if (spec.convChr == SECUREC_BRACE) {
+                    /* Malloc when first %[ is meet  for wchar version */
+#ifdef SECUREC_FOR_WCHAR
+                    if (SecAllocBracketTable(&bracketTable) != 0) {
+                        ++errRet;
+                        continue;
+                    }
+#endif
+                    (void)SECUREC_MEMSET_FUNC_OPT(bracketTable.table, 0, (size_t)SECUREC_BRACKET_TABLE_SIZE);
+                    if (SecSetupBracketTable(&format, &bracketTable) != 0) {
+                        ++errRet;
+                        continue;
+                    }
+
+                    if (*format == SECUREC_CHAR('\0')) {
+                        /* Default add string terminator */
+                        SecAddEndingZero(spec.argPtr, &spec);
+                        ++errRet;
+                        /* Truncated format */
+                        continue;
+                    }
+                }
+
+                /* Set completed.  Now read string or character */
+                if (SecInputString(stream, &spec, &bracketTable, &doneCount) != 0) {
+                    ++errRet;
+                    continue;
+                }
+                break;
+            case 'p':
+                /* Make %hp same as %p */
+                spec.numberWidth = SECUREC_NUM_WIDTH_INT;
+#ifdef SECUREC_ON_64BITS
+                spec.numberArgType = 1;
+#endif
+                /* fall-through */ /* FALLTHRU */
+            case 'o': /* fall-through */ /* FALLTHRU */
+            case 'u': /* fall-through */ /* FALLTHRU */
+            case 'd': /* fall-through */ /* FALLTHRU */
+            case 'i': /* fall-through */ /* FALLTHRU */
+            case 'x':
+                /* Unset last char to stream */
+                SecUnGetChar(spec.ch, stream, &(spec.charCount));
+                if (SecInputNumber(stream, &spec) != 0) {
+                    ++errRet;
+                    continue;
+                }
+                if (spec.suppress == 0) {
+                    spec.argPtr = (void *)va_arg(argList, void *);
+                    if (spec.argPtr == NULL) {
+                        paraIsNull = 1;
+                        ++errRet;
+                        continue;
+                    }
+                    SecAssignNumber(&spec);
+                    ++doneCount;
+                }
+                break;
+            case 'n': /* Char count */
+                if (spec.suppress == 0) {
+                    spec.argPtr = (void *)va_arg(argList, void *);
+                    if (spec.argPtr == NULL) {
+                        paraIsNull = 1;
+                        ++errRet;
+                        continue;
+                    }
+                    spec.number = (unsigned long)(unsigned int)(spec.charCount);
+                    spec.numberArgType = 0;
+                    SecAssignNumber(&spec);
+                }
+                break;
+            case 'e': /* fall-through */ /* FALLTHRU */
+            case 'f': /* fall-through */ /* FALLTHRU */
+            case 'g': /* Scan a float */
+                /* Unset last char to stream */
+                SecUnGetChar(spec.ch, stream, &(spec.charCount));
+#if SECUREC_ENABLE_SCANF_FLOAT
+                if (SecInputFloat(stream, &spec, &floatSpec) != 0) {
+                    ++errRet;
+                    continue;
+                }
+                if (spec.suppress == 0) {
+                    spec.argPtr = (void *)va_arg(argList, void *);
+                    if (spec.argPtr == NULL) {
+                        ++errRet;
+                        paraIsNull = 1;
+                        continue;
+                    }
+                    if (SecAssignFloat(&floatSpec, &spec) != 0) {
+                        ++errRet;
+                        continue;
+                    }
+                    ++doneCount;
+                }
+                break;
+#else /* SECUREC_ENABLE_SCANF_FLOAT */
+                ++errRet;
+                continue;
+#endif
+            default:
+                if ((int)(*format) != (int)spec.ch) {
+                    SecUnGetChar(spec.ch, stream, &(spec.charCount));
+                    formatError = 1;
+                    ++errRet;
+                    continue;
+                } else {
+                    --match; /* Compensate for the self-increment of the following code */
+                }
+                break;
+        }
+        ++match;
+        ++format;
+    }
+
+#ifdef SECUREC_FOR_WCHAR
+    SecFreeBracketTable(&bracketTable);
+#endif
+
+#if SECUREC_ENABLE_SCANF_FLOAT
+    SecFreeFloatSpec(&floatSpec, &doneCount);
+#endif
+
+#if SECUREC_ENABLE_SCANF_FILE
+    SecAdjustStream(stream);
+#endif
+
+    if (spec.ch == SECUREC_EOF) {
+        return ((doneCount != 0 || match != 0) ? doneCount : SECUREC_SCANF_EINVAL);
+    }
+    if (formatError != 0 || paraIsNull != 0) {
+        /* Invalid Input Format or parameter, but not meet EOF */
+        return SECUREC_SCANF_ERROR_PARA;
+    }
+    return doneCount;
+}
+
+#if SECUREC_ENABLE_SCANF_FILE
+/*
+ *  Get char from stream use std function
+ */
+SECUREC_INLINE SecInt SecGetCharFromStream(const SecFileStream *stream)
+{
+    SecInt ch;
+    ch = SECUREC_GETC(stream->pf);
+    return ch;
+}
+
+/*
+ * Try to read the BOM header, when meet a BOM head, discard it, then data is Aligned to base
+ */
+SECUREC_INLINE void SecReadAndSkipBomHeader(SecFileStream *stream)
+{
+    /* Use size_t type conversion  to clean e747 */
+    stream->count = fread(stream->base, (size_t)1, (size_t)SECUREC_BOM_HEADER_SIZE, stream->pf);
+    if (stream->count > SECUREC_BOM_HEADER_SIZE) {
+        stream->count = 0;
+    }
+    if (SECUREC_BEGIN_WITH_BOM(stream->base, stream->count)) {
+        /* It's BOM header, discard it */
+        stream->count = 0;
+    }
+}
+
+/*
+ *  Get char  from file stream or buffer
+ */
+SECUREC_INLINE SecInt SecGetCharFromFile(SecFileStream *stream)
+{
+    SecInt ch;
+    if (stream->count < sizeof(SecChar)) {
+        /* Load file to buffer */
+        size_t len;
+        if (stream->base != NULL) {
+            /* Put the last unread data in the buffer head */
+            for (len = 0; len < stream->count; ++len) {
+                stream->base[len] = stream->cur[len];
+            }
+        } else {
+            stream->oriFilePos = ftell(stream->pf);   /* Save original file read position */
+            if (stream->oriFilePos == -1) {
+                /* It may be a pipe stream */
+                stream->flag = SECUREC_PIPE_STREAM_FLAG;
+                return SecGetCharFromStream(stream);
+            }
+            /* Reserve the length of BOM head */
+            stream->base = (char *)SECUREC_MALLOC(SECUREC_BUFFERED_BLOK_SIZE +
+                SECUREC_BOM_HEADER_SIZE + sizeof(SecChar)); /* To store '\0' and aligned to wide char */
+            if (stream->base == NULL) {
+                return SECUREC_EOF;
+            }
+            /* First read file */
+            if (stream->oriFilePos == 0) {
+                /* Make sure the data is aligned to base */
+                SecReadAndSkipBomHeader(stream);
+            }
+        }
+
+        /* Skip existing data and read data */
+        len = fread(stream->base + stream->count, (size_t)1, (size_t)SECUREC_BUFFERED_BLOK_SIZE, stream->pf);
+        if (len > SECUREC_BUFFERED_BLOK_SIZE) { /* It won't happen, */
+            len = 0;
+        }
+        stream->count += len;
+        stream->cur = stream->base;
+        stream->flag |= SECUREC_LOAD_FILE_TO_MEM_FLAG;
+        stream->base[stream->count] = '\0';   /* For tool Warning string null */
+    }
+
+    SECUREC_GET_CHAR(stream, &ch);
+    if (ch != SECUREC_EOF) {
+        stream->fileRealRead += sizeof(SecChar);
+    }
+    return ch;
+}
+#endif
+
+/*
+ *  Get char  for wchar version
+ */
+SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter)
+{
+    *counter = *counter + 1; /* Always plus 1 */
+    /* The main scenario is scanf str */
+    if ((stream->flag & SECUREC_MEM_STR_FLAG) != 0) {
+        SecInt ch;
+        SECUREC_GET_CHAR(stream, &ch);
+        return ch;
+    }
+#if SECUREC_ENABLE_SCANF_FILE
+    if ((stream->flag & SECUREC_FILE_STREAM_FLAG) != 0) {
+        return SecGetCharFromFile(stream);
+    }
+    if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) != 0) {
+        return SecGetCharFromStream(stream);
+    }
+#endif
+    return SECUREC_EOF;
+}
+
+/*
+ *  Unget Public realizatio char for wchar and char version
+ */
+SECUREC_INLINE void SecUnGetCharImpl(SecInt ch, SecFileStream *stream)
+{
+    if ((stream->flag & SECUREC_MEM_STR_FLAG) != 0) {
+        SECUREC_UN_GET_CHAR(stream);
+        return;
+    }
+#if SECUREC_ENABLE_SCANF_FILE
+    if ((stream->flag & SECUREC_LOAD_FILE_TO_MEM_FLAG) != 0) {
+        SECUREC_UN_GET_CHAR(stream);
+        if (stream->fileRealRead > 0) {
+            stream->fileRealRead -= sizeof(SecChar);
+        }
+        return;
+    }
+    if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) != 0) {
+        (void)SECUREC_UN_GETC(ch, stream->pf);
+        return;
+    }
+#else
+    (void)ch; /* To clear e438 last value assigned not used , the compiler will optimize this code */
+#endif
+}
+
+/*
+ *  Unget char  for char version
+ */
+SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter)
+{
+    *counter = *counter - 1; /* Always mius 1 */
+    if (ch != SECUREC_EOF) {
+        SecUnGetCharImpl(ch, stream);
+    }
+}
+
+/*
+ *  Skip space char by isspace
+ */
+SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter)
+{
+    SecInt ch;
+    do {
+        ch = SecGetChar(stream, counter);
+        if (ch == SECUREC_EOF) {
+            break;
+        }
+    } while (SecIsSpace(ch) != 0);
+    return ch;
+}
+#endif /* INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 */
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memcpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memcpy_s.c
new file mode 100644 (file)
index 0000000..612f6e2
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: memcpy_s function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+#ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE
+#define SECUREC_MEMCOPY_THRESHOLD_SIZE 64UL
+#endif
+
+#define SECUREC_SMALL_MEM_COPY(dest, src, count) do { \
+    if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \
+        /* Use struct assignment */ \
+        switch (count) { \
+            case 1: \
+                *(unsigned char *)(dest) = *(const unsigned char *)(src); \
+                break; \
+            case 2: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 2); \
+                break; \
+            case 3: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 3); \
+                break; \
+            case 4: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 4); \
+                break; \
+            case 5: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 5); \
+                break; \
+            case 6: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 6); \
+                break; \
+            case 7: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 7); \
+                break; \
+            case 8: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 8); \
+                break; \
+            case 9: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 9); \
+                break; \
+            case 10: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 10); \
+                break; \
+            case 11: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 11); \
+                break; \
+            case 12: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 12); \
+                break; \
+            case 13: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 13); \
+                break; \
+            case 14: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 14); \
+                break; \
+            case 15: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 15); \
+                break; \
+            case 16: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 16); \
+                break; \
+            case 17: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 17); \
+                break; \
+            case 18: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 18); \
+                break; \
+            case 19: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 19); \
+                break; \
+            case 20: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 20); \
+                break; \
+            case 21: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 21); \
+                break; \
+            case 22: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 22); \
+                break; \
+            case 23: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 23); \
+                break; \
+            case 24: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 24); \
+                break; \
+            case 25: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 25); \
+                break; \
+            case 26: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 26); \
+                break; \
+            case 27: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 27); \
+                break; \
+            case 28: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 28); \
+                break; \
+            case 29: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 29); \
+                break; \
+            case 30: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 30); \
+                break; \
+            case 31: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 31); \
+                break; \
+            case 32: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 32); \
+                break; \
+            case 33: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 33); \
+                break; \
+            case 34: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 34); \
+                break; \
+            case 35: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 35); \
+                break; \
+            case 36: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 36); \
+                break; \
+            case 37: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 37); \
+                break; \
+            case 38: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 38); \
+                break; \
+            case 39: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 39); \
+                break; \
+            case 40: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 40); \
+                break; \
+            case 41: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 41); \
+                break; \
+            case 42: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 42); \
+                break; \
+            case 43: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 43); \
+                break; \
+            case 44: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 44); \
+                break; \
+            case 45: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 45); \
+                break; \
+            case 46: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 46); \
+                break; \
+            case 47: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 47); \
+                break; \
+            case 48: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 48); \
+                break; \
+            case 49: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 49); \
+                break; \
+            case 50: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 50); \
+                break; \
+            case 51: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 51); \
+                break; \
+            case 52: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 52); \
+                break; \
+            case 53: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 53); \
+                break; \
+            case 54: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 54); \
+                break; \
+            case 55: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 55); \
+                break; \
+            case 56: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 56); \
+                break; \
+            case 57: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 57); \
+                break; \
+            case 58: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 58); \
+                break; \
+            case 59: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 59); \
+                break; \
+            case 60: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 60); \
+                break; \
+            case 61: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 61); \
+                break; \
+            case 62: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 62); \
+                break; \
+            case 63: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 63); \
+                break; \
+            case 64: \
+                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 64); \
+                break; \
+            default: \
+                /* Do nothing */ \
+                break; \
+        } /* END switch */ \
+    } else { \
+        unsigned char *tmpDest_ = (unsigned char *)(dest); \
+        const unsigned char *tmpSrc_ = (const unsigned char *)(src); \
+        switch (count) { \
+            case 64: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 63: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 62: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 61: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 60: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 59: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 58: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 57: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 56: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 55: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 54: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 53: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 52: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 51: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 50: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 49: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 48: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 47: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 46: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 45: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 44: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 43: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 42: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 41: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 40: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 39: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 38: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 37: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 36: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 35: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 34: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 33: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 32: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 31: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 30: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 29: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 28: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 27: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 26: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 25: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 24: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 23: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 22: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 21: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 20: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 19: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 18: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 17: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 16: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 15: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 14: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 13: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 12: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 11: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 10: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 9: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 8: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 7: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 6: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 5: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 4: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 3: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 2: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 1: \
+                *(tmpDest_++) = *(tmpSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            default: \
+                /* Do nothing */ \
+                break; \
+        } \
+    } \
+} SECUREC_WHILE_ZERO
+
+/*
+ * Performance optimization
+ */
+#define SECUREC_MEMCPY_OPT(dest, src, count) do { \
+    if ((count) > SECUREC_MEMCOPY_THRESHOLD_SIZE) { \
+        SECUREC_MEMCPY_WARP_OPT((dest), (src), (count)); \
+    } else { \
+        SECUREC_SMALL_MEM_COPY((dest), (src), (count)); \
+    } \
+} SECUREC_WHILE_ZERO
+#endif
+
+/*
+ * Handling errors
+ */
+SECUREC_INLINE errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("memcpy_s");
+        return ERANGE;
+    }
+    if (dest == NULL || src == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("memcpy_s");
+        if (dest != NULL) {
+            (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > destMax) {
+        (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
+        SECUREC_ERROR_INVALID_RANGE("memcpy_s");
+        return ERANGE_AND_RESET;
+    }
+    if (SECUREC_MEMORY_IS_OVERLAP(dest, src, count)) {
+        (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
+        SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s");
+        return EOVERLAP_AND_RESET;
+    }
+    /* Count is 0 or dest equal src also ret EOK */
+    return EOK;
+}
+
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+    /*
+     * The fread API in windows will call memcpy_s and pass 0xffffffff to destMax.
+     * To avoid the failure of fread, we don't check desMax limit.
+     */
+#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \
+    (dest) != NULL && (src) != NULL && \
+    (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count))))
+#else
+#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \
+    (dest) != NULL && (src) != NULL && (destMax) <= SECUREC_MEM_MAX_LEN && \
+    (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count))))
+#endif
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest
+ *
+ * <INPUT PARAMETERS>
+ *    dest                      Destination buffer.
+ *    destMax                   Size of the destination buffer.
+ *    src                       Buffer to copy from.
+ *    count                     Number of characters to copy
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer               is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                      Success
+ *    EINVAL                   dest is  NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *    EINVAL_AND_RESET         dest != NULL and src is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *    ERANGE                   destMax > SECUREC_MEM_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET         count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *                             and dest  !=  NULL  and src != NULL
+ *    EOVERLAP_AND_RESET       dest buffer and source buffer are overlapped and
+ *                             count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest  !=  NULL
+ *                             and src != NULL  and dest != src
+ *
+ *    if an error occurred, dest will be filled with 0.
+ *    If the source and destination overlap, the behavior of memcpy_s is undefined.
+ *    Use memmove_s to handle overlapping regions.
+ */
+errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count)
+{
+    if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) {
+        SECUREC_MEMCPY_WARP_OPT(dest, src, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemcpyError(dest, destMax, src, count);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(memcpy_s);
+#endif
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+/*
+ * Performance optimization
+ */
+errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count)
+{
+    if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) {
+        SECUREC_MEMCPY_OPT(dest, src, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemcpyError(dest, destMax, src, count);
+}
+
+/* Trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */
+errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count)
+{
+    if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL && \
+                       count > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) {
+        SECUREC_MEMCPY_OPT(dest, src, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemcpyError(dest, destMax, src, count);
+}
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memmove_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memmove_s.c
new file mode 100644 (file)
index 0000000..ff61fca
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: memmove_s function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+#ifdef SECUREC_NOT_CALL_LIBC_CORE_API
+/*
+ * Implementing memory data movement
+ */
+SECUREC_INLINE void SecUtilMemmove(void *dst, const void *src, size_t count)
+{
+    unsigned char *pDest = (unsigned char *)dst;
+    const unsigned char *pSrc = (const unsigned char *)src;
+    size_t maxCount = count;
+
+    if (dst <= src || pDest >= (pSrc + maxCount)) {
+        /*
+         * Non-Overlapping Buffers
+         * Copy from lower addresses to higher addresses
+         */
+        while (maxCount > 0) {
+            --maxCount;
+            *pDest = *pSrc;
+            ++pDest;
+            ++pSrc;
+        }
+    } else {
+        /*
+         * Overlapping Buffers
+         * Copy from higher addresses to lower addresses
+         */
+        pDest = pDest + maxCount - 1;
+        pSrc = pSrc + maxCount - 1;
+        while (maxCount > 0) {
+            --maxCount;
+            *pDest = *pSrc;
+            --pDest;
+            --pSrc;
+        }
+    }
+}
+#endif
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The memmove_s function copies count bytes of characters from src to dest.
+ *    This function can be assigned correctly when memory overlaps.
+ * <INPUT PARAMETERS>
+ *    dest                    Destination object.
+ *    destMax                 Size of the destination buffer.
+ *    src                     Source object.
+ *    count                   Number of characters to copy.
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer             is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                     Success
+ *    EINVAL                  dest is  NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *    EINVAL_AND_RESET        dest != NULL and src is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *    ERANGE                  destMax > SECUREC_MEM_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET        count > destMax and dest  !=  NULL and src != NULL and destMax != 0
+ *                            and destMax <= SECUREC_MEM_MAX_LEN
+ *
+ *    If an error occurred, dest will  be filled with 0 when dest and destMax valid.
+ *    If some regions of the source area and the destination overlap, memmove_s
+ *    ensures that the original source bytes in the overlapping region are copied
+ *    before being overwritten.
+ */
+errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("memmove_s");
+        return ERANGE;
+    }
+    if (dest == NULL || src == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("memmove_s");
+        if (dest != NULL) {
+            (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > destMax) {
+        (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
+        SECUREC_ERROR_INVALID_RANGE("memmove_s");
+        return ERANGE_AND_RESET;
+    }
+    if (dest == src) {
+        return EOK;
+    }
+
+    if (count > 0) {
+#ifdef SECUREC_NOT_CALL_LIBC_CORE_API
+        SecUtilMemmove(dest, src, count);
+#else
+        /* Use underlying memmove for performance consideration */
+        (void)memmove(dest, src, count);
+#endif
+    }
+    return EOK;
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(memmove_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memset_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memset_s.c
new file mode 100644 (file)
index 0000000..226fb17
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: memset_s function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+#define SECUREC_MEMSET_PARAM_OK(dest, destMax, count) (SECUREC_LIKELY((destMax) <= SECUREC_MEM_MAX_LEN && \
+    (dest) != NULL && (count) <= (destMax)))
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+
+/* Use union to clear strict-aliasing warning */
+typedef union {
+    SecStrBuf32 buf32;
+    SecStrBuf31 buf31;
+    SecStrBuf30 buf30;
+    SecStrBuf29 buf29;
+    SecStrBuf28 buf28;
+    SecStrBuf27 buf27;
+    SecStrBuf26 buf26;
+    SecStrBuf25 buf25;
+    SecStrBuf24 buf24;
+    SecStrBuf23 buf23;
+    SecStrBuf22 buf22;
+    SecStrBuf21 buf21;
+    SecStrBuf20 buf20;
+    SecStrBuf19 buf19;
+    SecStrBuf18 buf18;
+    SecStrBuf17 buf17;
+    SecStrBuf16 buf16;
+    SecStrBuf15 buf15;
+    SecStrBuf14 buf14;
+    SecStrBuf13 buf13;
+    SecStrBuf12 buf12;
+    SecStrBuf11 buf11;
+    SecStrBuf10 buf10;
+    SecStrBuf9 buf9;
+    SecStrBuf8 buf8;
+    SecStrBuf7 buf7;
+    SecStrBuf6 buf6;
+    SecStrBuf5 buf5;
+    SecStrBuf4 buf4;
+    SecStrBuf3 buf3;
+    SecStrBuf2 buf2;
+} SecStrBuf32Union;
+/* C standard initializes the first member of the consortium. */
+static const SecStrBuf32 g_allZero = {{
+    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
+    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
+    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
+    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U
+}};
+static const SecStrBuf32 g_allFF = {{
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+}};
+
+/* Clear conversion warning strict aliasing" */
+SECUREC_INLINE const SecStrBuf32Union *SecStrictAliasingCast(const SecStrBuf32 *buf)
+{
+    return (const SecStrBuf32Union *)buf;
+}
+
+#ifndef SECUREC_MEMSET_THRESHOLD_SIZE
+#define SECUREC_MEMSET_THRESHOLD_SIZE 32UL
+#endif
+
+#define SECUREC_UNALIGNED_SET(dest, c, count) do { \
+    unsigned char *pDest_ = (unsigned char *)(dest); \
+    switch (count) { \
+        case 32: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 31: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 30: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 29: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 28: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 27: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 26: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 25: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 24: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 23: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 22: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 21: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 20: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 19: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 18: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 17: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 16: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 15: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 14: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 13: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 12: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 11: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 10: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 9: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 8: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 7: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 6: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 5: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 4: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 3: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 2: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        case 1: \
+            *(pDest_++) = (unsigned char)(c); \
+            /* fall-through */ /* FALLTHRU */ \
+        default: \
+            /* Do nothing */ \
+            break; \
+    } \
+} SECUREC_WHILE_ZERO
+
+#define SECUREC_SET_VALUE_BY_STRUCT(dest, dataName, n) do { \
+    *(SecStrBuf##n *)(dest) = *(const SecStrBuf##n *)(&((SecStrictAliasingCast(&(dataName)))->buf##n)); \
+} SECUREC_WHILE_ZERO
+
+#define SECUREC_ALIGNED_SET_OPT_ZERO_FF(dest, c, count) do { \
+    switch (c) { \
+        case 0: \
+            switch (count) { \
+                case 1: \
+                    *(unsigned char *)(dest) = (unsigned char)0; \
+                    break; \
+                case 2: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 2); \
+                    break; \
+                case 3: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 3); \
+                    break; \
+                case 4: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 4); \
+                    break; \
+                case 5: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 5); \
+                    break; \
+                case 6: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 6); \
+                    break; \
+                case 7: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 7); \
+                    break; \
+                case 8: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 8); \
+                    break; \
+                case 9: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 9); \
+                    break; \
+                case 10: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 10); \
+                    break; \
+                case 11: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 11); \
+                    break; \
+                case 12: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 12); \
+                    break; \
+                case 13: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 13); \
+                    break; \
+                case 14: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 14); \
+                    break; \
+                case 15: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 15); \
+                    break; \
+                case 16: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 16); \
+                    break; \
+                case 17: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 17); \
+                    break; \
+                case 18: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 18); \
+                    break; \
+                case 19: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 19); \
+                    break; \
+                case 20: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 20); \
+                    break; \
+                case 21: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 21); \
+                    break; \
+                case 22: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 22); \
+                    break; \
+                case 23: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 23); \
+                    break; \
+                case 24: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 24); \
+                    break; \
+                case 25: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 25); \
+                    break; \
+                case 26: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 26); \
+                    break; \
+                case 27: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 27); \
+                    break; \
+                case 28: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 28); \
+                    break; \
+                case 29: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 29); \
+                    break; \
+                case 30: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 30); \
+                    break; \
+                case 31: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 31); \
+                    break; \
+                case 32: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 32); \
+                    break; \
+                default: \
+                    /* Do nothing */ \
+                    break; \
+            } \
+            break; \
+        case 0xFF: \
+            switch (count) { \
+                case 1: \
+                    *(unsigned char *)(dest) = (unsigned char)0xffU; \
+                    break; \
+                case 2: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 2); \
+                    break; \
+                case 3: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 3); \
+                    break; \
+                case 4: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 4); \
+                    break; \
+                case 5: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 5); \
+                    break; \
+                case 6: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 6); \
+                    break; \
+                case 7: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 7); \
+                    break; \
+                case 8: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 8); \
+                    break; \
+                case 9: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 9); \
+                    break; \
+                case 10: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 10); \
+                    break; \
+                case 11: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 11); \
+                    break; \
+                case 12: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 12); \
+                    break; \
+                case 13: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 13); \
+                    break; \
+                case 14: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 14); \
+                    break; \
+                case 15: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 15); \
+                    break; \
+                case 16: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 16); \
+                    break; \
+                case 17: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 17); \
+                    break; \
+                case 18: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 18); \
+                    break; \
+                case 19: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 19); \
+                    break; \
+                case 20: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 20); \
+                    break; \
+                case 21: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 21); \
+                    break; \
+                case 22: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 22); \
+                    break; \
+                case 23: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 23); \
+                    break; \
+                case 24: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 24); \
+                    break; \
+                case 25: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 25); \
+                    break; \
+                case 26: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 26); \
+                    break; \
+                case 27: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 27); \
+                    break; \
+                case 28: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 28); \
+                    break; \
+                case 29: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 29); \
+                    break; \
+                case 30: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 30); \
+                    break; \
+                case 31: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 31); \
+                    break; \
+                case 32: \
+                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 32); \
+                    break; \
+                default: \
+                    /* Do nothing */ \
+                    break; \
+            } \
+            break; \
+        default: \
+            SECUREC_UNALIGNED_SET((dest), (c), (count)); \
+            break; \
+    } /* END switch */ \
+} SECUREC_WHILE_ZERO
+
+#define SECUREC_SMALL_MEM_SET(dest, c, count) do { \
+    if (SECUREC_ADDR_ALIGNED_8((dest))) { \
+        SECUREC_ALIGNED_SET_OPT_ZERO_FF((dest), (c), (count)); \
+    } else { \
+        SECUREC_UNALIGNED_SET((dest), (c), (count)); \
+    } \
+} SECUREC_WHILE_ZERO
+
+/*
+ * Performance optimization
+ */
+#define SECUREC_MEMSET_OPT(dest, c, count) do { \
+    if ((count) > SECUREC_MEMSET_THRESHOLD_SIZE) { \
+        SECUREC_MEMSET_PREVENT_DSE((dest), (c), (count)); \
+    } else { \
+        SECUREC_SMALL_MEM_SET((dest), (c), (count)); \
+    } \
+} SECUREC_WHILE_ZERO
+#endif
+
+/*
+ * Handling errors
+ */
+SECUREC_INLINE errno_t SecMemsetError(void *dest, size_t destMax, int c)
+{
+    /* Check destMax is 0 compatible with _sp macro */
+    if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("memset_s");
+        return ERANGE;
+    }
+    if (dest == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("memset_s");
+        return EINVAL;
+    }
+    SECUREC_MEMSET_PREVENT_DSE(dest, c, destMax); /* Set entire buffer to value c */
+    SECUREC_ERROR_INVALID_RANGE("memset_s");
+    return ERANGE_AND_RESET;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The memset_s function copies the value of c (converted to an unsigned char)
+ *     into each of the first count characters of the object pointed to by dest.
+ *
+ * <INPUT PARAMETERS>
+ *    dest                Pointer to destination.
+ *    destMax             The size of the buffer.
+ *    c                   Character to set.
+ *    count               Number of characters.
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer         is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                 Success
+ *    EINVAL              dest == NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
+ *    ERANGE              destMax > SECUREC_MEM_MAX_LEN or (destMax is 0 and count > destMax)
+ *    ERANGE_AND_RESET    count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL
+ *
+ *    if return ERANGE_AND_RESET then fill dest to c ,fill length is destMax
+ */
+errno_t memset_s(void *dest, size_t destMax, int c, size_t count)
+{
+    if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
+        SECUREC_MEMSET_PREVENT_DSE(dest, c, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemsetError(dest, destMax, c);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(memset_s);
+#endif
+
+#if SECUREC_WITH_PERFORMANCE_ADDONS
+/*
+ * Performance optimization
+ */
+errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count)
+{
+    if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
+        SECUREC_MEMSET_OPT(dest, c, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemsetError(dest, destMax, c);
+}
+
+/*
+ * Performance optimization, trim judgement on "destMax <= SECUREC_MEM_MAX_LEN"
+ */
+errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count)
+{
+    if (SECUREC_LIKELY(count <= destMax && dest != NULL)) {
+        SECUREC_MEMSET_OPT(dest, c, count);
+        return EOK;
+    }
+    /* Meet some runtime violation, return error code */
+    return SecMemsetError(dest, destMax, c);
+}
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/output.inl b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/output.inl
new file mode 100644 (file)
index 0000000..9392efa
--- /dev/null
@@ -0,0 +1,1720 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Used by secureprintoutput_a.c and secureprintoutput_w.c to include.
+ *              This file provides a template function for ANSI and UNICODE compiling
+ *              by different type definition. The functions of SecOutputS or
+ *              SecOutputSW  provides internal implementation for printf family API, such as sprintf, swprintf_s.
+ * Create: 2014-02-25
+ * Notes: see www.cplusplus.com/reference/cstdio/printf/
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+#ifndef OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
+#define OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
+
+#ifndef SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
+/* Some compilers do not support long double */
+#define SECUREC_ENABLE_SPRINTF_LONG_DOUBLE 1
+#endif
+
+#define SECUREC_NULL_STRING_SIZE            8
+#define SECUREC_STATE_TABLE_SIZE            337
+
+#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
+#define SECUREC_DIV_QUOTIENT_OCTAL(val64)     ((val64) >> 3ULL)
+#define SECUREC_DIV_RESIDUE_OCTAL(val64)      ((val64) & 7ULL)
+
+#define SECUREC_DIV_QUOTIENT_HEX(val64)       ((val64) >> 4ULL)
+#define SECUREC_DIV_RESIDUE_HEX(val64)        ((val64) & 0xfULL)
+#endif
+
+#define SECUREC_RADIX_OCTAL                 8U
+#define SECUREC_RADIX_DECIMAL               10U
+#define SECUREC_RADIX_HEX                   16U
+#define SECUREC_PREFIX_LEN                  2
+/* Size include '+' and '\0' */
+#define SECUREC_FLOAT_BUF_EXT               2
+
+/* Sign extend or Zero-extend */
+#define SECUREC_GET_LONG_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
+    (SecInt64)(long)va_arg(argList, long) : \
+    (SecInt64)(unsigned long)va_arg(argList, long))
+
+/* Sign extend or Zero-extend */
+#define SECUREC_GET_CHAR_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
+    SecUpdateNegativeChar(&(attr), ((char)va_arg(argList, int))) : \
+    (SecInt64)(unsigned char)va_arg(argList, int))
+
+/* Sign extend or Zero-extend */
+#define SECUREC_GET_SHORT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
+    (SecInt64)(short)va_arg(argList, int) : \
+    (SecInt64)(unsigned short)va_arg(argList, int))
+
+/* Sign extend or Zero-extend */
+#define SECUREC_GET_INT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
+    (SecInt64)(int)va_arg(argList, int) : \
+    (SecInt64)(unsigned int)va_arg(argList, int))
+
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+/* Sign extend or Zero-extend. No suitable macros were found to handle the branch */
+#define SECUREC_GET_SIZE_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
+    ((SecIsSameSize(sizeof(size_t), sizeof(long)) != 0) ? (SecInt64)(long)va_arg(argList, long) : \
+    ((SecIsSameSize(sizeof(size_t), sizeof(long long)) != 0) ? (SecInt64)(long long)va_arg(argList, long long) : \
+    (SecInt64)(int)va_arg(argList, int))) : \
+    (SecInt64)(size_t)va_arg(argList, size_t))
+#endif
+
+/* Format output buffer pointer and available size */
+typedef struct {
+    int count;
+    SecChar *cur;
+} SecPrintfStream;
+
+typedef union {
+    /* Integer formatting refers to the end of the buffer, plus 1 to prevent tool alarms */
+    char str[SECUREC_BUFFER_SIZE + 1];
+#if SECUREC_HAVE_WCHART
+    wchar_t wStr[SECUREC_WCHAR_BUFFER_SIZE]; /* Just for %lc */
+#endif
+} SecBuffer;
+
+typedef union {
+    char *str;                  /* Not a null terminated  string */
+#if SECUREC_HAVE_WCHART
+    wchar_t *wStr;
+#endif
+} SecFormatBuf;
+
+typedef struct {
+    const char *digits;                 /* Point to the hexadecimal subset */
+    SecFormatBuf text;                  /* Point to formatted string */
+    int textLen;                        /* Length of the text */
+    int textIsWide;                     /* Flag for text is wide chars ; 0 is not wide char */
+    unsigned int radix;                 /* Use for output number , default set to 10 */
+    unsigned int flags;
+    int fldWidth;
+    int precision;
+    int dynWidth;                       /* %*   1 width from variable parameter ;0 not */
+    int dynPrecision;                   /* %.*  1 precision from variable parameter ;0 not */
+    int padding;                        /* Padding len */
+    int prefixLen;                      /* Length of prefix, 0 or 1 or 2 */
+    SecChar prefix[SECUREC_PREFIX_LEN]; /* Prefix is  0 or 0x */
+    SecBuffer buffer;
+} SecFormatAttr;
+
+#if SECUREC_ENABLE_SPRINTF_FLOAT
+#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K
+#define SECUREC_FMT_STR_LEN                 8
+#else
+#define SECUREC_FMT_STR_LEN                 16
+#endif
+typedef struct {
+    char buffer[SECUREC_FMT_STR_LEN];
+    char *fmtStr;                     /* Initialization must point to buffer */
+    char *allocatedFmtStr;            /* Initialization must be NULL  to store allocated point */
+    char *floatBuffer;                /* Use heap memory if the SecFormatAttr.buffer is not enough */
+    int bufferSize;                   /* The size of floatBuffer */
+} SecFloatAdapt;
+#endif
+
+/* Use 20 to Align the data */
+#define SECUREC_DIGITS_BUF_SIZE  20
+/* The serial number of 'x' or 'X' is 16 */
+#define SECUREC_NUMBER_OF_X  16
+/* Some systems can not use pointers to point to string literals, but can use string arrays. */
+/* For example, when handling code under uboot, there is a problem with the pointer */
+static const char g_itoaUpperDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789ABCDEFX";
+static const char g_itoaLowerDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789abcdefx";
+
+#if SECUREC_ENABLE_SPRINTF_FLOAT
+/* Call system sprintf to format float value */
+SECUREC_INLINE int SecFormatFloat(char *strDest, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    SECUREC_MASK_VSPRINTF_WARNING
+    ret = vsprintf(strDest, format, argList);
+    SECUREC_END_MASK_VSPRINTF_WARNING
+    va_end(argList);
+    (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
+#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
+/* Out put long double value to dest */
+SECUREC_INLINE void SecFormatLongDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, long double ldValue)
+{
+    int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
+    if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, ldValue);
+    } else if (attr->dynWidth != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, ldValue);
+    } else if (attr->dynPrecision != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, ldValue);
+    } else {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, ldValue);
+    }
+    if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
+        attr->textLen = 0;
+    }
+}
+#endif
+
+/* Out put double value to dest */
+SECUREC_INLINE void SecFormatDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, double dValue)
+{
+    int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
+    if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, dValue);
+    } else if (attr->dynWidth != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, dValue);
+    } else if (attr->dynPrecision != 0) {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, dValue);
+    } else {
+        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, dValue);
+    }
+    if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
+        attr->textLen = 0;
+    }
+}
+#endif
+
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+/* To clear e506 warning */
+SECUREC_INLINE int SecIsSameSize(size_t sizeA, size_t sizeB)
+{
+    return (int)(sizeA == sizeB);
+}
+#endif
+
+#ifndef SECUREC_ON_64BITS
+/*
+ * Compiler Optimized Division 8.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber32ToOctalString(SecUnsignedInt32 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt32 val32 = number;
+    do {
+        --attr->text.str;
+        /* Just use lowerDigits for 0 - 9 */
+        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_OCTAL];
+        val32 /= SECUREC_RADIX_OCTAL;
+    } while (val32 != 0);
+}
+
+#ifdef _AIX
+/*
+ * Compiler Optimized Division 10.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber32ToDecString(SecUnsignedInt32 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt32 val32 = number;
+    do {
+        --attr->text.str;
+        /* Just use lowerDigits for 0 - 9 */
+        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
+        val32 /= SECUREC_RADIX_DECIMAL;
+    } while (val32 != 0);
+}
+#endif
+/*
+ * Compiler Optimized Division 16.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber32ToHexString(SecUnsignedInt32 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt32 val32 = number;
+    do {
+        --attr->text.str;
+        *(attr->text.str) = attr->digits[val32 % SECUREC_RADIX_HEX];
+        val32 /= SECUREC_RADIX_HEX;
+    } while (val32 != 0);
+}
+
+#ifndef _AIX
+/* Use fast div 10 */
+SECUREC_INLINE void SecNumber32ToDecStringFast(SecUnsignedInt32 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt32 val32 = number;
+    do {
+        SecUnsignedInt32 quotient;
+        SecUnsignedInt32 remain;
+        --attr->text.str;
+        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
+        quotient = (val32 >> 1U) + (val32 >> 2U); /* Fast div  magic 2 */
+        quotient = quotient + (quotient >> 4U); /* Fast div  magic 4 */
+        quotient = quotient + (quotient >> 8U); /* Fast div  magic 8 */
+        quotient = quotient + (quotient >> 16U); /* Fast div  magic 16 */
+        quotient = quotient >> 3U; /* Fast div  magic 3 */
+        remain = val32 - SECUREC_MUL_TEN(quotient);
+        val32 = (remain > 9U) ? (quotient + 1U) : quotient; /* Fast div  magic 9 */
+    } while (val32 != 0);
+}
+#endif
+
+SECUREC_INLINE void SecNumber32ToString(SecUnsignedInt32 number, SecFormatAttr *attr)
+{
+    switch (attr->radix) {
+        case SECUREC_RADIX_HEX:
+            SecNumber32ToHexString(number, attr);
+            break;
+        case SECUREC_RADIX_OCTAL:
+            SecNumber32ToOctalString(number, attr);
+            break;
+        case SECUREC_RADIX_DECIMAL:
+#ifdef _AIX
+            /* The compiler will optimize div 10 */
+            SecNumber32ToDecString(number, attr);
+#else
+            SecNumber32ToDecStringFast(number, attr);
+#endif
+            break;
+        default:
+            /* Do nothing */
+            break;
+    }
+}
+#endif
+
+#if defined(SECUREC_USE_SPECIAL_DIV64) || (defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS))
+/*
+ * This function just to clear warning, on sume vxworks compiler shift 32 bit make warnings
+ */
+SECUREC_INLINE SecUnsignedInt64 SecU64Shr32(SecUnsignedInt64 number)
+{
+    return (((number) >> 16U) >> 16U); /* Two shifts of 16 bits to realize shifts of 32 bits */
+}
+/*
+ * Fast divide by 10 algorithm.
+ * Calculation divisor multiply  0xcccccccccccccccdULL, resultHi64 >> 3 as quotient
+ */
+SECUREC_INLINE void SecU64Div10(SecUnsignedInt64 divisor, SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
+{
+    SecUnsignedInt64 mask = 0xffffffffULL; /* Use 0xffffffffULL as 32 bit mask */
+    SecUnsignedInt64 magicHi = 0xccccccccULL; /* Fast divide 10 magic numbers high 32bit 0xccccccccULL */
+    SecUnsignedInt64 magicLow = 0xcccccccdULL; /* Fast divide 10 magic numbers low 32bit  0xcccccccdULL */
+    SecUnsignedInt64 divisorHi = (SecUnsignedInt64)(SecU64Shr32(divisor)); /* High 32 bit use  */
+    SecUnsignedInt64 divisorLow = (SecUnsignedInt64)(divisor & mask); /* Low 32 bit mask */
+    SecUnsignedInt64 factorHi = divisorHi * magicHi;
+    SecUnsignedInt64 factorLow1 = divisorHi * magicLow;
+    SecUnsignedInt64 factorLow2 = divisorLow * magicHi;
+    SecUnsignedInt64 factorLow3 = divisorLow * magicLow;
+    SecUnsignedInt64 carry = (factorLow1 & mask) + (factorLow2 & mask) + SecU64Shr32(factorLow3);
+    SecUnsignedInt64 resultHi64 = factorHi + SecU64Shr32(factorLow1) + SecU64Shr32(factorLow2) + SecU64Shr32(carry);
+
+    *quotient = resultHi64 >> 3U; /* Fast divide 10 magic numbers 3 */
+    *residue = (SecUnsignedInt32)(divisor - ((*quotient) * 10)); /* Quotient mul 10 */
+    return;
+}
+#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
+/*
+ * Divide function for VXWORKS
+ */
+SECUREC_INLINE int SecU64Div32(SecUnsignedInt64 divisor, SecUnsignedInt32 radix,
+    SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
+{
+    switch (radix) {
+        case SECUREC_RADIX_DECIMAL:
+            SecU64Div10(divisor, quotient, residue);
+            break;
+        case SECUREC_RADIX_HEX:
+            *quotient = SECUREC_DIV_QUOTIENT_HEX(divisor);
+            *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_HEX(divisor);
+            break;
+        case SECUREC_RADIX_OCTAL:
+            *quotient = SECUREC_DIV_QUOTIENT_OCTAL(divisor);
+            *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_OCTAL(divisor);
+            break;
+        default:
+            return -1; /* This does not happen in the current file */
+    }
+    return 0;
+}
+SECUREC_INLINE void SecNumber64ToStringSpecial(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt64 val64 = number;
+    do {
+        SecUnsignedInt32 digit = 0; /* Ascii value of digit */
+        SecUnsignedInt64 quotient = 0;
+        if (SecU64Div32(val64, (SecUnsignedInt32)attr->radix, &quotient, &digit) != 0) {
+            /* Just break, when enter this function, no error is returned */
+            break;
+        }
+        --attr->text.str;
+        *(attr->text.str) = attr->digits[digit];
+        val64 = quotient;
+    } while (val64 != 0);
+}
+#endif
+#endif
+
+#if defined(SECUREC_ON_64BITS) || !defined(SECUREC_VXWORKS_VERSION_5_4)
+#if defined(SECUREC_USE_SPECIAL_DIV64)
+/* The compiler does not provide 64 bit division problems */
+SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt64 val64 = number;
+    do {
+        SecUnsignedInt64 quotient = 0;
+        SecUnsignedInt32 digit = 0;
+        SecU64Div10(val64, &quotient, &digit);
+        --attr->text.str;
+        /* Just use lowerDigits for 0 - 9 */
+        *(attr->text.str) = g_itoaLowerDigits[digit];
+        val64 = quotient;
+    } while (val64 != 0);
+}
+#else
+/*
+ * Compiler Optimized Division 10.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt64 val64 = number;
+    do {
+        --attr->text.str;
+        /* Just use lowerDigits for 0 - 9 */
+        *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_DECIMAL];
+        val64 /= SECUREC_RADIX_DECIMAL;
+    } while (val64 != 0);
+}
+#endif
+
+/*
+ * Compiler Optimized Division 8.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber64ToOctalString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt64 val64 = number;
+    do {
+        --attr->text.str;
+        /* Just use lowerDigits for 0 - 9 */
+        *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_OCTAL];
+        val64 /= SECUREC_RADIX_OCTAL;
+    } while (val64 != 0);
+}
+/*
+ * Compiler Optimized Division 16.
+ * The text.str point to buffer end, must be Large enough
+ */
+SECUREC_INLINE void SecNumber64ToHexString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    SecUnsignedInt64 val64 = number;
+    do {
+        --attr->text.str;
+        *(attr->text.str) = attr->digits[val64 % SECUREC_RADIX_HEX];
+        val64 /= SECUREC_RADIX_HEX;
+    } while (val64 != 0);
+}
+
+SECUREC_INLINE void SecNumber64ToString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+    switch (attr->radix) {
+        /* The compiler will optimize div 10 */
+        case SECUREC_RADIX_DECIMAL:
+            SecNumber64ToDecString(number, attr);
+            break;
+        case SECUREC_RADIX_OCTAL:
+            SecNumber64ToOctalString(number, attr);
+            break;
+        case SECUREC_RADIX_HEX:
+            SecNumber64ToHexString(number, attr);
+            break;
+        default:
+            /* Do nothing */
+            break;
+    }
+}
+#endif
+
+/*
+ * Converting integers to string
+ */
+SECUREC_INLINE void SecNumberToString(SecUnsignedInt64 number, SecFormatAttr *attr)
+{
+#ifdef SECUREC_ON_64BITS
+    SecNumber64ToString(number, attr);
+#else /* For 32 bits system */
+    if (number <= 0xffffffffUL) { /* Use 0xffffffffUL to check if the value is in the 32-bit range */
+        /* In most case, the value to be converted is small value */
+        SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number;
+        SecNumber32ToString(n32Tmp, attr);
+    } else {
+        /* The value to be converted is greater than 4G */
+#if defined(SECUREC_VXWORKS_VERSION_5_4)
+        SecNumber64ToStringSpecial(number, attr);
+#else
+        SecNumber64ToString(number, attr);
+#endif
+    }
+#endif
+}
+
+SECUREC_INLINE int SecIsNumberNeedTo32Bit(const SecFormatAttr *attr)
+{
+    return (int)(((attr->flags & SECUREC_FLAG_I64) == 0) &&
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+            ((attr->flags & SECUREC_FLAG_INTMAX) == 0) &&
+#endif
+#ifdef SECUREC_ON_64BITS
+            ((attr->flags & SECUREC_FLAG_PTRDIFF) == 0) &&
+            ((attr->flags & SECUREC_FLAG_SIZE) == 0) &&
+#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT)  /* on window 64 system sizeof long is 32bit */
+            ((attr->flags & SECUREC_FLAG_LONG) == 0) &&
+#endif
+#endif
+            ((attr->flags & SECUREC_FLAG_LONGLONG) == 0));
+}
+
+SECUREC_INLINE void SecNumberToBuffer(SecFormatAttr *attr, SecInt64 num64)
+{
+    SecUnsignedInt64 number;
+    /* Check for negative; copy into number */
+    if ((attr->flags & SECUREC_FLAG_SIGNED) != 0 && num64 < 0) {
+        number = (SecUnsignedInt64)(0 - (SecUnsignedInt64)num64); /* Wrap with unsigned int64 numbers */
+        attr->flags |= SECUREC_FLAG_NEGATIVE;
+    } else {
+        number = (SecUnsignedInt64)num64;
+    }
+    if (SecIsNumberNeedTo32Bit(attr) != 0) {
+        number = (number & (SecUnsignedInt64)0xffffffffUL);  /* Use 0xffffffff as 32 bit mask */
+    }
+
+    /* The text.str must be point to buffer.str, this pointer is used outside the function */
+    attr->text.str = &attr->buffer.str[SECUREC_BUFFER_SIZE];
+
+    if (number == 0) {
+        /* Turn off hex prefix default, and textLen is zero */
+        attr->prefixLen = 0;
+        attr->textLen = 0;
+        return;
+    }
+
+    /* Convert integer to string. It must be invoked when number > 0, otherwise the following logic is incorrect */
+    SecNumberToString(number, attr);
+    /* Compute length of number,  text.str must be in buffer.str */
+    attr->textLen = (int)(size_t)((char *)&attr->buffer.str[SECUREC_BUFFER_SIZE] - attr->text.str);
+}
+
+/*
+ * Write one character to dest buffer
+ */
+SECUREC_INLINE void SecWriteChar(SecPrintfStream *stream, SecChar ch, int *charsOut)
+{
+    /* Count must be reduced first, In order to identify insufficient length */
+    --stream->count;
+    if (stream->count >= 0) {
+        *(stream->cur) = ch;
+        ++stream->cur;
+        *charsOut = *charsOut + 1;
+        return;
+    }
+    /* No enough length */
+    *charsOut = -1;
+}
+
+/*
+* Write multiple identical characters.
+*/
+SECUREC_INLINE void SecWriteMultiChar(SecPrintfStream *stream, SecChar ch, int num, int *charsOut)
+{
+    int count;
+    for (count = num; count > 0; --count) {
+        --stream->count; /* count may be negative,indicating insufficient space */
+        if (stream->count < 0) {
+            *charsOut = -1;
+            return;
+        }
+        *(stream->cur) = ch;
+        ++stream->cur;
+    }
+    *charsOut = *charsOut + num;
+}
+
+/*
+* Write string function, where this function is called, make sure that len is greater than 0
+*/
+SECUREC_INLINE void SecWriteString(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
+{
+    const SecChar *tmp = str;
+    int count;
+    for (count = len; count > 0; --count) {
+        --stream->count; /* count may be negative,indicating insufficient space */
+        if (stream->count < 0) {
+            *charsOut = -1;
+            return;
+        }
+        *(stream->cur) = *tmp;
+        ++stream->cur;
+        ++tmp;
+    }
+    *charsOut = *charsOut + len;
+}
+
+/* Use loop copy char or wchar_t string */
+SECUREC_INLINE void SecWriteStringByLoop(SecPrintfStream *stream, const SecChar *str, int len)
+{
+    int i;
+    const SecChar *tmp = str;
+    for (i = 0; i < len; ++i) {
+        *stream->cur = *tmp;
+        ++stream->cur;
+        ++tmp;
+    }
+    stream->count -= len;
+}
+
+SECUREC_INLINE void SecWriteStringOpt(SecPrintfStream *stream, const SecChar *str, int len)
+{
+    if (len < 12) { /* Performance optimization for mobile number length 12 */
+        SecWriteStringByLoop(stream, str, len);
+    } else {
+        size_t count = (size_t)(unsigned int)len * sizeof(SecChar);
+        SECUREC_MEMCPY_WARP_OPT(stream->cur, str, count);
+        stream->cur += len;
+        stream->count -= len;
+    }
+}
+
+/*
+ * Return if buffer length is enough
+ * The count variable can be reduced to 0, and the external function complements the \0 terminator.
+ */
+SECUREC_INLINE int SecIsStreamBufEnough(const SecPrintfStream *stream, int needLen)
+{
+    return (int)(stream->count >= needLen);
+}
+
+/* Write text string */
+SECUREC_INLINE void SecWriteTextOpt(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
+{
+    if (SecIsStreamBufEnough(stream, len) != 0) {
+        SecWriteStringOpt(stream, str, len);
+        *charsOut += len;
+    } else {
+        SecWriteString(stream, str, len, charsOut);
+    }
+}
+
+/* Write left padding */
+SECUREC_INLINE void SecWriteLeftPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    if ((attr->flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) == 0 && attr->padding > 0) {
+        /* Pad on left with blanks */
+        SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
+    }
+}
+
+/* Write prefix */
+SECUREC_INLINE void SecWritePrefix(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    if (attr->prefixLen > 0) {
+        SecWriteString(stream, attr->prefix, attr->prefixLen, charsOut);
+    }
+}
+
+/* Write leading zeros */
+SECUREC_INLINE void SecWriteLeadingZero(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    if ((attr->flags & SECUREC_FLAG_LEADZERO) != 0 && (attr->flags & SECUREC_FLAG_LEFT) == 0 &&
+        attr->padding > 0) {
+        SecWriteMultiChar(stream, SECUREC_CHAR('0'), attr->padding, charsOut);
+    }
+}
+
+/* Write right padding */
+SECUREC_INLINE void SecWriteRightPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    if (*charsOut >= 0 && (attr->flags & SECUREC_FLAG_LEFT) != 0 && attr->padding > 0) {
+        /* Pad on right with blanks */
+        SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
+    }
+}
+
+#ifdef SECUREC_FOR_WCHAR
+#define SECUREC_TEXT_CHAR_PTR(text)  ((text).wStr)
+#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide == 0)
+#if SECUREC_HAVE_MBTOWC
+#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterMbtowc((stream), (attr), (charsOut))
+#else
+#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
+#endif
+#else
+#define SECUREC_TEXT_CHAR_PTR(text)  ((text).str)
+#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide != 0)
+#if SECUREC_HAVE_WCTOMB
+#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterWctomb((stream), (attr), (charsOut))
+#else
+#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
+#endif
+#endif
+
+#ifdef SECUREC_FOR_WCHAR
+#if SECUREC_HAVE_MBTOWC
+SECUREC_INLINE void SecWriteTextAfterMbtowc(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    const char *p = attr->text.str;
+    int count = attr->textLen;
+    while (count > 0) {
+        wchar_t wChar = L'\0';
+        int retVal = mbtowc(&wChar, p, (size_t)MB_CUR_MAX);
+        if (retVal <= 0) {
+            *charsOut = -1;
+            break;
+        }
+        SecWriteChar(stream, wChar, charsOut);
+        if (*charsOut == -1) {
+            break;
+        }
+        p += retVal;
+        count -= retVal;
+    }
+}
+#endif
+#else  /* Not SECUREC_FOR_WCHAR */
+#if SECUREC_HAVE_WCTOMB
+SECUREC_INLINE void SecWriteTextAfterWctomb(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    const wchar_t *p = attr->text.wStr;
+    int count = attr->textLen;
+    while (count > 0) {
+        char tmpBuf[SECUREC_MB_LEN + 1];
+        SECUREC_MASK_MSVC_CRT_WARNING
+        int retVal = wctomb(tmpBuf, *p);
+        SECUREC_END_MASK_MSVC_CRT_WARNING
+        if (retVal <= 0) {
+            *charsOut = -1;
+            break;
+        }
+        SecWriteString(stream, tmpBuf, retVal, charsOut);
+        if (*charsOut == -1) {
+            break;
+        }
+        --count;
+        ++p;
+    }
+}
+#endif
+#endif
+
+#if SECUREC_ENABLE_SPRINTF_FLOAT
+/*
+ * Write text of float
+ * Using independent functions to optimize the expansion of inline functions by the compiler
+ */
+SECUREC_INLINE void SecWriteFloatText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+#ifdef SECUREC_FOR_WCHAR
+#if SECUREC_HAVE_MBTOWC
+    SecWriteTextAfterMbtowc(stream, attr, charsOut);
+#else
+    *charsOut = -1;
+    (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */
+    (void)attr;   /* To clear e438 last value assigned not used , the compiler will optimize this code */
+#endif
+#else /* Not SECUREC_FOR_WCHAR */
+    SecWriteString(stream, attr->text.str, attr->textLen, charsOut);
+#endif
+}
+#endif
+
+/* Write text of integer or string ... */
+SECUREC_INLINE void SecWriteText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
+{
+    if (SECUREC_NEED_CONVERT_TEXT(attr)) {
+        SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut);
+    } else {
+        SecWriteTextOpt(stream, SECUREC_TEXT_CHAR_PTR(attr->text), attr->textLen, charsOut);
+    }
+}
+
+#define SECUREC_FMT_STATE_OFFSET  256
+
+SECUREC_INLINE SecFmtState SecDecodeState(SecChar ch, SecFmtState lastState)
+{
+    static const unsigned char stateTable[SECUREC_STATE_TABLE_SIZE] = {
+        /*
+         * Type
+         * 0:    nospecial meaning;
+         * 1:    '%'
+         * 2:    '.'
+         * 3:    '*'
+         * 4:    '0'
+         * 5:    '1' ... '9'
+         * 6:    ' ', '+', '-', '#'
+         * 7:    'h', 'l', 'L', 'w' , 'N', 'z', 'q', 't', 'j'
+         * 8:    'd', 'o', 'u', 'i', 'x', 'X', 'e', 'f', 'g', 'E', 'F', 'G', 's', 'c', '[', 'p'
+         */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00,
+        0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
+        0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08,
+        0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* Fill zero  for normal char 128 byte for 0x80 - 0xff */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /*
+         * State
+         * 0: normal
+         * 1: percent
+         * 2: flag
+         * 3: width
+         * 4: dot
+         * 5: precis
+         * 6: size
+         * 7: type
+         * 8: invalid
+         */
+        0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05,
+        0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03,
+        0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+        0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00,
+        0x00
+    };
+
+#ifdef SECUREC_FOR_WCHAR
+    /* Convert to unsigned char to clear gcc 4.3.4 warning */
+    unsigned char fmtType = (unsigned char)((((unsigned int)(int)(ch)) <= (unsigned int)(int)(L'~')) ? \
+        (stateTable[(unsigned char)(ch)]) : 0);
+    return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
+        (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
+#else
+    unsigned char fmtType = stateTable[(unsigned char)(ch)];
+    return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
+        (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
+#endif
+}
+
+SECUREC_INLINE void SecDecodeFlags(SecChar ch, SecFormatAttr *attr)
+{
+    switch (ch) {
+        case SECUREC_CHAR(' '):
+            attr->flags |= SECUREC_FLAG_SIGN_SPACE;
+            break;
+        case SECUREC_CHAR('+'):
+            attr->flags |= SECUREC_FLAG_SIGN;
+            break;
+        case SECUREC_CHAR('-'):
+            attr->flags |= SECUREC_FLAG_LEFT;
+            break;
+        case SECUREC_CHAR('0'):
+            attr->flags |= SECUREC_FLAG_LEADZERO;   /* Add zero th the front */
+            break;
+        case SECUREC_CHAR('#'):
+            attr->flags |= SECUREC_FLAG_ALTERNATE;  /* Output %x with 0x */
+            break;
+        default:
+            /* Do nothing */
+            break;
+    }
+    return;
+}
+
+/*
+ * Decoded size identifier in format string to Reduce the number of lines of function code
+ */
+SECUREC_INLINE int SecDecodeSizeI(SecFormatAttr *attr, const SecChar **format)
+{
+#ifdef SECUREC_ON_64BITS
+    attr->flags |= SECUREC_FLAG_I64;    /* %I  to  INT64 */
+#endif
+    if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) {
+        (*format) += 2; /* Add 2 to skip I64 */
+        attr->flags |= SECUREC_FLAG_I64;    /* %I64  to  INT64 */
+    } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) {
+        (*format) += 2; /* Add 2 to skip I32 */
+        attr->flags &= ~SECUREC_FLAG_I64;   /* %I64  to  INT32 */
+    } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) ||
+        (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) ||
+        (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) {
+        /* Do nothing */
+    } else {
+        /* Compatibility  code for "%I" just print I */
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Decoded size identifier in format string, and skip format to next charater
+ */
+SECUREC_INLINE int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format)
+{
+    switch (ch) {
+        case SECUREC_CHAR('l'):
+            if (**format == SECUREC_CHAR('l')) {
+                *format = *format + 1;
+                attr->flags |= SECUREC_FLAG_LONGLONG; /* For long long */
+            } else {
+                attr->flags |= SECUREC_FLAG_LONG;     /* For long int or wchar_t */
+            }
+            break;
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+        case SECUREC_CHAR('z'): /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('Z'):
+            attr->flags |= SECUREC_FLAG_SIZE;
+            break;
+        case SECUREC_CHAR('j'):
+            attr->flags |= SECUREC_FLAG_INTMAX;
+            break;
+#endif
+        case SECUREC_CHAR('t'):
+            attr->flags |= SECUREC_FLAG_PTRDIFF;
+            break;
+        case SECUREC_CHAR('q'): /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('L'):
+            attr->flags |= (SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE);
+            break;
+        case SECUREC_CHAR('I'):
+            if (SecDecodeSizeI(attr, format) != 0) {
+                /* Compatibility  code for "%I" just print I */
+                return -1;
+            }
+            break;
+        case SECUREC_CHAR('h'):
+            if (**format == SECUREC_CHAR('h')) {
+                *format = *format + 1;
+                attr->flags |= SECUREC_FLAG_CHAR;   /* For char */
+            } else {
+                attr->flags |= SECUREC_FLAG_SHORT;  /* For short int */
+            }
+            break;
+        case SECUREC_CHAR('w'):
+            attr->flags |= SECUREC_FLAG_WIDECHAR;   /* For wide char */
+            break;
+        default:
+            /* Do nothing */
+            break;
+    }
+    return 0;
+}
+
+/*
+ * Decoded char type identifier
+ */
+SECUREC_INLINE void SecDecodeTypeC(SecFormatAttr *attr, unsigned int c)
+{
+    attr->textLen = 1; /* Only 1 wide character */
+
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS))
+    attr->flags &= ~SECUREC_FLAG_LEADZERO;
+#endif
+
+#ifdef SECUREC_FOR_WCHAR
+    if ((attr->flags & SECUREC_FLAG_SHORT) != 0) {
+        /* Get  multibyte character from argument */
+        attr->buffer.str[0] = (char)c;
+        attr->text.str = attr->buffer.str;
+        attr->textIsWide = 0;
+    } else {
+        attr->buffer.wStr[0] = (wchar_t)c;
+        attr->text.wStr = attr->buffer.wStr;
+        attr->textIsWide = 1;
+    }
+#else /* Not SECUREC_FOR_WCHAR */
+    if ((attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) != 0) {
+#if SECUREC_HAVE_WCHART
+        attr->buffer.wStr[0] = (wchar_t)c;
+        attr->text.wStr = attr->buffer.wStr;
+        attr->textIsWide = 1;
+#else
+        attr->textLen = 0; /* Ignore unsupported characters */
+        attr->fldWidth = 0; /* No paddings  */
+#endif
+    } else {
+        /* Get  multibyte character from argument */
+        attr->buffer.str[0] = (char)c;
+        attr->text.str = attr->buffer.str;
+        attr->textIsWide = 0;
+    }
+#endif
+}
+
+#ifdef SECUREC_FOR_WCHAR
+#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & SECUREC_FLAG_SHORT) != 0)
+#else
+#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0)
+#endif
+
+SECUREC_INLINE void SecDecodeTypeSchar(SecFormatAttr *attr)
+{
+    size_t textLen;
+    if (attr->text.str == NULL) {
+        /*
+         * Literal string to print null ptr, define it as array rather than const text area
+         * To avoid gcc warning with pointing const text with variable
+         */
+        static char strNullString[SECUREC_NULL_STRING_SIZE] = "(null)";
+        attr->text.str = strNullString;
+    }
+    if (attr->precision == -1) {
+        /* Precision NOT assigned */
+        /* The strlen performance is high when the string length is greater than 32 */
+        textLen = strlen(attr->text.str);
+        if (textLen > SECUREC_STRING_MAX_LEN) {
+            textLen = 0;
+        }
+    } else {
+        /* Precision assigned */
+        SECUREC_CALC_STR_LEN(attr->text.str, (size_t)(unsigned int)attr->precision, &textLen);
+    }
+    attr->textLen = (int)textLen;
+}
+
+SECUREC_INLINE void SecDecodeTypeSwchar(SecFormatAttr *attr)
+{
+#if SECUREC_HAVE_WCHART
+    size_t textLen;
+    attr->textIsWide = 1;
+    if (attr->text.wStr == NULL) {
+        /*
+         * Literal string to print null ptr, define it as array rather than const text area
+         * To avoid gcc warning with pointing const text with variable
+         */
+        static wchar_t wStrNullString[SECUREC_NULL_STRING_SIZE] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' };
+        attr->text.wStr = wStrNullString;
+    }
+    /* The textLen in wchar_t,when precision is -1, it is unlimited  */
+    SECUREC_CALC_WSTR_LEN(attr->text.wStr, (size_t)(unsigned int)attr->precision, &textLen);
+    if (textLen > SECUREC_WCHAR_STRING_MAX_LEN) {
+        textLen = 0;
+    }
+    attr->textLen = (int)textLen;
+#else
+    attr->textLen = 0;
+#endif
+}
+
+/*
+ * Decoded string identifier
+ */
+SECUREC_INLINE void SecDecodeTypeS(SecFormatAttr *attr, char *argPtr)
+{
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT))
+#if (!defined(SECUREC_ON_UNIX))
+    attr->flags &= ~SECUREC_FLAG_LEADZERO;
+#endif
+#if (defined(SECUREC_FOR_WCHAR))
+    if ((attr->flags & SECUREC_FLAG_LONG) == 0) {
+        attr->flags |= SECUREC_FLAG_SHORT;
+    }
+#endif
+#endif
+    attr->text.str = argPtr;
+    if (SECUREC_IS_NARROW_STRING(attr)) {
+        /* The textLen now contains length in multibyte chars */
+        SecDecodeTypeSchar(attr);
+    } else {
+        /* The textLen now contains length in wide chars */
+        SecDecodeTypeSwchar(attr);
+    }
+}
+
+/*
+ * Check precision in format
+ */
+SECUREC_INLINE int SecDecodePrecision(SecChar ch, SecFormatAttr *attr)
+{
+    if (attr->dynPrecision == 0) {
+        /* Add digit to current precision */
+        if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->precision)) {
+            return -1;
+        }
+        attr->precision = (int)SECUREC_MUL_TEN((unsigned int)attr->precision) +
+            (unsigned char)(ch - SECUREC_CHAR('0'));
+    } else {
+        if (attr->precision < 0) {
+            attr->precision = -1;
+        }
+        if (attr->precision > SECUREC_MAX_WIDTH_LEN) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Check width in format
+ */
+SECUREC_INLINE int SecDecodeWidth(SecChar ch, SecFormatAttr *attr, SecFmtState lastState)
+{
+    if (attr->dynWidth == 0) {
+        if (lastState != STAT_WIDTH) {
+            attr->fldWidth = 0;
+        }
+        if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->fldWidth)) {
+            return -1;
+        }
+        attr->fldWidth = (int)SECUREC_MUL_TEN((unsigned int)attr->fldWidth) +
+            (unsigned char)(ch - SECUREC_CHAR('0'));
+    } else {
+        if (attr->fldWidth < 0) {
+            attr->flags |= SECUREC_FLAG_LEFT;
+            attr->fldWidth = (-attr->fldWidth);
+        }
+        if (attr->fldWidth > SECUREC_MAX_WIDTH_LEN) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * The sprintf_s function processes the wide character as a parameter for %C
+ * The swprintf_s function processes the multiple character as a parameter for %C
+ */
+SECUREC_INLINE void SecUpdateWcharFlags(SecFormatAttr *attr)
+{
+    if ((attr->flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0) {
+#ifdef SECUREC_FOR_WCHAR
+        attr->flags |= SECUREC_FLAG_SHORT;
+#else
+        attr->flags |= SECUREC_FLAG_WIDECHAR;
+#endif
+    }
+}
+/*
+ * When encountering %S, current just same as %C
+ */
+SECUREC_INLINE void SecUpdateWstringFlags(SecFormatAttr *attr)
+{
+    SecUpdateWcharFlags(attr);
+}
+
+#if SECUREC_IN_KERNEL
+SECUREC_INLINE void SecUpdatePointFlagsForKernel(SecFormatAttr *attr)
+{
+    /* Width is not set */
+    if (attr->fldWidth <= 0) {
+        attr->flags |= SECUREC_FLAG_LEADZERO;
+        attr->fldWidth = 2 * sizeof(void *);  /* 2 x byte number is the length of hex */
+    }
+    if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+        /* Alternate form means '0x' prefix */
+        attr->prefix[0] = SECUREC_CHAR('0');
+        attr->prefix[1] = SECUREC_CHAR('x');
+        attr->prefixLen = SECUREC_PREFIX_LEN;
+    }
+    attr->flags |= SECUREC_FLAG_LONG;  /* Converting a long */
+}
+#endif
+
+SECUREC_INLINE void SecUpdatePointFlags(SecFormatAttr *attr)
+{
+    attr->flags |= SECUREC_FLAG_POINTER;
+#if SECUREC_IN_KERNEL
+    SecUpdatePointFlagsForKernel(attr);
+#else
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX))
+#if defined(SECUREC_VXWORKS_PLATFORM)
+    attr->precision = 1;
+#else
+    attr->precision = 0;
+#endif
+    attr->flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */
+    attr->digits = g_itoaLowerDigits;
+#else /* On unix or win */
+#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
+    attr->precision = 1;
+#else
+    attr->precision = 2 * sizeof(void *);  /* 2 x byte number is the length of hex */
+#endif
+#if defined(SECUREC_ON_UNIX)
+    attr->digits = g_itoaLowerDigits;
+#else
+    attr->digits = g_itoaUpperDigits;
+#endif
+#endif
+
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+    attr->flags &= ~SECUREC_FLAG_LEADZERO;
+#endif
+
+#ifdef SECUREC_ON_64BITS
+    attr->flags |= SECUREC_FLAG_I64;   /* Converting an int64 */
+#else
+    attr->flags |= SECUREC_FLAG_LONG;  /* Converting a long */
+#endif
+    /* Set up for %#p on different system */
+    if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+        /* Alternate form means '0x' prefix */
+        attr->prefix[0] = SECUREC_CHAR('0');
+#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM))
+        attr->prefix[1] = SECUREC_CHAR('x');
+#else
+        attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
+#endif
+#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
+        attr->prefixLen = 0;
+#else
+        attr->prefixLen = SECUREC_PREFIX_LEN;
+#endif
+    }
+#endif
+}
+
+SECUREC_INLINE void SecUpdateXpxFlags(SecFormatAttr *attr, SecChar ch)
+{
+    /* Use unsigned lower hex output for 'x' */
+    attr->digits = g_itoaLowerDigits;
+    attr->radix = SECUREC_RADIX_HEX;
+    switch (ch) {
+        case SECUREC_CHAR('p'):
+            /* Print a pointer */
+            SecUpdatePointFlags(attr);
+            break;
+        case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
+            /* Unsigned upper hex output */
+            attr->digits = g_itoaUpperDigits;
+            /* fall-through */ /* FALLTHRU */
+        default:
+            /* For %#x or %#X */
+            if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+                /* Alternate form means '0x' prefix */
+                attr->prefix[0] = SECUREC_CHAR('0');
+                attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
+                attr->prefixLen = SECUREC_PREFIX_LEN;
+            }
+            break;
+    }
+}
+
+SECUREC_INLINE void SecUpdateOudiFlags(SecFormatAttr *attr, SecChar ch)
+{
+    /* Do not set digits here */
+    switch (ch) {
+        case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
+            /* For signed decimal output */
+            attr->flags |= SECUREC_FLAG_SIGNED;
+            /* fall-through */ /* FALLTHRU */
+        case SECUREC_CHAR('u'):
+            attr->radix = SECUREC_RADIX_DECIMAL;
+            attr->digits = g_itoaLowerDigits;
+            break;
+        case SECUREC_CHAR('o'):
+            /* For unsigned octal output */
+            attr->radix = SECUREC_RADIX_OCTAL;
+            attr->digits = g_itoaLowerDigits;
+            if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+                /* Alternate form means force a leading 0 */
+                attr->flags |= SECUREC_FLAG_FORCE_OCTAL;
+            }
+            break;
+        default:
+            /* Do nothing */
+            break;
+    }
+}
+
+#if SECUREC_ENABLE_SPRINTF_FLOAT
+SECUREC_INLINE void SecFreeFloatBuffer(SecFloatAdapt *floatAdapt)
+{
+    if (floatAdapt->floatBuffer != NULL) {
+        SECUREC_FREE(floatAdapt->floatBuffer);
+    }
+    if (floatAdapt->allocatedFmtStr != NULL) {
+        SECUREC_FREE(floatAdapt->allocatedFmtStr);
+    }
+    floatAdapt->floatBuffer = NULL;
+    floatAdapt->allocatedFmtStr = NULL;
+    floatAdapt->fmtStr = NULL;
+    floatAdapt->bufferSize = 0;
+}
+
+SECUREC_INLINE void SecSeekToFrontPercent(const SecChar **format)
+{
+    const SecChar *fmt = *format;
+    while (*fmt != SECUREC_CHAR('%')) { /* Must meet '%' */
+        --fmt;
+    }
+    *format = fmt;
+}
+
+/* Init float format, return 0 is OK */
+SECUREC_INLINE int SecInitFloatFmt(SecFloatAdapt *floatFmt, const SecChar *format)
+{
+    const SecChar *fmt = format - 2;  /* Sub 2 to the position before 'f' or 'g' */
+    int fmtStrLen;
+    int i;
+
+    SecSeekToFrontPercent(&fmt);
+    /* Now fmt point to '%' */
+    fmtStrLen = (int)(size_t)(format - fmt) + 1;   /* With ending terminator */
+    if (fmtStrLen > (int)sizeof(floatFmt->buffer)) {
+        /* When buffer is NOT enough, alloc a new buffer */
+        floatFmt->allocatedFmtStr = (char *)SECUREC_MALLOC((size_t)((unsigned int)fmtStrLen));
+        if (floatFmt->allocatedFmtStr == NULL) {
+            return -1;
+        }
+        floatFmt->fmtStr = floatFmt->allocatedFmtStr;
+    } else {
+        floatFmt->fmtStr = floatFmt->buffer;
+        floatFmt->allocatedFmtStr = NULL; /* Must set to NULL, later code free memory based on this identity */
+    }
+
+    for (i = 0; i < fmtStrLen - 1; ++i) {
+        /* Convert wchar to char */
+        floatFmt->fmtStr[i] = (char)(fmt[i]);  /* Copy the format string */
+    }
+    floatFmt->fmtStr[fmtStrLen - 1] = '\0';
+
+    return 0;
+}
+
+/* Init float buffer and format, return 0 is OK */
+SECUREC_INLINE int SecInitFloatBuffer(SecFloatAdapt *floatAdapt, const SecChar *format, SecFormatAttr *attr)
+{
+    floatAdapt->allocatedFmtStr = NULL;
+    floatAdapt->fmtStr = NULL;
+    floatAdapt->floatBuffer = NULL;
+    /* Compute the precision value */
+    if (attr->precision < 0) {
+        attr->precision = SECUREC_FLOAT_DEFAULT_PRECISION;
+    }
+    /*
+     * Calc buffer size to store double value
+     * The maximum length of SECUREC_MAX_WIDTH_LEN is enough
+     */
+    if ((attr->flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
+        if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE_LB)) {
+            return -1;
+        }
+        /* Long double needs to meet the basic print length */
+        floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE_LB + attr->precision + SECUREC_FLOAT_BUF_EXT;
+    } else {
+        if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE)) {
+            return -1;
+        }
+        /* Double needs to meet the basic print length */
+        floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE + attr->precision + SECUREC_FLOAT_BUF_EXT;
+    }
+    if (attr->fldWidth > floatAdapt->bufferSize) {
+        floatAdapt->bufferSize = attr->fldWidth + SECUREC_FLOAT_BUF_EXT;
+    }
+
+    if (floatAdapt->bufferSize > SECUREC_BUFFER_SIZE) {
+        /* The current value of SECUREC_BUFFER_SIZE could not store the formatted float string */
+        floatAdapt->floatBuffer = (char *)SECUREC_MALLOC(((size_t)(unsigned int)floatAdapt->bufferSize));
+        if (floatAdapt->floatBuffer == NULL) {
+            return -1;
+        }
+        attr->text.str = floatAdapt->floatBuffer;
+    } else {
+        attr->text.str = attr->buffer.str; /* Output buffer for float string with default size */
+    }
+
+    if (SecInitFloatFmt(floatAdapt, format) != 0) {
+        if (floatAdapt->floatBuffer != NULL) {
+            SECUREC_FREE(floatAdapt->floatBuffer);
+            floatAdapt->floatBuffer = NULL;
+        }
+        return -1;
+    }
+    return 0;
+}
+#endif
+
+SECUREC_INLINE SecInt64 SecUpdateNegativeChar(SecFormatAttr *attr, char ch)
+{
+    SecInt64 num64 = ch; /* Sign extend */
+    if (num64 >= 128) { /* 128 on some platform, char is always unsigned */
+        unsigned char tmp = (unsigned char)(~((unsigned char)ch));
+        num64 = tmp + 1;
+        attr->flags |= SECUREC_FLAG_NEGATIVE;
+    }
+    return num64;
+}
+
+/*
+ * If the precision is not satisfied, zero is added before the string
+ */
+SECUREC_INLINE void SecNumberSatisfyPrecision(SecFormatAttr *attr)
+{
+    int precision;
+    if (attr->precision < 0) {
+        precision = 1; /* Default precision 1 */
+    } else {
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+        attr->flags &= ~SECUREC_FLAG_LEADZERO;
+#else
+        if ((attr->flags & SECUREC_FLAG_POINTER) == 0) {
+            attr->flags &= ~SECUREC_FLAG_LEADZERO;
+        }
+#endif
+        if (attr->precision > SECUREC_MAX_PRECISION) {
+            attr->precision = SECUREC_MAX_PRECISION;
+        }
+        precision = attr->precision;
+    }
+    while (attr->textLen < precision) {
+        --attr->text.str;
+        *(attr->text.str) = '0';
+        ++attr->textLen;
+    }
+}
+
+/*
+ * Add leading zero for %#o
+ */
+SECUREC_INLINE void SecNumberForceOctal(SecFormatAttr *attr)
+{
+    /* Force a leading zero if FORCEOCTAL flag set */
+    if ((attr->flags & SECUREC_FLAG_FORCE_OCTAL) != 0 &&
+        (attr->textLen == 0 || attr->text.str[0] != '0')) {
+        --attr->text.str;
+        *(attr->text.str) = '0';
+        ++attr->textLen;
+    }
+}
+
+SECUREC_INLINE void SecUpdateSignedNumberPrefix(SecFormatAttr *attr)
+{
+    if ((attr->flags & SECUREC_FLAG_SIGNED) == 0) {
+        return;
+    }
+    if ((attr->flags & SECUREC_FLAG_NEGATIVE) != 0) {
+        /* Prefix is '-' */
+        attr->prefix[0] = SECUREC_CHAR('-');
+        attr->prefixLen = 1;
+        return;
+    }
+    if ((attr->flags & SECUREC_FLAG_SIGN) != 0) {
+        /* Prefix is '+' */
+        attr->prefix[0] = SECUREC_CHAR('+');
+        attr->prefixLen = 1;
+        return;
+    }
+    if ((attr->flags & SECUREC_FLAG_SIGN_SPACE) != 0) {
+        /* Prefix is ' ' */
+        attr->prefix[0] = SECUREC_CHAR(' ');
+        attr->prefixLen = 1;
+        return;
+    }
+    return;
+}
+
+SECUREC_INLINE void SecNumberCompatZero(SecFormatAttr *attr)
+{
+#if SECUREC_IN_KERNEL
+    if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
+        static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(null)";
+        attr->text.str = strNullPointer;
+        attr->textLen = 6; /* Length of (null) is 6 */
+        attr->flags &= ~SECUREC_FLAG_LEADZERO;
+        attr->prefixLen = 0;
+        if (attr->precision >= 0 && attr->precision < attr->textLen) {
+            attr->textLen = attr->precision;
+        }
+    }
+    if ((attr->flags & SECUREC_FLAG_POINTER) == 0 && attr->radix == SECUREC_RADIX_HEX &&
+        (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+        /* Add 0x prefix for %x or %X, the prefix string has been set before */
+        attr->prefixLen = SECUREC_PREFIX_LEN;
+    }
+#elif defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX))
+    if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
+        static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(nil)";
+        attr->text.str = strNullPointer;
+        attr->textLen = 5; /* Length of (nil) is 5 */
+        attr->flags &= ~SECUREC_FLAG_LEADZERO;
+    }
+#elif defined(SECUREC_VXWORKS_PLATFORM) || defined(__hpux)
+    if ((attr->flags & SECUREC_FLAG_POINTER) != 0 && (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
+        /* Add 0x prefix for %p, the prefix string has been set before */
+        attr->prefixLen = SECUREC_PREFIX_LEN;
+    }
+#endif
+    (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */
+}
+
+/*
+ * Formatting output core function
+ */
+SECUREC_INLINE int SecOutput(SecPrintfStream *stream, const SecChar *cFormat, va_list argList)
+{
+    const SecChar *format = cFormat;
+    int charsOut;               /* Characters written */
+    int noOutput = 0; /* Must be initialized or compiler alerts */
+    SecFmtState state;
+    SecFormatAttr formatAttr;
+
+    formatAttr.flags = 0;
+    formatAttr.textIsWide = 0;    /* Flag for buffer contains wide chars */
+    formatAttr.fldWidth = 0;
+    formatAttr.precision = 0;
+    formatAttr.dynWidth = 0;
+    formatAttr.dynPrecision = 0;
+    formatAttr.digits = g_itoaUpperDigits;
+    formatAttr.radix = SECUREC_RADIX_DECIMAL;
+    formatAttr.padding = 0;
+    formatAttr.textLen = 0;
+    formatAttr.text.str = NULL;
+    formatAttr.prefixLen = 0;
+    formatAttr.prefix[0] = SECUREC_CHAR('\0');
+    formatAttr.prefix[1] = SECUREC_CHAR('\0');
+    charsOut = 0;
+    state = STAT_NORMAL;        /* Starting state */
+
+    /* Loop each format character */
+    while (*format != SECUREC_CHAR('\0') && charsOut >= 0) {
+        SecFmtState lastState = state;
+        SecChar ch = *format; /* Currently read character */
+        ++format;
+        state = SecDecodeState(ch, lastState);
+        switch (state) {
+            case STAT_NORMAL:
+                SecWriteChar(stream, ch, &charsOut);
+                continue;
+            case STAT_PERCENT:
+                /* Set default values */
+                noOutput = 0;
+                formatAttr.prefixLen = 0;
+                formatAttr.textLen = 0;
+                formatAttr.flags = 0;
+                formatAttr.fldWidth = 0;
+                formatAttr.precision = -1;
+                formatAttr.textIsWide = 0;
+                formatAttr.dynWidth = 0;
+                formatAttr.dynPrecision = 0;
+                break;
+            case STAT_FLAG:
+                /* Set flag based on which flag character */
+                SecDecodeFlags(ch, &formatAttr);
+                break;
+            case STAT_WIDTH:
+                /* Update width value */
+                if (ch == SECUREC_CHAR('*')) {
+                    /* get width from arg list */
+                    formatAttr.fldWidth = (int)va_arg(argList, int);
+                    formatAttr.dynWidth = 1;
+                }
+                if (SecDecodeWidth(ch, &formatAttr, lastState) != 0) {
+                    return -1;
+                }
+                break;
+            case STAT_DOT:
+                formatAttr.precision = 0;
+                break;
+            case STAT_PRECIS:
+                /* Update precision value */
+                if (ch == SECUREC_CHAR('*')) {
+                    /* Get precision from arg list */
+                    formatAttr.precision = (int)va_arg(argList, int);
+                    formatAttr.dynPrecision = 1;
+                }
+                if (SecDecodePrecision(ch, &formatAttr) != 0) {
+                    return -1;
+                }
+                break;
+            case STAT_SIZE:
+                /* Read a size specifier, set the formatAttr.flags based on it, and skip format to next character */
+                if (SecDecodeSize(ch, &formatAttr, &format) != 0) {
+                    /* Compatibility  code for "%I" just print I */
+                    SecWriteChar(stream, ch, &charsOut);
+                    state = STAT_NORMAL;
+                    continue;
+                }
+                break;
+            case STAT_TYPE:
+                switch (ch) {
+                    case SECUREC_CHAR('C'): /* Wide char */
+                        SecUpdateWcharFlags(&formatAttr);
+                        /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('c'): {
+                        unsigned int cValue = (unsigned int)va_arg(argList, int);
+                        SecDecodeTypeC(&formatAttr, cValue);
+                        break;
+                    }
+                    case SECUREC_CHAR('S'):    /* Wide char string */
+                        SecUpdateWstringFlags(&formatAttr);
+                        /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('s'): {
+                        char *argPtr = (char *)va_arg(argList, char *);
+                        SecDecodeTypeS(&formatAttr, argPtr);
+                        break;
+                    }
+                    case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('f'): {
+#if SECUREC_ENABLE_SPRINTF_FLOAT
+                        /* Add following code to call system sprintf API for float number */
+                        SecFloatAdapt floatAdapt;
+                        noOutput = 1; /* It's no more data needs to be written */
+
+                        /* Now format is pointer to the next character of 'f' */
+                        if (SecInitFloatBuffer(&floatAdapt, format, &formatAttr) != 0) {
+                            break;
+                        }
+
+                        if ((formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
+#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
+                            long double tmp = (long double)va_arg(argList, long double);
+                            SecFormatLongDouble(&formatAttr, &floatAdapt, tmp);
+#else
+                            double tmp = (double)va_arg(argList, double);
+                            SecFormatDouble(&formatAttr, &floatAdapt, tmp);
+#endif
+                        } else {
+                            double tmp = (double)va_arg(argList, double);
+                            SecFormatDouble(&formatAttr, &floatAdapt, tmp);
+                        }
+
+                        /* Only need write formatted float string */
+                        SecWriteFloatText(stream, &formatAttr, &charsOut);
+                        SecFreeFloatBuffer(&floatAdapt);
+                        break;
+#else
+                        return -1;
+#endif
+                    }
+                    case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('p'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('x'): /* fall-through */ /* FALLTHRU */
+                        SecUpdateXpxFlags(&formatAttr, ch);
+                        /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */
+                    case SECUREC_CHAR('o'): {
+                        SecInt64 num64;
+                        SecUpdateOudiFlags(&formatAttr, ch);
+                        /* Read argument into variable num64. Be careful, depend on the order of judgment */
+                        if ((formatAttr.flags & SECUREC_FLAG_I64) != 0 ||
+                            (formatAttr.flags & SECUREC_FLAG_LONGLONG) != 0) {
+                            num64 = (SecInt64)va_arg(argList, SecInt64); /* Maximum Bit Width sign bit unchanged */
+                        } else if ((formatAttr.flags & SECUREC_FLAG_LONG) != 0) {
+                            num64 = SECUREC_GET_LONG_FROM_ARG(formatAttr);
+                        } else if ((formatAttr.flags & SECUREC_FLAG_CHAR) != 0) {
+                            num64 = SECUREC_GET_CHAR_FROM_ARG(formatAttr);
+                        } else if ((formatAttr.flags & SECUREC_FLAG_SHORT) != 0) {
+                            num64 = SECUREC_GET_SHORT_FROM_ARG(formatAttr);
+#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
+                        } else if ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) != 0) {
+                            num64 = (ptrdiff_t)va_arg(argList, ptrdiff_t);  /* Sign extend */
+                        } else if ((formatAttr.flags & SECUREC_FLAG_SIZE) != 0) {
+                            num64 = SECUREC_GET_SIZE_FROM_ARG(formatAttr);
+                        } else if ((formatAttr.flags & SECUREC_FLAG_INTMAX) != 0) {
+                            num64 = (SecInt64)va_arg(argList, SecInt64);
+#endif
+                        } else {
+                            num64 = SECUREC_GET_INT_FROM_ARG(formatAttr);
+                        }
+
+                        /* The order of the following calls must be correct */
+                        SecNumberToBuffer(&formatAttr, num64);
+                        SecNumberSatisfyPrecision(&formatAttr);
+                        SecNumberForceOctal(&formatAttr);
+                        SecUpdateSignedNumberPrefix(&formatAttr);
+                        if (num64 == 0) {
+                            SecNumberCompatZero(&formatAttr);
+                        }
+                        break;
+                    }
+                    default:
+                        /* Do nothing */
+                        break;
+                }
+
+                if (noOutput == 0) {
+                    /* Calculate amount of padding */
+                    formatAttr.padding = (formatAttr.fldWidth - formatAttr.textLen) - formatAttr.prefixLen;
+
+                    /* Put out the padding, prefix, and text, in the correct order */
+                    SecWriteLeftPadding(stream, &formatAttr, &charsOut);
+                    SecWritePrefix(stream, &formatAttr, &charsOut);
+                    SecWriteLeadingZero(stream, &formatAttr, &charsOut);
+                    SecWriteText(stream, &formatAttr, &charsOut);
+                    SecWriteRightPadding(stream, &formatAttr, &charsOut);
+                }
+                break;
+            case STAT_INVALID: /* fall-through */ /* FALLTHRU */
+            default:
+                return -1;  /* Input format is wrong(STAT_INVALID), directly return */
+        }
+    }
+
+    if (state != STAT_NORMAL && state != STAT_TYPE) {
+        return -1;
+    }
+
+    return charsOut;            /* The number of characters written */
+}
+
+/*
+ * Output one zero character zero into the SecPrintfStream structure
+ * If there is not enough space, make sure f->count is less than 0
+ */
+SECUREC_INLINE int SecPutZeroChar(SecPrintfStream *stream)
+{
+    --stream->count;
+    if (stream->count >= 0) {
+        *(stream->cur) = SECUREC_CHAR('\0');
+        ++stream->cur;
+        return 0;
+    }
+    return -1;
+}
+
+/*
+ * Multi character formatted output implementation
+ */
+#ifdef SECUREC_FOR_WCHAR
+int SecVswprintfImpl(wchar_t *string, size_t count, const wchar_t *format, va_list argList)
+#else
+int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
+#endif
+{
+    SecPrintfStream stream;
+    int retVal;
+
+    stream.count = (int)count; /* The count include \0 character, must be greater than zero */
+    stream.cur = string;
+
+    retVal = SecOutput(&stream, format, argList);
+    if (retVal >= 0) {
+        if (SecPutZeroChar(&stream) == 0) {
+            return retVal;
+        }
+    }
+    if (stream.count < 0) {
+        /* The buffer was too small, then truncate */
+        string[count - 1] = SECUREC_CHAR('\0');
+        return SECUREC_PRINTF_TRUNCATE;
+    }
+    string[0] = SECUREC_CHAR('\0'); /* Empty the dest string */
+    return -1;
+}
+#endif /* OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/scanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/scanf_s.c
new file mode 100644 (file)
index 0000000..fa5470b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: scanf_s function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The scanf_s function is equivalent to fscanf_s with the argument stdin interposed before the arguments to scanf_s
+ *     The scanf_s function reads data from the standard input stream stdin and
+ *    writes the data into the location that's given by argument. Each argument
+ *    must be a pointer to a variable of a type that corresponds to a type specifier
+ *    in format. If copying occurs between strings that overlap, the behavior is
+ *    undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    format                  Format control string.
+ *    ...                       Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                       The converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Returns the number of fields successfully converted and assigned;
+ *    the return value does not include fields that were read but not assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int scanf_s(const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vscanf_s(format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secinput.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secinput.h
new file mode 100644 (file)
index 0000000..176ee05
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Define macro, data struct, and declare function prototype,
+ *              which is used by input.inl, secureinput_a.c and secureinput_w.c.
+ * Create: 2014-02-25
+ */
+
+#ifndef SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C
+#define SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C
+#include "securecutil.h"
+
+#define SECUREC_SCANF_EINVAL             (-1)
+#define SECUREC_SCANF_ERROR_PARA         (-2)
+
+/* For internal stream flag */
+#define SECUREC_MEM_STR_FLAG             0x01U
+#define SECUREC_FILE_STREAM_FLAG         0x02U
+#define SECUREC_PIPE_STREAM_FLAG         0x04U
+#define SECUREC_LOAD_FILE_TO_MEM_FLAG    0x08U
+
+#define SECUREC_UCS_BOM_HEADER_SIZE      2U
+#define SECUREC_UCS_BOM_HEADER_BE_1ST    0xfeU
+#define SECUREC_UCS_BOM_HEADER_BE_2ST    0xffU
+#define SECUREC_UCS_BOM_HEADER_LE_1ST    0xffU
+#define SECUREC_UCS_BOM_HEADER_LE_2ST    0xfeU
+#define SECUREC_UTF8_BOM_HEADER_SIZE     3U
+#define SECUREC_UTF8_BOM_HEADER_1ST      0xefU
+#define SECUREC_UTF8_BOM_HEADER_2ND      0xbbU
+#define SECUREC_UTF8_BOM_HEADER_3RD      0xbfU
+#define SECUREC_UTF8_LEAD_1ST            0xe0U
+#define SECUREC_UTF8_LEAD_2ND            0x80U
+
+#define SECUREC_BEGIN_WITH_UCS_BOM(s, len) ((len) == SECUREC_UCS_BOM_HEADER_SIZE && \
+    (((unsigned char)((s)[0]) == SECUREC_UCS_BOM_HEADER_LE_1ST && \
+    (unsigned char)((s)[1]) == SECUREC_UCS_BOM_HEADER_LE_2ST) || \
+    ((unsigned char)((s)[0]) == SECUREC_UCS_BOM_HEADER_BE_1ST && \
+    (unsigned char)((s)[1]) == SECUREC_UCS_BOM_HEADER_BE_2ST)))
+
+#define SECUREC_BEGIN_WITH_UTF8_BOM(s, len) ((len) == SECUREC_UTF8_BOM_HEADER_SIZE && \
+    (unsigned char)((s)[0]) == SECUREC_UTF8_BOM_HEADER_1ST && \
+    (unsigned char)((s)[1]) == SECUREC_UTF8_BOM_HEADER_2ND && \
+    (unsigned char)((s)[2]) == SECUREC_UTF8_BOM_HEADER_3RD)
+
+#ifdef SECUREC_FOR_WCHAR
+#define SECUREC_BOM_HEADER_SIZE SECUREC_UCS_BOM_HEADER_SIZE
+#define SECUREC_BEGIN_WITH_BOM(s, len) SECUREC_BEGIN_WITH_UCS_BOM((s), (len))
+#else
+#define SECUREC_BOM_HEADER_SIZE SECUREC_UTF8_BOM_HEADER_SIZE
+#define SECUREC_BEGIN_WITH_BOM(s, len) SECUREC_BEGIN_WITH_UTF8_BOM((s), (len))
+#endif
+
+typedef struct {
+    unsigned int flag;          /* Mark the properties of input stream */
+    char *base;                 /* The pointer to the header of buffered string */
+    const char *cur;            /* The pointer to next read position */
+    size_t count;               /* The size of buffered string in bytes */
+#if SECUREC_ENABLE_SCANF_FILE
+    FILE *pf;                   /* The file pointer */
+    size_t fileRealRead;
+    long oriFilePos;            /* The original position of file offset when fscanf is called */
+#endif
+} SecFileStream;
+
+#if SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_FILE_STREAM_INIT_FILE(stream, fp) do { \
+    (stream)->pf = (fp); \
+    (stream)->fileRealRead = 0; \
+    (stream)->oriFilePos = 0; \
+} SECUREC_WHILE_ZERO
+#else
+/* Disable file */
+#define SECUREC_FILE_STREAM_INIT_FILE(stream, fp)
+#endif
+
+/* This initialization for eliminating redundant initialization. */
+#define SECUREC_FILE_STREAM_FROM_STRING(stream, buf, cnt) do { \
+    (stream)->flag = SECUREC_MEM_STR_FLAG; \
+    (stream)->base = NULL; \
+    (stream)->cur = (buf); \
+    (stream)->count = (cnt); \
+    SECUREC_FILE_STREAM_INIT_FILE((stream), NULL); \
+} SECUREC_WHILE_ZERO
+
+/* This initialization for eliminating redundant initialization. */
+#define SECUREC_FILE_STREAM_FROM_FILE(stream, fp) do { \
+    (stream)->flag = SECUREC_FILE_STREAM_FLAG; \
+    (stream)->base = NULL; \
+    (stream)->cur = NULL; \
+    (stream)->count = 0; \
+    SECUREC_FILE_STREAM_INIT_FILE((stream), (fp)); \
+} SECUREC_WHILE_ZERO
+
+/* This initialization for eliminating redundant initialization. */
+#define SECUREC_FILE_STREAM_FROM_STDIN(stream) do { \
+    (stream)->flag = SECUREC_PIPE_STREAM_FLAG; \
+    (stream)->base = NULL; \
+    (stream)->cur = NULL; \
+    (stream)->count = 0; \
+    SECUREC_FILE_STREAM_INIT_FILE((stream), SECUREC_STREAM_STDIN); \
+} SECUREC_WHILE_ZERO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList);
+void SecClearDestBuf(const char *buffer, const char *format, va_list argList);
+#ifdef SECUREC_FOR_WCHAR
+int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList);
+void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList);
+#endif
+
+/* 20150105 For software and hardware decoupling,such as UMG */
+#ifdef SECUREC_SYSAPI4VXWORKS
+#ifdef feof
+#undef feof
+#endif
+extern int feof(FILE *stream);
+#endif
+
+#if defined(SECUREC_SYSAPI4VXWORKS) || defined(SECUREC_CTYPE_MACRO_ADAPT)
+#ifndef isspace
+#define isspace(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n'))
+#endif
+#ifndef iswspace
+#define iswspace(c) (((c) == L' ') || ((c) == L'\t') || ((c) == L'\r') || ((c) == L'\n'))
+#endif
+#ifndef isascii
+#define isascii(c) (((unsigned char)(c)) <= 0x7f)
+#endif
+#ifndef isupper
+#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef islower
+#define islower(c) ((c) >= 'a' && (c) <= 'z')
+#endif
+#ifndef isalpha
+#define isalpha(c) (isupper(c) || (islower(c)))
+#endif
+#ifndef isdigit
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#endif
+#ifndef isxupper
+#define isxupper(c) ((c) >= 'A' && (c) <= 'F')
+#endif
+#ifndef isxlower
+#define isxlower(c) ((c) >= 'a' && (c) <= 'f')
+#endif
+#ifndef isxdigit
+#define isxdigit(c) (isdigit(c) || isxupper(c) || isxlower(c))
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* Reserved file operation macro interface, s is FILE *, i is fileno zero. */
+#ifndef SECUREC_LOCK_FILE
+#define SECUREC_LOCK_FILE(s)
+#endif
+
+#ifndef SECUREC_UNLOCK_FILE
+#define SECUREC_UNLOCK_FILE(s)
+#endif
+
+#ifndef SECUREC_LOCK_STDIN
+#define SECUREC_LOCK_STDIN(i, s)
+#endif
+
+#ifndef SECUREC_UNLOCK_STDIN
+#define SECUREC_UNLOCK_STDIN(i, s)
+#endif
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.c
new file mode 100644 (file)
index 0000000..935cf35
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Provides internal functions used by this library, such as memory
+ *              copy and memory move. Besides, include some helper function for
+ *              printf family API, such as SecVsnprintfImpl
+ * Create: 2014-02-25
+ */
+
+/* Avoid duplicate header files,not include securecutil.h */
+#include "securecutil.h"
+
+#if defined(ANDROID) && !defined(SECUREC_CLOSE_ANDROID_HANDLE) && (SECUREC_HAVE_WCTOMB || SECUREC_HAVE_MBTOWC)
+#include <wchar.h>
+#if SECUREC_HAVE_WCTOMB
+/*
+ * Convert wide characters to narrow multi-bytes
+ */
+int wctomb(char *s, wchar_t wc)
+{
+    return (int)wcrtomb(s, wc, NULL);
+}
+#endif
+
+#if SECUREC_HAVE_MBTOWC
+/*
+ * Converting narrow multi-byte characters to wide characters
+ * mbrtowc returns -1 or -2 upon failure, unlike mbtowc, which only returns -1
+ * When the return value is less than zero, we treat it as a failure
+ */
+int mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+    return (int)mbrtowc(pwc, s, n, NULL);
+}
+#endif
+#endif
+
+/* The V100R001C01 version num is 0x5 (High 8 bits) */
+#define SECUREC_C_VERSION     0x500U
+#define SECUREC_SPC_VERSION   0xbU
+#define SECUREC_VERSION_STR   "V100R001C01SPC011B003"
+
+/*
+ * Get version string and version number.
+ * The rules for version number are as follows:
+ * 1) SPC verNumber<->verStr like:
+ * 0x201<->C01
+ * 0x202<->C01SPC001   Redefine numbers after this version
+ * 0x502<->C01SPC002
+ * 0x503<->C01SPC003
+ * ...
+ * 0X50a<->SPC010
+ * 0X50b<->SPC011
+ * ...
+ * 0x700<->C02
+ * 0x701<->C01SPC001
+ * 0x702<->C02SPC002
+ * ...
+ * 2) CP verNumber<->verStr like:
+ * 0X601<->CP0001
+ * 0X602<->CP0002
+ * ...
+ */
+const char *GetHwSecureCVersion(unsigned short *verNumber)
+{
+    if (verNumber != NULL) {
+        *verNumber = (unsigned short)(SECUREC_C_VERSION | SECUREC_SPC_VERSION);
+    }
+    return SECUREC_VERSION_STR;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(GetHwSecureCVersion);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.h
new file mode 100644 (file)
index 0000000..7e3bd69
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Define macro, data struct, and declare internal used function prototype,
+ *              which is used by secure functions.
+ * Create: 2014-02-25
+ */
+
+#ifndef SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F
+#define SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F
+#include "securec.h"
+
+#if (defined(_MSC_VER)) && (_MSC_VER >= 1400)
+/* Shield compilation alerts using discarded functions and Constant  expression to maximize code compatibility */
+#define SECUREC_MASK_MSVC_CRT_WARNING __pragma(warning(push)) \
+    __pragma(warning(disable : 4996 4127))
+#define SECUREC_END_MASK_MSVC_CRT_WARNING  __pragma(warning(pop))
+#else
+#define SECUREC_MASK_MSVC_CRT_WARNING
+#define SECUREC_END_MASK_MSVC_CRT_WARNING
+#endif
+#define SECUREC_WHILE_ZERO SECUREC_MASK_MSVC_CRT_WARNING while (0) SECUREC_END_MASK_MSVC_CRT_WARNING
+
+/* Automatically identify the platform that supports strnlen function, and use this function to improve performance */
+#ifndef SECUREC_HAVE_STRNLEN
+#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L)
+#if SECUREC_IN_KERNEL
+#define SECUREC_HAVE_STRNLEN 0
+#else
+#if defined(__GLIBC__) && __GLIBC__ >= 2 && defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ >= 10
+#define SECUREC_HAVE_STRNLEN 1
+#else
+#define SECUREC_HAVE_STRNLEN 0
+#endif
+#endif
+#else
+#define SECUREC_HAVE_STRNLEN 0
+#endif
+#endif
+
+#if SECUREC_IN_KERNEL
+/* In kernel disable functions */
+#ifndef SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_SCANF_FILE 0
+#endif
+#ifndef SECUREC_ENABLE_SCANF_FLOAT
+#define SECUREC_ENABLE_SCANF_FLOAT 0
+#endif
+#ifndef SECUREC_ENABLE_SPRINTF_FLOAT
+#define SECUREC_ENABLE_SPRINTF_FLOAT 0
+#endif
+#ifndef SECUREC_HAVE_MBTOWC
+#define SECUREC_HAVE_MBTOWC 0
+#endif
+#ifndef SECUREC_HAVE_WCTOMB
+#define SECUREC_HAVE_WCTOMB 0
+#endif
+#ifndef SECUREC_HAVE_WCHART
+#define SECUREC_HAVE_WCHART 0
+#endif
+#else /* Not in kernel */
+/* Systems that do not support file, can define this macro to 0. */
+#ifndef SECUREC_ENABLE_SCANF_FILE
+#define SECUREC_ENABLE_SCANF_FILE 1
+#endif
+#ifndef SECUREC_ENABLE_SCANF_FLOAT
+#define SECUREC_ENABLE_SCANF_FLOAT 1
+#endif
+/* Systems that do not support float, can define this macro to 0. */
+#ifndef SECUREC_ENABLE_SPRINTF_FLOAT
+#define SECUREC_ENABLE_SPRINTF_FLOAT 1
+#endif
+#ifndef SECUREC_HAVE_MBTOWC
+#define SECUREC_HAVE_MBTOWC 1
+#endif
+#ifndef SECUREC_HAVE_WCTOMB
+#define SECUREC_HAVE_WCTOMB 1
+#endif
+#ifndef SECUREC_HAVE_WCHART
+#define SECUREC_HAVE_WCHART 1
+#endif
+#endif
+
+#ifndef SECUREC_ENABLE_INLINE
+#define SECUREC_ENABLE_INLINE 0
+#endif
+
+#ifndef SECUREC_INLINE
+#if SECUREC_ENABLE_INLINE
+#define SECUREC_INLINE static inline
+#else
+#define SECUREC_INLINE static
+#endif
+#endif
+
+#ifndef SECUREC_WARP_OUTPUT
+#if SECUREC_IN_KERNEL
+#define SECUREC_WARP_OUTPUT 1
+#else
+#define SECUREC_WARP_OUTPUT 0
+#endif
+#endif
+
+#ifndef SECUREC_STREAM_STDIN
+#define SECUREC_STREAM_STDIN stdin
+#endif
+
+#define SECUREC_MUL_SIXTEEN(x)              ((x) << 4U)
+#define SECUREC_MUL_EIGHT(x)                ((x) << 3U)
+#define SECUREC_MUL_TEN(x)                  ((((x) << 2U) + (x)) << 1U)
+/* Limited format input and output width, use signed integer */
+#define SECUREC_MAX_WIDTH_LEN_DIV_TEN       21474836
+#define SECUREC_MAX_WIDTH_LEN               (SECUREC_MAX_WIDTH_LEN_DIV_TEN * 10)
+/* Is the x multiplied by 10 greater than */
+#define SECUREC_MUL_TEN_ADD_BEYOND_MAX(x)   (((x) > SECUREC_MAX_WIDTH_LEN_DIV_TEN))
+
+#define SECUREC_FLOAT_BUFSIZE               (309 + 40)  /* Max length of double value */
+#define SECUREC_FLOAT_BUFSIZE_LB            (4932 + 40) /* Max length of long double value */
+#define SECUREC_FLOAT_DEFAULT_PRECISION     6
+
+/* This macro does not handle pointer equality or integer overflow */
+#define SECUREC_MEMORY_NO_OVERLAP(dest, src, count) \
+    (((src) < (dest) && ((const char *)(src) + (count)) <= (char *)(dest)) || \
+    ((dest) < (src) && ((char *)(dest) + (count)) <= (const char *)(src)))
+
+#define SECUREC_MEMORY_IS_OVERLAP(dest, src, count) \
+    (((src) < (dest) && ((const char *)(src) + (count)) > (char *)(dest)) || \
+    ((dest) < (src) && ((char *)(dest) + (count)) > (const char *)(src)))
+
+/*
+ * Check whether the strings overlap, len is the length of the string not include terminator
+ * Length is related to data type char or wchar , do not force conversion of types
+ */
+#define SECUREC_STRING_NO_OVERLAP(dest, src, len) \
+    (((src) < (dest) && ((src) + (len)) < (dest)) || \
+    ((dest) < (src) && ((dest) + (len)) < (src)))
+
+/*
+ * Check whether the strings overlap for strcpy wcscpy function, dest len and src Len are not include terminator
+ * Length is related to data type char or wchar , do not force conversion of types
+ */
+#define SECUREC_STRING_IS_OVERLAP(dest, src, len) \
+    (((src) < (dest) && ((src) + (len)) >= (dest)) || \
+    ((dest) < (src) && ((dest) + (len)) >= (src)))
+
+/*
+ * Check whether the strings overlap for strcat wcscat function, dest len and src Len are not include terminator
+ * Length is related to data type char or wchar , do not force conversion of types
+ */
+#define SECUREC_CAT_STRING_IS_OVERLAP(dest, destLen, src, srcLen) \
+    (((dest) < (src) && ((dest) + (destLen) + (srcLen)) >= (src)) || \
+    ((src) < (dest) && ((src) + (srcLen)) >= (dest)))
+
+#if SECUREC_HAVE_STRNLEN
+#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) do { \
+    *(outLen) = strnlen((str), (maxLen)); \
+} SECUREC_WHILE_ZERO
+#define SECUREC_CALC_STR_LEN_OPT(str, maxLen, outLen) do { \
+    if ((maxLen) > 8) { \
+        /* Optimization or len less then 8 */ \
+        if (*((str) + 0) == '\0') { \
+            *(outLen) = 0; \
+        } else if (*((str) + 1) == '\0') { \
+            *(outLen) = 1; \
+        } else if (*((str) + 2) == '\0') { \
+            *(outLen) = 2; \
+        } else if (*((str) + 3) == '\0') { \
+            *(outLen) = 3; \
+        } else if (*((str) + 4) == '\0') { \
+            *(outLen) = 4; \
+        } else if (*((str) + 5) == '\0') { \
+            *(outLen) = 5; \
+        } else if (*((str) + 6) == '\0') { \
+            *(outLen) = 6; \
+        } else if (*((str) + 7) == '\0') { \
+            *(outLen) = 7; \
+        } else if (*((str) + 8) == '\0') { \
+            /* Optimization with a length of 8 */ \
+            *(outLen) = 8; \
+        } else { \
+            /* The offset is 8 because the performance of 8 byte alignment is high */ \
+            *(outLen) = 8 + strnlen((str) + 8, (maxLen) - 8); \
+        } \
+    } else { \
+        SECUREC_CALC_STR_LEN((str), (maxLen), (outLen)); \
+    } \
+} SECUREC_WHILE_ZERO
+#else
+#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) do { \
+    const char *strEnd_ = (const char *)(str); \
+    size_t availableSize_ = (size_t)(maxLen); \
+    while (availableSize_ > 0 && *strEnd_ != '\0') { \
+        --availableSize_; \
+        ++strEnd_; \
+    } \
+    *(outLen) = (size_t)(strEnd_ - (str)); \
+} SECUREC_WHILE_ZERO
+#define SECUREC_CALC_STR_LEN_OPT SECUREC_CALC_STR_LEN
+#endif
+
+#define SECUREC_CALC_WSTR_LEN(str, maxLen, outLen) do { \
+    const wchar_t *strEnd_ = (const wchar_t *)(str); \
+    size_t len_ = 0; \
+    while (len_ < (maxLen) && *strEnd_ != L'\0') { \
+        ++len_; \
+        ++strEnd_; \
+    } \
+    *(outLen) = len_; \
+} SECUREC_WHILE_ZERO
+
+/*
+ * Performance optimization, product may disable inline function.
+ * Using function pointer for MEMSET to prevent compiler optimization when cleaning up memory.
+ */
+#ifdef SECUREC_USE_ASM
+#define SECUREC_MEMSET_FUNC_OPT  memset_opt
+#define SECUREC_MEMCPY_FUNC_OPT  memcpy_opt
+#else
+#define SECUREC_MEMSET_FUNC_OPT  memset
+#define SECUREC_MEMCPY_FUNC_OPT  memcpy
+#endif
+
+#define SECUREC_MEMCPY_WARP_OPT(dest, src, count)    (void)SECUREC_MEMCPY_FUNC_OPT((dest), (src), (count))
+
+#ifndef SECUREC_MEMSET_BARRIER
+#if defined(__GNUC__)
+/* Can be turned off for scenarios that do not use memory barrier */
+#define SECUREC_MEMSET_BARRIER 1
+#else
+#define SECUREC_MEMSET_BARRIER 0
+#endif
+#endif
+
+#ifndef SECUREC_MEMSET_INDIRECT_USE
+/* Can be turned off for scenarios that do not allow pointer calls */
+#define SECUREC_MEMSET_INDIRECT_USE 1
+#endif
+
+#if SECUREC_MEMSET_BARRIER
+#define SECUREC_MEMORY_BARRIER(dest) __asm__ __volatile__("": : "r"(dest) : "memory")
+#else
+#define SECUREC_MEMORY_BARRIER(dest)
+#endif
+
+#if SECUREC_MEMSET_BARRIER
+#define SECUREC_MEMSET_PREVENT_DSE(dest, value, count)  do { \
+        (void)SECUREC_MEMSET_FUNC_OPT(dest, value, count); \
+        SECUREC_MEMORY_BARRIER(dest); \
+} SECUREC_WHILE_ZERO
+#elif SECUREC_MEMSET_INDIRECT_USE
+#define SECUREC_MEMSET_PREVENT_DSE(dest, value, count)  do { \
+    void *(* const volatile fn_)(void *s_, int c_, size_t n_) = SECUREC_MEMSET_FUNC_OPT; \
+    (void)(*fn_)((dest), (value), (count)); \
+} SECUREC_WHILE_ZERO
+#else
+#define SECUREC_MEMSET_PREVENT_DSE(dest, value, count)  (void)SECUREC_MEMSET_FUNC_OPT((dest), (value), (count))
+#endif
+
+#ifdef SECUREC_FORMAT_OUTPUT_INPUT
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) || defined(__ARMCC_VERSION)
+typedef __int64 SecInt64;
+typedef unsigned __int64 SecUnsignedInt64;
+#if defined(__ARMCC_VERSION)
+typedef unsigned int SecUnsignedInt32;
+#else
+typedef unsigned __int32 SecUnsignedInt32;
+#endif
+#else
+typedef unsigned int SecUnsignedInt32;
+typedef long long SecInt64;
+typedef unsigned long long SecUnsignedInt64;
+#endif
+
+#ifdef SECUREC_FOR_WCHAR
+#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(__WINT_TYPE__)
+typedef wchar_t wint_t;
+#endif
+#ifndef WEOF
+#define WEOF ((wchar_t)(-1))
+#endif
+#define SECUREC_CHAR(x) L ## x
+typedef wchar_t SecChar;
+typedef wchar_t SecUnsignedChar;
+typedef wint_t SecInt;
+typedef wint_t SecUnsignedInt;
+#else /*  no SECUREC_FOR_WCHAR */
+#define SECUREC_CHAR(x) (x)
+typedef char SecChar;
+typedef unsigned char SecUnsignedChar;
+typedef int SecInt;
+typedef unsigned int SecUnsignedInt;
+#endif
+#endif
+
+/*
+ * Determine whether the address is 8-byte aligned
+ * Some systems do not have uintptr_t type, so  use NULL to clear tool alarm 507
+ */
+#define SECUREC_ADDR_ALIGNED_8(addr) ((((size_t)(addr)) & 7U) == 0) /* Use 7 to check aligned 8 */
+
+/*
+ * If you define the memory allocation function, you need to define the function prototype.
+ * You can define this macro as a header file.
+ */
+#if defined(SECUREC_MALLOC_PROTOTYPE)
+SECUREC_MALLOC_PROTOTYPE
+#endif
+
+#ifndef SECUREC_MALLOC
+#define SECUREC_MALLOC(x) malloc((size_t)(x))
+#endif
+
+#ifndef SECUREC_FREE
+#define SECUREC_FREE(x)   free((void *)(x))
+#endif
+
+/* Improve performance with struct assignment, buf1 is not defined to avoid tool false positive */
+#define SECUREC_COPY_VALUE_BY_STRUCT(dest, src, n) do { \
+    *(SecStrBuf##n *)(void *)(dest) = *(const SecStrBuf##n *)(const void *)(src); \
+} SECUREC_WHILE_ZERO
+
+typedef struct {
+    unsigned char buf[2]; /* Performance optimization code structure assignment length 2 bytes */
+} SecStrBuf2;
+typedef struct {
+    unsigned char buf[3]; /* Performance optimization code structure assignment length 3 bytes */
+} SecStrBuf3;
+typedef struct {
+    unsigned char buf[4]; /* Performance optimization code structure assignment length 4 bytes */
+} SecStrBuf4;
+typedef struct {
+    unsigned char buf[5]; /* Performance optimization code structure assignment length 5 bytes */
+} SecStrBuf5;
+typedef struct {
+    unsigned char buf[6]; /* Performance optimization code structure assignment length 6 bytes */
+} SecStrBuf6;
+typedef struct {
+    unsigned char buf[7]; /* Performance optimization code structure assignment length 7 bytes */
+} SecStrBuf7;
+typedef struct {
+    unsigned char buf[8]; /* Performance optimization code structure assignment length 8 bytes */
+} SecStrBuf8;
+typedef struct {
+    unsigned char buf[9]; /* Performance optimization code structure assignment length 9 bytes */
+} SecStrBuf9;
+typedef struct {
+    unsigned char buf[10]; /* Performance optimization code structure assignment length 10 bytes */
+} SecStrBuf10;
+typedef struct {
+    unsigned char buf[11]; /* Performance optimization code structure assignment length 11 bytes */
+} SecStrBuf11;
+typedef struct {
+    unsigned char buf[12]; /* Performance optimization code structure assignment length 12 bytes */
+} SecStrBuf12;
+typedef struct {
+    unsigned char buf[13]; /* Performance optimization code structure assignment length 13 bytes */
+} SecStrBuf13;
+typedef struct {
+    unsigned char buf[14]; /* Performance optimization code structure assignment length 14 bytes */
+} SecStrBuf14;
+typedef struct {
+    unsigned char buf[15]; /* Performance optimization code structure assignment length 15 bytes */
+} SecStrBuf15;
+typedef struct {
+    unsigned char buf[16]; /* Performance optimization code structure assignment length 16 bytes */
+} SecStrBuf16;
+typedef struct {
+    unsigned char buf[17]; /* Performance optimization code structure assignment length 17 bytes */
+} SecStrBuf17;
+typedef struct {
+    unsigned char buf[18]; /* Performance optimization code structure assignment length 18 bytes */
+} SecStrBuf18;
+typedef struct {
+    unsigned char buf[19]; /* Performance optimization code structure assignment length 19 bytes */
+} SecStrBuf19;
+typedef struct {
+    unsigned char buf[20]; /* Performance optimization code structure assignment length 20 bytes */
+} SecStrBuf20;
+typedef struct {
+    unsigned char buf[21]; /* Performance optimization code structure assignment length 21 bytes */
+} SecStrBuf21;
+typedef struct {
+    unsigned char buf[22]; /* Performance optimization code structure assignment length 22 bytes */
+} SecStrBuf22;
+typedef struct {
+    unsigned char buf[23]; /* Performance optimization code structure assignment length 23 bytes */
+} SecStrBuf23;
+typedef struct {
+    unsigned char buf[24]; /* Performance optimization code structure assignment length 24 bytes */
+} SecStrBuf24;
+typedef struct {
+    unsigned char buf[25]; /* Performance optimization code structure assignment length 25 bytes */
+} SecStrBuf25;
+typedef struct {
+    unsigned char buf[26]; /* Performance optimization code structure assignment length 26 bytes */
+} SecStrBuf26;
+typedef struct {
+    unsigned char buf[27]; /* Performance optimization code structure assignment length 27 bytes */
+} SecStrBuf27;
+typedef struct {
+    unsigned char buf[28]; /* Performance optimization code structure assignment length 28 bytes */
+} SecStrBuf28;
+typedef struct {
+    unsigned char buf[29]; /* Performance optimization code structure assignment length 29 bytes */
+} SecStrBuf29;
+typedef struct {
+    unsigned char buf[30]; /* Performance optimization code structure assignment length 30 bytes */
+} SecStrBuf30;
+typedef struct {
+    unsigned char buf[31]; /* Performance optimization code structure assignment length 31 bytes */
+} SecStrBuf31;
+typedef struct {
+    unsigned char buf[32]; /* Performance optimization code structure assignment length 32 bytes */
+} SecStrBuf32;
+typedef struct {
+    unsigned char buf[33]; /* Performance optimization code structure assignment length 33 bytes */
+} SecStrBuf33;
+typedef struct {
+    unsigned char buf[34]; /* Performance optimization code structure assignment length 34 bytes */
+} SecStrBuf34;
+typedef struct {
+    unsigned char buf[35]; /* Performance optimization code structure assignment length 35 bytes */
+} SecStrBuf35;
+typedef struct {
+    unsigned char buf[36]; /* Performance optimization code structure assignment length 36 bytes */
+} SecStrBuf36;
+typedef struct {
+    unsigned char buf[37]; /* Performance optimization code structure assignment length 37 bytes */
+} SecStrBuf37;
+typedef struct {
+    unsigned char buf[38]; /* Performance optimization code structure assignment length 38 bytes */
+} SecStrBuf38;
+typedef struct {
+    unsigned char buf[39]; /* Performance optimization code structure assignment length 39 bytes */
+} SecStrBuf39;
+typedef struct {
+    unsigned char buf[40]; /* Performance optimization code structure assignment length 40 bytes */
+} SecStrBuf40;
+typedef struct {
+    unsigned char buf[41]; /* Performance optimization code structure assignment length 41 bytes */
+} SecStrBuf41;
+typedef struct {
+    unsigned char buf[42]; /* Performance optimization code structure assignment length 42 bytes */
+} SecStrBuf42;
+typedef struct {
+    unsigned char buf[43]; /* Performance optimization code structure assignment length 43 bytes */
+} SecStrBuf43;
+typedef struct {
+    unsigned char buf[44]; /* Performance optimization code structure assignment length 44 bytes */
+} SecStrBuf44;
+typedef struct {
+    unsigned char buf[45]; /* Performance optimization code structure assignment length 45 bytes */
+} SecStrBuf45;
+typedef struct {
+    unsigned char buf[46]; /* Performance optimization code structure assignment length 46 bytes */
+} SecStrBuf46;
+typedef struct {
+    unsigned char buf[47]; /* Performance optimization code structure assignment length 47 bytes */
+} SecStrBuf47;
+typedef struct {
+    unsigned char buf[48]; /* Performance optimization code structure assignment length 48 bytes */
+} SecStrBuf48;
+typedef struct {
+    unsigned char buf[49]; /* Performance optimization code structure assignment length 49 bytes */
+} SecStrBuf49;
+typedef struct {
+    unsigned char buf[50]; /* Performance optimization code structure assignment length 50 bytes */
+} SecStrBuf50;
+typedef struct {
+    unsigned char buf[51]; /* Performance optimization code structure assignment length 51 bytes */
+} SecStrBuf51;
+typedef struct {
+    unsigned char buf[52]; /* Performance optimization code structure assignment length 52 bytes */
+} SecStrBuf52;
+typedef struct {
+    unsigned char buf[53]; /* Performance optimization code structure assignment length 53 bytes */
+} SecStrBuf53;
+typedef struct {
+    unsigned char buf[54]; /* Performance optimization code structure assignment length 54 bytes */
+} SecStrBuf54;
+typedef struct {
+    unsigned char buf[55]; /* Performance optimization code structure assignment length 55 bytes */
+} SecStrBuf55;
+typedef struct {
+    unsigned char buf[56]; /* Performance optimization code structure assignment length 56 bytes */
+} SecStrBuf56;
+typedef struct {
+    unsigned char buf[57]; /* Performance optimization code structure assignment length 57 bytes */
+} SecStrBuf57;
+typedef struct {
+    unsigned char buf[58]; /* Performance optimization code structure assignment length 58 bytes */
+} SecStrBuf58;
+typedef struct {
+    unsigned char buf[59]; /* Performance optimization code structure assignment length 59 bytes */
+} SecStrBuf59;
+typedef struct {
+    unsigned char buf[60]; /* Performance optimization code structure assignment length 60 bytes */
+} SecStrBuf60;
+typedef struct {
+    unsigned char buf[61]; /* Performance optimization code structure assignment length 61 bytes */
+} SecStrBuf61;
+typedef struct {
+    unsigned char buf[62]; /* Performance optimization code structure assignment length 62 bytes */
+} SecStrBuf62;
+typedef struct {
+    unsigned char buf[63]; /* Performance optimization code structure assignment length 63 bytes */
+} SecStrBuf63;
+typedef struct {
+    unsigned char buf[64]; /* Performance optimization code structure assignment length 64 bytes */
+} SecStrBuf64;
+
+/*
+ * User can change the error handler by modify the following definition,
+ * such as logging the detail error in file.
+ */
+#if defined(_DEBUG) || defined(DEBUG)
+#if defined(SECUREC_ERROR_HANDLER_BY_ASSERT)
+#define SECUREC_ERROR_INVALID_PARAMTER(msg) assert(msg "invalid argument" == NULL)
+#define SECUREC_ERROR_INVALID_RANGE(msg)    assert(msg "invalid dest buffer size" == NULL)
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)   assert(msg "buffer overlap" == NULL)
+#elif defined(SECUREC_ERROR_HANDLER_BY_PRINTF)
+#if SECUREC_IN_KERNEL
+#define SECUREC_ERROR_INVALID_PARAMTER(msg) printk("%s invalid argument\n", msg)
+#define SECUREC_ERROR_INVALID_RANGE(msg)    printk("%s invalid dest buffer size\n", msg)
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)   printk("%s buffer overlap\n", msg)
+#else
+#define SECUREC_ERROR_INVALID_PARAMTER(msg) printf("%s invalid argument\n", msg)
+#define SECUREC_ERROR_INVALID_RANGE(msg)    printf("%s invalid dest buffer size\n", msg)
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)   printf("%s buffer overlap\n", msg)
+#endif
+#elif defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG)
+#define SECUREC_ERROR_INVALID_PARAMTER(msg) LogSecureCRuntimeError(msg " EINVAL\n")
+#define SECUREC_ERROR_INVALID_RANGE(msg)    LogSecureCRuntimeError(msg " ERANGE\n")
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)   LogSecureCRuntimeError(msg " EOVERLAP\n")
+#endif
+#endif
+
+/* Default handler is none */
+#ifndef SECUREC_ERROR_INVALID_PARAMTER
+#define SECUREC_ERROR_INVALID_PARAMTER(msg)
+#endif
+#ifndef SECUREC_ERROR_INVALID_RANGE
+#define SECUREC_ERROR_INVALID_RANGE(msg)
+#endif
+#ifndef SECUREC_ERROR_BUFFER_OVERLAP
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Assembly language memory copy and memory set for X86 or MIPS ... */
+#ifdef SECUREC_USE_ASM
+void *memcpy_opt(void *dest, const void *src, size_t n);
+void *memset_opt(void *s, int c, size_t n);
+#endif
+
+#if defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG)
+void LogSecureCRuntimeError(const char *errDetail);
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_a.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_a.c
new file mode 100644 (file)
index 0000000..8a1e678
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: By defining data type for ANSI string and including "input.inl",
+ *              this file generates real underlying function used by scanf family API.
+ * Create: 2014-02-25
+ */
+
+#define SECUREC_FORMAT_OUTPUT_INPUT 1
+#ifdef SECUREC_FOR_WCHAR
+#undef SECUREC_FOR_WCHAR
+#endif
+
+#include "secinput.h"
+
+#include "input.inl"
+
+SECUREC_INLINE int SecIsDigit(SecInt ch)
+{
+    /* SecInt to unsigned char clear  571, use bit mask to clear negative return of ch */
+    return isdigit((int)((unsigned int)(unsigned char)(ch) & 0xffU));
+}
+SECUREC_INLINE int SecIsXdigit(SecInt ch)
+{
+    return isxdigit((int)((unsigned int)(unsigned char)(ch) & 0xffU));
+}
+SECUREC_INLINE int SecIsSpace(SecInt ch)
+{
+    return isspace((int)((unsigned int)(unsigned char)(ch) & 0xffU));
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_w.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_w.c
new file mode 100644 (file)
index 0000000..12c9ef8
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: By defining data type for UNICODE string and including "input.inl",
+ *             this file generates real underlying function used by scanf family API.
+ * Create: 2014-02-25
+ */
+
+/* If some platforms don't have wchar.h, don't include it */
+#if !(defined(SECUREC_VXWORKS_PLATFORM))
+/* If there is no macro below, it will cause vs2010 compiling alarm */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#ifndef __STDC_WANT_SECURE_LIB__
+/* The order of adjustment is to eliminate alarm of Duplicate Block */
+#define __STDC_WANT_SECURE_LIB__ 0
+#endif
+#ifndef _CRTIMP_ALTERNATIVE
+#define _CRTIMP_ALTERNATIVE     /* Comment microsoft *_s function */
+#endif
+#endif
+#include <wchar.h>
+#endif
+
+/* Disable wchar func to clear vs warning */
+#define SECUREC_ENABLE_WCHAR_FUNC       0
+#define SECUREC_FORMAT_OUTPUT_INPUT     1
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secinput.h"
+
+#include "input.inl"
+
+SECUREC_INLINE unsigned int SecWcharHighBits(SecInt ch)
+{
+    /* Convert int to unsigned int clear 571 */
+    return ((unsigned int)(int)ch & (~0xffU));
+}
+
+SECUREC_INLINE unsigned char SecWcharLowByte(SecInt ch)
+{
+    /* Convert int to unsigned int clear 571 */
+    return (unsigned char)((unsigned int)(int)ch & 0xffU);
+}
+
+SECUREC_INLINE int SecIsDigit(SecInt ch)
+{
+    if (SecWcharHighBits(ch) != 0) {
+        return 0; /* Same as isdigit */
+    }
+    return isdigit((int)SecWcharLowByte(ch));
+}
+
+SECUREC_INLINE int SecIsXdigit(SecInt ch)
+{
+    if (SecWcharHighBits(ch) != 0) {
+        return 0; /* Same as isxdigit */
+    }
+    return isxdigit((int)SecWcharLowByte(ch));
+}
+
+SECUREC_INLINE int SecIsSpace(SecInt ch)
+{
+    return iswspace((wint_t)(int)(ch));
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput.h
new file mode 100644 (file)
index 0000000..a00b10d
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: Define macro, enum, data struct, and declare internal used function
+ *              prototype, which is used by output.inl, secureprintoutput_w.c and
+ *              secureprintoutput_a.c.
+ * Create: 2014-02-25
+ */
+
+#ifndef SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C
+#define SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C
+#include "securecutil.h"
+
+/* Shield compilation alerts about using sprintf without format attribute to format float value. */
+#ifndef SECUREC_HANDLE_WFORMAT
+#define SECUREC_HANDLE_WFORMAT 1
+#endif
+
+#if SECUREC_HANDLE_WFORMAT && defined(__GNUC__) && ((__GNUC__ >= 5) || \
+    (defined(__GNUC_MINOR__) && (__GNUC__ == 4 && __GNUC_MINOR__ > 7)))
+#if defined(__clang__)
+#define SECUREC_MASK_WFORMAT_WARNING  _Pragma("GCC diagnostic push") \
+    _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
+#else
+#define SECUREC_MASK_WFORMAT_WARNING  _Pragma("GCC diagnostic push") \
+    _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") \
+    _Pragma("GCC diagnostic ignored \"-Wmissing-format-attribute\"") \
+    _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
+#endif
+#define SECUREC_END_MASK_WFORMAT_WARNING  _Pragma("GCC diagnostic pop")
+#else
+#define SECUREC_MASK_WFORMAT_WARNING
+#define SECUREC_END_MASK_WFORMAT_WARNING
+#endif
+
+#define SECUREC_MASK_VSPRINTF_WARNING  SECUREC_MASK_WFORMAT_WARNING \
+    SECUREC_MASK_MSVC_CRT_WARNING
+
+#define SECUREC_END_MASK_VSPRINTF_WARNING  SECUREC_END_MASK_WFORMAT_WARNING \
+    SECUREC_END_MASK_MSVC_CRT_WARNING
+
+/*
+ * Flag definitions.
+ * Using macros instead of enumerations is because some of the enumerated types under the compiler are 16bit.
+ */
+#define SECUREC_FLAG_SIGN           0x00001U
+#define SECUREC_FLAG_SIGN_SPACE     0x00002U
+#define SECUREC_FLAG_LEFT           0x00004U
+#define SECUREC_FLAG_LEADZERO       0x00008U
+#define SECUREC_FLAG_LONG           0x00010U
+#define SECUREC_FLAG_SHORT          0x00020U
+#define SECUREC_FLAG_SIGNED         0x00040U
+#define SECUREC_FLAG_ALTERNATE      0x00080U
+#define SECUREC_FLAG_NEGATIVE       0x00100U
+#define SECUREC_FLAG_FORCE_OCTAL    0x00200U
+#define SECUREC_FLAG_LONG_DOUBLE    0x00400U
+#define SECUREC_FLAG_WIDECHAR       0x00800U
+#define SECUREC_FLAG_LONGLONG       0x01000U
+#define SECUREC_FLAG_CHAR           0x02000U
+#define SECUREC_FLAG_POINTER        0x04000U
+#define SECUREC_FLAG_I64            0x08000U
+#define SECUREC_FLAG_PTRDIFF        0x10000U
+#define SECUREC_FLAG_SIZE           0x20000U
+#ifdef  SECUREC_COMPATIBLE_LINUX_FORMAT
+#define SECUREC_FLAG_INTMAX         0x40000U
+#endif
+
+/* State definitions. Identify the status of the current format */
+typedef enum {
+    STAT_NORMAL,
+    STAT_PERCENT,
+    STAT_FLAG,
+    STAT_WIDTH,
+    STAT_DOT,
+    STAT_PRECIS,
+    STAT_SIZE,
+    STAT_TYPE,
+    STAT_INVALID
+} SecFmtState;
+
+#ifndef SECUREC_BUFFER_SIZE
+#if SECUREC_IN_KERNEL
+#define SECUREC_BUFFER_SIZE    32
+#elif defined(SECUREC_STACK_SIZE_LESS_THAN_1K)
+/*
+ * SECUREC BUFFER SIZE Can not be less than 23
+ * The length of the octal representation of 64-bit integers with zero lead
+ */
+#define SECUREC_BUFFER_SIZE    256
+#else
+#define SECUREC_BUFFER_SIZE    512
+#endif
+#endif
+#if SECUREC_BUFFER_SIZE < 23
+#error SECUREC_BUFFER_SIZE Can not be less than 23
+#endif
+/* Buffer size for wchar, use 4 to make the compiler aligns as 8 bytes as possible */
+#define SECUREC_WCHAR_BUFFER_SIZE 4
+
+#define SECUREC_MAX_PRECISION  SECUREC_BUFFER_SIZE
+/* Max. # bytes in multibyte char,see MB_LEN_MAX */
+#define SECUREC_MB_LEN 16
+/* The return value of the internal function, which is returned when truncated */
+#define SECUREC_PRINTF_TRUNCATE (-2)
+
+#define SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, maxLimit) \
+    ((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit))
+
+#define SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, maxLimit) do { \
+    if ((strDest) != NULL && (destMax) > 0 && (destMax) <= (maxLimit)) { \
+        *(strDest) = '\0'; \
+    } \
+} SECUREC_WHILE_ZERO
+
+#ifdef SECUREC_COMPATIBLE_WIN_FORMAT
+#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \
+    (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \
+    ((count) > (SECUREC_STRING_MAX_LEN - 1) && (count) != (size_t)(-1)))
+
+#else
+#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \
+    (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \
+    ((count) > (SECUREC_STRING_MAX_LEN - 1)))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef SECUREC_FOR_WCHAR
+int SecVswprintfImpl(wchar_t *string, size_t count, const wchar_t *format, va_list argList);
+#else
+int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_a.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_a.c
new file mode 100644 (file)
index 0000000..b2b4b6a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: By defining corresponding macro for ANSI string and including "output.inl",
+ *              this file generates real underlying function used by printf family API.
+ * Create: 2014-02-25
+ */
+
+#define SECUREC_FORMAT_OUTPUT_INPUT 1
+
+#ifdef SECUREC_FOR_WCHAR
+#undef SECUREC_FOR_WCHAR
+#endif
+
+#include "secureprintoutput.h"
+#if SECUREC_WARP_OUTPUT
+#define SECUREC_FORMAT_FLAG_TABLE_SIZE 128
+SECUREC_INLINE const char *SecSkipKnownFlags(const char *format)
+{
+    static const unsigned char flagTable[SECUREC_FORMAT_FLAG_TABLE_SIZE] = {
+        /*
+         * Known flag is  "0123456789 +-#hlLwZzjqt*I$"
+         */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00,
+        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    const char *fmt = format;
+    while (*fmt != '\0') {
+        char fmtChar = *fmt;
+        if ((unsigned char)fmtChar > 0x7f) { /* 0x7f is upper limit of format char value */
+            break;
+        }
+        if (flagTable[(unsigned char)fmtChar] == 0) {
+            break;
+        }
+        ++fmt;
+    }
+    return fmt;
+}
+
+SECUREC_INLINE int SecFormatContainN(const char *format)
+{
+    const char *fmt = format;
+    while (*fmt != '\0') {
+        ++fmt;
+        /* Skip normal char */
+        if (*(fmt - 1) != '%') {
+            continue;
+        }
+        /* Meet %% */
+        if (*fmt == '%') {
+            ++fmt; /* Point to  the character after the %. Correct handling %%xx */
+            continue;
+        }
+        /* Now parse %..., fmt point to the character after the % */
+        fmt = SecSkipKnownFlags(fmt);
+        if (*fmt == 'n') {
+            return 1;
+        }
+    }
+    return 0;
+}
+/*
+ * Multi character formatted output implementation, the count include \0 character, must be greater than zero
+ */
+int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
+{
+    int retVal;
+    if (SecFormatContainN(format) != 0) {
+        string[0] = '\0';
+        return -1;
+    }
+    SECUREC_MASK_VSPRINTF_WARNING
+    retVal = vsnprintf(string, count, format, argList);
+    SECUREC_END_MASK_VSPRINTF_WARNING
+    if (retVal >= (int)count) { /* The size_t to int is ok, count max is SECUREC_STRING_MAX_LEN */
+        /* The buffer was too small; we return truncation */
+        string[count - 1] = '\0';
+        return SECUREC_PRINTF_TRUNCATE;
+    }
+    if (retVal < 0) {
+        string[0] = '\0'; /* Empty the dest strDest */
+        return -1;
+    }
+    return retVal;
+}
+#else
+#if SECUREC_IN_KERNEL
+#include <linux/ctype.h>
+#endif
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#include "output.inl"
+
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_w.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_w.c
new file mode 100644 (file)
index 0000000..672c018
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: By defining corresponding macro for UNICODE string and including "output.inl",
+ *              this file generates real underlying function used by printf family API.
+ * Create: 2014-02-25
+ */
+
+/* If some platforms don't have wchar.h, don't include it */
+#if !(defined(SECUREC_VXWORKS_PLATFORM))
+/* If there is no macro above, it will cause compiling alarm */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#ifndef _CRTIMP_ALTERNATIVE
+#define _CRTIMP_ALTERNATIVE     /* Comment microsoft *_s function */
+#endif
+#ifndef __STDC_WANT_SECURE_LIB__
+#define __STDC_WANT_SECURE_LIB__ 0
+#endif
+#endif
+#include <wchar.h>
+#endif
+
+/* Disable wchar func to clear vs warning */
+#define SECUREC_ENABLE_WCHAR_FUNC   0
+#define SECUREC_FORMAT_OUTPUT_INPUT 1
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secureprintoutput.h"
+
+#include "output.inl"
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/snprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/snprintf_s.c
new file mode 100644 (file)
index 0000000..b8b83dc
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: snprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+#if SECUREC_ENABLE_SNPRINTF
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The snprintf_s function is equivalent to the snprintf function
+ *    except for the parameter destMax/count and the explicit runtime-constraints violation
+ *    The snprintf_s function formats and stores count or fewer characters in
+ *    strDest and appends a terminating null. Each argument (if any) is converted
+ *    and output according to the corresponding format specification in format.
+ *    The formatting is consistent with the printf family of functions; If copying
+ *    occurs between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                 Storage location for the output.
+ *    destMax                 The size of the storage location for output. Size
+ *                                 in bytes for snprintf_s or size in words for snwprintf_s.
+ *    count                    Maximum number of character to store.
+ *    format                  Format-control string.
+ *    ...                        Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                 is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of characters written, not including the terminating null
+ *    return -1 if an  error occurs.
+ *    return -1 if count < destMax and the output string  has been truncated
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ *
+ */
+int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vsnprintf_s(strDest, destMax, count, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(snprintf_s);
+#endif
+#endif
+
+#if SECUREC_SNPRINTF_TRUNCATED
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The snprintf_truncated_s function is equivalent to the snprintf function
+ *    except for the parameter destMax/count and the explicit runtime-constraints violation
+ *    The snprintf_truncated_s function formats and stores count or fewer characters in
+ *    strDest and appends a terminating null. Each argument (if any) is converted
+ *    and output according to the corresponding format specification in format.
+ *    The formatting is consistent with the printf family of functions; If copying
+ *    occurs between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                 Storage location for the output.
+ *    destMax                 The size of the storage location for output. Size
+ *                                 in bytes for snprintf_truncated_s or size in words for snwprintf_s.
+ *    format                  Format-control string.
+ *    ...                        Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                 is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of characters written, not including the terminating null
+ *    return -1 if an  error occurs.
+ *    return destMax-1 if output string  has been truncated
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ *
+ */
+int snprintf_truncated_s(char *strDest, size_t destMax, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vsnprintf_truncated_s(strDest, destMax, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(snprintf_truncated_s);
+#endif
+
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sprintf_s.c
new file mode 100644 (file)
index 0000000..a039853
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: sprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The sprintf_s function is equivalent to the sprintf function
+ *    except for the parameter destMax and the explicit runtime-constraints violation
+ *    The sprintf_s function formats and stores a series of characters and values
+ *    in strDest. Each argument (if any) is converted and output according to
+ *    the corresponding format specification in format. The format consists of
+ *    ordinary characters and has the same form and function as the format argument
+ *    for printf. A null character is appended after the last character written.
+ *    If copying occurs between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                 Storage location for output.
+ *    destMax                Maximum number of characters to store.
+ *    format                  Format-control string.
+ *    ...                        Optional arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                 is updated
+ *
+ * <RETURN VALUE>
+ *    return the number of bytes stored in strDest, not counting the terminating null character.
+ *    return -1 if an error occurred.
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int sprintf_s(char *strDest, size_t destMax, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vsprintf_s(strDest, destMax, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(sprintf_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sscanf_s.c
new file mode 100644 (file)
index 0000000..b441329
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: sscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The sscanf_s function is equivalent to fscanf_s,
+ *     except that input is obtained from a string (specified by the argument buffer) rather than from a stream
+ *    The sscanf function reads data from buffer into the location given by each
+ *    argument. Every argument must be a pointer to a variable with a type that
+ *    corresponds to a type specifier in format. The format argument controls the
+ *    interpretation of the input fields and has the same form and function as
+ *    the format argument for the scanf function.
+ *    If copying takes place between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    buffer                 Stored data.
+ *    format                 Format control string, see Format Specifications.
+ *    ...                    Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                    The converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int sscanf_s(const char *buffer, const char *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vsscanf_s(buffer, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(sscanf_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcat_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcat_s.c
new file mode 100644 (file)
index 0000000..13b56a8
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: strcat_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+/*
+ * Befor this function, the basic parameter checking has been done
+ */
+SECUREC_INLINE errno_t SecDoCat(char *strDest, size_t destMax, const char *strSrc)
+{
+    size_t destLen;
+    size_t srcLen;
+    size_t maxSrcLen;
+    SECUREC_CALC_STR_LEN(strDest, destMax, &destLen);
+    /* Only optimize strSrc, do not apply this function to strDest */
+    maxSrcLen = destMax - destLen;
+    SECUREC_CALC_STR_LEN_OPT(strSrc, maxSrcLen, &srcLen);
+
+    if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) {
+        strDest[0] = '\0';
+        if (strDest + destLen <= strSrc && destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_BUFFER_OVERLAP("strcat_s");
+        return EOVERLAP_AND_RESET;
+    }
+    if (srcLen + destLen >= destMax || strDest == strSrc) {
+        strDest[0] = '\0';
+        if (destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_INVALID_RANGE("strcat_s");
+        return ERANGE_AND_RESET;
+    }
+    SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen + 1); /* Single character length  include \0 */
+    return EOK;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *  The strcat_s function appends a copy of the string pointed to by strSrc (including the terminating null character)
+ *  to the end of the  string pointed to by strDest.
+ *  The initial character of strSrc overwrites the terminating null character of strDest.
+ *  strcat_s will return EOVERLAP_AND_RESET if the source and destination strings overlap.
+ *
+ *  Note that the second parameter is the total size of the buffer, not the
+ *  remaining size.
+ *
+ * <INPUT PARAMETERS>
+ *  strDest             Null-terminated destination string buffer.
+ *  destMax             Size of the destination string buffer.
+ *  strSrc              Null-terminated source string buffer.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest             is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                 Success
+ *    EINVAL              strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    EINVAL_AND_RESET    (strDest unterminated  and all other parameters are valid) or
+ *                        (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN)
+ *    ERANGE              destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc)
+{
+    if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("strcat_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
+        if (strDest != NULL) {
+            strDest[0] = '\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    return SecDoCat(strDest, destMax, strSrc);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(strcat_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcpy_s.c
new file mode 100644 (file)
index 0000000..78f2e6f
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: strcpy_s  function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Performance-sensitive
+ * [reason] Always used in the performance critical path,
+ *          and sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+#ifndef SECUREC_STRCPY_WITH_PERFORMANCE
+#define SECUREC_STRCPY_WITH_PERFORMANCE 1
+#endif
+
+#define SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc) ((destMax) > 0 && \
+    (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && (strDest) != (strSrc))
+
+#if (!SECUREC_IN_KERNEL) && SECUREC_STRCPY_WITH_PERFORMANCE
+#ifndef SECUREC_STRCOPY_THRESHOLD_SIZE
+#define SECUREC_STRCOPY_THRESHOLD_SIZE   32UL
+#endif
+/* The purpose of converting to void is to clean up the alarm */
+#define SECUREC_SMALL_STR_COPY(strDest, strSrc, lenWithTerm) do { \
+    if (SECUREC_ADDR_ALIGNED_8(strDest) && SECUREC_ADDR_ALIGNED_8(strSrc)) { \
+        /* Use struct assignment */ \
+        switch (lenWithTerm) { \
+            case 1: \
+                *(strDest) = *(strSrc); \
+                break; \
+            case 2: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 2); \
+                break; \
+            case 3: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 3); \
+                break; \
+            case 4: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 4); \
+                break; \
+            case 5: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 5); \
+                break; \
+            case 6: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 6); \
+                break; \
+            case 7: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 7); \
+                break; \
+            case 8: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 8); \
+                break; \
+            case 9: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 9); \
+                break; \
+            case 10: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 10); \
+                break; \
+            case 11: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 11); \
+                break; \
+            case 12: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 12); \
+                break; \
+            case 13: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 13); \
+                break; \
+            case 14: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 14); \
+                break; \
+            case 15: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 15); \
+                break; \
+            case 16: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 16); \
+                break; \
+            case 17: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 17); \
+                break; \
+            case 18: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 18); \
+                break; \
+            case 19: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 19); \
+                break; \
+            case 20: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 20); \
+                break; \
+            case 21: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 21); \
+                break; \
+            case 22: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 22); \
+                break; \
+            case 23: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 23); \
+                break; \
+            case 24: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 24); \
+                break; \
+            case 25: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 25); \
+                break; \
+            case 26: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 26); \
+                break; \
+            case 27: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 27); \
+                break; \
+            case 28: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 28); \
+                break; \
+            case 29: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 29); \
+                break; \
+            case 30: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 30); \
+                break; \
+            case 31: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 31); \
+                break; \
+            case 32: \
+                SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 32); \
+                break; \
+            default: \
+                /* Do nothing */ \
+                break; \
+        } /* END switch */ \
+    } else { \
+        char *tmpStrDest_ = (char *)(strDest); \
+        const char *tmpStrSrc_ = (const char *)(strSrc); \
+        switch (lenWithTerm) { \
+            case 32: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 31: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 30: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 29: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 28: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 27: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 26: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 25: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 24: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 23: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 22: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 21: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 20: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 19: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 18: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 17: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 16: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 15: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 14: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 13: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 12: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 11: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 10: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 9: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 8: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 7: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 6: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 5: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 4: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 3: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 2: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            case 1: \
+                *(tmpStrDest_++) = *(tmpStrSrc_++); \
+                /* fall-through */ /* FALLTHRU */ \
+            default: \
+                /* Do nothing */ \
+                break; \
+        } \
+    } \
+} SECUREC_WHILE_ZERO
+#endif
+
+#if SECUREC_IN_KERNEL || (!SECUREC_STRCPY_WITH_PERFORMANCE)
+#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm))
+#else
+/*
+ * Performance optimization. lenWithTerm  include '\0'
+ */
+#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) do { \
+    if ((lenWithTerm) > SECUREC_STRCOPY_THRESHOLD_SIZE) { \
+        SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)); \
+    } else { \
+        SECUREC_SMALL_STR_COPY((dest), (src), (lenWithTerm)); \
+    } \
+} SECUREC_WHILE_ZERO
+#endif
+
+/*
+ * Check Src Range
+ */
+SECUREC_INLINE errno_t CheckSrcRange(char *strDest, size_t destMax, const char *strSrc)
+{
+    size_t tmpDestMax = destMax;
+    const char *tmpSrc = strSrc;
+    /* Use destMax as boundary checker and destMax must be greater than zero */
+    while (*tmpSrc != '\0' && tmpDestMax > 0) {
+        ++tmpSrc;
+        --tmpDestMax;
+    }
+    if (tmpDestMax == 0) {
+        strDest[0] = '\0';
+        SECUREC_ERROR_INVALID_RANGE("strcpy_s");
+        return ERANGE_AND_RESET;
+    }
+    return EOK;
+}
+
+/*
+ * Handling errors
+ */
+errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc)
+{
+    if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("strcpy_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("strcpy_s");
+        if (strDest != NULL) {
+            strDest[0] = '\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    return CheckSrcRange(strDest, destMax, strSrc);
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The strcpy_s function copies the string pointed to  strSrc
+ *          (including the terminating null character) into the array pointed to by strDest
+ *    The destination string must be large enough to hold the source string,
+ *    including the terminating null character. strcpy_s will return EOVERLAP_AND_RESET
+ *    if the source and destination strings overlap.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                          Location of destination string buffer
+ *    destMax                        Size of the destination string buffer.
+ *    strSrc                            Null-terminated source string buffer.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                         is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                               Success
+ *    EINVAL                          strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    EINVAL_AND_RESET       strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc)
+{
+    if (SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc)) {
+        size_t srcStrLen;
+        SECUREC_CALC_STR_LEN(strSrc, destMax, &srcStrLen);
+        ++srcStrLen; /* The length include '\0' */
+
+        if (srcStrLen <= destMax) {
+            /* Use mem overlap check include '\0' */
+            if (SECUREC_MEMORY_NO_OVERLAP(strDest, strSrc, srcStrLen)) {
+                /* Performance optimization srcStrLen include '\0' */
+                SECUREC_STRCPY_OPT(strDest, strSrc, srcStrLen);
+                return EOK;
+            } else {
+                strDest[0] = '\0';
+                SECUREC_ERROR_BUFFER_OVERLAP("strcpy_s");
+                return EOVERLAP_AND_RESET;
+            }
+        }
+    }
+    return strcpy_error(strDest, destMax, strSrc);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(strcpy_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncat_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncat_s.c
new file mode 100644 (file)
index 0000000..e9d0b94
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: strncat_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+/*
+ * Befor this function, the basic parameter checking has been done
+ */
+SECUREC_INLINE errno_t SecDoCatLimit(char *strDest, size_t destMax, const char *strSrc, size_t count)
+{
+    size_t destLen;
+    size_t srcLen;
+    SECUREC_CALC_STR_LEN(strDest, destMax, &destLen);
+    /*
+     * The strSrc is no longer optimized. The reason is that when count is small,
+     * the efficiency of strnlen is higher than that of self realization.
+     */
+    SECUREC_CALC_STR_LEN(strSrc, count, &srcLen);
+
+    if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) {
+        strDest[0] = '\0';
+        if (strDest + destLen <= strSrc && destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
+        return EOVERLAP_AND_RESET;
+    }
+    if (srcLen + destLen >= destMax || strDest == strSrc) {
+        strDest[0] = '\0';
+        if (destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_INVALID_RANGE("strncat_s");
+        return ERANGE_AND_RESET;
+    }
+    SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen);    /* No terminator */
+    *(strDest + destLen + srcLen) = '\0';
+    return EOK;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The strncat_s function appends not more than n successive  characters
+ *    (not including the terminating null  character)
+ *     from the array pointed to by strSrc to the end of the  string pointed to by strDest
+ *    The strncat_s function try to append the first D characters of strSrc to
+ *    the end of strDest, where D is the lesser of count and the length of strSrc.
+ *    If appending those D characters will fit within strDest (whose size is given
+ *    as destMax) and still leave room for a null terminator, then those characters
+ *    are appended, starting at the original terminating null of strDest, and a
+ *    new terminating null is appended; otherwise, strDest[0] is set to the null
+ *    character.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest            Null-terminated destination string.
+ *    destMax            Size of the destination buffer.
+ *    strSrc             Null-terminated source string.
+ *    count              Number of character to append, or truncate.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest            is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                Success
+ *    EINVAL             strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    EINVAL_AND_RESET      (strDest unterminated  and all other parameters are valid)or
+ *                        (strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN)
+ *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("strncat_s");
+        return ERANGE;
+    }
+
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
+        if (strDest != NULL) {
+            strDest[0] = '\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > SECUREC_STRING_MAX_LEN) {
+#ifdef  SECUREC_COMPATIBLE_WIN_FORMAT
+        if (count == (size_t)(-1)) {
+            /* Windows internal functions may pass in -1 when calling this function */
+            return SecDoCatLimit(strDest, destMax, strSrc, destMax);
+        }
+#endif
+        strDest[0] = '\0';
+        SECUREC_ERROR_INVALID_RANGE("strncat_s");
+        return ERANGE_AND_RESET;
+    }
+    return SecDoCatLimit(strDest, destMax, strSrc, count);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(strncat_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncpy_s.c
new file mode 100644 (file)
index 0000000..fe8b291
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: strncpy_s  function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Performance-sensitive
+ * [reason] Always used in the performance critical path,
+ *          and sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
+#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \
+    (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \
+    ((count) <= SECUREC_STRING_MAX_LEN || (count) == ((size_t)(-1))) && (count) > 0))
+#else
+#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \
+    (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \
+    (count) <= SECUREC_STRING_MAX_LEN && (count) > 0))
+#endif
+
+/*
+ * Check Src Count Range
+ */
+SECUREC_INLINE errno_t CheckSrcCountRange(char *strDest, size_t destMax, const char *strSrc, size_t count)
+{
+    size_t tmpDestMax = destMax;
+    size_t tmpCount = count;
+    const char *endPos = strSrc;
+
+    /* Use destMax and  count as boundary checker and destMax must be greater than zero */
+    while (*(endPos) != '\0' && tmpDestMax > 0 && tmpCount > 0) {
+        ++endPos;
+        --tmpCount;
+        --tmpDestMax;
+    }
+    if (tmpDestMax == 0) {
+        strDest[0] = '\0';
+        SECUREC_ERROR_INVALID_RANGE("strncpy_s");
+        return ERANGE_AND_RESET;
+    }
+    return EOK;
+}
+
+/*
+ * Handling errors, when dest equal src return EOK
+ */
+errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("strncpy_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("strncpy_s");
+        if (strDest != NULL) {
+            strDest[0] = '\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > SECUREC_STRING_MAX_LEN) {
+        strDest[0] = '\0';      /* Clear dest string */
+        SECUREC_ERROR_INVALID_RANGE("strncpy_s");
+        return ERANGE_AND_RESET;
+    }
+    if (count == 0) {
+        strDest[0] = '\0';
+        return EOK;
+    }
+    return CheckSrcCountRange(strDest, destMax, strSrc, count);
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *   The strncpy_s function copies not more than n successive characters (not including the terminating null character)
+ *                     from the array pointed to by strSrc to the array pointed to by strDest.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                          Destination string.
+ *    destMax                          The size of the destination string, in characters.
+ *    strSrc                            Source string.
+ *    count                              Number of characters to be copied.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                           is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                               Success
+ *    EINVAL                          strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    EINVAL_AND_RESET       strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
+ *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
+{
+    if (SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count)) {
+        size_t minCpLen;        /* Use it to store the maxi length limit */
+        if (count < destMax) {
+            SECUREC_CALC_STR_LEN(strSrc, count, &minCpLen); /* No ending terminator */
+        } else {
+            size_t tmpCount = destMax;
+#ifdef  SECUREC_COMPATIBLE_WIN_FORMAT
+            if (count == ((size_t)(-1))) {
+                tmpCount = destMax - 1;
+            }
+#endif
+            SECUREC_CALC_STR_LEN(strSrc, tmpCount, &minCpLen); /* No ending terminator */
+            if (minCpLen == destMax) {
+                strDest[0] = '\0';
+                SECUREC_ERROR_INVALID_RANGE("strncpy_s");
+                return ERANGE_AND_RESET;
+            }
+        }
+        if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, minCpLen) || strDest == strSrc) {
+            /* Not overlap */
+            SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, minCpLen);    /* Copy string without terminator */
+            strDest[minCpLen] = '\0';
+            return EOK;
+        } else {
+            strDest[0] = '\0';
+            SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s");
+            return EOVERLAP_AND_RESET;
+        }
+    }
+    return strncpy_error(strDest, destMax, strSrc, count);
+}
+
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(strncpy_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strtok_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strtok_s.c
new file mode 100644 (file)
index 0000000..e5689e8
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: strtok_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+SECUREC_INLINE int SecIsInDelimit(char ch, const char *strDelimit)
+{
+    const char *ctl = strDelimit;
+    while (*ctl != '\0' && *ctl != ch) {
+        ++ctl;
+    }
+    return (int)(*ctl != '\0');
+}
+
+/*
+ * Find beginning of token (skip over leading delimiters).
+ * Note that there is no token if this loop sets string to point to the terminal null.
+ */
+SECUREC_INLINE char *SecFindBegin(char *strToken, const char *strDelimit)
+{
+    char *token = strToken;
+    while (*token != '\0') {
+        if (SecIsInDelimit(*token, strDelimit) != 0) {
+            ++token;
+            continue;
+        }
+        /* Don't find any delimiter in string header, break the loop */
+        break;
+    }
+    return token;
+}
+
+/*
+ * Find rest of token
+ */
+SECUREC_INLINE char *SecFindRest(char *strToken, const char *strDelimit)
+{
+    /* Find the rest of the token. If it is not the end of the string, put a null there */
+    char *token = strToken;
+    while (*token != '\0') {
+        if (SecIsInDelimit(*token, strDelimit) != 0) {
+            /* Find a delimiter, set string terminator */
+            *token = '\0';
+            ++token;
+            break;
+        }
+        ++token;
+    }
+    return token;
+}
+
+/*
+ * Find the final position pointer
+ */
+SECUREC_INLINE char *SecUpdateToken(char *strToken, const char *strDelimit, char **context)
+{
+    /* Point to updated position. Record string position for next search in the context */
+    *context = SecFindRest(strToken, strDelimit);
+    /* Determine if a token has been found. */
+    if (*context == strToken) {
+        return NULL;
+    }
+    return strToken;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The strtok_s function parses a string into a sequence of strToken,
+ *    replace all characters in strToken string that match to strDelimit set with 0.
+ *    On the first call to strtok_s the string to be parsed should be specified in strToken.
+ *    In each subsequent call that should parse the same string, strToken should be NULL
+ * <INPUT PARAMETERS>
+ *    strToken            String containing token or tokens.
+ *    strDelimit          Set of delimiter characters.
+ *    context             Used to store position information between calls
+ *                             to strtok_s
+ * <OUTPUT PARAMETERS>
+ *   context               is updated
+ * <RETURN VALUE>
+ *   On the first call returns the address of the first non \0 character, otherwise NULL is returned.
+ *   In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call,
+ *   return NULL if the *context string length is equal 0, otherwise return *context.
+ */
+char *strtok_s(char *strToken, const char *strDelimit, char **context)
+{
+    char *orgToken = strToken;
+    /* Validate delimiter and string context */
+    if (context == NULL || strDelimit == NULL) {
+        return NULL;
+    }
+    /* Valid input string and string pointer from where to search */
+    if (orgToken == NULL && *context == NULL) {
+        return NULL;
+    }
+    /* If string is null, continue searching from previous string position stored in context */
+    if (orgToken == NULL) {
+        orgToken = *context;
+    }
+    orgToken = SecFindBegin(orgToken, strDelimit);
+    return SecUpdateToken(orgToken, strDelimit, context);
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(strtok_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swprintf_s.c
new file mode 100644 (file)
index 0000000..09d77a2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: swprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *   The  swprintf_s  function  is  the  wide-character  equivalent  of the sprintf_s function
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                   Storage location for the output.
+ *    destMax                   Maximum number of characters to store.
+ *    format                    Format-control string.
+ *    ...                        Optional arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                    is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of wide characters stored in strDest, not  counting the terminating null wide character.
+ *    return -1  if an error occurred.
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vswprintf_s(strDest, destMax, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swscanf_s.c
new file mode 100644 (file)
index 0000000..e5b8bbf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: swscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The  swscanf_s  function  is  the  wide-character  equivalent  of the sscanf_s function
+ *    The swscanf_s function reads data from buffer into the location given by
+ *    each argument. Every argument must be a pointer to a variable with a type
+ *    that corresponds to a type specifier in format. The format argument controls
+ *    the interpretation of the input fields and has the same form and function
+ *    as the format argument for the scanf function. If copying takes place between
+ *    strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    buffer                 Stored data.
+ *    format                 Format control string, see Format Specifications.
+ *    ...                    Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                    the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; The return value does not include fields that were read but not
+ *    assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vswscanf_s(buffer, format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfscanf_s.c
new file mode 100644 (file)
index 0000000..214ee6a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vfscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "secinput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The vfscanf_s function is equivalent to fscanf_s, with the variable argument list replaced by argList
+ *    The vfscanf_s function reads data from the current position of stream into
+ *    the locations given by argument (if any). Each argument must be a pointer
+ *    to a variable of a type that corresponds to a type specifier in format.
+ *    format controls the interpretation of the input fields and has the same
+ *    form and function as the format argument for scanf.
+ *
+ * <INPUT PARAMETERS>
+ *    stream               Pointer to FILE structure.
+ *    format               Format control string, see Format Specifications.
+ *    argList              pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList              the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vfscanf_s(FILE *stream, const char *format, va_list argList)
+{
+    int retVal;                 /* If initialization causes  e838 */
+    SecFileStream fStr;
+
+    if (stream == NULL || format == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    if (stream == SECUREC_STREAM_STDIN) {
+        return vscanf_s(format, argList);
+    }
+
+    SECUREC_LOCK_FILE(stream);
+    SECUREC_FILE_STREAM_FROM_FILE(&fStr, stream);
+    retVal = SecInputS(&fStr, format, argList);
+    SECUREC_UNLOCK_FILE(stream);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfwscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfwscanf_s.c
new file mode 100644 (file)
index 0000000..1ab9c3c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vfwscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secinput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The  vfwscanf_s  function  is  the  wide-character  equivalent  of the vfscanf_s function
+ *    The vfwscanf_s function reads data from the current position of stream into
+ *    the locations given by argument (if any). Each argument must be a pointer
+ *    to a variable of a type that corresponds to a type specifier in format.
+ *    format controls the interpretation of the input fields and has the same form
+ *    and function as the format argument for scanf.
+ *
+ * <INPUT PARAMETERS>
+ *    stream               Pointer to FILE structure.
+ *    format               Format control string, see Format Specifications.
+ *    argList              pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList              the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList)
+{
+    int retVal; /* If initialization causes  e838 */
+    SecFileStream fStr;
+
+    if (stream == NULL || format == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    if (stream == SECUREC_STREAM_STDIN) {
+        return vwscanf_s(format, argList);
+    }
+
+    SECUREC_LOCK_FILE(stream);
+    SECUREC_FILE_STREAM_FROM_FILE(&fStr, stream);
+    retVal = SecInputSW(&fStr, format, argList);
+    SECUREC_UNLOCK_FILE(stream);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vscanf_s.c
new file mode 100644 (file)
index 0000000..61480a6
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "secinput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *     The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList,
+ *     The vscanf_s function reads data from the standard input stream stdin and
+ *    writes the data into the location that's given by argument. Each argument
+ *    must be a pointer to a variable of a type that corresponds to a type specifier
+ *    in format. If copying occurs between strings that overlap, the behavior is
+ *    undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    format                Format control string.
+ *    argList               pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList               the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Returns the number of fields successfully converted and assigned;
+ *    the return value does not include fields that were read but not assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vscanf_s(const char *format, va_list argList)
+{
+    int retVal;                 /* If initialization causes  e838 */
+    SecFileStream fStr;
+    SECUREC_FILE_STREAM_FROM_STDIN(&fStr);
+    /*
+     * The "va_list" has different definition on different platform, so we can't use argList == NULL
+     * To determine it's invalid. If you has fixed platform, you can check some fields to validate it,
+     * such as "argList == NULL" or argList.xxx != NULL or *(size_t *)&argList != 0.
+     */
+    if (format == NULL || fStr.pf == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+
+    SECUREC_LOCK_STDIN(0, fStr.pf);
+    retVal = SecInputS(&fStr, format, argList);
+    SECUREC_UNLOCK_STDIN(0, fStr.pf);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsnprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsnprintf_s.c
new file mode 100644 (file)
index 0000000..a4bec70
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vsnprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "secureprintoutput.h"
+
+#if SECUREC_ENABLE_VSNPRINTF
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The vsnprintf_s function is equivalent to the vsnprintf function
+ *     except for the parameter destMax/count and the explicit runtime-constraints violation
+ *    The vsnprintf_s function takes a pointer to an argument list, then formats
+ *    and writes up to count characters of the given data to the memory pointed
+ *    to by strDest and appends a terminating null.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                  Storage location for the output.
+ *    destMax                The size of the strDest for output.
+ *    count                    Maximum number of character to write(not including
+ *                                the terminating NULL)
+ *    format                   Format-control string.
+ *    argList                     pointer to list of arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of characters written, not including the terminating null
+ *    return -1 if an  error occurs.
+ *    return -1 if count < destMax and the output string  has been truncated
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format, va_list argList)
+{
+    int retVal;
+
+    if (SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, SECUREC_STRING_MAX_LEN)) {
+        SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN);
+        SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s");
+        return -1;
+    }
+
+    if (destMax > count) {
+        retVal = SecVsnprintfImpl(strDest, count + 1, format, argList);
+        if (retVal == SECUREC_PRINTF_TRUNCATE) {  /* To keep dest buffer not destroyed 2014.2.18 */
+            /* The string has been truncated, return  -1 */
+            return -1;          /* To skip error handler,  return strlen(strDest) or -1 */
+        }
+    } else {
+        retVal = SecVsnprintfImpl(strDest, destMax, format, argList);
+#ifdef SECUREC_COMPATIBLE_WIN_FORMAT
+        if (retVal == SECUREC_PRINTF_TRUNCATE && count == (size_t)(-1)) {
+            return -1;
+        }
+#endif
+    }
+
+    if (retVal < 0) {
+        strDest[0] = '\0';      /* Empty the dest strDest */
+        if (retVal == SECUREC_PRINTF_TRUNCATE) {
+            /* Buffer too small */
+            SECUREC_ERROR_INVALID_RANGE("vsnprintf_s");
+        }
+        SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s");
+        return -1;
+    }
+
+    return retVal;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(vsnprintf_s);
+#endif
+#endif
+
+#if SECUREC_SNPRINTF_TRUNCATED
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The vsnprintf_truncated_s function is equivalent to the vsnprintf function
+ *     except for the parameter destMax/count and the explicit runtime-constraints violation
+ *    The vsnprintf_truncated_s function takes a pointer to an argument list, then formats
+ *    and writes up to count characters of the given data to the memory pointed
+ *    to by strDest and appends a terminating null.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                  Storage location for the output.
+ *    destMax                The size of the strDest for output.
+ *                                the terminating NULL)
+ *    format                   Format-control string.
+ *    argList                     pointer to list of arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of characters written, not including the terminating null
+ *    return -1 if an  error occurs.
+ *    return destMax-1 if output string  has been truncated
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format, va_list argList)
+{
+    int retVal;
+
+    if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) {
+        SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN);
+        SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s");
+        return -1;
+    }
+
+    retVal = SecVsnprintfImpl(strDest, destMax, format, argList);
+    if (retVal < 0) {
+        if (retVal == SECUREC_PRINTF_TRUNCATE) {
+            return (int)(destMax - 1);  /* To skip error handler,  return strlen(strDest) */
+        }
+        strDest[0] = '\0';      /* Empty the dest strDest */
+        SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s");
+        return -1;
+    }
+
+    return retVal;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(vsnprintf_truncated_s);
+#endif
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsprintf_s.c
new file mode 100644 (file)
index 0000000..23bf04a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vsprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "secureprintoutput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The vsprintf_s function is equivalent to the vsprintf function
+ *    except for the parameter destMax and the explicit runtime-constraints violation
+ *    The vsprintf_s function takes a pointer to an argument list, and then formats
+ *    and writes the given data to the memory pointed to by strDest.
+ *    The function differ from the non-secure versions only in that the secure
+ *    versions support positional parameters.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                Storage location for the output.
+ *    destMax                Size of strDest
+ *    format                 Format specification.
+ *    argList                pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of characters written, not including the terminating null character,
+ *    return -1  if an  error occurs.
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int vsprintf_s(char *strDest, size_t destMax, const char *format, va_list argList)
+{
+    int retVal;               /* If initialization causes  e838 */
+
+    if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) {
+        SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN);
+        SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s");
+        return -1;
+    }
+
+    retVal = SecVsnprintfImpl(strDest, destMax, format, argList);
+    if (retVal < 0) {
+        strDest[0] = '\0';
+        if (retVal == SECUREC_PRINTF_TRUNCATE) {
+            /* Buffer is too small */
+            SECUREC_ERROR_INVALID_RANGE("vsprintf_s");
+        }
+        SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s");
+        return -1;
+    }
+
+    return retVal;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(vsprintf_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsscanf_s.c
new file mode 100644 (file)
index 0000000..a19abe2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vsscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "secinput.h"
+#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL && \
+    (!defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT))
+#include <ctype.h>
+#endif
+
+/*
+ * <NAME>
+ *    vsscanf_s
+ *
+ *
+ * <FUNCTION DESCRIPTION>
+ *    The vsscanf_s function is equivalent to sscanf_s, with the variable argument list replaced by argList
+ *    The vsscanf_s function reads data from buffer into the location given by
+ *    each argument. Every argument must be a pointer to a variable with a type
+ *    that corresponds to a type specifier in format. The format argument controls
+ *    the interpretation of the input fields and has the same form and function
+ *    as the format argument for the scanf function.
+ *    If copying takes place between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    buffer                Stored data
+ *    format                Format control string, see Format Specifications.
+ *    argList               pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList               the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vsscanf_s(const char *buffer, const char *format, va_list argList)
+{
+    size_t count;               /* If initialization causes  e838 */
+    int retVal;
+    SecFileStream fStr;
+
+    /* Validation section */
+    if (buffer == NULL || format == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    count = strlen(buffer);
+    if (count == 0 || count > SECUREC_STRING_MAX_LEN) {
+        SecClearDestBuf(buffer, format, argList);
+        SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL
+    /*
+     * On vxworks platform when buffer is white string, will set first %s argument to zero.Like following usage:
+     * "   \v\f\t\r\n", "%s", str, strSize
+     * Do not check all character, just first and last character then consider it is white string
+     */
+    if (isspace((int)(unsigned char)buffer[0]) != 0 && isspace((int)(unsigned char)buffer[count - 1]) != 0) {
+        SecClearDestBuf(buffer, format, argList);
+    }
+#endif
+    SECUREC_FILE_STREAM_FROM_STRING(&fStr, buffer, count);
+    retVal = SecInputS(&fStr, format, argList);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    return retVal;
+}
+#if SECUREC_EXPORT_KERNEL_SYMBOL
+EXPORT_SYMBOL(vsscanf_s);
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswprintf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswprintf_s.c
new file mode 100644 (file)
index 0000000..29715fc
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vswprintf_s  function
+ * Create: 2014-02-25
+ */
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secureprintoutput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The  vswprintf_s  function  is  the  wide-character  equivalent  of the vsprintf_s function
+ *
+ * <INPUT PARAMETERS>
+ *    strDest                  Storage location for the output.
+ *    destMax                  Maximum number of characters to store
+ *    format                   Format specification.
+ *    argList                  pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest                 is updated
+ *
+ * <RETURN VALUE>
+ *    return  the number of wide characters stored in strDest, not  counting the terminating null wide character.
+ *    return -1  if an error occurred.
+ *
+ * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList)
+{
+    int retVal;               /* If initialization causes  e838 */
+    if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN)) {
+        SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN);
+        SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s");
+        return -1;
+    }
+
+    retVal = SecVswprintfImpl(strDest, destMax, format, argList);
+    if (retVal < 0) {
+        strDest[0] = L'\0';
+        if (retVal == SECUREC_PRINTF_TRUNCATE) {
+            /* Buffer too small */
+            SECUREC_ERROR_INVALID_RANGE("vswprintf_s");
+        }
+        SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s");
+        return -1;
+    }
+
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswscanf_s.c
new file mode 100644 (file)
index 0000000..bab53a3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vswscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secinput.h"
+
+SECUREC_INLINE size_t SecWcslen(const wchar_t *s)
+{
+    const wchar_t *end = s;
+    while (*end != L'\0') {
+        ++end;
+    }
+    return ((size_t)((end - s)));
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The  vswscanf_s  function  is  the  wide-character  equivalent  of the vsscanf_s function
+ *    The vsscanf_s function reads data from buffer into the location given by
+ *    each argument. Every argument must be a pointer to a variable with a type
+ *    that corresponds to a type specifier in format.
+ *    The format argument controls the interpretation of the input fields and
+ *    has the same form and function as the format argument for the scanf function.
+ *    If copying takes place between strings that overlap, the behavior is undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    buffer                Stored data
+ *    format                Format control string, see Format Specifications.
+ *    argList               pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList               the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Each of these functions returns the number of fields successfully converted
+ *    and assigned; the return value does not include fields that were read but
+ *    not assigned. A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList)
+{
+    size_t count; /* If initialization causes  e838 */
+    SecFileStream fStr;
+    int retVal;
+
+    /* Validation section */
+    if (buffer == NULL || format == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    count = SecWcslen(buffer);
+    if (count == 0 || count > SECUREC_WCHAR_STRING_MAX_LEN) {
+        SecClearDestBufW(buffer, format, argList);
+        SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    SECUREC_FILE_STREAM_FROM_STRING(&fStr, (const char *)buffer, count * sizeof(wchar_t));
+    retVal = SecInputSW(&fStr, format, argList);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vwscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vwscanf_s.c
new file mode 100644 (file)
index 0000000..b39f9bc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: vwscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#ifndef SECUREC_FOR_WCHAR
+#define SECUREC_FOR_WCHAR
+#endif
+
+#include "secinput.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The  vwscanf_s  function  is  the  wide-character  equivalent  of the vscanf_s function
+ *    The vwscanf_s function is the wide-character version of vscanf_s. The
+ *    function reads data from the standard input stream stdin and writes the
+ *    data into the location that's given by argument. Each argument  must be a
+ *    pointer to a variable of a type that corresponds to a type specifier in
+ *    format. If copying occurs between strings that overlap, the behavior is
+ *    undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    format                 Format control string.
+ *    argList                pointer to list of arguments
+ *
+ * <OUTPUT PARAMETERS>
+ *    argList                the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Returns the number of fields successfully converted and assigned;
+ *    the return value does not include fields that were read but not assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int vwscanf_s(const wchar_t *format, va_list argList)
+{
+    int retVal;                 /* If initialization causes  e838 */
+    SecFileStream fStr;
+    SECUREC_FILE_STREAM_FROM_STDIN(&fStr);
+    if (format == NULL || fStr.pf == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+
+    SECUREC_LOCK_STDIN(0, fStr.pf);
+    retVal = SecInputSW(&fStr, format, argList);
+    SECUREC_UNLOCK_STDIN(0, fStr.pf);
+    if (retVal < 0) {
+        SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s");
+        return SECUREC_SCANF_EINVAL;
+    }
+
+    return retVal;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscat_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscat_s.c
new file mode 100644 (file)
index 0000000..fa7d847
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wcscat_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+/*
+ * Befor this function, the basic parameter checking has been done
+ */
+SECUREC_INLINE errno_t SecDoCatW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc)
+{
+    size_t destLen;
+    size_t srcLen;
+    size_t maxCount; /* Store the maximum available count */
+
+    /* To calculate the length of a wide character, the parameter must be a wide character */
+    SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen);
+    maxCount = destMax - destLen;
+    SECUREC_CALC_WSTR_LEN(strSrc, maxCount, &srcLen);
+
+    if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) {
+        strDest[0] = L'\0';
+        if (strDest + destLen <= strSrc && destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("wcscat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_BUFFER_OVERLAP("wcscat_s");
+        return EOVERLAP_AND_RESET;
+    }
+    if (srcLen + destLen >= destMax || strDest == strSrc) {
+        strDest[0] = L'\0';
+        if (destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("wcscat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_INVALID_RANGE("wcscat_s");
+        return ERANGE_AND_RESET;
+    }
+    /* Copy single character length  include \0 */
+    SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, (srcLen + 1) * sizeof(wchar_t));
+    return EOK;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The wcscat_s function appends a copy of the wide string pointed to by strSrc
+*      (including the terminating null wide character)
+ *     to the end of the wide string pointed to by strDest.
+ *    The arguments and return value of wcscat_s are wide-character strings.
+ *
+ *    The wcscat_s function appends strSrc to strDest and terminates the resulting
+ *    string with a null character. The initial character of strSrc overwrites the
+ *    terminating null character of strDest. wcscat_s will return EOVERLAP_AND_RESET if the
+ *    source and destination strings overlap.
+ *
+ *    Note that the second parameter is the total size of the buffer, not the
+ *    remaining size.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest              Null-terminated destination string buffer.
+ *    destMax              Size of the destination string buffer.
+ *    strSrc               Null-terminated source string buffer.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest               is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                   Success
+ *    EINVAL                strDest is  NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    EINVAL_AND_RESET      (strDest unterminated and all other parameters are valid) or
+ *                          (strDest != NULL and strSrc is NULL and destMax != 0
+ *                           and destMax <= SECUREC_WCHAR_STRING_MAX_LEN)
+ *    ERANGE                destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET     dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("wcscat_s");
+        return ERANGE;
+    }
+
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("wcscat_s");
+        if (strDest != NULL) {
+            strDest[0] = L'\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+
+    return SecDoCatW(strDest, destMax, strSrc);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscpy_s.c
new file mode 100644 (file)
index 0000000..8c4a4af
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wcscpy_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+SECUREC_INLINE errno_t SecDoCpyW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc)
+{
+    size_t srcStrLen;
+    SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen);
+
+    if (srcStrLen == destMax) {
+        strDest[0] = L'\0';
+        SECUREC_ERROR_INVALID_RANGE("wcscpy_s");
+        return ERANGE_AND_RESET;
+    }
+    if (strDest == strSrc) {
+        return EOK;
+    }
+
+    if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) {
+        /* Performance optimization, srcStrLen is single character length  include '\0' */
+        SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, (srcStrLen + 1) * sizeof(wchar_t));
+        return EOK;
+    } else {
+        strDest[0] = L'\0';
+        SECUREC_ERROR_BUFFER_OVERLAP("wcscpy_s");
+        return EOVERLAP_AND_RESET;
+    }
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *   The wcscpy_s function copies the wide string pointed to by strSrc
+ *   (including the terminating null wide character) into the array pointed to by strDest
+
+ * <INPUT PARAMETERS>
+ *    strDest               Destination string buffer
+ *    destMax               Size of the destination string buffer.
+ *    strSrc                Null-terminated source string buffer.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest               is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                   Success
+ *    EINVAL                strDest is  NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    EINVAL_AND_RESET      strDest != NULL and strSrc is NULL and destMax != 0
+ *                          and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    ERANGE                destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET      destMax <= length of strSrc and strDest != strSrc
+ *                          and strDest != NULL and strSrc != NULL and destMax != 0
+ *                          and destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap
+ *    EOVERLAP_AND_RESET    dest buffer and source buffer are overlapped and destMax != 0
+ *                          and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *                          and strDest != NULL and strSrc !=NULL and strDest != strSrc
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("wcscpy_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("wcscpy_s");
+        if (strDest != NULL) {
+            strDest[0] = L'\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    return SecDoCpyW(strDest, destMax, strSrc);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncat_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncat_s.c
new file mode 100644 (file)
index 0000000..33e53a3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wcsncat_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+/*
+ * Befor this function, the basic parameter checking has been done
+ */
+SECUREC_INLINE errno_t SecDoCatLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
+{
+    /* To calculate the length of a wide character, the parameter must be a wide character */
+    size_t destLen;
+    size_t srcLen;
+    SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen);
+    SECUREC_CALC_WSTR_LEN(strSrc, count, &srcLen);
+
+    if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) {
+        strDest[0] = L'\0';
+        if (strDest + destLen <= strSrc && destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s");
+        return EOVERLAP_AND_RESET;
+    }
+    if (srcLen + destLen >= destMax || strDest == strSrc) {
+        strDest[0] = L'\0';
+        if (destLen == destMax) {
+            SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
+            return EINVAL_AND_RESET;
+        }
+        SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
+        return ERANGE_AND_RESET;
+    }
+    SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen * sizeof(wchar_t)); /* no  terminator */
+    *(strDest + destLen + srcLen) = L'\0';
+    return EOK;
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The wcsncat_s function appends not more than n successive wide characters
+ *     (not including the terminating null wide character)
+ *     from the array pointed to by strSrc to the end of the wide string pointed to by strDest.
+ *
+ *    The wcsncat_s function try to append the first D characters of strSrc to
+ *    the end of strDest, where D is the lesser of count and the length of strSrc.
+ *    If appending those D characters will fit within strDest (whose size is
+ *    given as destMax) and still leave room for a null terminator, then those
+ *    characters are appended, starting at the original terminating null of
+ *    strDest, and a new terminating null is appended; otherwise, strDest[0] is
+ *    set to the null character.
+ *
+ * <INPUT PARAMETERS>
+ *    strDest               Null-terminated destination string.
+ *    destMax               Size of the destination buffer.
+ *    strSrc                Null-terminated source string.
+ *    count                 Number of character to append, or truncate.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest               is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                   Success
+ *    EINVAL                strDest is  NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    EINVAL_AND_RESET      (strDest unterminated and all other parameters are valid) or
+ *                          (strDest != NULL and strSrc is NULL and destMax != 0 and
+ *                           destMax <= SECUREC_WCHAR_STRING_MAX_LEN)
+ *    ERANGE                destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
+ *    EOVERLAP_AND_RESET     dest buffer and source buffer are overlapped and all  parameters are valid
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
+        if (strDest != NULL) {
+            strDest[0] = L'\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > SECUREC_WCHAR_STRING_MAX_LEN) {
+#ifdef  SECUREC_COMPATIBLE_WIN_FORMAT
+        if (count == ((size_t)(-1))) {
+            /* Windows internal functions may pass in -1 when calling this function */
+            return SecDoCatLimitW(strDest, destMax, strSrc, destMax);
+        }
+#endif
+        strDest[0] = L'\0';
+        SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
+        return ERANGE_AND_RESET;
+    }
+    return SecDoCatLimitW(strDest, destMax, strSrc, count);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncpy_s.c
new file mode 100644 (file)
index 0000000..463f90e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wcsncpy_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+SECUREC_INLINE errno_t SecDoCpyLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
+{
+    size_t srcStrLen;
+    if (count < destMax) {
+        SECUREC_CALC_WSTR_LEN(strSrc, count, &srcStrLen);
+    } else {
+        SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen);
+    }
+    if (srcStrLen == destMax) {
+        strDest[0] = L'\0';
+        SECUREC_ERROR_INVALID_RANGE("wcsncpy_s");
+        return ERANGE_AND_RESET;
+    }
+    if (strDest == strSrc) {
+        return EOK;
+    }
+    if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) {
+        /* Performance optimization srcStrLen not include '\0' */
+        SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, srcStrLen * sizeof(wchar_t));
+        *(strDest + srcStrLen) = L'\0';
+        return EOK;
+    } else {
+        strDest[0] = L'\0';
+        SECUREC_ERROR_BUFFER_OVERLAP("wcsncpy_s");
+        return EOVERLAP_AND_RESET;
+    }
+}
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *    The wcsncpy_s function copies not more than n successive wide characters
+ *     (not including the terminating null wide character)
+ *     from the array pointed to by strSrc to the array pointed to by strDest
+ *
+ * <INPUT PARAMETERS>
+ *    strDest             Destination string.
+ *    destMax             The size of the destination string, in characters.
+ *    strSrc              Source string.
+ *    count                Number of characters to be copied.
+ *
+ * <OUTPUT PARAMETERS>
+ *    strDest              is updated
+ *
+ * <RETURN VALUE>
+ *    EOK                  Success
+ *    EINVAL               strDest is  NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    EINVAL_AND_RESET     strDest != NULL and strSrc is NULL and destMax != 0
+ *                         and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
+ *    ERANGE               destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0
+ *    ERANGE_AND_RESET     count > SECUREC_WCHAR_STRING_MAX_LEN or
+ *                         (destMax <= length of strSrc and destMax <= count and strDest != strSrc
+ *                          and strDest != NULL and strSrc != NULL and destMax != 0 and
+ *                          destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap)
+ *    EOVERLAP_AND_RESET     dest buffer and source buffer are overlapped and  all  parameters are valid
+ *
+ *
+ *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
+ */
+errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) {
+        SECUREC_ERROR_INVALID_RANGE("wcsncpy_s");
+        return ERANGE;
+    }
+    if (strDest == NULL || strSrc == NULL) {
+        SECUREC_ERROR_INVALID_PARAMTER("wcsncpy_s");
+        if (strDest != NULL) {
+            strDest[0] = L'\0';
+            return EINVAL_AND_RESET;
+        }
+        return EINVAL;
+    }
+    if (count > SECUREC_WCHAR_STRING_MAX_LEN) {
+#ifdef SECUREC_COMPATIBLE_WIN_FORMAT
+        if (count == (size_t)(-1)) {
+            return SecDoCpyLimitW(strDest, destMax, strSrc, destMax - 1);
+        }
+#endif
+        strDest[0] = L'\0';      /* Clear dest string */
+        SECUREC_ERROR_INVALID_RANGE("wcsncpy_s");
+        return ERANGE_AND_RESET;
+    }
+
+    if (count == 0) {
+        strDest[0] = L'\0';
+        return EOK;
+    }
+
+    return SecDoCpyLimitW(strDest, destMax, strSrc, count);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcstok_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcstok_s.c
new file mode 100644 (file)
index 0000000..063ca69
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wcstok_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securecutil.h"
+
+SECUREC_INLINE int SecIsInDelimitW(wchar_t ch, const wchar_t *strDelimit)
+{
+    const wchar_t *ctl = strDelimit;
+    while (*ctl != L'\0' && *ctl != ch) {
+        ++ctl;
+    }
+    return (int)(*ctl != L'\0');
+}
+
+/*
+ * Find beginning of token (skip over leading delimiters).
+ * Note that there is no token if this loop sets string to point to the terminal null.
+ */
+SECUREC_INLINE wchar_t *SecFindBeginW(wchar_t *strToken, const wchar_t *strDelimit)
+{
+    wchar_t *token = strToken;
+    while (*token != L'\0') {
+        if (SecIsInDelimitW(*token, strDelimit) != 0) {
+            ++token;
+            continue;
+        }
+        /* Don't find any delimiter in string header, break the loop */
+        break;
+    }
+    return token;
+}
+
+/*
+ * Find the end of the token. If it is not the end of the string, put a null there.
+ */
+SECUREC_INLINE wchar_t *SecFindRestW(wchar_t *strToken, const wchar_t *strDelimit)
+{
+    wchar_t *token = strToken;
+    while (*token != L'\0') {
+        if (SecIsInDelimitW(*token, strDelimit) != 0) {
+            /* Find a delimiter, set string terminator */
+            *token = L'\0';
+            ++token;
+            break;
+        }
+        ++token;
+    }
+    return token;
+}
+
+/*
+ * Update Token wide character  function
+ */
+SECUREC_INLINE wchar_t *SecUpdateTokenW(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context)
+{
+    /* Point to updated position.  Record string position for next search in the context */
+    *context = SecFindRestW(strToken, strDelimit);
+    /* Determine if a token has been found */
+    if (*context == strToken) {
+        return NULL;
+    }
+    return strToken;
+}
+
+/*
+ * <NAME>
+ *    wcstok_s
+ *
+ *
+ * <FUNCTION DESCRIPTION>
+ *   The  wcstok_s  function  is  the  wide-character  equivalent  of the strtok_s function
+ *
+ * <INPUT PARAMETERS>
+ *    strToken               String containing token or tokens.
+ *    strDelimit             Set of delimiter characters.
+ *    context                Used to store position information between calls to
+ *                               wcstok_s.
+ *
+ * <OUTPUT PARAMETERS>
+ *    context               is updated
+ * <RETURN VALUE>
+ *   The  wcstok_s  function  is  the  wide-character  equivalent  of the strtok_s function
+ */
+wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context)
+{
+    wchar_t *orgToken = strToken;
+    /* Validation section */
+    if (context == NULL || strDelimit == NULL) {
+        return NULL;
+    }
+    if (orgToken == NULL && *context == NULL) {
+        return NULL;
+    }
+    /* If string==NULL, continue with previous string */
+    if (orgToken == NULL) {
+        orgToken = *context;
+    }
+    orgToken = SecFindBeginW(orgToken, strDelimit);
+    return SecUpdateTokenW(orgToken, strDelimit, context);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemcpy_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemcpy_s.c
new file mode 100644 (file)
index 0000000..2f2b4a3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wmemcpy_s  function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *   The wmemcpy_s function copies n successive wide characters
+ *    from the object pointed to by src into the object pointed to by dest.t.
+ *
+ * <INPUT PARAMETERS>
+ *    dest                   Destination buffer.
+ *    destMax                Size of the destination buffer.
+ *    src                     Buffer to copy from.
+ *    count                  Number of characters to copy.
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer            is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                    Success
+ *    EINVAL                 dest is  NULL  and destMax != 0 and count <= destMax
+ *                           and destMax <= SECUREC_WCHAR_MEM_MAX_LEN
+ *    EINVAL_AND_RESET       dest != NULL and src is NULL and destMax != 0
+ *                           and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax
+ *    ERANGE                 destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or
+ *                           (count > destMax and dest is  NULL and destMax != 0
+ *                            and destMax <= SECUREC_WCHAR_MEM_MAX_LEN)
+ *    ERANGE_AND_RESET       count > destMax and dest  !=  NULL and destMax != 0
+ *                           and destMax <= SECUREC_WCHAR_MEM_MAX_LEN
+ *    EOVERLAP_AND_RESET     dest buffer and source buffer are overlapped and
+ *                           count <= destMax destMax != 0 and destMax <= SECUREC_WCHAR_MEM_MAX_LEN
+ *                           and dest  !=  NULL  and src != NULL and dest != src
+ *
+ *    if an error occurred, dest will be filled with 0 when dest and destMax valid .
+ *    If the source and destination overlap, the behavior of wmemcpy_s is undefined.
+ *    Use wmemmove_s to handle overlapping regions.
+ */
+errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) {
+        SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s");
+        return ERANGE;
+    }
+    if (count > destMax) {
+        SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s");
+        if (dest != NULL) {
+            (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax * sizeof(wchar_t));
+            return ERANGE_AND_RESET;
+        }
+        return ERANGE;
+    }
+    return memcpy_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t));
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemmove_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemmove_s.c
new file mode 100644 (file)
index 0000000..88bb97b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wmemmove_s  function
+ * Create: 2014-02-25
+ */
+/*
+ * [Standardize-exceptions] Use unsafe function: Portability
+ * [reason] Use unsafe function to implement security function to maintain platform compatibility.
+ *          And sufficient input validation is performed before calling
+ */
+
+#include "securecutil.h"
+
+/*
+ * <FUNCTION DESCRIPTION>
+ *   The wmemmove_s function copies n successive wide characters from the object pointed
+ *   to by src into the object pointed to by dest.
+ *
+ * <INPUT PARAMETERS>
+ *    dest                     Destination buffer.
+ *    destMax                  Size of the destination buffer.
+ *    src                      Source object.
+ *    count                    Number of bytes or character to copy.
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest                     is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                      Success
+ *    EINVAL                   dest is  NULL and destMax != 0 and count <= destMax
+ *                             and destMax <= SECUREC_WCHAR_MEM_MAX_LEN
+ *    EINVAL_AND_RESET         dest != NULL and src is NULL and destMax != 0
+ *                             and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax
+ *    ERANGE                   destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or
+ *                             (count > destMax and dest is  NULL and destMax != 0
+ *                             and destMax <= SECUREC_WCHAR_MEM_MAX_LEN)
+ *    ERANGE_AND_RESET        count > destMax and dest  !=  NULL and destMax != 0
+ *                             and destMax <= SECUREC_WCHAR_MEM_MAX_LEN
+ *
+ *
+ *     If an error occurred, dest will  be filled with 0 when dest and destMax valid.
+ *     If some regions of the source area and the destination overlap, wmemmove_s
+ *     ensures that the original source bytes in the overlapping region are copied
+ *     before being overwritten
+ */
+errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count)
+{
+    if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) {
+        SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s");
+        return ERANGE;
+    }
+    if (count > destMax) {
+        SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s");
+        if (dest != NULL) {
+            (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax * sizeof(wchar_t));
+            return ERANGE_AND_RESET;
+        }
+        return ERANGE;
+    }
+    return memmove_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t));
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wscanf_s.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wscanf_s.c
new file mode 100644 (file)
index 0000000..badb04e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
+ * Licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Description: wscanf_s  function
+ * Create: 2014-02-25
+ */
+
+#include "securec.h"
+
+/*
+ * <NAME>
+ * <FUNCTION DESCRIPTION>
+ *    The  wscanf_s  function  is  the  wide-character  equivalent  of the scanf_s function
+ *    The wscanf_s function reads data from the standard input stream stdin and
+ *    writes the data into the location that's given by argument. Each argument
+ *    must be a pointer to a variable of a type that corresponds to a type specifier
+ *    in format. If copying occurs between strings that overlap, the behavior is
+ *    undefined.
+ *
+ * <INPUT PARAMETERS>
+ *    format                  Format control string.
+ *    ...                         Optional arguments.
+ *
+ * <OUTPUT PARAMETERS>
+ *    ...                     the converted value stored in user assigned address
+ *
+ * <RETURN VALUE>
+ *    Returns the number of fields successfully converted and assigned;
+ *    the return value does not include fields that were read but not assigned.
+ *    A return value of 0 indicates that no fields were assigned.
+ *    return -1 if an error occurs.
+ */
+int wscanf_s(const wchar_t *format, ...)
+{
+    int ret;                    /* If initialization causes  e838 */
+    va_list argList;
+
+    va_start(argList, format);
+    ret = vwscanf_s(format, argList);
+    va_end(argList);
+    (void)argList;              /* To clear e438 last value assigned not used , the compiler will optimize this code */
+
+    return ret;
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6d6660d
--- /dev/null
@@ -0,0 +1,18 @@
+#===============================================================================\r
+# @brief    cmake make file\r
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+#===============================================================================\r
+set(\r
+    tiot_pm_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm.c\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm_wakelock.c\r
+)\r
+\r
+add_subdirectory(pm_default)\r
+\r
+if(DEFINED CONFIG_DEV_TIOT_SLAVE)\r
+add_subdirectory(pm_slave)\r
+endif()\r
+\r
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)\r
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_pm_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3f3d898
--- /dev/null
@@ -0,0 +1,7 @@
+set(
+    tiot_pm_default_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm_default.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_pm_default_src_list}" CACHE INTERNAL "tiot src list" FORCE)
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.c
new file mode 100644 (file)
index 0000000..01a60ef
--- /dev/null
@@ -0,0 +1,288 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT pm default. \n
+ *
+ * History: \n
+ * 2023-06-09, Create file. \n
+ */
+
+#include "tiot_pm_default.h"
+#include "tiot_pm_wakelock.h"
+#include "tiot_board_pin_port.h"
+#include "tiot_board_log.h"
+#include "tiot_controller.h"
+#include "tiot_xfer_utils.h"
+#include "tiot_board.h"
+#include "tiot_sys_msg_types.h"
+#ifdef CONFIG_PM_WAKEUP_BY_UART
+#include "tiot_board_uart_port.h"
+#endif
+
+tiot_pm_retcode tiot_pm_default_power_off(tiot_pm *pm)
+{
+    if (tiot_board_pin_set_level(pm->pm_info[TIOT_PIN_POWER_CTRL], TIOT_PIN_LEVEL_LOW) != 0) {
+        return TIOT_PM_EVTRET_FAIL;
+    }
+    /* 下电时unlock。 */
+    tiot_pm_wake_unlock();
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_default_power_on(tiot_pm *pm)
+{
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    const tiot_device_timings *timings = &ctrl->dev_info->timings;
+    uint32_t power_ctrl_pin = pm->pm_info[TIOT_PIN_POWER_CTRL];
+    int32_t ret = 0;
+    do {
+        ret = tiot_board_pin_set_level(power_ctrl_pin, TIOT_PIN_LEVEL_LOW);
+        if (ret != 0) {
+            tiot_print_err("[TIoT][pm]set pwr pin level low fail.\n");
+            break;
+        }
+        osal_msleep(timings->power_on_wait_ms);
+        ret = tiot_board_pin_set_level(power_ctrl_pin, TIOT_PIN_LEVEL_HIGH);
+        if (ret != 0) {
+            tiot_print_err("[TIoT][pm]set pwr pin level high fail.\n");
+            break;
+        }
+        osal_msleep(timings->boot_time_ms);
+    } while (0);
+
+    if (ret != 0) {
+        tiot_print_err("[TIoT:pm]power on fail.\n");
+        return TIOT_PM_EVTRET_FAIL;
+    }
+    /* 上电时lock。 */
+    tiot_pm_wake_lock();
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+/* 不可在中断环境下使用. */
+int32_t tiot_pm_check_sleeped(uint32_t wakein_pin, uint8_t check_times)
+{
+    int32_t ret;
+    uint8_t level;
+    uint8_t i;
+    const uint8_t sleep_check = check_times;      /* 等待睡眠,重试check_times次. */
+    const uint8_t sleep_wait_ms = 2;     /* 等待睡眠,每次等待2ms. */
+    /* 唤醒时,如果wakein_pin存在,检查wakein_pin拉低后再发送唤醒, 确保主机已休眠. */
+    if (wakein_pin == TIOT_PIN_NONE) {
+        return 0;
+    }
+    for (i = 0; i < sleep_check; i++) {
+        ret = tiot_board_pin_get_level(wakein_pin, &level);
+        if (ret != 0) {
+            tiot_print_err("[TIoT:pm]wakein pin level get error.\n");
+            return -1;
+        }
+        if (level == TIOT_PIN_LEVEL_LOW) {
+            return 0;
+        }
+        osal_msleep(sleep_wait_ms);
+    }
+    /* 此时device侧可能又重新拉高管脚通知有数据上报,保持状态即可, 响应event即转成work. */
+    tiot_print_warning("[TIoT:pm]wakein pin level high after check (%d) times.\n", sleep_check);
+    return -1;
+}
+
+#ifdef CONFIG_PM_WAKEUP_BY_UART
+tiot_pm_retcode tiot_pm_default_wakeup_device_by_uart(tiot_pm *pm)
+{
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    int32_t ret;
+    tiot_print_info("[TIoT][pm]wakeup device enter.\n");
+    const uint32_t wakeup_baudrate = 115200;    /* UART唤醒时设为115200波特率. */
+    const uint8_t wakeup_cmd = 0x00;
+    const uint8_t check_times = 10;
+    tiot_xfer_manager *xfer = &ctrl->transfer;
+    ret = tiot_pm_check_sleeped(pm->pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST], check_times);
+    if (ret != 0) {
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+
+    tiot_uart_config old_config = { 0 };
+    tiot_uart_config wakeup_config = { wakeup_baudrate,
+        { .data_bits = TIOT_UART_ATTR_DATABIT_8, .parity = TIOT_UART_ATTR_PARITY_NONE,
+          .stop_bits = TIOT_UART_ATTR_STOPBIT_1, .flow_ctrl = TIOT_UART_ATTR_FLOW_CTRL_DISABLE } };
+    (void)tiot_xfer_get_config(xfer, &old_config);
+    (void)tiot_xfer_set_config(xfer, &wakeup_config);
+    ret = tiot_xfer_direct_send(xfer, &wakeup_cmd, sizeof(uint8_t));
+    (void)tiot_xfer_set_config(xfer, &old_config);
+    if (ret != sizeof(uint8_t)) {
+        return TIOT_PM_EVTRET_FAIL;
+    }
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+#endif
+
+tiot_pm_retcode tiot_pm_default_wakeup_device_by_gpio(tiot_pm *pm)
+{
+    int32_t ret;
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    const tiot_device_timings *timings = &ctrl->dev_info->timings;
+    uint32_t wakeup_device_pin = pm->pm_info[TIOT_PIN_HOST_WAKEUP_DEVICE];
+    const uint8_t check_times = 10;
+
+    tiot_print_info("[TIoT][pm]wakeup device enter.\n");
+    if (wakeup_device_pin == TIOT_PIN_NONE) {
+        tiot_print_err("[TIoT][pm]wakeup pin not set.\n");
+        return TIOT_PM_EVTRET_FAIL;
+    }
+
+    ret = tiot_pm_check_sleeped(pm->pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST], check_times);
+    if (ret != 0) {
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+
+    do {
+        ret = tiot_board_pin_set_level(wakeup_device_pin, TIOT_PIN_LEVEL_LOW);
+        if (ret != 0) {
+            tiot_print_err("[TIoT][pm]set wakeup pin level low fail.\n");
+            break;
+        }
+        osal_msleep(timings->wakeup_pulse_ms);
+        ret = tiot_board_pin_set_level(wakeup_device_pin, TIOT_PIN_LEVEL_HIGH);
+        if (ret != 0) {
+            tiot_print_err("[TIoT][pm]set wakeup pin level high fail.\n");
+            break;
+        }
+        osal_msleep(timings->wakeup_pulse_ms);
+        ret = tiot_board_pin_set_level(wakeup_device_pin, TIOT_PIN_LEVEL_LOW);
+        if (ret != 0) {
+            tiot_print_err("[TIoT][pm]set wakeup pin level low fail.\n");
+            break;
+        }
+    } while (0);
+
+    if (ret != 0) {
+        return TIOT_PM_EVTRET_FAIL;
+    }
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+#ifdef CONFIG_PM_MANAGE_LOWPOWER
+tiot_pm_retcode tiot_pm_default_request_sleep_handle(tiot_pm *pm)
+{
+    const uint8_t allow_sleep_command[] = { 0x7e, 0x00, 0x06, 0x00,
+                                            SYS_PL_BFGNI_HOST_ASKTO_SLP,
+                                            0x7e };
+    int32_t ret;
+    tiot_controller *ctrl = NULL;
+    tiot_xfer_manager *xfer = NULL;
+    if (pm->work_vote == 1) {
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+    ctrl = tiot_container_of(pm, tiot_controller, pm);
+    xfer = &ctrl->transfer;
+    ret = xfer->xmit_ops->write(&xfer->xmit, allow_sleep_command, sizeof(allow_sleep_command));
+    if (ret != sizeof(allow_sleep_command)) {
+        tiot_print_alert("[TIoT:fatal]send allow sleep msg fail.\r\n");
+        return TIOT_PM_EVTRET_FAIL;
+    }
+    tiot_print_info("[TIoT][pm]allow device sleep.\n");
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_default_sleep_ack_handle(tiot_pm *pm)
+{
+    tiot_unused(pm);
+    /* device侧睡眠时可睡眠 */
+    tiot_pm_wake_unlock();
+    tiot_print_info("[TIoT][pm]goes to sleep.\n");
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+/*
+ * 非S3状态,由于在中断中无法等待Sleep Ack(dev wkup host gpio拉低),
+ * 所以在下发allow sleep消息后,就立刻释放唤醒锁进入睡眠。
+ */
+tiot_pm_retcode tiot_pm_default_request_sleep_ack_handle(tiot_pm *pm)
+{
+    tiot_pm_retcode ret = tiot_pm_default_request_sleep_handle(pm);
+    if (ret != TIOT_PM_EVTRET_NEXT_STATE) {
+        return ret;
+    }
+    return tiot_pm_default_sleep_ack_handle(pm);
+}
+
+int32_t tiot_pm_send_disallow_sleep(tiot_xfer_manager *xfer)
+{
+    const uint8_t disallow_sleep_command[] = { 0x7e, 0x00, 0x06, 0x00,
+                                               SYS_PL_BFGNI_HOST_DISALLOW_DEVSLP,
+                                               0x7e };
+    int32_t ret;
+    ret = xfer->xmit_ops->write(&xfer->xmit, disallow_sleep_command, sizeof(disallow_sleep_command));
+    if (ret != sizeof(disallow_sleep_command)) {
+        tiot_print_alert("[TIoT:fatal]send disallow msg fail.\r\n");
+        return -1;
+    }
+    return 0;
+}
+
+tiot_pm_retcode tiot_pm_default_wakeup_ack_handle(tiot_pm *pm)
+{
+    int32_t ret;
+    uint8_t input_level = TIOT_PIN_LEVEL_LOW;
+    uint16_t pre_state = pm->state;
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    tiot_xfer_manager *xfer = &ctrl->transfer;
+    uint32_t wakeup_host_pin = pm->pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];
+
+    if (wakeup_host_pin == TIOT_PIN_NONE) {
+        tiot_print_err("[TIoT][pm]wakeup ack event called but dev_wk_host pin is none.\n");
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+
+    /*
+     * host上电后处于INIT状态时,此时接收到device拉高wakeup_host gpio,则不能下发disallow消息,
+     * 否则会多lock()一次,导致host后续无法睡下去。
+     */
+    if (pre_state == TIOT_PM_STATE_INIT) {
+        /* INIT -> WORK */
+        return TIOT_PM_EVTRET_NEXT_STATE;
+    }
+
+    /* 有数据上报时不睡眠 */
+    /* 自唤醒流程: device_wake_out --> wake_lock -......-> request_sleep --> wake_unlock */
+    /* 当前在唤醒中断内持锁,并直接回复disallow消息。 */
+
+    /* check wakeup_ack */
+    ret = tiot_board_pin_get_level(wakeup_host_pin, &input_level);
+    if ((ret != 0) || (input_level == TIOT_PIN_LEVEL_LOW)) {
+        tiot_print_err("[TIoT][pm]get dev_wk_host pin level fail or false positive [state:0x%x].\n", pre_state);
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+    /* 使用临时flag区分suspend. */
+    if (xfer->xmit_suspend & TIOT_XFER_SUSPEND) {
+        tiot_print_info("[TIoT:pm]delay disallow msg [state:0x%x].\n", pre_state);
+        xfer->xmit_suspend |= TIOT_XFER_DELAY_MSG;
+    } else {
+        tiot_print_info("[TIoT][pm]send disallow sleep msg [state:0x%x].\n", pre_state);
+        if (tiot_pm_send_disallow_sleep(xfer) != 0) {
+            return TIOT_PM_EVTRET_FAIL;
+        }
+    }
+    if ((pre_state == TIOT_PM_STATE_SLEEP) || (pre_state == TIOT_PM_STATE_WAKING)) {
+        tiot_pm_wake_lock();
+    }
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_default_work_vote_up(tiot_pm *pm)
+{
+    /* 发送时不睡眠 */
+    tiot_pm_wake_lock();
+    pm->work_vote = 1;
+    return TIOT_PM_EVTRET_KEEP_STATE;
+}
+
+tiot_pm_retcode tiot_pm_default_work_vote_down(tiot_pm *pm)
+{
+    pm->work_vote = 0;
+    /* 发送结束后可睡眠 */
+    tiot_pm_wake_unlock();
+    return TIOT_PM_EVTRET_KEEP_STATE;
+}
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.h
new file mode 100644 (file)
index 0000000..b9d4f9f
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT pm default. \n
+ *
+ * History: \n
+ * 2023-06-09, Create file. \n
+ */
+#ifndef TIOT_PM_DEFAULT_H
+#define TIOT_PM_DEFAULT_H
+
+#include "tiot_pm.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_pm_default PM Default Handlers
+ * @ingroup  tiot_common_pm
+ * @{
+ */
+
+/**
+ * @brief  Default power off handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_power_off(tiot_pm *pm);
+
+/**
+ * @brief  Default power on handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_power_on(tiot_pm *pm);
+
+#ifdef CONFIG_PM_WAKEUP_BY_UART
+/**
+ * @brief  Default wakeup by uart handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_wakeup_device_by_uart(tiot_pm *pm);
+#endif
+
+/**
+ * @brief  Default wakeup by gpio handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_wakeup_device_by_gpio(tiot_pm *pm);
+
+#ifdef CONFIG_PM_MANAGE_LOWPOWER
+/**
+ * @brief  Default request sleep handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_request_sleep_handle(tiot_pm *pm);
+
+/**
+ * @brief  Default sleep ack handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_sleep_ack_handle(tiot_pm *pm);
+
+/**
+ * @brief  Default request sleep ack handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_request_sleep_ack_handle(tiot_pm *pm);
+
+/**
+ * @brief  Default wakeup ack handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_wakeup_ack_handle(tiot_pm *pm);
+
+/**
+ * @brief  Default work vote up handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_work_vote_up(tiot_pm *pm);
+
+/**
+ * @brief  Default work vote down handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_default_work_vote_down(tiot_pm *pm);
+#endif
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cdc63ca
--- /dev/null
@@ -0,0 +1,7 @@
+set(
+    tiot_pm_slave_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm_slave.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_pm_slave_src_list}" CACHE INTERNAL "tiot src list" FORCE)
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.c
new file mode 100644 (file)
index 0000000..7e8669b
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: TIoT pm slave. \n
+ *
+ * History: \n
+ * 2024-02-28, Create file. \n
+ */
+#include "tiot_pm_slave.h"
+#include "tiot_pm_wakelock.h"
+#include "tiot_board_pin_port.h"
+#include "tiot_board_log.h"
+#include "tiot_controller.h"
+#include "tiot_sys_msg_types.h"
+#include "tiot_packet.h"
+#include "tiot_board.h"
+
+tiot_pm_retcode tiot_pm_slave_power_off(tiot_pm *pm)
+{
+    tiot_unused(pm);
+    tiot_pm_wake_unlock();
+    tiot_print_info("[TIoT][pm]power off.\r\n");
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_power_on(tiot_pm *pm)
+{
+    tiot_unused(pm);
+    tiot_pm_wake_lock();
+    tiot_print_info("[TIoT][pm]power on.\r\n");
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_wakeup_handle(tiot_pm *pm)
+{
+    /* Only SLEEP -> WAKING */
+    uint32_t wakeup_in_pin;
+    uint32_t wakeup_out_pin;
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    const tiot_device_timings *timings = &ctrl->dev_info->timings;
+
+    if (pm->state != TIOT_PM_STATE_SLEEP) {
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+
+    tiot_pm_wake_lock();
+
+    wakeup_out_pin = pm->pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];
+    if (wakeup_out_pin != TIOT_PIN_NONE) {
+        if (tiot_board_pin_set_level(wakeup_out_pin, TIOT_PIN_LEVEL_LOW) != 0) {
+            tiot_print_err("[TIoT:pm]wakeout pin set level low fail.\r\n");
+            goto wakeout_fail;
+        }
+        osal_msleep(timings->wakeup_pulse_ms);
+        if (tiot_board_pin_set_level(wakeup_out_pin, TIOT_PIN_LEVEL_HIGH) != 0) {
+            tiot_print_err("[TIoT:pm]wakeout pin set level high fail.\r\n");
+            goto wakeout_fail;
+        }
+    } else {
+        tiot_print_warning("[TIoT][pm]wakeout pin is invalid.\r\n");
+    }
+    /* 唤醒host/唤醒ack后关闭唤醒源中断使能. */
+    wakeup_in_pin = pm->pm_info[TIOT_PIN_HOST_WAKEUP_DEVICE];
+    tiot_board_pin_enable_int(wakeup_in_pin, TIOT_PIN_INT_DISABLE);
+    return TIOT_PM_EVTRET_NEXT_STATE;
+wakeout_fail:
+    tiot_pm_wake_unlock();
+    return TIOT_PM_EVTRET_FAIL;
+}
+
+#ifdef CONFIG_PM_MANAGE_LOWPOWER
+/* 不允许在中断环境下调用 */
+tiot_pm_retcode tiot_pm_slave_request_sleep_handle(tiot_pm *pm)
+{
+    int32_t ret;
+    tiot_controller *ctrl = tiot_container_of(pm, tiot_controller, pm);
+    tiot_xfer_manager *xfer = &ctrl->transfer;
+    const uint8_t request_sleep_command = SYS_INF_REQUEST_SLEEP;
+    tiot_xfer_tx_param tx_param = { SUBSYS_SYS };
+
+    tiot_print_info("[TIoT][pm]request sleep enter.\n");
+
+    ret = tiot_xfer_send(xfer, &request_sleep_command, sizeof(request_sleep_command), &tx_param);
+    if (ret != sizeof(request_sleep_command)) {
+        tiot_print_err("[TIoT][pm]send request sleep msg fail.\r\n");
+        return TIOT_PM_EVTRET_FAIL;
+    }
+
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_sleep_ack_handle(tiot_pm *pm)
+{
+    uint32_t wakeup_in_pin;
+    uint32_t wakeup_out_pin;
+    /* When we reporting msg, ignore allow sleep msg. */
+    if (pm->work_vote == 1) {
+        return TIOT_PM_EVTRET_KEEP_STATE;
+    }
+
+    wakeup_out_pin = pm->pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];
+    /* 睡眠前,slave侧拉低唤醒主机管脚. */
+    if (wakeup_out_pin != TIOT_PIN_NONE) {
+        if (tiot_board_pin_set_level(wakeup_out_pin, TIOT_PIN_LEVEL_LOW) != 0) {
+            tiot_print_err("[TIoT][pm]wakeup_out_pin set low fail.\r\n");
+            return TIOT_PM_EVTRET_FAIL;
+        }
+    }
+    /* 进睡眠前 打开唤醒源中断使能. */
+    wakeup_in_pin = pm->pm_info[TIOT_PIN_HOST_WAKEUP_DEVICE];
+    tiot_board_pin_enable_int(wakeup_in_pin, TIOT_PIN_INT_ENABLE);
+    tiot_print_info("[TIoT][pm]goes to sleep.\r\n");
+    /* 移除否决票 */
+    tiot_pm_wake_unlock();
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_wakeup_ack_handle(tiot_pm *pm)
+{
+    tiot_unused(pm);
+    tiot_print_info("[TIoT][pm]wakeup succ.\r\n");
+    return TIOT_PM_EVTRET_NEXT_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_work_vote_up(tiot_pm *pm)
+{
+    /* Prevent sleeping while sending data. */
+    tiot_pm_wake_lock();
+    pm->work_vote = 1;
+    return TIOT_PM_EVTRET_KEEP_STATE;
+}
+
+tiot_pm_retcode tiot_pm_slave_work_vote_down(tiot_pm *pm)
+{
+    pm->work_vote = 0;
+    tiot_pm_wake_unlock();
+    return TIOT_PM_EVTRET_KEEP_STATE;
+}
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.h
new file mode 100644 (file)
index 0000000..7c15a97
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: TIoT pm slave. \n
+ *
+ * History: \n
+ * 2024-02-28, Create file. \n
+ */
+#ifndef TIOT_PM_SLAVE_H
+#define TIOT_PM_SLAVE_H
+
+#include "tiot_pm.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_pm_slave PM Slave Handlers
+ * @ingroup  tiot_common_pm
+ * @{
+ */
+
+/**
+ * @brief  Slave power off handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_power_off(tiot_pm *pm);
+
+/**
+ * @brief  Slave power on handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_power_on(tiot_pm *pm);
+
+/**
+ * @brief  Slave wakeup by gpio handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_wakeup_handle(tiot_pm *pm);
+
+#ifdef CONFIG_PM_MANAGE_LOWPOWER
+/**
+ * @brief  Slave request sleep handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_request_sleep_handle(tiot_pm *pm);
+
+/**
+ * @brief  Slave sleep ack handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_sleep_ack_handle(tiot_pm *pm);
+
+/**
+ * @brief  Slave wakeup ack handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_wakeup_ack_handle(tiot_pm *pm);
+
+/**
+ * @brief  Slave work vote up handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_work_vote_up(tiot_pm *pm);
+
+/**
+ * @brief  Slave work vote down handler.
+ * @param  [in]  pm PM control block.
+ * @return see@ref tiot_pm_retcode.
+ */
+tiot_pm_retcode tiot_pm_slave_work_vote_down(tiot_pm *pm);
+
+#endif
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.c
new file mode 100644 (file)
index 0000000..10a51fe
--- /dev/null
@@ -0,0 +1,149 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Power Manager module. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-27, Create file. \n\r
+ */\r
+\r
+#include "tiot_pm.h"\r
+#include "tiot_pm_wakelock.h"\r
+#include "tiot_osal.h"\r
+#include "securec.h"\r
+#include "tiot_controller.h"\r
+#include "tiot_board_log.h"\r
+\r
+typedef struct {\r
+    tiot_pm *pm;\r
+    uint16_t state;\r
+} pm_wait_state;\r
+\r
+/* 传入的event_map必须为静态申请数组 */\r
+int32_t tiot_pm_init(tiot_pm *pm, const uint32_t *pm_info,\r
+                     const tiot_pm_event_entry *event_map, uint8_t event_map_size)\r
+{\r
+    if ((pm == NULL) || (pm_info == NULL) || (event_map == NULL) || (event_map_size == 0)) {\r
+        tiot_print_dbg("[TIoT][pm]pm or pm info or event_map is NULL.\n");\r
+        return -1;\r
+    }\r
+    if (osal_wait_init(&pm->state_wait) != OSAL_SUCCESS) {\r
+        tiot_print_err("[TIoT][pm]pm wait init fail.\n");\r
+        return -1;\r
+    }\r
+\r
+    /* 外部确保为静态变量 */\r
+    pm->pm_info = pm_info;\r
+    pm->event_map = event_map;\r
+    pm->event_map_size = event_map_size;\r
+\r
+    /* 此队列仅用于处理中断内产生pm事件情况,按产生顺序排序,预计不会同时在多个中断内产生pm事件,预留8个已经足够. */\r
+    (void)memset_s(pm->event_queue_buff, TIOT_PM_EVENT_BUFF_MAX, 0, TIOT_PM_EVENT_BUFF_MAX);\r
+    tiot_circ_queue_init(&pm->event_queue, TIOT_PM_EVENT_BUFF_MAX,\r
+                         sizeof(tiot_pm_event), (uintptr_t)pm->event_queue_buff);\r
+    pm->is_in_event = 0;\r
+    pm->work_vote = 0;\r
+    pm->state = TIOT_PM_STATE_POWEROFF;\r
+    return 0;\r
+}\r
+\r
+static int32_t tiot_pm_handle_event(tiot_pm *pm, tiot_pm_event event)\r
+{\r
+    tiot_pm_retcode ret = TIOT_PM_EVTRET_NEXT_STATE;\r
+    /* 取对应事件的 [判断条件 - 执行处理 - 设置下个状态] 流程 */\r
+    const tiot_pm_event_entry *entry = &pm->event_map[event];\r
+\r
+    /* 当前状态不符合tag mask条件, 不需要处理,直接返回OK */\r
+    if ((pm->state & entry->condition_mask) == 0) {\r
+        tiot_print_dbg("[TIoT][pm]state %x not match condition %x, ignore event\n", pm->state, entry->condition_mask);\r
+        return 0;\r
+    }\r
+\r
+    /* pm处理过程持唤醒锁,防止pm未转换完状态就直接进sleep。 */\r
+    tiot_pm_wake_lock();\r
+\r
+    /* 当前状态符合tag mask条件,执行对应事件处理 */\r
+    /* 约定:handler为空不需要处理,例如上报业务消息说明芯片处于WORK状态,只需要切换状态即可 */\r
+    if (entry->handler != NULL) {\r
+        ret = entry->handler(pm);\r
+    }\r
+\r
+    if (ret == TIOT_PM_EVTRET_NEXT_STATE) {\r
+        /* 处理成功,设为下一个状态 */\r
+        tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, next_st: %x.\n", event, pm->state, entry->next_state);\r
+        pm->state = entry->next_state;\r
+        /* 切换状态时保证设置event. */\r
+        osal_wait_wakeup_interruptible(&pm->state_wait);\r
+    } else if (ret == TIOT_PM_EVTRET_FAIL) {\r
+        /* 处理失败,返回false. */\r
+        tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, event fail.\n", event, pm->state);\r
+        tiot_pm_wake_unlock();\r
+        return -1;\r
+    } else {   /* ret == TIOT_PM_EVTRET_KEEP_STATE */\r
+        /* 处理成功,保持当前状态 */\r
+        tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, keep state.\n", event, pm->state);\r
+    }\r
+    tiot_pm_wake_unlock();\r
+\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_pm_set_event(tiot_pm *pm, tiot_pm_event event)\r
+{\r
+    int32_t ret;\r
+    tiot_pm_event *event_node;\r
+\r
+    if ((pm == NULL) || (event >= TIOT_PM_EVENT_MAX) || (event >= pm->event_map_size)) {\r
+        tiot_print_dbg("[TIoT][pm]pm is NULL or illegal event.\n");\r
+        return -1;\r
+    }\r
+\r
+    tiot_circ_queue_enqueue(&pm->event_queue, (uintptr_t)&event);\r
+    /* 依靠队列防止pm事件处理嵌套,此处不使用互斥锁(可能在中断内产生事件),也不使用自旋锁(不能保证提供自旋锁) */\r
+    if (pm->is_in_event == 1) {\r
+        return 0;\r
+    }\r
+\r
+    do {\r
+        event_node = (tiot_pm_event *)tiot_circ_queue_dequeue(&pm->event_queue);\r
+        if (event_node == NULL) {\r
+            return 0;\r
+        }\r
+        pm->is_in_event = 1;\r
+        ret = tiot_pm_handle_event(pm, *event_node);\r
+        pm->is_in_event = 0;\r
+        if (ret != 0) {\r
+            tiot_circ_queue_clear(&pm->event_queue);\r
+            break;\r
+        }\r
+    } while (event_node != NULL);\r
+\r
+    return ret;\r
+}\r
+\r
+static int pm_wait_state_condition(const void *param)\r
+{\r
+    pm_wait_state *wait_state = (pm_wait_state *)param;\r
+    return (wait_state->pm->state == wait_state->state);\r
+}\r
+\r
+int32_t tiot_pm_wait_state(tiot_pm *pm, uint16_t state, uint32_t wait_timeout)\r
+{\r
+    pm_wait_state wait_state = { 0 };\r
+    if (state == TIOT_PM_STATE_INVALID) {\r
+        return -1;\r
+    }\r
+    wait_state.pm = pm;\r
+    wait_state.state = state;\r
+    return osal_wait_timeout_interruptible(&pm->state_wait, pm_wait_state_condition, &wait_state, wait_timeout);\r
+}\r
+\r
+void tiot_pm_deinit(tiot_pm *pm)\r
+{\r
+    tiot_circ_queue_clear(&pm->event_queue);\r
+    osal_spin_lock_destroy(&pm->event_queue.lock);\r
+    osal_wait_destroy(&pm->state_wait);\r
+    (void)memset_s(pm->event_queue_buff, TIOT_PM_EVENT_BUFF_MAX, 0, TIOT_PM_EVENT_BUFF_MAX);\r
+    pm->state = TIOT_PM_STATE_INVALID;\r
+    pm->work_vote = 0;\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.h
new file mode 100644 (file)
index 0000000..587d6c7
--- /dev/null
@@ -0,0 +1,182 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Power Manager module header. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-27, Create file. \n\r
+ */\r
+#ifndef TIOT_PM_H\r
+#define TIOT_PM_H\r
+\r
+#include "tiot_types.h"\r
+#include "tiot_circ_queue.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_pm Power Manager\r
+ * @ingroup  tiot_common\r
+ * @{\r
+ */\r
+\r
+#define TIOT_PM_EVENT_BUFF_MAX    8\r
+\r
+/**\r
+ * @brief  TIoT PM tags.\r
+ */\r
+typedef enum {\r
+    TIOT_PM_TAG_INVALID = 0,                     /*!< Invalid PM tag. */\r
+    TIOT_PM_TAG_POWEROFF = ((uint16_t)1 << 0),   /*!< Power off tag. */\r
+    TIOT_PM_TAG_POWERON  = ((uint16_t)1 << 1),   /*!< Power on tag. */\r
+    /* Low power tags. */\r
+    TIOT_PM_TAG_CAN_WORK  = ((uint16_t)1 << 2),  /*!< Low power can work tag. */\r
+    TIOT_PM_TAG_CAN_SLEEP = ((uint16_t)1 << 3),  /*!< Low power can sleep tag. */\r
+    TIOT_PM_TAG_CAN_WAKEUP = ((uint16_t)1 << 4), /*!< Low power can wakeup tag. */\r
+    TIOT_PM_TAG_CAN_ALLOW_SLEEP = ((uint16_t)1 << 5), /*!< Low power can allow sleep tag. */\r
+    TIOT_PM_TAG_MAX = (uint16_t)0xFFFF           /* PM tag max. */\r
+} tiot_pm_tag;\r
+\r
+/**\r
+ * @brief  TIoT PM states.\r
+ */\r
+typedef enum {\r
+    TIOT_PM_STATE_INVALID = 0,                        /*!< Invalid PM state. */\r
+    TIOT_PM_STATE_POWEROFF = TIOT_PM_TAG_POWEROFF,    /*!< Power off state. */\r
+    TIOT_PM_STATE_POWERON = TIOT_PM_TAG_POWERON,      /*!< Power on state. */\r
+    /* Low power states */\r
+    /*!< Low power init state, can work, can sleep. */\r
+    TIOT_PM_STATE_INIT = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WORK | TIOT_PM_TAG_CAN_SLEEP,\r
+    /*!< Low power work state, can sleep, can allow sleep. */\r
+    /*!< Host: WORK -> SLEEPING -> SLEEP (正常睡眠流程,等待sleep ack)\r
+               WORK -> SLEEP (非S3状态,不等待sleep ack)\r
+       Device: WORK -> SLEEPING -> SLEEP (Device主动请求睡眠)\r
+               WORK -> SLEEP (S3状态,Host强制要求睡眠) */\r
+    TIOT_PM_STATE_WORK = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_SLEEP | TIOT_PM_TAG_CAN_ALLOW_SLEEP,\r
+    /*!< Low power sleep state, can work, can be waked up. */\r
+    TIOT_PM_STATE_SLEEP = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WORK | TIOT_PM_TAG_CAN_WAKEUP,\r
+    /*!< Low power waking state, can be waked up. */\r
+    TIOT_PM_STATE_WAKING = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WAKEUP,\r
+    /*!< Low power sleeping state, can allow sleep. */\r
+    TIOT_PM_STATE_SLEEPING = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_SLEEP\r
+} tiot_pm_state;\r
+\r
+/**\r
+ * @brief Tiot PM event types.\r
+ */\r
+typedef enum {\r
+    /* OUTPUT */\r
+    TIOT_PM_EVENT_POWEROFF,       /*!< Power off. */\r
+    TIOT_PM_EVENT_POWERON,        /*!< Power on. */\r
+    TIOT_PM_EVENT_WAKEUP,         /*!< Host: wakeup device.\r
+                                     Device: wakeup host(pull up dev_wkup_host gpio). */\r
+    /* INPUT,for host to manage device lowpower */\r
+    TIOT_PM_EVENT_WAKEUP_ACK,     /*!< Host: send disallow sleep cmd to ack(device wakeup host).\r
+                                     Device: handle the ack of disallow sleep cmd. */\r
+    TIOT_PM_EVENT_REQUEST_SLEEP,  /*!< Host: send allow sleep cmd.\r
+                                     Device: send request sleep cmd to request sleep. */\r
+    TIOT_PM_EVENT_SLEEP_ACK,      /*!< Host: handle the ack of allow sleep cmd.\r
+                                     Device: pull down dev_wkup_host gpio to ack (host allow sleep cmd). */\r
+    TIOT_PM_EVENT_REQUEST_SLEEP_ACK, /*!< Combine TIOT_PM_EVENT_REQUEST_SLEEP and TIOT_PM_EVENT_SLEEP_ACK */\r
+    TIOT_PM_EVENT_REPORT_WORK,    /*!< Device transmit port report message. */\r
+    /* Vote */\r
+    TIOT_PM_EVENT_WORK_VOTE_UP,   /*!< Host keep device at work state. */\r
+    TIOT_PM_EVENT_WORK_VOTE_DOWN, /*!< Host not keep device at work state. */\r
+    TIOT_PM_EVENT_MAX\r
+} tiot_pm_event;\r
+\r
+/**\r
+ * @brief Tiot PM event retcode.\r
+ */\r
+typedef enum {\r
+    TIOT_PM_EVTRET_FAIL = -1,         /* Event handle failed. */\r
+    TIOT_PM_EVTRET_NEXT_STATE = 0,    /* Change to next state. */\r
+    TIOT_PM_EVTRET_KEEP_STATE = 1,    /* Keep current state. */\r
+} tiot_pm_retcode;\r
+\r
+struct _tiot_pm;\r
+\r
+/**\r
+ * @brief  Tiot PM event handler.\r
+ */\r
+typedef tiot_pm_retcode (* tiot_pm_event_handler)(struct _tiot_pm *pm);\r
+\r
+/**\r
+ * @brief Tiot PM event handle entry.\r
+ */\r
+typedef struct {\r
+    uint16_t condition_mask;        /*!< Enter event condition, could be combination of PM tags. */\r
+    uint16_t next_state;            /*!< Next PM state. */\r
+    tiot_pm_event_handler handler;  /*!< PM event handler, NULL mean this event don't need operation. */\r
+} tiot_pm_event_entry;\r
+\r
+/**\r
+ * @brief Tiot PM control block.\r
+ */\r
+typedef struct _tiot_pm {\r
+    uint16_t state;                        /*!< Current PM state. */\r
+    uint16_t work_vote;                    /*!< Host require device work vote. */\r
+    const uint32_t *pm_info;               /*!< PM board info, pin indexs. */\r
+    osal_wait state_wait;                  /*!< PM state wait, used for wait some state. */\r
+    tiot_circ_queue_t event_queue;         /*!< PM event queue for syncing events. */\r
+    /*!< PM event queue buffer. */\r
+    tiot_pm_event event_queue_buff[TIOT_PM_EVENT_BUFF_MAX];\r
+    volatile uint8_t is_in_event;          /*!< PM event processing. */\r
+    uint8_t event_map_size;                /*!< PM event handle map size. */\r
+    /*!< PM event handle map, must point to static allocated array. */\r
+    const tiot_pm_event_entry *event_map;\r
+} tiot_pm;\r
+\r
+/**\r
+ * @brief  PM control block init.\r
+ * @param  [in]  pm        PM control block.\r
+ * @param  [in]  pm_info   Pointer to board PM info, static allocated, from device saved board info.\r
+ * @param  [in]  event_map Registed PM event handle map, static allocated, from *_device_info.c.\r
+ * @param  [in]  event_map_size Registed PM event handle map size.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_pm_init(tiot_pm *pm, const uint32_t *pm_info,\r
+                     const tiot_pm_event_entry *event_map, uint8_t event_map_size);\r
+\r
+/**\r
+ * @brief  Set event to PM control block.\r
+ * @param  [in]  pm    PM control block.\r
+ * @param  [in]  event PM event.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_pm_set_event(tiot_pm *pm, tiot_pm_event event);\r
+\r
+/**\r
+ * @brief  PM control block wait for state.\r
+ * @param  [in]  pm    PM control block.\r
+ * @param  [in]  state PM state,caller must ensure state is valid.\r
+ * @param  [in]  wait_timeout Wait timeout, shound not be too long.\r
+ * @return negative if wait state fail;\r
+ *         zero if wait state timeout;\r
+ *         postive if wait state OK.\r
+ */\r
+int32_t tiot_pm_wait_state(tiot_pm *pm, uint16_t state, uint32_t wait_timeout);\r
+\r
+/**\r
+ * @brief  PM control block deinit.\r
+ * @param  [in]  pm        PM control block.\r
+ */\r
+void tiot_pm_deinit(tiot_pm *pm);\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.c
new file mode 100644 (file)
index 0000000..1101a77
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2024-03-01, Create file. \n
+ */
+#include "tiot_pm_wakelock.h"
+#include "tiot_board_misc_port.h"
+#include "tiot_board_log.h"
+#include "tiot_osal.h"
+
+/* 所有controller共享同一个wakelock, 只有所有controller未持锁时才允许睡眠. */
+static tiot_board_wakelock g_top_wakelock;
+static osal_spinlock g_top_wakelock_spinlock;
+static uint16_t g_top_lock_count;
+
+int32_t tiot_pm_wake_lock_init(void)
+{
+    if (tiot_board_wake_lock_init(&g_top_wakelock) != 0) {
+        return -1;
+    }
+    if (osal_spin_lock_init(&g_top_wakelock_spinlock) != OSAL_SUCCESS) {
+        tiot_board_wake_lock_destroy(&g_top_wakelock);
+        return -1;
+    }
+    g_top_lock_count = 0;
+    return 0;
+}
+
+void tiot_pm_wake_lock(void)
+{
+    unsigned long flags;
+    osal_spin_lock_irqsave(&g_top_wakelock_spinlock, &flags);
+    if (g_top_lock_count == 0) {
+        tiot_board_wake_lock(&g_top_wakelock);
+    }
+    g_top_lock_count++;
+    osal_spin_unlock_irqrestore(&g_top_wakelock_spinlock, &flags);
+}
+
+void tiot_pm_wake_unlock(void)
+{
+    unsigned long flags;
+    osal_spin_lock_irqsave(&g_top_wakelock_spinlock, &flags);
+    if (g_top_lock_count > 0) {
+        g_top_lock_count--;
+        /* 防止count为0时多次调用unlock接口。 */
+        if (g_top_lock_count == 0) {
+            tiot_board_wake_unlock(&g_top_wakelock);
+        }
+    }
+    osal_spin_unlock_irqrestore(&g_top_wakelock_spinlock, &flags);
+}
+
+void tiot_pm_wake_lock_destroy(void)
+{
+    /* 确保destroy时一定释放。 */
+    unsigned long flags;
+    osal_spin_lock_irqsave(&g_top_wakelock_spinlock, &flags);
+    if (g_top_lock_count > 0) {
+        tiot_print_err("[TIoT][wakelock]g_top_lock_count should be 0, but is %d\n", g_top_lock_count);
+        g_top_lock_count = 0;
+        tiot_board_wake_unlock(&g_top_wakelock);
+    }
+    osal_spin_unlock_irqrestore(&g_top_wakelock_spinlock, &flags);
+
+    tiot_board_wake_lock_destroy(&g_top_wakelock);
+    osal_spin_lock_destroy(&g_top_wakelock_spinlock);
+}
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.h
new file mode 100644 (file)
index 0000000..f29b86a
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2024-03-01, Create file. \n
+ */
+#ifndef TIOT_PM_WAKELOCK_H
+#define TIOT_PM_WAKELOCK_H
+
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_pm_wakelock PM Wake Lock
+ * @ingroup  tiot_common_pm
+ * @{
+ */
+
+/**
+ * @if Eng
+ * @brief PM wake lock initialization interface.
+ * @return if OK return 0, else return -1.
+ * @else
+ * @brief PM唤醒锁初始化接口。
+ * @return 初始化成功返回0,否则返回-1。
+ * @endif
+ */
+int32_t tiot_pm_wake_lock_init(void);
+
+/**
+ * @if Eng
+ * @brief PM wake lock interface, support nested, pair with unlock.
+ * @else
+ * @brief PM唤醒锁接口,支持嵌套使用,需要和unlock配对。
+ * @endif
+ */
+void tiot_pm_wake_lock(void);
+
+/**
+ * @if Eng
+ * @brief PM wake unlock interface, support nested, pair with unlock.
+ * @else
+ * @brief PM唤醒解锁接口,支持嵌套使用,需要和lock配对。
+ * @endif
+ */
+void tiot_pm_wake_unlock(void);
+
+/**
+ * @if Eng
+ * @brief PM wake lock destroy interface.
+ * @else
+ * @brief PM唤醒锁销毁接口。
+ * @endif
+ */
+void tiot_pm_wake_lock_destroy(void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9631fb6
--- /dev/null
@@ -0,0 +1,14 @@
+set(
+    tiot_sys_msg_handler_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_sys_msg_handle.c
+)
+
+if(DEFINED CONFIG_DEV_TIOT_SLAVE)
+list(
+    APPEND tiot_sys_msg_handler_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_sys_msg_slave_handle.c
+)
+endif()
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_sys_msg_handler_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.c
new file mode 100644 (file)
index 0000000..f72d88c
--- /dev/null
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-02-29, Create file. \n
+ */
+#include "tiot_sys_msg_handle.h"
+#include "tiot_sys_msg_types.h"
+#include "tiot_pm.h"
+#include "tiot_board_log.h"
+
+void tiot_pkt_sys_msg_handle(tiot_controller *ctrl, uint8_t code)
+{
+    if ((code == SYS_INF_GNSS_INIT) || (code == SYS_INF_GNSS_LPPE_INIT)) {
+        tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_REPORT_WORK);
+    } else if (code == SYS_INF_REQUEST_SLEEP) {
+        tiot_print_info("[TIoT:pkt]recv request sleep\n");
+        tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_REQUEST_SLEEP_ACK);
+    } else {
+        tiot_print_warning("[TIoT:pkt]recv unknown sys msg:0x%x\n", code);
+    }
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.h
new file mode 100644 (file)
index 0000000..154645a
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-02-29, Create file. \n
+ */
+#ifndef TIOT_SYS_MSG_HANDLE_H
+#define TIOT_SYS_MSG_HANDLE_H
+
+#include "tiot_controller.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+void tiot_pkt_sys_msg_handle(tiot_controller *ctrl, uint8_t code);
+
+void tiot_pkt_sys_msg_slave_handle(tiot_controller *ctrl, uint8_t code);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_slave_handle.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_slave_handle.c
new file mode 100644 (file)
index 0000000..7b359ff
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-02-29, Create file. \n
+ */
+#include "tiot_sys_msg_handle.h"
+#include "tiot_sys_msg_types.h"
+#include "tiot_slave_board_port.h"
+#include "tiot_pm_slave.h"
+#include "tiot_board_log.h"
+
+void tiot_pkt_sys_msg_slave_handle(tiot_controller *ctrl, uint8_t code)
+{
+    switch (code) {
+        case SYS_PL_BFGNI_HOST_ASKTO_SLP:
+            tiot_print_info("[TIoT:pkt]recv allow sleep.\n");
+            tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_SLEEP_ACK);
+            break;
+        case SYS_PL_BFGNI_HOST_DISALLOW_DEVSLP:
+            tiot_print_info("[TIoT:pkt]recv disallow sleep.\n");
+            tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_WAKEUP_ACK);
+            break;
+        default:
+            tiot_print_warning("[TIoT:pkt]recv unknown sys msg:0x%x\n", code);
+            break;
+    }
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_types.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_types.h
new file mode 100644 (file)
index 0000000..7c5cb36
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: TIoT sys msg types. \n
+ *
+ * History: \n
+ * 2024-03-11, Create file. \n
+ */
+#ifndef TIOT_SYS_MSG_TYPES_H
+#define TIOT_SYS_MSG_TYPES_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_interface_types TIoT sys msg types.
+ * @ingroup  tiot_common_interface
+ * @{
+ */
+enum SYS_INF_MSG_VALUE_ENUM {
+    SYS_INF_PF_INIT = 0x00,                /* 平台软件初始化完成 */
+    SYS_INF_BT_INIT = 0x01,                /* BT软件初始化完成 */
+    SYS_INF_GNSS_INIT = 0x02,              /* GNSS软件初始化完成 */
+    SYS_INF_FM_INIT = 0x03,                /* FM软件初始化完成 */
+    SYS_INF_BT_DISABLE = 0x04,             /* BT禁能 */
+    SYS_INF_GNSS_DISABLE = 0x05,           /* GNSS禁能 */
+    SYS_INF_FM_DISABLE = 0x06,             /* FM禁能 */
+    SYS_INF_BT_EXIT = 0x07,                /* BT退出 */
+    SYS_INF_GNSS_EXIT = 0x08,              /* GNSS退出 */
+    SYS_INF_FM_EXIT = 0x09,                /* FM退出 */
+    SYS_INF_GNSS_WAIT_DOWNLOAD = 0x0A,     /* 等待GNSS代码下载 */
+    SYS_INF_GNSS_DOWNLOAD_COMPLETE = 0x0B, /* GNSS代码下载完毕 */
+    SYS_INF_BFG_HEART_BEAT = 0x0C,         /* 心跳信号 */
+    SYS_INF_DEV_AGREE_HOST_SLP = 0x0D,     /* device回复host可睡 */
+    SYS_INF_DEV_NOAGREE_HOST_SLP = 0x0E,   /* device回复host不可睡 */
+    SYS_INF_WIFI_OPEN = 0x0F,              /* WCPU上电完成 */
+    SYS_INF_IR_INIT = 0x10,                /* IR软件初始化完成 */
+    SYS_INF_IR_EXIT = 0x11,                /* IR退出 */
+    SYS_INF_NFC_INIT = 0x12,               /* NFC软件初始化完成 */
+    SYS_INF_NFC_EXIT = 0x13,               /* NFC退出 */
+    SYS_INF_WIFI_CLOSE = 0x14,             /* WCPU下电完成 */
+    SYS_INF_RF_TEMP_NORMAL = 0x15,         /* RF温度正常 */
+    SYS_INF_RF_TEMP_OVERHEAT = 0x16,       /* RF温度过热 */
+    SYS_INF_MEM_DUMP_COMPLETE = 0x17,      /* bfgx异常时,MEM DUMP已完成 */
+    SYS_INF_WIFI_MEM_DUMP_COMPLETE = 0X18, /* bfgx异常时,MEM DUMP已完成 */
+    SYS_INF_UART_HALT_WCPU = 0x19,         /* uart halt wcpu ok */
+    SYS_INF_UART_LOOP_SET_DONE = 0x1a,     /* device 设置uart环回ok */
+    SYS_INF_CHR_ERRNO_REPORT = 0x1b,       /* device向host上报CHR异常码 */
+
+    SYS_INF_FAKE_CLOSE_BT =  0x1c,         /* FAKE CLOSE BT的ACK */
+    SYS_INF_RSV1 = 0x1d,                   /* rsv */
+    SYS_INF_RSV2 = 0x1e,                   /* rsv */
+
+    SYS_INF_GNSS_LPPE_INIT = 0x1F,         /* MP13 GNSS 新增的线程初始化完成 */
+    SYS_INF_GNSS_LPPE_EXIT = 0x20,         /* MP13 GNSS 新增的线程退出 */
+    SYS_INF_GNSS_TRICKLE_SLEEP = 0x21,     /* MP13 GNSS_TRICKLE_SLEEP */
+    SYS_INF_ENABLE_GPIO_WKUP_BFG_RSP = 0x22, /* 配置uart or gpio唤醒 */
+    SYS_INF_BOOT_UP_ACK = 0x23,             /* device启动时通过消息回复ack的场景(通常是通过GPIO回复ack) */
+    SYS_INF_WAKE_UP_ACK = 0x24,             /* device被唤醒时通过消息回复ack的场景(通常是通过GPIO回复ack) */
+    SYS_INF_SLE_INIT = 0x25,                /* SLE软件初始化完成 */
+    SYS_INF_SLE_EXIT = 0x26,                /* SLE退出 */
+    SYS_INF_REQUEST_SLEEP = 0x27,           /* device请求睡眠 */
+
+    SYS_INF_BUTT /* 枚举定义最大不能超过127,因为128~255被用来当做心跳的时间戳 */
+};
+
+enum SYS_PL_MSG_VALUE_ENUM {
+    SYS_PL_OPEN_BT = 0x0,
+    SYS_PL_CLOSE_BT = 0x1,
+    SYS_PL_OPEN_GNSS = 0x2,
+    SYS_PL_CLOSE_GNSS = 0x3,
+    SYS_PL_OPEN_FM = 0x4,
+    SYS_PL_CLOSE_FM = 0x5,
+    SYS_PL_OPEN_NFC = 0x6,
+    SYS_PL_CLOSE_NFC = 0x7,
+    SYS_PL_OPEN_IR = 0x8,
+    SYS_PL_CLOSE_IR = 0x9,
+    SYS_PL_OPEN_WIFI = 0xa,                  /* host通过uart打开WCPU */
+    SYS_PL_CLOSE_WIFI = 0xb,                 /* host通过uart关闭WCPU */
+
+    SYS_PL_READ_STACK = 0xc,                 /* host通过uart读栈,心跳超时时使用 */
+    SYS_PL_QUERY_RF_TEMP = 0xd,              /* host通过uart查询rf温度 */
+
+    SYS_PL_BFGNI_HOST_ASKTO_SLP = 0xe,       /* host allow device sleep */
+    SYS_PL_BFGNI_HOST_DISALLOW_DEVSLP = 0xf, /* host disallow device sleep */
+
+    SYS_PL_BFGNI_SHUTDOWN = 0x10,
+    SYS_PL_ENABLE_PM = 0x11,                     /* enable plat dev lowpower feature */
+    SYS_PL_DISABLE_PM = 0x12,                    /* disable plat dev lowpower feature */
+    SYS_PL_BT_ENABLE_PM = 0x13,                  /* enable BT dev lowpower feature */
+    SYS_PL_BT_DISABLE_PM = 0x14,                 /* disable BT dev lowpower feature */
+    SYS_PL_GNSS_ENABLE_PM = 0x15,                /* enable GNSS dev lowpower feature */
+    SYS_PL_GNSS_DISABLE_PM = 0x16,               /* disable GNSS dev lowpower feature */
+    SYS_PL_NFC_ENABLE_PM = 0x17,                 /* enable NFC dev lowpower feature */
+    SYS_PL_NFC_DISABLE_PM = 0x18,                /* disable NFC dev lowpower feature */
+
+    SYS_PL_TEST_CAUSE_PANIC = 0x19,              /* HOST发命令,触发device进入exception */
+    SYS_PL_DUMP_RESET_WCPU = 0x1a,               /* host通过uart不掉电复位WCPU */
+
+    SYS_PL_HALT_WCPU = 0x1b,                     /* halt WCPU */
+    SYS_PL_READ_WLAN_PUB_REG = 0x1c,             /* 读取wcpu的公共寄存器 */
+    SYS_PL_READ_WLAN_PRIV_REG = 0x1d,            /* 读取wcpu的私有寄存器 */
+    SYS_PL_READ_WLAN_MEM = 0x1e,                 /* 读取wcpu的mem */
+
+    SYS_PL_EXCEP_RESET_WCPU = 0x1f,              /* wifi DFR WCPU复位 */
+
+    SYS_PL_SET_UART_LOOP_HANDLER = 0x20,         /* 设置device侧uart环回处理函数 */
+    SYS_PL_SET_UART_LOOP_FINISH = 0x21,          /* UART环回test ok,恢复gnss消息处理函数 */
+
+    SYS_PL_PM_DEBUG = 0x22,                      /* 低功耗维测开关 */
+    SYS_PL_BAUT_CHG_REQ_ACK = 0x23,              /* 波特率切换请求ACK */
+    SYS_PL_BAUT_CHG_COMPLETE = 0x24,             /* 波特率切换完成 */
+
+    SYS_PL_WIFI_OPEN_NOTIFY = 0x25,              /* wifi open  通知 */
+    SYS_PL_WIFI_CLOSE_NOTIFY = 0x26,             /* wifi close 通知 */
+
+    SYS_PL_CFG_OPEN_GLE  = 0x28,                 /* host通过uart打开GLE */
+    SYS_PL_CFG_CLOSE_GLE = 0x29,                 /* host通过uart打开GLE */
+
+    SYS_PL_PM_SET_WAKEUP_HOST_VALID = 0x30,     /* 根据板级连接配置device可以唤醒host */
+    SYS_PL_PM_SET_WAKEUP_HOST_INVALID = 0x31,   /* 根据板级连接配置device不需要唤醒host */
+
+    SYS_PL_BUTT
+};
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7ca3278
--- /dev/null
@@ -0,0 +1,21 @@
+set(\r
+    tiot_transfer_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_xfer.c\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_xfer_utils.c\r
+)\r
+\r
+set(\r
+    tiot_transfer_header_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}\r
+)\r
+\r
+if(DEFINED CONFIG_XFER_PACKET_TIOT)\r
+add_subdirectory(packet_handle/tiot_packet)\r
+endif()\r
+\r
+if(DEFINED CONFIG_XFER_PACKET_NCI)\r
+add_subdirectory(packet_handle/nci_packet)\r
+endif()\r
+\r
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_transfer_src_list}" CACHE INTERNAL "tiot src list" FORCE)\r
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${tiot_transfer_header_list}" CACHE INTERNAL "tiot header list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5ec3271
--- /dev/null
@@ -0,0 +1,8 @@
+set(
+    tiot_packet_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_packet_manager.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_packet.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_packet_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.c
new file mode 100644 (file)
index 0000000..746933f
--- /dev/null
@@ -0,0 +1,919 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-08-03, Create file. \n
+ */
+
+#include "tiot_packet.h"
+#include "tiot_sys_msg_handle.h"
+#include "tiot_controller.h"
+#include "tiot_board_log.h"
+#include "tiot_board_pin_port.h"
+#include "tiot_xfer_utils.h"
+#include "securec.h"
+
+typedef enum {
+    TIOT_PKT_FRAME_IDLE,
+    TIOT_PKT_FRAME_HEAD,
+    TIOT_PKT_FRAME_PAYLOAD,
+    TIOT_PKT_FRAME_TAIL
+} tiot_pkt_rx_frame;
+
+typedef enum {
+    TIOT_PKT_RX_SEPERATE_START,
+    TIOT_PKT_RX_SEPERATE_COMMON,
+    TIOT_PKT_RX_SEPERATE_LAST,
+    TIOT_PKT_RX_COMPLETE,
+} tiot_pkt_rx_sep_tag;
+
+typedef void (* tiot_pkt_msg_handler)(tiot_packet_context *ctx);
+
+static void tiot_packet_sys_func(tiot_packet_context *ctx);
+static void tiot_packet_recv_not_seperated_data(tiot_packet_context *ctx);
+static void tiot_packet_recv_seperated_data(tiot_packet_context *ctx);
+static int32_t tiot_packet_copy_from_queue(tiot_packet_context *ctx, tiot_packet_queue *queue,
+                                           uint8_t *buff, uint32_t buff_len);
+
+static tiot_pkt_msg_handler g_tiot_pkt_msg_handle[MSG_BUTT] = {
+    [SYS_MSG] = tiot_packet_sys_func,                      // SYS_MSG = 0x00,         系统串口消息
+    [GNSS_FIRST_MSG] = tiot_packet_recv_seperated_data,    // GNSS_FIRST_MSG = 0x02,  GNSS串口消息,第一个分段消息
+    [GNSS_COMMON_MSG] = tiot_packet_recv_seperated_data,   // GNSS_COMMON_MSG = 0x03, GNSS串口消息,中间分段消息
+    [GNSS_LAST_MSG] = tiot_packet_recv_seperated_data,     // GNSS_LAST_MSG = 0x04,   GNSS串口消息,最后一个分段消息
+    [OML_MSG] = tiot_packet_recv_not_seperated_data,       // OML_MSG = 0x0e,         OML串口消息
+    [SLE_MSG] = tiot_packet_recv_not_seperated_data,       // SLE_MSG = 0x15,         SLE串口消息
+};
+
+static const tiot_packet_subsys_info g_tiot_pkt_subsys_info[SUBSYS_BUTT] = {
+    { PKG_SEPRETED, GNSS_FIRST_MSG, GNSS_COMMON_MSG, GNSS_LAST_MSG },
+    { PKG_NOT_SEPRETED, OML_MSG, OML_MSG, OML_MSG },
+    { PKG_NOT_SEPRETED, SYS_MSG, SYS_MSG, SYS_MSG }
+};
+
+/* 将旧packet节点推入队列,若队列已满,则丢包. */
+static inline void tiot_cur_packet_to_queue(tiot_packet_context *ctx)
+{
+    tiot_packet_manager_enqueue_packet(&ctx->rx_manager, ctx->rx_queue_id);
+    ctx->frame_cnt = 0;
+    ctx->packet = NULL;
+}
+
+/* 丢包时释放packet节点,重置当前packet节点为空,收到新数据时重新获取对应节点. */
+static inline void tiot_cur_packet_discard(tiot_packet_context *ctx)
+{
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC
+    if (ctx->packet != NULL) {
+        circ_buf_update_read_pos(&(ctx->rx_buff.buf), ctx->packet->len);
+    }
+#endif
+    tiot_packet_manager_discard_packet(&ctx->rx_manager, ctx->rx_queue_id);
+    ctx->frame_cnt = 0;
+    ctx->packet = NULL;
+}
+
+/* 按照subsys code更新当前packet节点. */
+static inline void tiot_cur_packet_update(tiot_packet_context *ctx, uint8_t subsys_code)
+{
+    uint16_t queue_id = ctx->rx_manager.match(subsys_code);
+    if ((ctx->packet == NULL) || (queue_id != ctx->rx_queue_id)) {
+        ctx->rx_queue_id = queue_id;
+        ctx->packet = tiot_packet_manager_get_packet(&ctx->rx_manager, queue_id);
+    }
+}
+
+static inline void packet_frame_error(tiot_packet_context *ctx)
+{
+    ctx->frame_error = 1;
+    ctx->pos = NULL;
+}
+
+static void tiot_packet_report_work(tiot_packet_context *ctx)
+{
+    tiot_controller *ctrl;
+    tiot_xfer_manager *xfer;
+    uint32_t wakein_pin;
+    if (ctx == NULL) {
+        return;
+    }
+    xfer = ctx->xfer;
+    if (xfer == NULL) {
+        return;
+    }
+    ctrl = tiot_container_of(xfer, tiot_controller, transfer);
+    wakein_pin = ctrl->pm.pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];
+    if (wakein_pin == TIOT_PIN_NONE) {
+        /* 没有dev_wkup_host管脚时,host不休眠(只是PM状态切换),通过上报消息来判断device状态 */
+        tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_REPORT_WORK);
+    }
+}
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+static inline tiot_packet_rx_node *tiot_packet_rx_node_malloc(uint32_t len)
+{
+    tiot_packet_rx_node *node = (tiot_packet_rx_node *)osal_kmalloc(sizeof(tiot_packet_rx_node) + len, OSAL_GFP_KERNEL);
+    if (node == NULL) {
+        tiot_print_err("[TIoT]pkt rx node malloc fail.");
+        return NULL;
+    }
+    node->data = (uint8_t *)node + sizeof(tiot_packet_rx_node);
+    node->len = len;
+    return node;
+}
+#endif
+
+int32_t tiot_packet_init(tiot_packet_context *ctx, tiot_xfer_manager *xfer, const tiot_packet_context_param *param)
+{
+    tiot_packet_buffer *buff;
+    if ((ctx == NULL) || (xfer == NULL) || (xfer->pkt_context != 0) || (param == NULL)) {
+        return -1;
+    }
+
+    /* 接收状态机初始状态均为0,只需要memset为0即可. */
+    (void)memset_s((void *)ctx, sizeof(tiot_packet_context), 0, sizeof(tiot_packet_context));
+    (void)memcpy_s((void *)&ctx->rx_manager, sizeof(tiot_packet_manager),
+                   &param->rx_manager_info, sizeof(tiot_packet_manager));
+
+    if (osal_mutex_init(&ctx->tx_packet_mutex) != OSAL_SUCCESS) {
+        tiot_print_err("[TIoT][pkt]tx packet mutex init failed.\n");
+        return -1;
+    }
+
+    if (tiot_packet_manager_init(&ctx->rx_manager) != 0) {
+        osal_mutex_destroy(&ctx->tx_packet_mutex);
+        return -1;
+    }
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    tiot_unused(buff);
+#else
+    buff = param->buff;
+    (void)memset_s(buff->start, buff->size, 0, buff->size);
+    circ_buf_init(&(ctx->rx_buff.buf), &(ctx->rx_buff.buff_write), &(ctx->rx_buff.buff_read), buff->start, buff->size);
+#endif
+    ctx->flags = param->flags;
+    ctx->xfer = xfer;
+    /* 调用tiot_xfer_install_packet后才注册到xfer内. */
+    return 0;
+}
+
+void tiot_packet_deinit(tiot_packet_context *ctx)
+{
+    if (ctx == NULL) {
+        return;
+    }
+    ctx->xfer = NULL;
+    ctx->packet = NULL;
+    tiot_packet_manager_deinit(&ctx->rx_manager);
+    osal_mutex_destroy(&ctx->tx_packet_mutex);
+}
+
+static void tiot_packet_sys_func(tiot_packet_context *ctx)
+{
+    uint8_t syschar = ctx->sys_msg;
+    tiot_xfer_manager *xfer = ctx->xfer;
+    tiot_controller *ctrl = tiot_container_of(xfer, tiot_controller, transfer);
+
+    if (ctrl->dev_info->pkt_sys_msg_handle != NULL) {
+        ctrl->dev_info->pkt_sys_msg_handle(ctrl, syschar);
+    } else {
+        tiot_print_warning("[TIoT][pkt]pkt_sys_msg_handle is NULL.\r\n");
+    }
+}
+
+static void tiot_packet_cums_recv_handle(tiot_packet_context *ctx)
+{
+    int32_t copy_len;
+    tiot_packet_queue *queue;
+    tiot_xfer_cbk_param rx_cbk_param = ctx->xfer->rx_cbk_param;
+
+    /* 直接使用上一次的rx_queue_id. */
+    queue = tiot_packet_manager_find_queue(&ctx->rx_manager, ctx->rx_queue_id);
+    if (queue == NULL) {
+        tiot_print_err("[TIoT:pkt]can't find subsys queue(%d).\r\n", ctx->rx_queue_id);
+        return;
+    }
+
+    if (rx_cbk_param.rx_callback != NULL) {
+        /* 用户注册了rx callback,直接就地处理 */
+        copy_len = tiot_packet_copy_from_queue(ctx, queue, rx_cbk_param.buff, rx_cbk_param.buff_len);
+        rx_cbk_param.rx_callback(rx_cbk_param.buff, copy_len);
+    } else {
+        /* 唤醒等待的reader */
+        osal_wait_wakeup_interruptible(&queue->rx_wait);
+    }
+}
+
+static void tiot_packet_recv_not_seperated_data(tiot_packet_context *ctx)
+{
+    /* 处理之前的包错误, 释放当前包 */
+    if (ctx->frame_error == 1) {
+        tiot_cur_packet_discard(ctx);
+        ctx->frame_error = 0;
+        return;
+    }
+    /* 正常完整包. */
+    ctx->packet->tag = TIOT_PKT_TAG_BINARY;
+    tiot_cur_packet_to_queue(ctx);
+    tiot_packet_cums_recv_handle(ctx);
+}
+
+static void tiot_packet_recv_seperated_data(tiot_packet_context *ctx)
+{
+    uint8_t subsys_code = ctx->head.subsys_code;
+    /* 包顺序检测 */
+    if (subsys_code == GNSS_FIRST_MSG) {
+        /* First 包必须为第一个包 */
+        if (ctx->frame_cnt != 1) {
+            tiot_print_err("[TIoT:pkt]parse error: expect first packet.\r\n");
+            packet_frame_error(ctx);
+        }
+        return;
+    }
+    if (subsys_code == GNSS_COMMON_MSG) {
+        /* 必须先有fisrt包再有common包,所以收到common包时frame_cnt最小为2 */
+        if (ctx->frame_cnt < 2) {
+            tiot_print_err("[TIoT:pkt]parse error: expect first-common packet.\r\n");
+            packet_frame_error(ctx);
+        }
+        return;
+    }
+    /* 收完Last包数据才处理之前的包序错误, 确保完整包被释放 */
+    if ((subsys_code == GNSS_LAST_MSG) && (ctx->frame_error == 1)) {
+        tiot_print_err("[TIoT:pkt]packet order error, discard the whole packet.\r\n");
+        tiot_cur_packet_discard(ctx);
+        ctx->frame_error = 0;
+        return;
+    }
+    /* 正常完整包. */
+    ctx->packet->tag = TIOT_PKT_TAG_BINARY;
+    tiot_cur_packet_to_queue(ctx);
+    tiot_packet_cums_recv_handle(ctx);
+}
+
+static int32_t tiot_packet_head_check(tiot_packet_head *head)
+{
+    /* 包头错误!!! */
+    if (head->head != TIOT_PKT_HEAD) {
+        tiot_print_err("[TIoT:pkt]head error: 0x%x\r\n", head->head);
+        return -1;
+    }
+    /* 子系统错误 */
+    if (head->subsys_code >= MSG_BUTT) {
+        tiot_print_err("[TIoT:pkt]subsys error: 0x%x\r\n", head->subsys_code);
+        return -1;
+    }
+    /* 系统消息特殊判断, 长度必须为0x6. */
+    if ((head->subsys_code == SYS_MSG) && (head->len != (TIOT_PKT_PKG_SIZE + sizeof(uint8_t)))) {
+        tiot_print_err("[TIoT:pkt]sys msg len error: 0x%x\r\n", head->len);
+        return -1;
+    }
+    /* payload大小 小于0 或大于最大包大小 */
+    if ((head->len <= TIOT_PKT_PKG_SIZE) ||
+        (head->len > (TIOT_PKT_PAYLOAD_MAX_SIZE + TIOT_PKT_PKG_SIZE))) {
+        tiot_print_err("[TIoT:pkt]payload error: 0x%x\r\n", head->len);
+        return -1;
+    }
+    return 0;
+}
+
+static int32_t tiot_packet_head_try_recovery(tiot_packet_context *ctx)
+{
+    uint8_t i;
+    uint8_t *head_data;
+    errno_t err;
+    head_data = (uint8_t *)&ctx->head;
+    /* 出现问题时,先把上一个起始标志位丢弃. */
+    for (i = 1; i < sizeof(tiot_packet_head); i++) {
+        /* 头部出现其他pkt_head时,可以尝试恢复. */
+        if (head_data[i] == TIOT_PKT_HEAD) {
+            break;
+        }
+    }
+    if (i == sizeof(tiot_packet_head)) {
+        return -1;
+    }
+    tiot_print_dbg("[TIoT][pkt]head: [%x %x %x %x].\r\n",
+                   head_data[0], head_data[1], head_data[2], head_data[3]);  /* 打印恢复前head数据. */
+    tiot_print_warning("[TIoT][pkt]head recovery.\r\n");
+    err = memmove_s((void *)&ctx->head, sizeof(tiot_packet_head), &head_data[i], sizeof(tiot_packet_head) - i);
+    if (err != EOK) {
+        tiot_print_err("[TIoT][pkt]memmove_s error.\r\n");
+        return -1;
+    }
+    /* 更新需要读取的个数 & 位置. */
+    ctx->frame_need_read = i;
+    ctx->pos = &head_data[sizeof(tiot_packet_head) - i];
+    return 0;
+}
+
+static void tiot_packet_head_done(tiot_packet_context *ctx)
+{
+    tiot_packet_head *head = &ctx->head;
+    uint16_t payload_len = head->len - TIOT_PKT_PKG_SIZE;
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    tiot_packet_rx_node *node = NULL;
+#endif
+    if (tiot_packet_head_check(head) != 0) {
+        if (tiot_packet_head_try_recovery(ctx) == 0) {
+            /* 恢复成功,继续处理. */
+            return;
+        }
+        goto discard;
+    }
+    /* 消息头校验OK时,认为work. */
+    tiot_packet_report_work(ctx);
+    /* 系统消息不分包特殊处理,避免申请内存. */
+    if (head->subsys_code == SYS_MSG) {
+        ctx->frame_need_read = sizeof(uint8_t);
+        ctx->pos = &ctx->sys_msg;
+        ctx->current_frame = TIOT_PKT_FRAME_PAYLOAD;
+        return;
+    }
+
+    tiot_cur_packet_update(ctx, head->subsys_code);
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    if (ctx->packet != NULL) {
+        node = tiot_packet_rx_node_malloc(payload_len);
+        if (node == NULL) {
+            packet_frame_error(ctx);
+        } else {
+            tiot_list_add_tail(&(node->node), ctx->packet->head);
+            ctx->pos = node->data;
+        }
+    } else {
+        tiot_print_err("[TIoT:rx]circ queue no space.\n");
+        packet_frame_error(ctx);
+    }
+#else
+    if ((ctx->packet == NULL) || (circ_buf_query_free(&(ctx->rx_buff.buf)) <= payload_len)) {
+        tiot_print_err("[TIoT:rx]circ queue or rx buff no space.\n");
+        packet_frame_error(ctx);
+    }
+    if (ctx->packet != NULL) {
+        ctx->packet->len += payload_len;
+    }
+#endif
+    ctx->frame_need_read = payload_len;
+    ctx->frame_cnt++;
+    ctx->current_frame = TIOT_PKT_FRAME_PAYLOAD;
+    return;
+
+discard:
+    tiot_cur_packet_discard(ctx);
+    ctx->current_frame = TIOT_PKT_FRAME_IDLE;
+}
+
+static void tiot_packet_payload_done(tiot_packet_context *ctx)
+{
+    ctx->current_frame = TIOT_PKT_FRAME_TAIL;
+    ctx->frame_need_read = TIOT_PKT_TAIL_SIZE;
+    ctx->pos = &ctx->tail;
+}
+
+static void tiot_packet_tail_done(tiot_packet_context *ctx)
+{
+    uint8_t tail = ctx->tail;
+    uint8_t subsys_code;
+    if (tail != TIOT_PKT_TAIL) {
+        tiot_cur_packet_discard(ctx);
+        ctx->current_frame = TIOT_PKT_FRAME_IDLE;
+        ctx->frame_error = 0;
+        return;
+    }
+
+    /* 在head done内已经确保subsys_code正确 */
+    subsys_code = ctx->head.subsys_code;
+    if (g_tiot_pkt_msg_handle[subsys_code] != NULL) {
+        g_tiot_pkt_msg_handle[subsys_code](ctx);
+    }
+    ctx->current_frame = TIOT_PKT_FRAME_IDLE;
+}
+
+uint32_t tiot_packet_handle(tiot_packet_context *ctx, uint8_t *data, uint32_t data_len)
+{
+    uint16_t packet_len = (uint16_t)(data_len & 0xFFFF);  /* 取低16位,包格式只需要16位大小. */
+    uint32_t handle_len = packet_len < ctx->frame_need_read ? packet_len : ctx->frame_need_read;
+    ctx->frame_need_read -= handle_len;
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    if (ctx->pos != NULL) {
+        (void)memcpy_s(ctx->pos, handle_len, data, handle_len);
+        ctx->pos += handle_len;
+    } else {
+        tiot_print_dbg("[TIoT][rx]packet buff pos is NULL.\n");
+    }
+#else
+    /* 系统消息直接拷贝;buffer放不下时丢包处理,使用frame_error标识. */
+    if ((ctx->current_frame == TIOT_PKT_FRAME_PAYLOAD) &&
+        (ctx->head.subsys_code != SYS_MSG)) {
+        circ_buf_write_data(&(ctx->rx_buff.buf), data, handle_len, ctx->rx_buff.buff_write);
+        circ_buf_update_write_pos(&(ctx->rx_buff.buf), handle_len);
+    } else {
+        if (ctx->pos != NULL) {
+            (void)memcpy_s(ctx->pos, handle_len, data, handle_len);
+            ctx->pos += handle_len;
+        } else {
+            tiot_print_dbg("[TIoT][rx]packet buff pos is NULL.\n");
+        }
+    }
+#endif
+
+    if (ctx->frame_need_read != 0) {
+        return handle_len;
+    }
+
+    /* 完成一帧数据 */
+    switch (ctx->current_frame) {
+        case TIOT_PKT_FRAME_HEAD:
+            tiot_packet_head_done(ctx);
+            break;
+        case TIOT_PKT_FRAME_PAYLOAD:
+            tiot_packet_payload_done(ctx);
+            break;
+        case TIOT_PKT_FRAME_TAIL:
+            tiot_packet_tail_done(ctx);
+            break;
+        default:
+            tiot_print_dbg("[TIoT][rx]err frame: %d\n", ctx->current_frame);
+            break;
+    }
+    return handle_len;
+}
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+static inline void tiot_packet_ascii_line_store(tiot_packet_context *ctx, uint8_t *line_start, uint32_t line_len)
+{
+    tiot_packet_rx_node *node = tiot_packet_rx_node_malloc(line_len);
+    if (node == NULL) {
+        /* discard */
+        return;
+    }
+    (void)memcpy_s(node->data, line_len, line_start, line_len);
+    tiot_list_add_tail(&(node->node), ctx->packet->head);
+}
+#else
+static inline void tiot_packet_ascii_line_store(tiot_packet_context *ctx, uint8_t *line_start, uint32_t line_len)
+{
+    if (circ_buf_query_free(&(ctx->rx_buff.buf)) <= line_len) {
+        tiot_print_err("[TIoT][rx]rx buffer no space for data.");
+        return;
+    }
+    circ_buf_write(&(ctx->rx_buff.buf), line_start, line_len);
+    ctx->packet->len += line_len;
+}
+#endif
+
+static void tiot_packet_ascii_line_handle(tiot_packet_context *ctx, uint8_t *data, uint32_t handle_len)
+{
+    uint8_t *left = data;
+    uint8_t *right = data;
+    uint32_t line_len = 0;
+    while (right < (data + handle_len)) {
+        if (*right != '\n') {
+            right++;
+            continue;
+        }
+        /* 找到行尾. */
+        line_len = right - left + 1; /* 当前字符也复制 '\n'. */
+        tiot_cur_packet_update(ctx, MSG_BUTT); /* ASCII消息使用MSG_BUTT,避免重复. */
+        if (ctx->packet != NULL) {
+            tiot_packet_ascii_line_store(ctx, left, line_len);
+            ctx->packet->tag = TIOT_PKT_TAG_ASCII;
+            tiot_cur_packet_to_queue(ctx);
+            tiot_packet_cums_recv_handle(ctx);
+        } else {
+            tiot_print_err("[TIoT:rx]circ queue no space, discard: 0x%x\r\n", line_len);
+        }
+        left = right + 1;  /* 下一行起始 */
+        right = left;
+    }
+    /* 最后一段没有结尾的情况 */
+    line_len = (data + handle_len) - left;
+    if (line_len == 0) {
+        return;
+    }
+    tiot_cur_packet_update(ctx, MSG_BUTT); /* ASCII消息使用MSG_BUTT,避免重复. */
+    if (ctx->packet != NULL) {
+        tiot_packet_ascii_line_store(ctx, left, line_len);
+        /* ASCII字符串结束判断. */
+        if (ctx->current_frame == TIOT_PKT_FRAME_HEAD) {
+            ctx->packet->tag = TIOT_PKT_TAG_ASCII;
+            tiot_cur_packet_to_queue(ctx);
+            tiot_packet_cums_recv_handle(ctx);
+        }
+    } else {
+        tiot_print_err("[TIoT:rx]circ queue no space, discard: 0x%x\r\n", line_len);
+    }
+}
+
+uint32_t tiot_packet_ascii_handle(tiot_packet_context *ctx, uint8_t *data, uint32_t data_len)
+{
+    /* ascii字符串处理 */
+    uint32_t handle_len = 0;
+    uint8_t *tmp = data;
+    /* 寻找包头起始 */
+    while (handle_len < data_len) {
+        if (*tmp == 0x7e) {
+            break;
+        }
+        tmp++;
+        handle_len++;
+    }
+
+    if (handle_len < data_len) {
+        /* 找到包头 */
+        ctx->current_frame = TIOT_PKT_FRAME_HEAD;
+        ctx->frame_need_read = TIOT_PKT_HEAD_SIZE;
+        ctx->pos = (uint8_t *)&ctx->head;
+    }
+
+    if ((handle_len == 0) || !(ctx->flags & TIOT_PKT_FLAGS_SUPPORT_ASCII)) {
+        /* 1. 第一个字节即0x7e, 不需要处理. */
+        /* 2. 不支持上报ascii数据,直接丢包处理. */
+        goto discard;
+    }
+    /* 支持上报ascii数据时,有数据认为work. */
+    tiot_packet_report_work(ctx);
+    tiot_packet_ascii_line_handle(ctx, data, handle_len);
+discard:
+    return handle_len;
+}
+
+void tiot_packet_rx_data_parse(tiot_packet_context *ctx, uint8_t *data, uint32_t len)
+{
+    uint8_t *buff = data;
+    uint32_t handle_len = 0;
+    uint32_t total_len = len;
+
+    while (total_len) {
+        if (ctx->current_frame == TIOT_PKT_FRAME_IDLE) {
+            handle_len = tiot_packet_ascii_handle(ctx, buff, total_len);
+        } else {
+            handle_len = tiot_packet_handle(ctx, buff, total_len);
+        }
+        buff += handle_len;
+        total_len -= handle_len;
+    }
+}
+
+void tiot_packet_rx_data_store(tiot_xfer_manager *xfer, uint8_t *data, uint32_t len)
+{
+    tiot_packet_context *ctx = NULL;
+    /* 入参已在调用处判空 */
+    ctx = (tiot_packet_context *)xfer->pkt_context;
+    tiot_packet_rx_data_parse(ctx, data, len);
+}
+
+static int tiot_packet_read_out_check(const void *param)
+{
+    int check;
+    tiot_packet_manager_query *query = (tiot_packet_manager_query *)param;
+    tiot_xfer_manager *xfer = query->xfer;
+    tiot_packet_context *ctx = (tiot_packet_context *)xfer->pkt_context;
+    if (ctx == NULL) {
+        tiot_print_warning("[TIoT][rx]read out check: pkt_context is NULL\n");
+        return 1;
+    }
+    check = (xfer->rx_wait_func(xfer) != 0) ||
+            (tiot_packet_manager_has_data(&ctx->rx_manager, query->queue_id));
+    return check;
+}
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+static int32_t tiot_packet_is_valid(tiot_packet *packet)
+{
+    uint16_t frame_cnt = 0;
+    tiot_packet_rx_node *pos;
+    if (packet->head == NULL) {
+        return -1;
+    }
+    tiot_list_for_each_entry(pos, packet->head, node, tiot_packet_rx_node) {
+        if ((pos->data == NULL) || (pos->len == 0)) {
+            return -1;
+        }
+        frame_cnt++;
+    }
+    if (frame_cnt == 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static int32_t tiot_packet_copy_from_queue(tiot_packet_context *ctx, tiot_packet_queue *queue,
+                                           uint8_t *buff, uint32_t buff_len)
+{
+    tiot_packet *packet = NULL;
+    uint8_t *tmp_buff = buff;
+    uint32_t copy_len;
+    tiot_packet_rx_node *pos;
+
+    do {
+        copy_len = 0;
+        packet = (tiot_packet *)tiot_circ_queue_dequeue(&queue->queue);
+        if (packet == NULL) {
+            tiot_print_info("[TIoT][rx]packet queue is empty.\n");
+            break;
+        }
+        if (tiot_packet_is_valid(packet) != 0) {
+            tiot_print_err("[TIoT][rx]invalid packet.");
+            tiot_packet_free_packet(packet);
+            continue;
+        }
+
+        tiot_list_for_each_entry(pos, packet->head, node, tiot_packet_rx_node) {
+            copy_len += pos->len;
+        }
+        if (ctx->flags & TIOT_PKT_FLAGS_SUPPORT_ASCII) {
+            copy_len += sizeof(uint16_t);
+        }
+        if (copy_len > buff_len) {
+            tiot_print_info("[TIoT][rx]not enough buff len:%d for this packet: %d.", buff_len, copy_len);
+            tiot_packet_free_packet(packet);
+            continue;
+        }
+        /* 完整包正常, 复制一包到用户buffer后退出. */
+        if (ctx->flags & TIOT_PKT_FLAGS_SUPPORT_ASCII) {
+            (void)memcpy_s((void *)tmp_buff, sizeof(uint16_t), (void *)&packet->tag, sizeof(uint16_t));
+            tmp_buff += sizeof(uint16_t);
+        }
+        tiot_list_for_each_entry(pos, packet->head, node, tiot_packet_rx_node) {
+            (void)memcpy_s((void *)tmp_buff, pos->len, (void *)pos->data, pos->len);
+            tmp_buff += pos->len;
+        }
+        tiot_packet_free_packet(packet);
+        break;
+    } while (packet != NULL);
+
+    return copy_len;
+}
+#else
+static int32_t tiot_packet_copy_from_queue(tiot_packet_context *ctx, tiot_packet_queue *queue,
+                                           uint8_t *buff, uint32_t buff_len)
+{
+    uint32_t copy_len;
+    uint8_t *tmp_buff = buff;
+    tiot_packet *packet;
+    do {
+        copy_len = 0;
+        packet = (tiot_packet *)tiot_circ_queue_dequeue(&queue->queue);
+        if (packet == NULL) {
+            tiot_print_info("[TIoT][rx]packet queue is empty.");
+            break;
+        }
+        copy_len = packet->len;
+        if (ctx->flags & TIOT_PKT_FLAGS_SUPPORT_ASCII) {
+            copy_len += sizeof(uint16_t);
+        }
+        if (copy_len > buff_len) {
+            tiot_print_info("[TIoT][rx]not enough buff len:%d for this packet: %d.", buff_len, copy_len);
+            (void)circ_buf_update_read_pos(&(ctx->rx_buff.buf), packet->len);
+            continue;
+        }
+        /* 完整包正常, 复制一包到用户buffer后退出. */
+        if (ctx->flags & TIOT_PKT_FLAGS_SUPPORT_ASCII) {
+            (void)memcpy_s((void *)tmp_buff, sizeof(uint16_t), (void *)&packet->tag, sizeof(uint16_t));
+            tmp_buff += sizeof(uint16_t);
+        }
+        /* 按顺序读即可,不需要记录起始. */
+        (void)circ_buf_read(&(ctx->rx_buff.buf), tmp_buff, packet->len);
+        break;
+    } while (packet != NULL);
+    return copy_len;
+}
+#endif
+
+#ifdef __KERNEL__
+static int32_t packet_poll(tiot_packet_manager_query *query, tiot_packet_queue *queue, const tiot_xfer_rx_param *param)
+{
+    if (tiot_packet_read_out_check(query) != 0) {
+        return 1;
+    }
+
+    poll_wait(param->filp, (wait_queue_head_t *)(queue->rx_wait.wait), param->poll_wait);
+
+    if (tiot_packet_read_out_check(query) != 0) {
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+int32_t tiot_packet_read_out(tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, const tiot_xfer_rx_param *param)
+{
+    int32_t read_ret;
+    tiot_packet_queue *queue;
+    tiot_packet_manager_query query;
+    tiot_packet_context *ctx = (tiot_packet_context *)xfer->pkt_context;
+    if (ctx == NULL) {
+        return -1;
+    }
+    queue = tiot_packet_manager_find_queue(&ctx->rx_manager, param->subsys); /* 对应queue_id */
+    if (queue == NULL) {
+        return -1;
+    }
+    query.xfer = xfer;
+    query.queue_id = param->subsys;  /* 对应queue_id. */
+
+#ifdef __KERNEL__
+    if (param->filp != NULL && param->poll_wait != NULL) { /* poll mode */
+        return packet_poll(&query, queue, param);
+    }
+#endif
+
+    if (param->timeout == 0) { /* 非阻塞. */
+        /* 没有数据直接返回. */
+        if (tiot_packet_read_out_check(&query) == 0) {
+            tiot_print_dbg("[TIoT:pkt][%d]no data to read.\r\n", param->subsys);
+            return 0;
+        }
+    } else { /* 阻塞. */
+        if (queue->flags & TIOT_PACKET_QUEUE_RX_WAITING) {
+            tiot_print_err("[TIoT:pkt][%d]there's already a thread blocking read().\r\n", param->subsys);
+            return -1;
+        }
+        queue->flags |= TIOT_PACKET_QUEUE_RX_WAITING;
+        /* 等待接收到一个完整包. */
+        read_ret = osal_wait_timeout_interruptible(&queue->rx_wait, tiot_packet_read_out_check, &query, param->timeout);
+        if (xfer->pkt_context == 0) {
+            read_ret = 0;
+        }
+        queue->flags &= ~TIOT_PACKET_QUEUE_RX_WAITING;
+        if (read_ret <= 0) {
+            tiot_print_warning("[TIoT:pkt][%d]osal_wait timeout.\r\n", param->subsys);
+            return read_ret;
+        }
+    }
+
+    return tiot_packet_copy_from_queue(ctx, queue, buff, len);
+}
+
+#ifdef CONFIG_XFER_SUPPORT_TX_TASK
+static int32_t tiot_tx_packet_fill(uint8_t *dest, uint8_t *payload, uint16_t payload_len, uint8_t subsys_code)
+{
+    uint16_t packet_len = payload_len + TIOT_PKT_PKG_SIZE;
+    uint8_t *packet_buff = dest;
+
+    tiot_packet_head *head = (tiot_packet_head *)packet_buff;
+    head->head = TIOT_PKT_HEAD;
+    head->subsys_code = subsys_code;
+    head->len = packet_len;
+
+    if (memcpy_s(&packet_buff[TIOT_PKT_HEAD_SIZE], payload_len, payload, payload_len) != EOK) {
+        tiot_print_err("[TIoT][tx]packet memcpy err.\r\n");
+        return -1;
+    }
+    packet_buff[packet_len - 1] = TIOT_PKT_TAIL;
+    return 0;
+}
+
+int32_t tiot_packet_tx_push(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len,
+                            const tiot_xfer_tx_param *param)
+{
+    int32_t ret;
+    uint16_t payload_len;
+    uint32_t total_len;
+    const uint8_t *buff;
+    uint8_t packet_count;
+    const tiot_packet_subsys_info *subsys_info;
+    tiot_xfer_tx_data new_data;
+
+    /* data外部已验证 */
+    if ((param == NULL) || (len == 0)) {
+        tiot_print_err("[TIoT:pkt]tx param is NULL or len is 0.\r\n");
+        return -1;
+    }
+
+    total_len = len;
+    subsys_info = &g_tiot_pkt_subsys_info[param->subsys];
+    /* 分包个数: tx_len / 4095 + (tx_len % 4095 ? 1 : 0) ==> (tx_len + (4095 - 1)) / 4095。 */
+    packet_count = (total_len + TIOT_PKT_PAYLOAD_MAX_SIZE - 1) / TIOT_PKT_PAYLOAD_MAX_SIZE;
+    /* 预先申请 */
+    packet_buff = osal_kmalloc(total_len + packet_count * (TIOT_PKT_PKG_SIZE));
+    if (packet_buff == NULL) {
+        return -1;
+    }
+    tmp = packet_buff;
+
+    for (i = 0; i < packet_count - 1; i++) {
+        payload_len = TIOT_PKT_PAYLOAD_MAX_SIZE;
+        if (i == 0) {
+            ret = tiot_tx_packet_fill(tmp, buff, payload_len, subsys_info->common);
+        } else {
+            ret = tiot_tx_packet_fill(tmp, buff, payload_len, subsys_info->first);
+        }
+        if (ret != 0) {
+            /* 复制数据出错,释放buffer */
+            osal_kfree(packet_buff);
+            return -1;
+        }
+        tmp += payload_len + TIOT_PKT_PKG_SIZE;
+        buff += payload_len;
+    }
+
+    payload_len = total_len - (packet_count - 1) * TIOT_PKT_PAYLOAD_MAX_SIZE;
+    ret = tiot_tx_packet_fill(tmp, buff, payload_len, subsys_info->last);
+    if (ret != 0) {
+        /* 复制数据出错,释放buffer */
+        osal_kfree(packet_buff);
+        return -1;
+    }
+
+    new_data.data = packet_buff;
+    new_data.len = total_len + packet_count * (TIOT_PKT_PKG_SIZE);
+    if (tiot_circ_queue_enqueue(&xfer->tx_queue, (uintptr_t)&new_data) != 0) {
+        osal_kfree(packet_buff);
+        return -1;
+    }
+    return (ret >= 0) ? total_len : (-1);
+}
+#else
+static int32_t tiot_tx_packet_push(tiot_xfer_manager *xfer, const uint8_t *payload,
+                                   uint16_t payload_len, uint8_t subsys_code)
+{
+    int32_t ret = 0;
+    uint16_t packet_len = payload_len + TIOT_PKT_PKG_SIZE;
+    const uint8_t tail = TIOT_PKT_TAIL;
+    tiot_packet_head head = { TIOT_PKT_HEAD, subsys_code, packet_len };
+
+    do {
+        ret = tiot_xfer_direct_send(xfer, (uint8_t *)&head, sizeof(tiot_packet_head));
+        if (ret != sizeof(tiot_packet_head)) {
+            ret = -1;
+            break;
+        }
+        ret = tiot_xfer_direct_send(xfer, payload, payload_len);
+        if (ret != payload_len) {
+            ret = -1;
+            break;
+        }
+        ret = tiot_xfer_direct_send(xfer, &tail, sizeof(uint8_t));
+        if (ret != sizeof(uint8_t)) {
+            ret = -1;
+            break;
+        }
+    } while (0);
+
+    return (ret >= 0) ? (int32_t)packet_len : (-1);
+}
+
+int32_t tiot_packet_tx_push(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len,
+                            const tiot_xfer_tx_param *param)
+{
+    int32_t ret;
+    uint16_t payload_len;
+    uint32_t total_len;
+    const uint8_t *buff;
+    uint8_t packet_count;
+    uint8_t i;
+    const tiot_packet_subsys_info *subsys_info;
+    tiot_packet_context *pkt_ctx;
+
+    /* data外部已验证 */
+    if ((param == NULL) || (len == 0)) {
+        tiot_print_err("[TIoT:pkt]tx param is NULL or len is 0.\r\n");
+        return -1;
+    }
+
+    pkt_ctx = (tiot_packet_context*)(xfer->pkt_context);
+    if (pkt_ctx == NULL) {
+        tiot_print_err("[TIoT][pkt]packet context is NULL.\r\n");
+        return -1;
+    }
+
+    total_len = len;
+    buff = data;
+    /* 分包个数: tx_len / 4095 + (tx_len % 4095 ? 1 : 0) ==> (tx_len + (4095 - 1)) / 4095。 */
+    packet_count = (total_len + TIOT_PKT_PAYLOAD_MAX_SIZE - 1) / TIOT_PKT_PAYLOAD_MAX_SIZE;
+    subsys_info = &g_tiot_pkt_subsys_info[param->subsys];
+
+    /*
+     * 多线程并发情况下,必须保证每个线程完整地发完整个packet,中间不能插入同类型的其他packet
+     * thread1:  gnss-first           gnss-last
+     * thread2:            gnss-first
+     * 像如上情况就会出现first-first-last,导致解包出现错误
+     */
+    osal_mutex_lock(&pkt_ctx->tx_packet_mutex);
+
+    for (i = 0; i < packet_count - 1; i++) {
+        payload_len = TIOT_PKT_PAYLOAD_MAX_SIZE;
+        if (i == 0) {
+            ret = tiot_tx_packet_push(xfer, buff, payload_len, subsys_info->first);
+        } else {
+            ret = tiot_tx_packet_push(xfer, buff, payload_len, subsys_info->common);
+        }
+
+        if (ret == -1) {
+            osal_mutex_unlock(&pkt_ctx->tx_packet_mutex);
+            return -1;
+        }
+        buff += payload_len;
+    }
+    payload_len = total_len - (packet_count - 1) * TIOT_PKT_PAYLOAD_MAX_SIZE;
+    ret = tiot_tx_packet_push(xfer, buff, payload_len, subsys_info->last);
+
+    osal_mutex_unlock(&pkt_ctx->tx_packet_mutex);
+
+    return (ret >= 0) ? (int32_t)total_len : (-1);
+}
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.h
new file mode 100644 (file)
index 0000000..9fa18d7
--- /dev/null
@@ -0,0 +1,205 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-07-21, Create file. \n
+ */
+#ifndef TIOT_PACKET_H
+#define TIOT_PACKET_H
+
+#include "tiot_types.h"
+#include "tiot_xfer.h"
+#include "tiot_list.h"
+#include "tiot_packet_manager.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_transfer_packet_handle_tiot_packet Packet Handle
+ * @ingroup  tiot_common_transfer_packet_handle
+ * @{
+ */
+
+#define TIOT_PKT_FLAGS_SUPPORT_ASCII       0x1U
+
+#define TIOT_PKT_PAYLOAD_MAX_SIZE 4095U
+#define TIOT_PKT_HEAD_SIZE 4
+#define TIOT_PKT_TAIL_SIZE 1
+#define TIOT_PKT_PKG_SIZE  (TIOT_PKT_HEAD_SIZE + TIOT_PKT_TAIL_SIZE)
+
+#define TIOT_PKT_HEAD  0x7e
+#define TIOT_PKT_TAIL  0x7e
+
+/* 重新定义, 暂时只需要这些 */
+typedef enum {
+    SUBSYS_GNSS = 0x00,
+    SUBSYS_OM  = 0x01,
+    SUBSYS_SYS  = 0x02,
+    SUBSYS_BUTT
+} subsys_type_enum;
+
+typedef enum {
+    TIOT_PKT_TAG_BINARY,
+    TIOT_PKT_TAG_ASCII
+} tiot_pkt_rx_tag;
+
+typedef enum {
+    PKG_NOT_SEPRETED = 0,
+    PKG_SEPRETED = 1,
+} pkg_sepreted_state;
+
+enum TIOT_PKT_DATA_MSG_TYPE_ENUM {
+    SYS_MSG = 0x00,         /* 系统串口消息 */
+    BT_MSG = 0x01,          /* BT串口消息 */
+    GNSS_FIRST_MSG = 0x02,  /* GNSS串口消息,第一个分段消息 */
+    GNSS_COMMON_MSG = 0x03, /* GNSS串口消息,中间分段消息 */
+    GNSS_LAST_MSG = 0x04,   /* GNSS串口消息,最后一个分段消息 */
+    FM_FIRST_MSG = 0x05,    /* FM串口消息,第一个分段消息 */
+    FM_COMMON_MSG = 0x06,   /* FM串口消息,中间分段消息 */
+    FM_LAST_MSG = 0x07,     /* FM串口消息,最后一个分段消息 */
+    IR_FIRST_MSG = 0x08,    /* 红外串口消息,第一个分段消息 */
+    IR_COMMON_MSG = 0x09,   /* 红外串口消息,中间分段消息 */
+    IR_LAST_MSG = 0x0A,     /* 红外串口消息,最后一个分段消息 */
+    NFC_FIRST_MSG = 0x0B,   /* NFC串口消息,第一个分段消息 */
+    NFC_COMMON_MSG = 0x0C,  /* NFC串口消息,中间分段消息 */
+    NFC_LAST_MSG = 0x0D,    /* NFC串口消息,最后一个分段消息 */
+    OML_MSG = 0x0E,         /* 可维可测消息 */
+    MEM_DUMP_SIZE = 0x0f,   /* bfgx异常时,要dump的mem长度消息 */
+    MEM_DUMP = 0x10,        /* bfgx异常时,内存dump消息 */
+    WIFI_MEM_DUMP = 0x11,   /* UART READ WIFI MEM,内存dump消息 */
+    BFGX_CALI_MSG = 0x12,   /* BFGX 校准数据上报 */
+
+    /* GF_CPU消息 */
+    GF_SYS_MSG = 0x13,      /* GF系统串口消息 */
+    GF_OML_MSG = 0x14,      /* GF可维可测消息 */
+
+    SLE_MSG = 0x15,         /* SLE串口消息 */
+
+    MSG_BUTT,
+};
+
+typedef struct {
+    uint8_t seperated;
+    uint8_t first;
+    uint8_t common;
+    uint8_t last;
+} tiot_packet_subsys_info;
+
+typedef struct {
+    uint8_t head;
+    uint8_t subsys_code;
+    uint16_t len;
+} tiot_packet_head;
+
+typedef struct {
+    uint8_t *start;
+    uint32_t size;
+    uint32_t recv_cnt;
+} tiot_packet_buffer;
+
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC
+typedef struct {
+    tiot_circ_buf buf;
+    uint32_t buff_write;
+    uint32_t buff_read;
+} tiot_packet_circ_buffer;
+#endif
+
+typedef struct {
+    uint32_t flags;              /*!< Control behave. */
+    tiot_packet_manager rx_manager_info;
+    tiot_packet_buffer *buff;
+} tiot_packet_context_param;
+
+/**
+ * @brief  Packet parser context.
+ */
+typedef struct {
+    tiot_packet_manager rx_manager;
+    tiot_packet *packet;
+    uint32_t flags;              /*!< Control behave. */
+    osal_mutex tx_packet_mutex;
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC
+    tiot_packet_circ_buffer rx_buff;
+#endif
+    /* Rx State machine. */
+    uint8_t *pos;
+    tiot_packet_head head;
+    uint8_t tail;
+    uint8_t sys_msg;
+    uint8_t frame_error;
+    uint16_t frame_cnt;
+    uint16_t current_frame;
+    uint16_t frame_need_read;
+    uint16_t rx_queue_id;
+
+    tiot_xfer_manager *xfer;  /*!< Connect transfer manager. */
+} tiot_packet_context;
+
+typedef struct {
+    tiot_xfer_tx_data data;
+    uint16_t subsys;
+} tiot_packet_tx_data;
+
+/**
+ * @brief  Packet context init.
+ * @param  [in]  ctx   packet context.
+ * @param  [in]  xfer  Transfer manager.
+ * @param  [in]  flags control flags.
+ * @return if OK, return 0, else return -1.
+ */
+int32_t tiot_packet_init(tiot_packet_context *ctx, tiot_xfer_manager *xfer, const tiot_packet_context_param *param);
+
+/**
+ * @brief  Packet context deinit.
+ * @param  [in]  ctx packet context.
+ */
+void tiot_packet_deinit(tiot_packet_context *ctx);
+
+/**
+ * @brief  tx packet push.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [out] data Caller send data.
+ * @param  [in]  len  Caller data len.
+ * @param  [in]  param Caller send param, must.
+ * @return if OK, return sent data, else return -1.
+ */
+int32_t tiot_packet_tx_push(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len,
+                            const tiot_xfer_tx_param *param);
+
+/**
+ * @brief  rx data store.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [in]  data Received data.
+ * @param  [in]  len  Received data length.
+ */
+void tiot_packet_rx_data_store(tiot_xfer_manager *xfer, uint8_t *data, uint32_t len);
+
+/**
+ * @brief  rx data read out, copy uint16_t data_tag and single complete packet into user buffer.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [out] buff User buffer.
+ * @param  [in]  len  Max read length.
+ * @param  [in]  param Caller receive param.
+ * @return int32_t if OK, return readout length;if wait timeout, return 0; if err, return -1.
+ * @note   First two bytes copyed to buff indicate data type, ASCII or BINARY.
+ */
+int32_t tiot_packet_read_out(tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, const tiot_xfer_rx_param *param);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.c
new file mode 100644 (file)
index 0000000..9f11492
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2024-01-27, Create file. \n
+ */
+
+#include "tiot_packet_manager.h"
+#include "tiot_osal.h"
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+void tiot_packet_free_packet(tiot_packet *packet)
+{
+    tiot_packet_rx_node *pos, *next;
+    tiot_list_head_create(tmp_head);
+    if ((packet == NULL) || (packet->head == NULL)) {
+        return;
+    }
+    tiot_list_replace(packet->head, &tmp_head);
+    /* 使用临时节点遍历删除. */
+    tiot_list_for_each_entry_safe(pos, next, &tmp_head, node, tiot_packet_rx_node, tiot_packet_rx_node) {
+        if (pos != NULL) {
+            tiot___list_del_entry(&pos->node);
+            osal_kfree(pos);
+        }
+    }
+    osal_kfree(packet->head);
+}
+#endif
+
+void tiot_packet_queue_deinit(tiot_packet_queue *queue)
+{
+    /* 唤醒并等待可能的blocking-read()线程正常退出 */
+    osal_wait_wakeup_interruptible(&queue->rx_wait);
+    while (queue->flags & TIOT_PACKET_QUEUE_RX_WAITING) {
+        osal_msleep(1);
+    }
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    /* 动态申请buffer时才需要清除. */
+    /* 释放所有未处理缓存数据. */
+    tiot_packet *packet = NULL;
+    tiot_packet_free_packet(&queue->active_node);
+    do {
+        packet = (tiot_packet *)tiot_circ_queue_dequeue(&queue->queue);
+        if (packet == NULL) {
+            break;
+        }
+        tiot_packet_free_packet(packet);
+    } while (packet != NULL);
+#endif
+    osal_spin_lock_destroy(&queue->queue.lock);
+    osal_wait_destroy(&queue->rx_wait);
+}
+
+tiot_packet *tiot_packet_manager_get_packet(tiot_packet_manager *manager, uint16_t queue_id)
+{
+    tiot_packet_queue *queue = tiot_packet_manager_find_queue(manager, queue_id);
+    if (queue == NULL) {
+        return NULL;
+    }
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    if (queue->active_node.head == NULL) {
+        queue->active_node.head = (struct tiot_list_head *)osal_kmalloc(sizeof(struct tiot_list_head), OSAL_GFP_KERNEL);
+        if (queue->active_node.head == NULL) {
+            return NULL;
+        }
+        tiot_init_list_head(queue->active_node.head);
+    }
+#endif
+    return &queue->active_node;
+}
+
+int32_t tiot_packet_manager_init(tiot_packet_manager *manager)
+{
+    uint16_t i, j;
+    if (manager->match == NULL) {
+        return -1;
+    }
+    for (i = 0; i < manager->queue_num; i++) {
+        if (tiot_packet_queue_init((tiot_packet_queue *)&(manager->queues[i])) != 0) {
+            for (j = 0; j < i; j++) { /* 释放之前已初始化的queue */
+                tiot_packet_queue_deinit((tiot_packet_queue *)&manager->queues[j]);
+            }
+            return -1;
+        }
+    }
+    return 0;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.h
new file mode 100644 (file)
index 0000000..29605bb
--- /dev/null
@@ -0,0 +1,213 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: TIoT Packet Manager. \n
+ *
+ * History: \n
+ * 2024-01-13, Create file. \n
+ */
+#ifndef TIOT_PACKET_MANAGER_H
+#define TIOT_PACKET_MANAGER_H
+
+#include "tiot_types.h"
+#include "tiot_xfer.h"
+#include "tiot_circ_queue.h"
+#include "tiot_list.h"
+#include "tiot_board_log.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_transfer_packet_handle_tiot_packet_manager Packet Manager
+ * @ingroup  tiot_common_transfer_packet_handle_tiot_packet
+ * @{
+ */
+
+#define TIOT_PACKET_QUEUE_RX_WAITING    0x1
+
+/**
+ * @brief  TIOT Complete Packet, simple replace for skb_queue.
+ */
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+typedef struct {
+    struct tiot_list_head *head;  /* Dynamic Allocated. */
+    uint16_t tag;                 /* BINARY | ASCII. */
+} tiot_packet;
+
+typedef struct {
+    struct tiot_list_head node;
+    uint8_t *data;
+    uint32_t len;
+} tiot_packet_rx_node;
+#else
+typedef struct {
+    uint32_t len;
+    uint16_t tag;        /* BINARY | ASCII. */
+} tiot_packet;
+#endif
+
+typedef struct {
+    tiot_circ_queue_t queue;
+    const tiot_packet *queue_nodes;
+    uint16_t queue_size;
+    uint8_t flags;
+    tiot_packet active_node;
+    osal_wait rx_wait;
+} tiot_packet_queue;
+
+typedef uint16_t (* tiot_packet_match_func)(uint32_t msg_type);
+
+typedef struct {
+    const tiot_packet_queue *queues;
+    uint16_t queue_num;
+    tiot_packet_match_func match;
+} tiot_packet_manager;
+
+typedef struct {
+    tiot_xfer_manager *xfer;
+    uint16_t queue_id;
+} tiot_packet_manager_query;
+
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+/**
+ * @if Eng
+ * @brief  Free TIoT packlet.
+ * @param  packet Pointer to TIoT packet.
+ * @else
+ * @brief  释放TIoT消息包。
+ * @param  packet TIoT消息包指针。
+ * @endif
+ */
+void tiot_packet_free_packet(tiot_packet *packet);
+#endif
+
+/**
+ * @if Eng
+ * @brief  Deinit packet queue.
+ * @param  queue Pointer to TIoT packet queue.
+ * @else
+ * @brief  去初始化包格式队列。
+ * @param  queue 包格式队列指针。
+ * @endif
+ */
+void tiot_packet_queue_deinit(tiot_packet_queue *queue);
+
+/**
+ * @if Eng
+ * @brief  Get packet pointer for queue_id, from packet manager.
+ * @param  manager Packet manager.
+ * @param  queue_id The index of queue in packet manager.
+ * @return Return packet pointer for queue_id,if no such queue or malloc fail, return NULL.
+ * @else
+ * @brief  从包管理器中获取指定队列ID的包。
+ * @param  manager 包管理器。
+ * @param  queue_id 包管理器内队列ID。
+ * @return 返回指定队列ID的包的指针,如果没有对应队列,或内存申请失败则返回NULL。
+ * @endif
+ */
+tiot_packet *tiot_packet_manager_get_packet(tiot_packet_manager *manager, uint16_t queue_id);
+
+/**
+ * @if Eng
+ * @brief  init packet manager.
+ * @param  manager Packet manager.
+ * @else
+ * @brief  初始化包包管理器。
+ * @param  manager 包管理器。
+ * @endif
+ */
+int32_t tiot_packet_manager_init(tiot_packet_manager *manager);
+
+static inline int32_t tiot_packet_queue_init(tiot_packet_queue *queue)
+{
+    const uint32_t queue_mem_size = queue->queue_size * sizeof(tiot_packet);
+    tiot_circ_queue_init(&queue->queue, queue->queue_size, sizeof(tiot_packet), (uintptr_t)queue->queue_nodes);
+    (void)memset_s((void *)queue->queue_nodes, queue_mem_size, 0, queue_mem_size);
+    (void)memset_s((void *)&queue->active_node, sizeof(tiot_packet), 0, sizeof(tiot_packet));
+    queue->flags = 0;
+    if (osal_wait_init(&queue->rx_wait) != OSAL_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+static inline void tiot_packet_manager_deinit(tiot_packet_manager *manager)
+{
+    uint16_t i;
+    for (i = 0; i < manager->queue_num; i++) {
+        tiot_packet_queue_deinit((tiot_packet_queue *)&manager->queues[i]);
+    }
+}
+
+static inline tiot_packet_queue *tiot_packet_manager_find_queue(tiot_packet_manager *manager, uint16_t queue_id)
+{
+    tiot_packet_queue *queue = NULL;
+    if (manager == NULL) {
+        return queue;
+    }
+    if (queue_id < manager->queue_num) {
+        queue = (tiot_packet_queue *)&manager->queues[queue_id];
+    }
+    return queue;
+}
+
+static inline void tiot_packet_manager_enqueue_packet(tiot_packet_manager *manager, uint16_t queue_id)
+{
+    tiot_packet_queue *queue = tiot_packet_manager_find_queue(manager, queue_id);
+    if (queue == NULL) {
+        return;
+    }
+    if (tiot_circ_queue_enqueue(&queue->queue, (uintptr_t)&queue->active_node) != 0) {
+        tiot_print_err("[TIoT:rx]circ queue [%d] no space.\r\n", queue_id);
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+        tiot_packet_free_packet(&queue->active_node);
+#endif
+    }
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    /* 指针转移至循环队列内或已释放. */
+    queue->active_node.head = NULL;
+#else
+    queue->active_node.len = 0;
+#endif
+}
+
+static inline void tiot_packet_manager_discard_packet(tiot_packet_manager *manager, uint16_t queue_id)
+{
+    tiot_packet_queue *queue = tiot_packet_manager_find_queue(manager, queue_id);
+    if (queue == NULL) {
+        return;
+    }
+#ifdef CONFIG_BOARD_DYNAMIC_ALLOC
+    tiot_packet_free_packet(&queue->active_node);
+    /* 指针已释放. */
+    queue->active_node.head = NULL;
+#else
+    queue->active_node.len = 0;
+#endif
+}
+
+static inline int32_t tiot_packet_manager_has_data(tiot_packet_manager *manager, uint16_t queue_id)
+{
+    tiot_packet_queue *queue;
+    queue = tiot_packet_manager_find_queue(manager, queue_id);
+    if (queue == NULL) {
+        return 0;
+    }
+    return (tiot_circ_queue_empty(&queue->queue) == 0);
+}
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.c
new file mode 100644 (file)
index 0000000..1b82ac8
--- /dev/null
@@ -0,0 +1,493 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT transfer module. \n
+ *
+ * History: \n
+ * 2023-04-18, Create file. \n
+ */
+#include "tiot_xfer.h"
+#include "tiot_xfer_utils.h"
+#include "tiot_board_log.h"
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+#define TIOT_XFER_MANAGER_MAX   16
+
+typedef enum {
+    TIOT_XFER_TASK_UNINIT,
+    TIOT_XFER_TASK_INIT,
+    TIOT_XFER_TASK_ABORT,
+} tiot_xfer_task_state;
+
+typedef struct {
+    osal_task *task;
+    tiot_xfer_manager *xfer_list[TIOT_XFER_MANAGER_MAX];
+    volatile uint16_t xfer_count;
+    volatile uint16_t state;
+    osal_wait tx_wait;
+} tiot_xfer_send_task;
+
+/* 单线程 */
+static tiot_xfer_send_task g_tiot_xfer_send_task = { 0 };
+
+static int32_t tiot_xfer_send_task_init(tiot_xfer_manager *xfer);
+static void tiot_xfer_send_task_quit(tiot_xfer_manager *xfer);
+
+static int32_t tiot_xfer_send_task_queue_init(tiot_xfer_manager *xfer)
+{
+    /* 仅单一发送队列 */
+    const uint32_t tx_queue_node_num = CONFIG_XFER_TX_NODE_NUM;
+    uint32_t tx_queue_mem_size = sizeof(tiot_xfer_tx_data) * tx_queue_node_num;
+    xfer->tx_queue_mem = (uintptr_t)osal_kmalloc(tx_queue_mem_size, OSAL_GFP_KERNEL);
+    if (xfer->tx_queue_mem == 0) {
+        tiot_print_err("[TIoT][xfer]tx queue malloc failed.\n");
+        return -1;
+    }
+    (void)memset_s((void *)xfer->tx_queue_mem, tx_queue_mem_size, 0, tx_queue_mem_size);
+    tiot_circ_queue_init(&xfer->tx_queue, tx_queue_node_num, sizeof(tiot_xfer_tx_data), xfer->tx_queue_mem);
+    return 0;
+}
+
+static void tiot_xfer_send_task_queue_deinit(tiot_xfer_manager *xfer)
+{
+    if (xfer->tx_queue_mem != 0) {
+        osal_kfree((void *)xfer->tx_queue_mem);
+        xfer->tx_queue_mem = 0;
+    }
+}
+#endif
+
+static inline int32_t tiot_xfer_default_rx_buff_init(tiot_xfer_manager *xfer)
+{
+#ifdef CONFIG_XFER_DEFAULT_RX_BUFF
+    (void)memset_s((void *)xfer->rx_buff_mem, CONFIG_XFER_RX_BUFF_SIZE, 0, CONFIG_XFER_RX_BUFF_SIZE);
+    circ_buf_init(&xfer->rx_buff, &xfer->rx_buff_write, &xfer->rx_buff_read,
+                  (void *)xfer->rx_buff_mem, CONFIG_XFER_RX_BUFF_SIZE);
+    return 0;
+#else
+    tiot_unused(xfer);
+    tiot_print_err("[TIoT][xfer]no rx buff, check tiot_autoconfig.h.\n");
+    return -1;
+#endif
+}
+
+int32_t tiot_xfer_init(tiot_xfer_manager *xfer, uintptr_t xmit_id, const tiot_xfer_device_info *dev_info)
+{
+    int32_t ret = 0;
+    const tiot_xmit_ops *xmit_ops;
+    /* 等待函数必须不为空,否则osal_wait_timeout_interruptible不能正常工作. */
+    if ((xfer == NULL) || (dev_info == NULL) || (dev_info->rx_wait_func == NULL)) {
+        return -1;
+    }
+    xmit_ops = tiot_xmit_get_ops(dev_info->xmit_type);
+    if (xmit_ops == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transmit type invalid.\n");
+        return -1;
+    }
+    xfer->tx_queue_mem = 0;
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+    /* 仅单一发送队列 */
+    ret = tiot_xfer_send_task_init(xfer);
+    if (ret != 0) {
+        goto rx_wait_err;
+    }
+#endif
+    if ((xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) && (tiot_xfer_default_rx_buff_init(xfer) != 0)) {
+        goto rx_wait_err;
+    }
+    if (osal_wait_init(&xfer->rx_wait) != OSAL_SUCCESS) {
+        tiot_print_err("[TIoT][xfer]rx wait init failed.\n");
+        goto rx_wait_err;
+    }
+    if (osal_mutex_init(&xfer->dev_mutex) != OSAL_SUCCESS) {
+        tiot_print_err("[TIoT][xfer]device mutex init failed.\n");
+        goto dev_mutex_err;
+    }
+    if (osal_mutex_init(&xfer->read_mutex) != OSAL_SUCCESS) {
+        tiot_print_err("[TIoT][xfer]read mutex init failed.\n");
+        goto read_mutex_err;
+    }
+
+    /* Transmit实例初始化. */
+    xfer->xmit_ops = xmit_ops;
+    xfer->xmit.id = xmit_id;
+    xfer->xmit_state = TIOT_XMIT_STATE_CLOSE;
+    /* 接收初始化 */
+    xfer->rx_wait_func = dev_info->rx_wait_func;
+    (void)memset_s(&xfer->config, sizeof(struct tiot_xmit_config), 0, sizeof(struct tiot_xmit_config));
+     /* 包格式处理初始化 */
+    (void)memset_s(&xfer->pkt_ops, sizeof(tiot_xfer_packet_ops), 0, sizeof(tiot_xfer_packet_ops));
+    tiot_print_suc("[TIoT][xfer]transfer manager init succ.\n");
+    return ret;
+read_mutex_err:
+    osal_mutex_destroy(&xfer->dev_mutex);
+dev_mutex_err:
+    osal_wait_destroy(&xfer->rx_wait);
+rx_wait_err:
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+    tiot_xfer_send_task_quit(xfer);
+#endif
+    return -1;
+}
+
+void tiot_xfer_deinit(tiot_xfer_manager *xfer)
+{
+    if (xfer == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager is NULL.\n");
+        return;
+    }
+
+    tiot_print_info("[TIoT][xfer]transfer manager deinit.\n");
+    /* 先关闭xfer保证硬件不再发送接收 */
+    tiot_xfer_close(xfer);
+
+    /* Transmit实例去初始化. */
+    (void)memset_s(&xfer->xmit, sizeof(tiot_xmit), 0, sizeof(tiot_xmit));
+    (void)memset_s(&xfer->config, sizeof(struct tiot_xmit_config), 0, sizeof(struct tiot_xmit_config));
+    xfer->xmit_ops = NULL;
+
+    tiot_xfer_uninstall_packet(xfer);
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+    tiot_xfer_send_task_quit(xfer);
+#endif
+    osal_wait_destroy(&xfer->rx_wait);
+
+    /* 互斥锁初始化 */
+    osal_mutex_destroy(&xfer->dev_mutex);
+    osal_mutex_destroy(&xfer->read_mutex);
+}
+
+int32_t tiot_xfer_install_packet(tiot_xfer_manager *xfer, tiot_xfer_packet_ops *pkt_ops, uintptr_t pkt_context)
+{
+    if (xfer == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager is NULL.\n");
+        return -1;
+    }
+
+    osal_mutex_lock(&xfer->dev_mutex);
+    (void)memcpy_s(&xfer->pkt_ops, sizeof(tiot_xfer_packet_ops), pkt_ops, sizeof(tiot_xfer_packet_ops));
+    xfer->pkt_context = pkt_context;
+    osal_mutex_unlock(&xfer->dev_mutex);
+    return 0;
+}
+
+void tiot_xfer_uninstall_packet(tiot_xfer_manager *xfer)
+{
+    if (xfer == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager is NULL.\n");
+        return;
+    }
+
+    osal_mutex_lock(&xfer->dev_mutex);
+    xfer->pkt_context = 0;
+    memset_s(&xfer->pkt_ops, sizeof(tiot_xfer_packet_ops), 0, sizeof(tiot_xfer_packet_ops));
+    osal_mutex_unlock(&xfer->dev_mutex);
+}
+
+int32_t tiot_xfer_open(tiot_xfer_manager *xfer, tiot_xfer_open_param *param)
+{
+    int32_t ret;
+    tiot_xmit_callbacks cbs = { tiot_xfer_rx_notify };
+    if (xfer == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager is NULL.\n");
+        return -1;
+    }
+
+    osal_mutex_lock(&xfer->dev_mutex);
+    if (xfer->xmit_state != TIOT_XMIT_STATE_CLOSE) {
+        osal_mutex_unlock(&xfer->dev_mutex);
+        tiot_print_err("[TIoT][xfer]transmit state already opened.\n");
+        return -1;
+    }
+    ret = xfer->xmit_ops->open(&xfer->xmit, &cbs);
+    if (ret != 0) {
+        osal_mutex_unlock(&xfer->dev_mutex);
+        tiot_print_err("[TIoT][xfer]transmit open failed.\n");
+        return ret;
+    }
+
+    if ((xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) && (param != NULL)) {
+        (void)memcpy_s(&xfer->rx_cbk_param, sizeof(tiot_xfer_cbk_param),
+                       &param->rx_cbk_param, sizeof(tiot_xfer_cbk_param));
+    } else {
+        xfer->rx_cbk_param.rx_callback = NULL;
+    }
+
+    xfer->xmit_state = TIOT_XMIT_STATE_OPEN;
+
+    osal_mutex_unlock(&xfer->dev_mutex);
+    return ret;
+}
+
+int32_t tiot_xfer_set_config(tiot_xfer_manager *xfer, struct tiot_xmit_config *config)
+{
+    int32_t ret;
+    if ((xfer == NULL) || (config == NULL)) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager or config is NULL.\n");
+        return -1;
+    }
+    (void)osal_mutex_lock(&xfer->dev_mutex);
+    if (xfer->xmit_state == TIOT_XMIT_STATE_CLOSE) {
+        tiot_print_dbg("[TIoT][xfer]transmit state closed, cannot set config.\n");
+        (void)osal_mutex_unlock(&xfer->dev_mutex);
+        return -1;
+    }
+    ret = xfer->xmit_ops->set_config(&xfer->xmit, config);
+    if (ret == 0) {
+        (void)memcpy_s(&xfer->config, sizeof(struct tiot_xmit_config), config, sizeof(struct tiot_xmit_config));
+    }
+    (void)osal_mutex_unlock(&xfer->dev_mutex);
+    return ret;
+}
+
+int32_t tiot_xfer_get_config(tiot_xfer_manager *xfer, struct tiot_xmit_config *config)
+{
+    if ((xfer == NULL) || (config == NULL)) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager or config is NULL.\n");
+        return -1;
+    }
+
+    (void)memcpy_s(config, sizeof(struct tiot_xmit_config), &xfer->config, sizeof(struct tiot_xmit_config));
+    return 0;
+}
+
+void tiot_xfer_close(tiot_xfer_manager *xfer)
+{
+    if (xfer == NULL) {
+        tiot_print_dbg("[TIoT][xfer]transfer manager is NULL.\n");
+        return;
+    }
+
+    (void)osal_mutex_lock(&xfer->dev_mutex);
+    if (xfer->xmit_state == TIOT_XMIT_STATE_CLOSE) {
+        (void)osal_mutex_unlock(&xfer->dev_mutex);
+        tiot_print_dbg("[TIoT][xfer]transmit state already closed.\n");
+        return;
+    }
+
+    xfer->xmit_ops->close(&xfer->xmit);
+    (void)memset_s(&xfer->rx_cbk_param, sizeof(tiot_xfer_cbk_param), 0, sizeof(tiot_xfer_cbk_param));
+
+    xfer->xmit_state = TIOT_XMIT_STATE_CLOSE;
+#ifdef CONFIG_XFER_DEFAULT_RX_BUFF
+    (void)memset_s((void *)xfer->rx_buff_mem, CONFIG_XFER_RX_BUFF_SIZE, 0, CONFIG_XFER_RX_BUFF_SIZE);
+    circ_buf_flush(&xfer->rx_buff);
+#endif
+    (void)osal_mutex_unlock(&xfer->dev_mutex);
+    return;
+}
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+static int tiot_xfer_send_task_wait_condition(void *param)
+{
+    tiot_xfer_send_task *send_task = &g_tiot_xfer_send_task;
+    if (send_task->state == TIOT_XFER_TASK_ABORT) {
+        return OSAL_WAIT_CONDITION_TRUE;
+    }
+
+    uint16_t xfer_count = g_tiot_xfer_send_task.xfer_count;
+    for (uint16_t i = 0; i < xfer_count; i++) {
+        if (tiot_circ_queue_empty(&xfer_list[i]->tx_queue) == 0) {
+            return OSAL_WAIT_CONDITION_TRUE;
+        }
+    }
+    return 0;
+}
+
+static void tiot_xfer_send_schedule(tiot_xfer_manager *xfer)
+{
+    if ((xfer == NULL) || (xfer->xmit_state == TIOT_XMIT_STATE_CLOSE)) {
+        tiot_print_info("[TIoT][xfer]xfer is null or xmit close.");
+        return;
+    }
+    tiot_xfer_tx_data *node = NULL;
+    do {
+        node = (tiot_xfer_tx_data *)tiot_circ_queue_dequeue(&xfer->tx_queue);
+        if (node != NULL) {
+            tiot_xfer_direct_send(xfer, node->data, node->len);
+        } else {
+            tiot_print_info("[TIoT][xfer]tx queue is empty.");
+        }
+    } while (node != NULL);
+}
+
+static void tiot_xfer_send_task_handle(void *param)
+{
+    (void)param;
+    tiot_xfer_manager **xfer_list = g_tiot_xfer_send_task.xfer_list;
+    uint16_t xfer_count;
+    for (;;) {
+        /* 等待某个transfer manager有数据或退出 */
+        osal_wait_timeout_interruptible(&g_tiot_xfer_send_task.tx_wait, tiot_xfer_send_task_wait_condition,
+                                        NULL, OSAL_WAIT_FOREVER);
+        if (g_tiot_xfer_send_task.state == TIOT_XFER_TASK_ABORT) {
+            break;
+        }
+        xfer_count = g_tiot_xfer_send_task.xfer_count;
+        for (uint16_t i = 0; i < xfer_count; i++) {
+            tiot_xfer_send_schedule(xfer_list[i]);
+        }
+    }
+
+    /* 退出流程. */
+    g_tiot_xfer_send_task.state = TIOT_XFER_TASK_UNINIT;
+    osal_wait_wakeup(&g_tiot_xfer_send_task.tx_wait);
+}
+
+static int32_t tiot_xfer_send_task_init(tiot_xfer_manager *xfer)
+{
+    const uint32_t stack_size = 2048;
+    tiot_xfer_send_task *send_task = &g_tiot_xfer_send_task;
+    if (send_task->xfer_count == 0) {
+        if (osal_wait_init(&send_task->tx_wait) != OSAL_SUCCESS) {
+            tiot_print_err("[TIoT][xfer]send task wait init failed.\n");
+            return -1;
+        }
+        send_task->task = osal_kthread_create(tiot_xfer_send_task_handle, NULL, "tiot_tx", stack_size);
+        if (send_task->task == NULL) {
+            osal_wait_destroy(&send_task->tx_wait);
+            tiot_print_err("[TIoT][xfer]send task init failed.\n");
+            return -1;
+        }
+    }
+    if (tiot_xfer_send_task_queue_init(xfer) != 0) {
+        return -1;
+    }
+    send_task->xfer_count++;
+    send_task->xfer_list[send_task->xfer_count] = xfer;
+    return 0;
+}
+
+static int tiot_xfer_send_task_quit_wait_condition(void *param)
+{
+    if (g_tiot_xfer_send_task.state == TIOT_XFER_TASK_UNINIT) {
+        return OSAL_WAIT_CONDITION_TRUE;
+    }
+    return 0;
+}
+
+/* Transfer manager去初始化时调用 */
+static void tiot_xfer_send_task_quit(tiot_xfer_manager *xfer)
+{
+    tiot_xfer_send_task *send_task = &g_tiot_xfer_send_task;
+    uint16_t xfer_count = send_task->xfer_count;
+    uint16_t i = 0;
+    for (; i < xfer_count; i++) {
+        if (send_task->xfer_list[i] == xfer) {
+            send_task->xfer_list[i] = NULL;
+            break;
+        }
+    }
+    tiot_xfer_send_task_queue_deinit(xfer);
+    if (i == xfer_count) {
+        /* 未注册 */
+        return;
+    }
+    send_task->xfer_count--;
+    /* 当所有transfer manager均去初始化时,释放task */
+    if (send_task->xfer_count == 0) {
+        g_tiot_xfer_send_task.state = TIOT_XFER_TASK_ABORT;
+        osal_wait_wakeup(&g_tiot_xfer_send_task.tx_wait);
+        /* 等待任务退出 */
+        osal_wait_timeout_interruptible(&g_tiot_xfer_send_task.tx_wait,
+                                        tiot_xfer_send_task_quit_wait_condition, NULL, OSAL_WAIT_FOREVER);
+        osal_kthread_destroy(g_tiot_xfer_send_task.task, 0);
+        g_tiot_xfer_send_task.task = NULL;
+        (void)memset_s(&g_tiot_xfer_send_task, sizeof(tiot_xfer_send_task), 0, sizeof(tiot_xfer_send_task));
+    }
+}
+#endif
+
+int32_t tiot_xfer_send(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len, const tiot_xfer_tx_param *param)
+{
+    int32_t ret;
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+    tiot_xfer_tx_data node = { data, len };
+#endif
+    if ((xfer == NULL) || (data == NULL)) {
+        tiot_print_err("[TIoT][xfer]transfer manager is NULL or input data is NULL.");
+        return -1;
+    }
+
+    if (xfer->pkt_ops.tx_push != NULL) {
+        ret = xfer->pkt_ops.tx_push(xfer, data, len, param);
+    } else {
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+        ret = tiot_circ_queue_enqueue(&xfer->tx_queue, (uintptr_t)&node);
+#else
+        ret = tiot_xfer_direct_send(xfer, data, len);
+#endif
+    }
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+    tiot_xfer_send_task *send_task = &g_tiot_xfer_send_task;
+    if (ret == 0) {
+        osal_wait_wakeup(&send_task->tx_wait);
+    }
+#endif
+    return ret;
+}
+
+void tiot_xfer_rx_notify(tiot_xmit *xmit, uint8_t *data, uint32_t len)
+{
+    int32_t ret = 0;
+    tiot_xfer_manager *xfer = (tiot_xfer_manager *)xmit;
+    if (xfer == NULL) {
+        tiot_print_err("[TIoT][rx]notified transmit is NULL.\n");
+        return;
+    }
+
+    /* 可能中断内被调用 */
+    if (xfer->xmit_state == TIOT_XMIT_STATE_CLOSE) {
+        tiot_print_dbg("[TIoT][rx]transmit state closed.\n");
+        return;
+    }
+
+    if (xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) {
+        if ((data == NULL) || (len == 0)) {
+            tiot_print_err("[TIoT][rx]notified data is NULL or len is 0.\n");
+            return;
+        }
+        if (xfer->pkt_ops.rx_data_store != NULL) {
+            /* 由包格式决定什么时候唤醒rx_wait */
+            xfer->pkt_ops.rx_data_store(xfer, data, len);
+            return;
+        } else {
+            /* 存入默认buffer */
+            ret = tiot_xfer_read_store(&xfer->rx_buff, data, len);
+        }
+    }
+
+    if (ret == 0) {
+        osal_wait_wakeup_interruptible(&xfer->rx_wait);
+    } else {
+        tiot_print_err("[TIoT][rx]circ buff not stored.\n");
+    }
+}
+
+int32_t tiot_xfer_recv(tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, const tiot_xfer_rx_param *param)
+{
+    int32_t ret;
+    if ((xfer == NULL) || (param == NULL)) {
+        tiot_print_dbg("[TIoT][rx]transfer manager is NULL or param is NULL.\n");
+        return -1;
+    }
+
+    osal_mutex_lock(&xfer->dev_mutex);
+    if (xfer->xmit_state == TIOT_XMIT_STATE_CLOSE) {
+        osal_mutex_unlock(&xfer->dev_mutex);
+        tiot_print_dbg("[TIoT][rx]transmit state closed.\n");
+        return -1;
+    }
+    osal_mutex_unlock(&xfer->dev_mutex);
+
+    if (xfer->pkt_ops.read_out != NULL) {
+        ret =  xfer->pkt_ops.read_out(xfer, buff, len, param);
+    } else {
+        /* 默认读取路径,固件加载时使用. */
+        ret = tiot_xfer_read_out(xfer, buff, len, param->timeout);
+    }
+
+    return ret;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.h
new file mode 100644 (file)
index 0000000..1fe2165
--- /dev/null
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT transfer module. \n
+ *
+ * History: \n
+ * 2023-04-18, Create file. \n
+ */
+#ifndef TIOT_XFER_H
+#define TIOT_XFER_H
+
+#include "tiot_board_xmit.h"
+#include "tiot_board_xmit_ops.h"
+#include "tiot_circ_queue.h"
+#include "tiot_circ_buf.h"
+#include "tiot_osal.h"
+
+#ifdef __KERNEL__
+#include <linux/poll.h>
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_transfer Transfer
+ * @ingroup  tiot_common
+ * @{
+ */
+
+/* 临时flags, 用于拆分低功耗持锁 & disallow消息. */
+#define TIOT_XFER_RESUME                0U
+#define TIOT_XFER_SUSPEND               ((uint16_t)1 << 1)
+#define TIOT_XFER_DELAY_MSG             ((uint16_t)1 << 2)
+
+#define TIOT_XFER_RECV_NO_WAIT       ((uint32_t)0)
+#define TIOT_XFER_RECV_WAIT_FOREVER  ((uint32_t)0xFFFFFFF)
+
+/**
+ * @brief  TIoT Transmit port state.
+ */
+typedef enum {
+    TIOT_XMIT_STATE_CLOSE,  /* TIoT Transmit state close. */
+    TIOT_XMIT_STATE_OPEN,   /* TIoT Transmit state open. */
+    TIOT_XMIT_STATE_BUSY    /* TIoT Transmit state busy for reading or writing. */
+} tiot_xmit_state;
+
+/**
+ * @brief  TIoT Transfer send node, cound be exetend by packet ops with other attributes.
+ */
+typedef struct {
+    const uint8_t *data;    /* Pointer to send buff. */
+    uint32_t len;     /* Send len. */
+} tiot_xfer_tx_data;
+
+/**
+ * @brief  TIoT Transfer send param, cound be exetend by packet ops with other attributes.
+ */
+typedef struct {
+    uint32_t subsys;     /* subsys info. */
+} tiot_xfer_tx_param;
+
+/**
+ * @brief  TIoT Transfer receive param, cound be exetend by packet ops with other attributes.
+ */
+typedef struct {
+    uint32_t timeout;    /* Read timeout by ms, 0 timeout means no wait. */
+    uint32_t subsys;     /* subsys info. */
+#ifdef __KERNEL__
+    struct file *filp;
+    poll_table *poll_wait;
+#endif
+} tiot_xfer_rx_param;
+
+struct _tiot_xfer_manager;
+struct _tiot_xfer_packet;
+
+/**
+ * @brief  TIoT Transfer packet operations.
+ */
+typedef struct {
+    /*!< Packet parse tx node, and push to transmit or tx queue. */
+    int32_t (* tx_push)(struct _tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len,
+                        const tiot_xfer_tx_param *param);
+    /*!< Read data out to caller buffer, same as tiot_xfer_recv. */
+    int32_t (* read_out)(struct _tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, const tiot_xfer_rx_param *param);
+    /*!< For async read, store data from board transmit isr. */
+    void (* rx_data_store)(struct _tiot_xfer_manager *xfer, uint8_t *data, uint32_t len);
+} tiot_xfer_packet_ops;
+
+/**
+ * @brief  TIoT Transfer device info.
+ */
+typedef struct {
+    tiot_xmit_type xmit_type;
+    osal_wait_condition_func rx_wait_func;  /*!< Device related read wait func, could be gpio level. */
+} tiot_xfer_device_info;
+
+typedef struct {
+    uint8_t *buff;
+    uint32_t buff_len;
+    void (*rx_callback)(const uint8_t *buff, uint32_t len);
+} tiot_xfer_cbk_param;
+
+typedef struct {
+    tiot_xfer_cbk_param rx_cbk_param;
+} tiot_xfer_open_param;
+
+/**
+ * @brief  TIoT Transfer manager.
+ */
+typedef struct _tiot_xfer_manager {
+    /* Board transmit infos. */
+    tiot_xmit xmit;                   /*!< Board transmit instance. */
+    const tiot_xmit_ops *xmit_ops;    /*!< Board transmit operations. */
+    struct tiot_xmit_config config;   /*!< Board transmit config saved. */
+    uint16_t xmit_state;              /*!< Board transmit state, close or open. */
+    uint16_t xmit_suspend;            /*!< Tmp flag for suspend, will merge to state. */
+
+    /* Mutexes */
+    osal_mutex dev_mutex;             /*!< Transmit device mutex. */
+    osal_mutex read_mutex;            /*!< Transmit read mutex. */
+
+    /* Send */
+    tiot_circ_queue_t tx_queue;       /*!< Tx circular queue, with tiot_xfer_tx_node as node. */
+    uintptr_t tx_queue_mem;           /*!< Tx circular queue allocated memory. */
+
+    /* Recieve */
+    osal_wait rx_wait;
+    osal_wait_condition_func rx_wait_func;  /*!< Registed read wait func, could be gpio level. */
+
+    tiot_circ_buf rx_buff;            /*!< Rx circular buff. */
+    uint32_t rx_buff_write;           /*!< Rx circular buff write index. */
+    uint32_t rx_buff_read;            /*!< Rx circular buff read index. */
+#ifdef CONFIG_XFER_DEFAULT_RX_BUFF
+    /*!< Rx circular buff memory. */
+    uint8_t rx_buff_mem[CONFIG_XFER_RX_BUFF_SIZE];
+#endif
+
+    /* Packet */
+    tiot_xfer_packet_ops pkt_ops;    /*!< Packet operation, tx & rx data packet parse. */
+    uintptr_t pkt_context;           /*!< Packet operation used context. */
+
+    tiot_xfer_cbk_param rx_cbk_param;
+} tiot_xfer_manager;
+
+/**
+ * @brief  TIoT Transfer manager init.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [in]  xmit_id Board Transmit id.
+ * @param  [in]  dev_info Device Transfer related info.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_xfer_init(tiot_xfer_manager *xfer, uintptr_t xmit_id, const tiot_xfer_device_info *dev_info);
+
+/**
+ * @brief  TIoT Transfer manager deinit.
+ * @param  [in]  xfer Transfer manager.
+ */
+void tiot_xfer_deinit(tiot_xfer_manager *xfer);
+
+/**
+ * @brief  TIoT Transfer manager install packet.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [in]  pkt_ops Transfer packet ops.
+ * @param  [in]  pkt_context Transfer packet context.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_xfer_install_packet(tiot_xfer_manager *xfer, tiot_xfer_packet_ops *pkt_ops, uintptr_t pkt_context);
+
+/**
+ * @brief  TIoT Transfer manager uninstall packet.
+ * @param  [in]  xfer Transfer manager.
+ */
+void tiot_xfer_uninstall_packet(tiot_xfer_manager *xfer);
+
+/**
+ * @brief  TIoT Transfer manager open, with packet installed.
+ * @param  [in]  xfer Transfer manager.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_xfer_open(tiot_xfer_manager *xfer, tiot_xfer_open_param *param);
+
+/**
+ * @brief  TIoT Transfer manager close.
+ * @param  [in]  xfer Transfer manager.
+ */
+void tiot_xfer_close(tiot_xfer_manager *xfer);
+
+/**
+ * @brief  TIoT Transfer manager set config.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [in]  config New config to be set.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_xfer_set_config(tiot_xfer_manager *xfer, struct tiot_xmit_config *config);
+
+/**
+ * @brief  TIoT Transfer manager get config.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [out] config copy old transmit config to caller.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_xfer_get_config(tiot_xfer_manager *xfer, struct tiot_xmit_config *config);
+
+/**
+ * @brief  TIoT Transfer manager send.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [out] data Caller send data.
+ * @param  [in]  len  Caller data len.
+ * @param  [in]  param Caller send param, optional.
+ * @return if Send OK return actual send len, else return -1.
+ */
+int32_t tiot_xfer_send(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len, const tiot_xfer_tx_param *param);
+
+/**
+ * @brief  TIoT Transfer RX read notify.
+ * @param  [in]  xmit Transmit instance, will be extend to Transfer manager instance.
+ * @param  [in]  data RX data need to read, could be NULL for sync read.
+ * @param  [in]  len  Rx data len need to read, 0 indicates sync read.
+ */
+void tiot_xfer_rx_notify(tiot_xmit *xmit, uint8_t *data, uint32_t len);
+
+/**
+ * @brief  TIoT Transfer receive.
+ * @param  [in]  xfer Transfer manager.
+ * @param  [out] data Caller read buff.
+ * @param  [in]  len  Caller expected read len.
+ * @param  [in]  param Caller receive param.
+ * @return if Read OK return actual read len, if timeout, return 0, else return -1.
+ */
+int32_t tiot_xfer_recv(tiot_xfer_manager *xfer, uint8_t *data, uint32_t len, const tiot_xfer_rx_param *param);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.c
new file mode 100644 (file)
index 0000000..0393775
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-04-26, Create file. \n
+ */
+
+#include "tiot_xfer_utils.h"
+
+int32_t tiot_xfer_direct_send(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len)
+{
+    int32_t ret;
+    const uint8_t *buff = data;
+    uint32_t remain_len = len;
+    while (remain_len) {
+        /* 板级接口可能有单次发送限制. */
+        (void)osal_mutex_lock(&xfer->dev_mutex);
+        if (xfer->xmit_state != TIOT_XMIT_STATE_OPEN) {
+            ret = -1;
+        } else {
+            ret = xfer->xmit_ops->write(&xfer->xmit, buff, remain_len);
+        }
+        (void)osal_mutex_unlock(&xfer->dev_mutex);
+        /* 阻塞式接口,发送结果为0情况时继续发送 */
+        if (ret < 0) {
+            return -1;
+        }
+
+        remain_len -= ret;
+        buff += ret;
+    }
+    return len;
+}
+
+int32_t tiot_xfer_read_store(tiot_circ_buf *cb, uint8_t *data, uint32_t len)
+{
+    int32_t ret;
+    if ((cb == NULL) || (circ_buf_query_free(cb) < len)) {
+        return -1;
+    }
+    ret = circ_buf_write(cb, data, len);
+    if (ret == 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static int tiot_xfer_read_out_check(const void *param)
+{
+    tiot_xfer_manager *xfer = (tiot_xfer_manager *)param;
+    if ((xfer->rx_wait_func(xfer) != 0) ||
+        ((xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) && (circ_buf_query_busy(&xfer->rx_buff) != 0))) {
+        return 1;
+    }
+    return 0;
+}
+
+int32_t tiot_xfer_read_out(tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, uint32_t timeout_ms)
+{
+    int32_t read_len;
+    int32_t timeout = osal_wait_timeout_interruptible(&xfer->rx_wait, tiot_xfer_read_out_check,
+                                                      (const void *)xfer, timeout_ms);
+    /* 超时返回 0, 失败返回-1 */
+    if (timeout <= 0) {
+        return timeout;
+    }
+    osal_mutex_lock(&xfer->dev_mutex);
+
+    if (xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) {
+        uint32_t buff_data_len = circ_buf_query_busy(&xfer->rx_buff);
+        read_len = buff_data_len < len ? buff_data_len : len;
+        read_len = circ_buf_read(&xfer->rx_buff, buff, read_len);
+        if (read_len == 0) {
+            read_len = -1;
+        }
+    } else {
+        read_len = xfer->xmit_ops->read(&xfer->xmit, buff, len);
+    }
+
+    osal_mutex_unlock(&xfer->dev_mutex);
+    return read_len;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.h
new file mode 100644 (file)
index 0000000..748e53f
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-04-26, Create file. \n
+ */
+#ifndef TIOT_XFER_UTILS_H
+#define TIOT_XFER_UTILS_H
+
+#include "tiot_xfer.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_transfer_utils Transfer Utils
+ * @ingroup  tiot_common_transfer
+ * @{
+ */
+
+int32_t tiot_xfer_direct_send(tiot_xfer_manager *xfer, const uint8_t *data, uint32_t len);
+
+int32_t tiot_xfer_read_store(tiot_circ_buf *cb, uint8_t *data, uint32_t len);
+
+int32_t tiot_xfer_read_out(tiot_xfer_manager *xfer, uint8_t *buff, uint32_t len, uint32_t timeout_ms);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7f5d5bc
--- /dev/null
@@ -0,0 +1,15 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    utils_header_lists
+    "${CMAKE_CURRENT_SOURCE_DIR}"
+    "${CMAKE_CURRENT_SOURCE_DIR}/circ_buf"
+    "${CMAKE_CURRENT_SOURCE_DIR}/list"
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${utils_header_lists}" CACHE INTERNAL "tiot header list" FORCE)
+add_subdirectory(circ_queue)
+add_subdirectory(fileops)
+add_subdirectory(misc)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_buf/tiot_circ_buf.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_buf/tiot_circ_buf.h
new file mode 100644 (file)
index 0000000..d1e538d
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd.. 2019-2024. All rights reserved.
+ * Description: audio circle buffer function
+ * Author: audio
+ * Create: 2019-05-30
+ */
+
+#ifndef TIOT_CIRC_BUF_H
+#define TIOT_CIRC_BUF_H
+
+#include "securec.h"
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+typedef struct {
+    volatile uint32_t *write; /* circle buffer write pointer */
+    volatile uint32_t *read;  /* circle buffer read pointer */
+    uint8_t *data;            /* circle buffer data virtual address */
+    uint32_t size;            /* circle buffer size */
+} tiot_circ_buf;
+
+static inline uint32_t circ_buf_min(uint32_t x, uint32_t y)
+{
+    return (x <= y) ? x : y;
+}
+
+static inline uint32_t saturate_add(uint32_t x, uint32_t y, uint32_t saturation)
+{
+    /* add x and y, saturate to saturation */
+    uint32_t x_temp = x + y;
+
+    return (x_temp >= saturation) ? (x_temp - saturation) : x_temp;
+}
+
+static inline void circ_buf_init(tiot_circ_buf *cb, uint32_t *write, uint32_t *read, void *data, uint32_t len)
+{
+    cb->write = write;
+    cb->read = read;
+    cb->data = (uint8_t*)data;
+    cb->size = len;
+
+    *cb->write = 0;
+    *cb->read = 0;
+}
+
+static inline void circ_buf_flush(tiot_circ_buf *cb)
+{
+    *cb->read = 0;
+    *cb->write = 0;
+}
+
+static inline uint32_t circ_buf_data_size(uint32_t write, uint32_t read, uint32_t size)
+{
+    return (write >= read) ? (write - read) : (size - read + write);
+}
+
+static inline uint32_t circ_buf_free_size(uint32_t write, uint32_t read, uint32_t size)
+{
+    return size - circ_buf_data_size(write, read, size);
+}
+
+static inline uint32_t __circ_buf_read_data(const tiot_circ_buf *cb, uint8_t *to, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memcpy_s(to, len * sizeof(uint8_t), cb->data + off, len) != EOK)) {
+        return 0;
+    }
+
+    return len;
+}
+
+/* read data from circle buffer */
+static inline uint32_t circ_buf_read_data(const tiot_circ_buf *cb, uint8_t *to, uint32_t len, uint32_t off)
+{
+    uint32_t l = circ_buf_min(len, cb->size - off);
+
+    if (to == NULL) {
+        /* dump data in circle buffer */
+        return len;
+    }
+
+    return __circ_buf_read_data(cb, to, l, off) + __circ_buf_read_data(cb, to + l, len - l, 0);
+}
+
+static inline uint32_t __circ_buf_write_zero(tiot_circ_buf *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memset_s(cb->data + off, len, 0, len) != EOK)) {
+        return 0;
+    }
+    (void)from;
+    return len;
+}
+
+static inline uint32_t __circ_buf_write_data(tiot_circ_buf *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memcpy_s(cb->data + off, cb->size - off, from, len) != EOK)) {
+        return 0;
+    }
+
+    return len;
+}
+
+/*
+ * circ_buf_write_data - puts some data from kernel space into the circle buffer
+ * @cb: address of the circle buffer to be used
+ * @from: pointer to the data to be added
+ * @len: the length of the data to be added
+ * @off: data write offset in circle buffer
+ *
+ * Note: Check free space in circle buffer before calling this function
+ */
+static inline uint32_t circ_buf_write_data(tiot_circ_buf *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    uint32_t l = circ_buf_min(len, cb->size - off);
+
+    /* generate mute data if input buffer is NULL */
+    uint32_t (*action)(tiot_circ_buf *, const uint8_t *, uint32_t, uint32_t) =
+        (from == NULL) ? __circ_buf_write_zero : __circ_buf_write_data;
+
+    return action(cb, from, l, off) + action(cb, from + l, len - l, 0);
+}
+
+static inline uint32_t circ_buf_query_busy(const tiot_circ_buf *cb)
+{
+    return circ_buf_data_size(*cb->write, *cb->read, cb->size);
+}
+
+static inline uint32_t circ_buf_query_free(const tiot_circ_buf *cb)
+{
+    return circ_buf_free_size(*cb->write, *cb->read, cb->size);
+}
+
+/* read data from circle buffer */
+static inline uint32_t circ_buf_read(tiot_circ_buf *cb, uint8_t *to, uint32_t len)
+{
+    uint32_t read = *cb->read;
+
+    if ((len == 0) || (circ_buf_data_size(*cb->write, read, cb->size) < len) ||
+        (circ_buf_read_data(cb, to, len, read) != len)) {
+        return 0;
+    }
+
+    *cb->read = saturate_add(read, len, cb->size);
+    return len;
+}
+
+/* write data into circle buffer */
+static inline uint32_t circ_buf_write(tiot_circ_buf *cb, const uint8_t *from, uint32_t len)
+{
+    uint32_t write = *cb->write;
+
+    if ((len == 0) || (circ_buf_write_data(cb, from, len, write) != len)) {
+        return 0;
+    }
+
+    *cb->write = saturate_add(write, len, cb->size);
+    return len;
+}
+
+static inline uint32_t circ_buf_update_read_pos(tiot_circ_buf *cb, uint32_t len)
+{
+    *cb->read = saturate_add(*cb->read, len, cb->size);
+    return len;
+}
+
+static inline uint32_t circ_buf_update_write_pos(tiot_circ_buf *cb, uint32_t len)
+{
+    *cb->write = saturate_add(*cb->write, len, cb->size);
+    return len;
+}
+
+static inline uint32_t circ_buf_cast_read(const tiot_circ_buf *cb, uint32_t *data_offset, uint32_t len)
+{
+    uint32_t read = *cb->read;
+
+    if (circ_buf_data_size(*cb->write, read, cb->size) < len) {
+        *data_offset = 0;
+        return 0;
+    }
+
+    *data_offset = read;
+    return len;
+}
+
+static inline uint32_t circ_buf_cast_relese(tiot_circ_buf *cb, uint32_t len)
+{
+    uint32_t read = *cb->read;
+    uint32_t data_size = circ_buf_data_size(*cb->write, read, cb->size);
+    uint32_t len_temp;
+
+    len_temp = circ_buf_min(data_size, len);
+    *cb->read = saturate_add(read, len_temp, cb->size);
+
+    return len_temp;
+}
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4b0bdb4
--- /dev/null
@@ -0,0 +1,11 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    tiot_circ_queue_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_circ_queue.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_circ_queue_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.c
new file mode 100644 (file)
index 0000000..f56f4a6
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Tiot Circular queue header. \n
+ *
+ * History: \n
+ * 2023-04-18, Create file. \n
+ */
+#include "tiot_circ_queue.h"
+#ifdef __KERNEL__
+#include <linux/compiler.h>
+#endif
+#include "securec.h"
+
+#ifndef __KERNEL__
+#if (defined(__GNUC__))
+#define likely(_expr)      __builtin_expect(!!(_expr), 1)
+#define unlikely(_expr)    __builtin_expect(!!(_expr), 0)
+#else
+#define likely(_expr)   (_expr)
+#define unlikely(_expr) (_expr)
+#endif
+#endif
+
+static inline uint16_t tiot_circ_queue_mask(const tiot_circ_queue_t *queue)
+{
+    return (queue->size - 1);
+}
+
+static inline uintptr_t tiot_circ_queue_node(const tiot_circ_queue_t *queue, uint16_t idx)
+{
+    return (queue->mem_addr + ((idx & tiot_circ_queue_mask(queue)) * queue->node_bytes));
+}
+
+static inline uint16_t _tiot_circ_queue_space(tiot_circ_queue_t *queue)
+{
+    return ((queue->tail - (queue->head + 1)) & tiot_circ_queue_mask(queue));
+}
+
+void tiot_circ_queue_init(tiot_circ_queue_t *queue, uint16_t size, uint16_t node_bytes, uintptr_t mem_addr)
+{
+    if (unlikely((queue == NULL) || (size == 0) || (node_bytes == 0) || (mem_addr == 0))) {
+        return;
+    }
+
+    /* 队列大小应为2的幂次方 */
+    if ((size & (size - 1)) != 0) {
+        return;
+    }
+
+    osal_spin_lock_init(&queue->lock);
+
+    queue->head = 0;
+    queue->tail = 0;
+    queue->size = size;
+    queue->node_bytes = node_bytes;
+    queue->mem_addr = mem_addr;
+}
+
+/*
+ * 功能描述: 入队列一个节点
+ */
+int32_t tiot_circ_queue_enqueue(tiot_circ_queue_t *queue, uintptr_t src_node)
+{
+    uintptr_t dis_node;
+    unsigned long flags;
+
+    osal_spin_lock_irqsave(&queue->lock, &flags);
+
+    // 检查队列是否已满
+    if (_tiot_circ_queue_space(queue) == 0) {
+        osal_spin_unlock_irqrestore(&queue->lock, &flags);
+        return -1;
+    }
+
+    // 保存节点内容
+    dis_node = tiot_circ_queue_node(queue, queue->head);
+    if (memcpy_s((void *)dis_node, queue->node_bytes, (void *)src_node, queue->node_bytes) != EOK) {
+        osal_spin_unlock_irqrestore(&queue->lock, &flags);
+        return -1;
+    }
+
+    // 索引更新到下一位置
+    queue->head = (queue->head + 1) & tiot_circ_queue_mask(queue);
+
+    osal_spin_unlock_irqrestore(&queue->lock, &flags);
+    return 0;
+}
+
+/*
+ * 功能描述: 从循环队列中,取出最早入队列的节点
+ */
+uintptr_t tiot_circ_queue_dequeue(tiot_circ_queue_t *queue)
+{
+    uintptr_t node;
+    unsigned long flags;
+
+    osal_spin_lock_irqsave(&queue->lock, &flags);
+
+    // 检查是否为空
+    if (queue->head == queue->tail) {
+        osal_spin_unlock_irqrestore(&queue->lock, &flags);
+        return 0;
+    }
+
+    node = tiot_circ_queue_node(queue, queue->tail);
+
+    // 索引更新到下一位置
+    queue->tail = (queue->tail + 1) & tiot_circ_queue_mask(queue);
+
+    osal_spin_unlock_irqrestore(&queue->lock, &flags);
+    return node;
+}
+
+uint16_t tiot_circ_queue_space(tiot_circ_queue_t *queue)
+{
+    uint16_t space;
+    unsigned long flags;
+
+    osal_spin_lock_irqsave(&queue->lock, &flags);
+    space = _tiot_circ_queue_space(queue);
+    osal_spin_unlock_irqrestore(&queue->lock, &flags);
+    return space;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.h
new file mode 100644 (file)
index 0000000..5d2d668
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Tiot Circular queue header. \n
+ *
+ * History: \n
+ * 2023-04-18, Create file. \n
+ */
+#ifndef TIOT_CIRC_QUEUE_H
+#define TIOT_CIRC_QUEUE_H
+
+#include "tiot_types.h"
+#include "tiot_osal.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_util_tiot_circ_queue Circular Queue
+ * @ingroup  tiot_common_util
+ * @{
+ */
+
+typedef struct {
+    uint16_t head; // 队列头索引,入队索引
+    uint16_t tail; // 队列尾索引,出队索引
+    uint16_t size; // 队列总大小,深度
+    uint16_t node_bytes; // 每个节点的长度
+    uintptr_t mem_addr; // 队列管理的内存空间(size * node_bytes)起始地址
+    osal_spinlock lock;
+} tiot_circ_queue_t;
+
+/**
+ * @brief  TIoT circ queue empty or not.
+ * @param  [in]  queue Circular queue.
+ * @return if empty return 1, else return 0.
+ */
+static inline int32_t tiot_circ_queue_empty(tiot_circ_queue_t *queue)
+{
+    int32_t ret;
+    unsigned long flags;
+    osal_spin_lock_irqsave(&queue->lock, &flags);
+    ret = (queue->head == queue->tail);
+    osal_spin_unlock_irqrestore(&queue->lock, &flags);
+    return ret;
+}
+
+/**
+ * @brief  TIoT circ queue clear.
+ * @param  queue Circular queue.
+ */
+static inline void tiot_circ_queue_clear(tiot_circ_queue_t *queue)
+{
+    unsigned long flags;
+    osal_spin_lock_irqsave(&queue->lock, &flags);
+    queue->head = 0;
+    queue->tail = 0;
+    osal_spin_unlock_irqrestore(&queue->lock, &flags);
+}
+
+/**
+ * @brief  TIoT circ queue init.
+ * @param  [in]  queue Circular queue.
+ * @param  [in]  size  Queue size, nodes number max is size - 1, must be power of 2.
+ * @param  [in]  node_bytes Fixed node size.
+ * @param  [in]  mem_addr   Queue memory start address, ensure has init outside, length should be size * node_bytes.
+ */
+void tiot_circ_queue_init(tiot_circ_queue_t *queue, uint16_t size, uint16_t node_bytes, uintptr_t mem_addr);
+
+/**
+ * @brief  TIoT circ queue enqueue.
+ * @param  [in]  queue Circular queue.
+ * @param  [in]  src_node Node to be enqueued, will be copyed in queue memory.
+ * @return if OK return 0, else return -1.
+ */
+int32_t tiot_circ_queue_enqueue(tiot_circ_queue_t *queue, uintptr_t src_node);
+
+/**
+ * @brief  TIoT circ queue dequeue.
+ * @param  [in]  queue Circular queue.
+ * @return Pointer to deequeued node.
+ */
+uintptr_t tiot_circ_queue_dequeue(tiot_circ_queue_t *queue);
+
+/**
+ * @brief  TIoT circ queue space.
+ * @param  [in]  queue Circular queue.
+ * @return Circ queue avalible space for nodes.
+ */
+uint16_t tiot_circ_queue_space(tiot_circ_queue_t *queue);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/CMakeLists.txt
new file mode 100644 (file)
index 0000000..40434cf
--- /dev/null
@@ -0,0 +1,11 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    tiot_fileops_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_fileops.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_fileops_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.c
new file mode 100644 (file)
index 0000000..c2179c1
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT file ops. \n
+ *
+ * History: \n
+ * 2023-04-13, Create file. \n
+ */
+
+#include "tiot_fileops.h"
+#include "tiot_board_log.h"
+#include "tiot_osal.h"
+#include "securec.h"
+#include "tiot_types.h"
+
+#ifdef CONFIG_FILE_BY_ARRAY
+tiot_file *tiot_file_open(const tiot_file_path *path, const char *file_name, int flags, int mode)
+{
+    unsigned int i;
+    const tiot_file *file_list;
+    /* 非只读文件 */
+    tiot_unused(mode);
+    if (flags != OSAL_O_RDONLY) {
+        tiot_print_dbg("[TIoT][file]rw file\n");
+        return NULL;
+    }
+    if (path == NULL) {
+        tiot_print_dbg("[TIoT][file]array file path is NULL\n");
+        return NULL;
+    }
+
+    file_list = path->file_list;  /* 文件数组生成保证不为NULL. */
+    for (i = 0; i < path->file_num; i++) {
+        if (strcmp(file_list->name, file_name) == 0) {
+            return (tiot_file *)file_list;
+        }
+        file_list++;
+    }
+    return NULL;
+}
+
+int tiot_file_read(tiot_file *filp, char *buf, unsigned long size, int offset)
+{
+    uint32_t remain_size;
+    uint32_t copy_size;
+    int ret;
+    if (buf == NULL) {
+        return -1;
+    }
+    /* 偏移值需在文件数据范围内. */
+    if ((offset < 0) || (offset > filp->len)) {
+        tiot_print_err("[TIoT][file]exceed file range!\n");
+        return -1;
+    }
+
+    remain_size = filp->len - offset;
+    copy_size = size > remain_size ? remain_size : size;
+    if (copy_size == 0) {
+        /* 处于文件末尾 */
+        return 0;
+    }
+    ret = memcpy_s(buf, copy_size, &filp->data[offset], copy_size);
+    if (ret != EOK) {
+        return -1;
+    }
+    return copy_size;
+}
+#else
+tiot_file *tiot_file_open(const tiot_file_path *path, const char *file_name, int flags, int mode)
+{
+    (void)path;
+    return (tiot_file *)osal_klib_fopen(file_name, flags, mode);
+}
+
+void tiot_file_close(tiot_file *filp)
+{
+    osal_klib_fclose((void *)filp);
+}
+
+int tiot_file_read(tiot_file *filp, char *buf, unsigned long size, int offset)
+{
+    if (buf == NULL) {
+        tiot_print_err("[TIoT][file]read buff is NULL!\n");
+        return -1;
+    }
+    if (osal_klib_fseek(offset, OSAL_SEEK_SET, (void *)filp) < 0) {
+        tiot_print_err("[TIoT][file]fseek error!\n");
+        return -1;
+    }
+    return osal_klib_fread(buf, size, (void *)filp);
+}
+#endif
+
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.h
new file mode 100644 (file)
index 0000000..131269c
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Tiot file types. \n
+ *
+ * History: \n
+ * 2023-04-12, Create file. \n
+ */
+#ifndef TIOT_FILEOPS_H
+#define TIOT_FILEOPS_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_utils_file_ops File Ops
+ * @ingroup  tiot_common_utils
+ * @{
+ */
+
+#ifdef CONFIG_FILE_BY_ARRAY
+#define TIOT_FILE_NAME_MAX  16
+
+/**
+ * @brief  TIoT file struct for file array, read only.
+ */
+typedef struct {
+    const char name[TIOT_FILE_NAME_MAX];
+    int len;
+    const char *data;
+} tiot_file;
+
+/**
+ * @brief  TIoT file search path, set for search file array, read only.
+ */
+typedef struct {
+    const tiot_file *file_list;   /* A list of file array, read only. */
+    const unsigned int file_num;  /* File array num, read only. */
+} tiot_file_path;
+#else
+typedef void *tiot_file;          /*!< Dummy type for filp when board has file system. */
+typedef char tiot_file_path;      /*!< Dummy type for path when board has file system. */
+#endif
+
+#ifdef CONFIG_FILE_BY_ARRAY
+#define tiot_file_close(filp)   /*!< No need to close for file array. */
+#else
+/**
+ * @brief  TIoT file open, redirect to osal_klib_fclose.
+ * @param  [in]  filp File handle.
+ */
+void tiot_file_close(tiot_file *filp);
+#endif
+
+/**
+ * @brief  TIoT file open, for file system see @ref osal_klib_fopen, path is ignored.
+ *                         for file array, search in file name in the tiot_file_path.
+ * @param  [in]  path File array path, ignore for file system.
+ * @param  [in]  file_name File name.
+ * @param  [in]  flags File flags, like: OSAL_O_RDONLY.
+ * @param  [in]  mode File rwx mode, like: 0644.
+ * @return if OK return file handle, else return NULL.
+ */
+tiot_file *tiot_file_open(const tiot_file_path *path, const char *file_name, int flags, int mode);
+
+/**
+ * @brief  TIoT file read, for file system read to buf->buff.
+ *                         for file array, only move the buff pointer to offset.
+ * @param  [in]  filp   TIoT file handle.
+ * @param  [in]  buf    TIoT file readbuf.
+ * @param  [in]  size   Required read size.
+ * @param  [in]  offset Read offset of file.
+ * @return The length that has been read, could less than required size, or -1 if fail.
+ */
+int tiot_file_read(tiot_file *filp, char *buf, unsigned long size, int offset);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/list/tiot_list.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/list/tiot_list.h
new file mode 100644 (file)
index 0000000..717b5ba
--- /dev/null
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: TIoT list. \n
+ *
+ * History: \n
+ * 2023-08-03, Create file. \n
+ */
+#ifndef TIOT_LIST_H
+#define TIOT_LIST_H
+
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_util_tiot_list List
+ * @ingroup  tiot_common_util
+ * @{
+ */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct tiot_list_head {
+    struct tiot_list_head *next, *prev;
+};
+
+#define tiot_list_head_init(name) \
+    {                             \
+        &(name), &(name)          \
+    }
+
+#define tiot_list_head_create(name) \
+    struct tiot_list_head name = tiot_list_head_init(name)
+
+static inline void tiot_init_list_head(struct tiot_list_head *list)
+{
+    if (list == NULL) {
+        return;
+    }
+    list->next = list;
+    list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void tiot___list_add(struct tiot_list_head *_new,
+    struct tiot_list_head *prev,
+    struct tiot_list_head *next)
+{
+    if (_new == NULL || prev == NULL || next == NULL) {
+        return;
+    }
+    next->prev = _new;
+    _new->next = next;
+    _new->prev = prev;
+    prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void tiot_list_add_tail(struct tiot_list_head *cur, struct tiot_list_head *head)
+{
+    tiot___list_add(cur, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void tiot___list_del(struct tiot_list_head *prev, struct tiot_list_head *next)
+{
+    if (prev == NULL || next == NULL) {
+        return;
+    }
+
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void tiot___list_del_entry(struct tiot_list_head *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    tiot___list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void tiot_list_replace(struct tiot_list_head *old,
+    struct tiot_list_head *_new)
+{
+    _new->next = old->next;
+    _new->next->prev = _new;
+    _new->prev = old->prev;
+    _new->prev->next = _new;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:    the &struct list_head pointer.
+ * @type:    the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define tiot_list_entry(ptr, type, member) \
+    tiot_container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry    -    iterate over list of given type
+ * @pos:    the type * to use as a loop cursor.
+ * @head:    the head for your list.
+ * @member:  the name of the list_struct within the struct.
+ * @pos_type:  type of the struct which the list_node in.
+ */
+#define tiot_list_for_each_entry(pos, head, member, pos_type)            \
+    for ((pos) = tiot_list_entry((head)->next, pos_type, member);        \
+         &(pos)->member != (head);                                         \
+         (pos) = tiot_list_entry((pos)->member.next, pos_type, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:    the type * to use as a loop cursor.
+ * @n:        another type * to use as temporary storage
+ * @head:    the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ * @pos_type:  type of pos.
+ * @n_type:    type of n.
+ */
+#define tiot_list_for_each_entry_safe(pos, n, head, member, pos_type, n_type)         \
+    for ((pos) = tiot_list_entry((head)->next, pos_type, member),                     \
+        (n) = tiot_list_entry((pos)->member.next, pos_type, member);                  \
+         &(pos)->member != (head);                                                      \
+         (pos) = (n), (n) = tiot_list_entry((n)->member.next, n_type, member))
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d20f3a5
--- /dev/null
@@ -0,0 +1,11 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(
+    tiot_misc_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_misc.c
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_misc_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.c
new file mode 100644 (file)
index 0000000..2e2c61f
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. \n
+ *
+ * Description: TIoT miscellaneous file. \n
+ *
+ * History: \n
+ * 2024-06-20, Create file. \n
+ */
+
+#include "tiot_misc.h"
+
+#define TIOT_HEX_RADIX           16
+#define TIOT_CONVERT_BASIC_LEN   1
+#define TIOT_CONVERT_STR_MIN_LEN 4
+
+// For example, if 3200 is entered, 0xC80 is displayed.
+int32_t tiot_num_to_hex(uint32_t num, char* str_buff, uint32_t str_buff_len)
+{
+    int right = 0;
+    int str_num = 0;
+    uint32_t number = num;
+    int left = 2; // 跳过前两个字符"0x".
+    const char map[] = "0123456789ABCDEF";
+
+    if (str_buff == NULL || str_buff_len < TIOT_CONVERT_STR_MIN_LEN) {
+        return -1;
+    }
+
+    str_buff[str_num++] = '0';
+    str_buff[str_num++] = 'x';
+
+    // Conversion part.
+    do {
+        str_buff[str_num++] = map[number % TIOT_HEX_RADIX];
+        number /= TIOT_HEX_RADIX;
+
+        // 确保有空间存放结束符'\0'.
+        if ((uint32_t)(str_num + TIOT_CONVERT_BASIC_LEN) > str_buff_len) {
+            str_buff[0] = '\0';
+            return -1;
+        }
+    } while (number);
+
+    // Inverting Data
+    right = str_num - TIOT_CONVERT_BASIC_LEN;
+    while (right > left) {
+        char tmp = str_buff[left];
+        str_buff[left] = str_buff[right];
+        str_buff[right] = tmp;
+        left++;
+        right--;
+    }
+    str_buff[str_num++] = '\0';
+    return 0;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.h
new file mode 100644 (file)
index 0000000..4f7e441
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. \n
+ *
+ * Description: Tiot miscellaneous header file. \n
+ *
+ * History: \n
+ * 2024-06-20, Create file. \n
+ */
+#ifndef TIOT_MISC_H
+#define TIOT_MISC_H
+
+#include "tiot_types.h"
+#include "tiot_osal.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_common_utils_tiot_misc TIOT miscellaneous function
+ * @ingroup  tiot_common_utils
+ * @{
+ */
+
+/**
+ * @brief  TIoT converts a non-negative integer to a hexadecimal string.
+ * @param  [in]  num   Nonnegative integer.
+ * @param  [in]  str_buff   String after conversion num.
+ * @param  [in]  str_buff_len Length of str_buff.
+ * @return 0 is returned if Conversion succeeded. Otherwise, -1 is returned.
+ */
+int32_t tiot_num_to_hex(uint32_t num, char* str_buff, uint32_t str_buff_len);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/tiot_types.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/tiot_types.h
new file mode 100644 (file)
index 0000000..4854c71
--- /dev/null
@@ -0,0 +1,66 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: TIoT types. \n\r
+ *\r
+ * History: \n\r
+ * 2023-06-01, Create file. \n\r
+ */\r
+#ifndef TIOT_TYPES_H\r
+#define TIOT_TYPES_H\r
+\r
+#ifdef __KERNEL__\r
+/* 内核类型可能与编译器stdint.h冲突. */\r
+#include <linux/kernel.h>\r
+#include <linux/version.h>\r
+#else\r
+#include <stdint.h>\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_common_interface_types TIoT types.\r
+ * @ingroup  tiot_common_interface\r
+ * @{\r
+ */\r
+#ifndef NULL\r
+#define NULL ((void*)0)\r
+#endif\r
+\r
+/* container */\r
+#undef tiot_offsetof\r
+#ifdef __compiler_offsetof\r
+#define tiot_offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)\r
+#else\r
+#define tiot_offsetof(TYPE, MEMBER) ((int)(unsigned long)&((TYPE *)0)->MEMBER)\r
+#endif\r
+\r
+#ifdef _MSC_VER\r
+#define tiot_container_of(ptr, type, member) ((type *)((char *)(const void *){ptr} - tiot_offsetof(type, member)))\r
+#else\r
+#define tiot_container_of(ptr, type, member) ({                 \\r
+    const __typeof__( ((type *)0)->member ) *__mptr = (ptr);    \\r
+    (type *)((char *)__mptr - tiot_offsetof(type, member)); })\r
+#endif\r
+\r
+#define tiot_unused(var) \\r
+    do {                 \\r
+        (void)(var);       \\r
+    } while (0)\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt
new file mode 100644 (file)
index 0000000..adbe7fb
--- /dev/null
@@ -0,0 +1,31 @@
+#===============================================================================\r
+# @brief    cmake make file\r
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+#===============================================================================\r
+if(DEFINED CONFIG_DEV_GNSS)\r
+set(\r
+    device_include_list\r
+    "${CMAKE_CURRENT_SOURCE_DIR}"\r
+)\r
+\r
+set(\r
+    device_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/gnss_device_info.c\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/gnss_service.c\r
+)\r
+\r
+if(DEFINED CONFIG_FILE_BY_ARRAY)\r
+list(\r
+    APPEND device_src_list\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/firmware/gnss_fw_file_array.c\r
+)\r
+\r
+list(\r
+    APPEND device_include_list\r
+    "${CMAKE_CURRENT_SOURCE_DIR}/firmware"\r
+)\r
+endif()\r
+\r
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${device_include_list}" CACHE INTERNAL "tiot header list" FORCE)\r
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${device_src_list}" CACHE INTERNAL "tiot src list" FORCE)\r
+endif()\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/Makefile b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/Makefile
new file mode 100644 (file)
index 0000000..fc03118
--- /dev/null
@@ -0,0 +1,16 @@
+# GNSS Makefile
+ifeq ($(CONFIG_DEV_GNSS), y)
+tiot-gnss-objs += gnss_device_info.o gnss_service.o
+
+ifeq ($(CONFIG_FILE_BY_ARRAY), y)
+ifneq (,$(wildcard $(TIOT_DRIVER_PATH)/device/gnss/firmware/gnss_fw_file_array.c))
+tiot-gnss-objs += firmware/gnss_fw_file_array.o
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/device/gnss/firmware
+endif
+endif
+
+tiot-gnss-objs := $(addprefix device/gnss/,$(tiot-gnss-objs))
+tiot_driver-objs += $(tiot-gnss-objs)
+
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/device/gnss
+endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.c
new file mode 100644 (file)
index 0000000..362a4d6
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  gnss firmware dummy file arrays.
+ *
+ * History:
+ * 2023-11-01, Create file.
+ */
+#include "gnss_fw_file_array.h"
+#include "tiot_types.h"
+
+/* 仅用于SDK,无文件系统使用文件数组时,替换此目录下文件. */
+
+const tiot_file_path *gnss_fw_file_path_get(void)
+{
+    return NULL;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.h
new file mode 100644 (file)
index 0000000..36312d9
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  gnss firmware file arrays.
+ *
+ * History:
+ * 2023-11-01, Create file.
+ */
+
+#ifndef GNSS_FW_FILE_ARRAY_H
+#define GNSS_FW_FILE_ARRAY_H
+
+#include "tiot_fileops.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+const tiot_file_path *gnss_fw_file_path_get(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.c
new file mode 100644 (file)
index 0000000..38578d9
--- /dev/null
@@ -0,0 +1,157 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: GNSS device info. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+\r
+#include "gnss_device_info.h"\r
+#include "tiot_pm_default.h"\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_log.h"\r
+#include "tiot_controller.h"\r
+#include "tiot_board_pin_port.h"\r
+#include "tiot_cfg_handle_priv.h"\r
+#include "tiot_sys_msg_handle.h"\r
+#ifdef CONFIG_FILE_BY_ARRAY\r
+#include "gnss_fw_file_array.h"\r
+#endif\r
+\r
+#define GNSS_POWERON_WAIT_MS      1      /* Wait time before power on. */\r
+#define GNSS_BOOT_TIME_MS         200    /* Power on ==> Boot time. */\r
+#define GNSS_INIT_TIME_MS         600    /* Boot ==> Init time. */\r
+#define GNSS_WAKEUP_PULSE_MS      1      /* GPIO wake up pulse. */\r
+#define GNSS_WAKEUP_WAIT_MS       50     /* Wake up wait ms. */\r
+#define GNSS_BAUD_CHANGE_WAIT_US  11000  /* Baudrate change wait μs. */\r
+\r
+#ifdef CONFIG_GNSS_TCXO_FREQ_38P4M\r
+#define GNSS_WAKEUP_PIN_INIT_LEVEL  TIOT_PIN_LEVEL_LOW\r
+#else\r
+#define GNSS_WAKEUP_PIN_INIT_LEVEL  TIOT_PIN_LEVEL_HIGH\r
+#endif\r
+\r
+#ifdef CONFIG_GNSS_UART_WITH_FLOWCTRL\r
+#define GNSS_UART_ATTR_FLOW_CTRL    TIOT_UART_ATTR_FLOW_CTRL_ENABLE\r
+#else\r
+#define GNSS_UART_ATTR_FLOW_CTRL    TIOT_UART_ATTR_FLOW_CTRL_DISABLE\r
+#endif\r
+\r
+#define GNSS_DEFAULT_UART_CONFIG                        \\r
+{                                                       \\r
+    115200,                                             \\r
+    { .data_bits = TIOT_UART_ATTR_DATABIT_8,            \\r
+      .parity    = TIOT_UART_ATTR_PARITY_NONE,          \\r
+      .stop_bits = TIOT_UART_ATTR_STOPBIT_1,            \\r
+      .flow_ctrl = GNSS_UART_ATTR_FLOW_CTRL             \\r
+    }                                                   \\r
+}\r
+\r
+static inline int32_t gnss_pin_set_level_if_exist(uint32_t pin, uint32_t pin_level)\r
+{\r
+    if (pin != TIOT_PIN_NONE) {\r
+        return tiot_board_pin_set_level(pin, pin_level);\r
+    }\r
+    return 0;\r
+}\r
+\r
+static tiot_pm_retcode gnss_pm_power_on(tiot_pm *pm)\r
+{\r
+    uint32_t wakeup_device_pin = pm->pm_info[TIOT_PIN_HOST_WAKEUP_DEVICE];\r
+    /* GNSS板级连接唤醒管脚时,上拉或下拉 */\r
+    if (gnss_pin_set_level_if_exist(wakeup_device_pin, GNSS_WAKEUP_PIN_INIT_LEVEL) != 0) {\r
+        tiot_print_err("[TIoT][pm]set wkup pin level %d fail.\n", GNSS_WAKEUP_PIN_INIT_LEVEL);\r
+        return TIOT_PM_EVTRET_FAIL;\r
+    }\r
+    if (tiot_pm_default_power_on(pm) == TIOT_PM_EVTRET_FAIL) {\r
+        return TIOT_PM_EVTRET_FAIL;\r
+    }\r
+    if (gnss_pin_set_level_if_exist(wakeup_device_pin, TIOT_PIN_LEVEL_LOW) != 0) {\r
+        tiot_print_err("[TIoT][pm]set wkup pin level low fail.\n");\r
+        return TIOT_PM_EVTRET_FAIL;\r
+    }\r
+    return TIOT_PM_EVTRET_NEXT_STATE;\r
+}\r
+\r
+static const tiot_pm_event_entry g_gnss_pm_event_map[TIOT_PM_EVENT_MAX] = {\r
+    { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_POWEROFF, tiot_pm_default_power_off },\r
+    /* 上电后等待init消息或业务消息才说明进入work状态 */\r
+    /* GNSS板级连接唤醒管脚时,上电特殊处理 */\r
+    { TIOT_PM_TAG_POWEROFF, TIOT_PM_STATE_INIT, gnss_pm_power_on },\r
+#ifdef CONFIG_GNSS_WAKEUP_TYPE_UART\r
+    /* 只有sleep态才需要唤醒 */\r
+    { TIOT_PM_TAG_CAN_WAKEUP, TIOT_PM_STATE_WAKING, tiot_pm_default_wakeup_device_by_uart },\r
+#else\r
+    /* 只有sleep态才需要唤醒 */\r
+    { TIOT_PM_TAG_CAN_WAKEUP, TIOT_PM_STATE_WAKING, tiot_pm_default_wakeup_device_by_gpio },\r
+#endif\r
+    /* 有device wakeup host管脚时,通过此管脚说明已唤醒,且需要下发disallow消息 */\r
+    { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_WORK, tiot_pm_default_wakeup_ack_handle },\r
+    /* 接收到request sleep消息,下发allow sleep消息 */\r
+    { TIOT_PM_TAG_CAN_ALLOW_SLEEP, TIOT_PM_STATE_SLEEPING, tiot_pm_default_request_sleep_handle },\r
+    /* 接收到dev wkup host gpio拉低,需要释放唤醒锁 */\r
+    { TIOT_PM_TAG_CAN_SLEEP, TIOT_PM_STATE_SLEEP, tiot_pm_default_sleep_ack_handle },\r
+    /* 非S3状态,下发allow sleep并释放唤醒锁 */\r
+    { TIOT_PM_TAG_CAN_ALLOW_SLEEP, TIOT_PM_STATE_SLEEP, tiot_pm_default_request_sleep_ack_handle },\r
+    /* 上报init消息或业务消息说明唤醒成功 */\r
+    { TIOT_PM_TAG_CAN_WORK, TIOT_PM_STATE_WORK, NULL },\r
+    { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_INVALID, tiot_pm_default_work_vote_up },\r
+    { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_INVALID, tiot_pm_default_work_vote_down }\r
+};\r
+\r
+static void gnss_firmware_before_load(tiot_fw *fw)\r
+{\r
+    /* 加载前设置为固件加载默认波特率 */\r
+    tiot_uart_config gnss_firmware_load_config = GNSS_DEFAULT_UART_CONFIG;\r
+    tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware);\r
+    tiot_xfer_manager *xfer = &ctrl->transfer;\r
+    if (tiot_xfer_set_config(xfer, &gnss_firmware_load_config) != 0) {\r
+        tiot_print_dbg("[TIoT:fw]config before load fail.\r\n");\r
+    }\r
+    /* 加载前先清掉rx_buff */\r
+#ifdef CONFIG_XFER_DEFAULT_RX_BUFF\r
+    if (xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) {\r
+        circ_buf_flush(&xfer->rx_buff);\r
+    }\r
+#endif\r
+}\r
+\r
+static void gnss_firmware_after_load(tiot_fw *fw)\r
+{\r
+    /* 加载过程中可能切换波特率,加载后设置为业务默认波特率 */\r
+    tiot_uart_config gnss_transfer_config = GNSS_DEFAULT_UART_CONFIG;\r
+    tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware);\r
+    tiot_xfer_manager *xfer = &ctrl->transfer;\r
+    if (tiot_xfer_set_config(xfer, &gnss_transfer_config) != 0) {\r
+        tiot_print_dbg("[TIoT:fw]config after load fail.\r\n");\r
+    }\r
+}\r
+\r
+static int gnss_rx_wait_func(const void *param)\r
+{\r
+    (void)param;\r
+    /* GNSS通过UART上报数据,不需要拉高管脚来通知读取 */\r
+    return 0;\r
+}\r
+\r
+static const tiot_device_info g_gnss_device_info = {\r
+    .pm_event_map = (tiot_pm_event_entry *)g_gnss_pm_event_map,\r
+    .pm_event_map_size = sizeof(g_gnss_pm_event_map) / sizeof(tiot_pm_event_entry),\r
+    .exec_cbs = { gnss_firmware_before_load, gnss_firmware_after_load, tiot_fw_ext_cmd_handle_priv, NULL },\r
+    .xfer_info = { TIOT_XMIT_TYPE_UART, gnss_rx_wait_func },\r
+    .pkt_sys_msg_handle = tiot_pkt_sys_msg_handle,\r
+    .timings = {\r
+        .power_on_wait_ms = GNSS_POWERON_WAIT_MS,\r
+        .boot_time_ms = GNSS_BOOT_TIME_MS,\r
+        .init_time_ms = GNSS_INIT_TIME_MS,\r
+        .wakeup_pulse_ms = GNSS_WAKEUP_PULSE_MS,\r
+        .wakeup_wait_ms = GNSS_WAKEUP_WAIT_MS,\r
+        .baud_change_wait_us = GNSS_BAUD_CHANGE_WAIT_US,\r
+    }\r
+};\r
+\r
+const tiot_device_info *gnss_device_get_info(void)\r
+{\r
+    return &g_gnss_device_info;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.h
new file mode 100644 (file)
index 0000000..5356fbd
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: GNSS device info header. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+#ifndef GNSS_DEVICE_INFO_H
+#define GNSS_DEVICE_INFO_H
+
+#include "tiot_device_info.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_device_gnss_device_info  GNSS Device Info
+ * @ingroup  tiot_device_gnss
+ * @{
+ */
+
+/**
+ * @brief  GNSS device get info, same for all GNSS devices.
+ * @return GNSS device info.
+ */
+const tiot_device_info *gnss_device_get_info(void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.c
new file mode 100644 (file)
index 0000000..6a570e5
--- /dev/null
@@ -0,0 +1,434 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-31, Create file. \n\r
+ */\r
+#include "gnss_service.h"\r
+#include "gnss_device_info.h"\r
+#include "gnss_board_port.h"\r
+#include "tiot_board_log.h"\r
+#include "tiot_controller.h"\r
+#include "tiot_controller_helper.h"\r
+#include "tiot_packet.h"\r
+#include "tiot_sys_msg_types.h"\r
+#include "tiot_board_pin_port.h"\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_misc_port.h"\r
+#include "tiot_board.h"\r
+#include "tiot_service_interface.h"\r
+\r
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC\r
+/* 加载 & 数据收发复用buffer,不同时使用 */\r
+/* 数据收发需求 ~10K用于缓存数据. */\r
+/* 固件加载时 ~3K用于保存解析后命令, ~128字节用于加载回复接收. */\r
+#define GNSS_FW_LOAD_REUSE_BUFF_START 0U\r
+#define GNSS_FW_LOAD_RX_BUFF_START    GNSS_FW_LOAD_REUSE_BUFF_START\r
+#define GNSS_FW_LOAD_RX_BUFF_SIZE     128U\r
+\r
+#define GNSS_FW_LOAD_REUSE_BUFF_END   (GNSS_FW_LOAD_RX_BUFF_START + GNSS_FW_LOAD_RX_BUFF_SIZE)\r
+\r
+#define GNSS_COMMON_BUFF_MAX    ((CONFIG_GNSS_PACKET_BUFF_MAX > GNSS_FW_LOAD_REUSE_BUFF_END) ? \\r
+                                 CONFIG_GNSS_PACKET_BUFF_MAX : GNSS_FW_LOAD_REUSE_BUFF_END)\r
+#endif\r
+\r
+#define GNSS_PACKET_QUEUE_NODES    8\r
+\r
+typedef enum {\r
+    GNSS_RX_SUBSYS_0 = 0,\r
+    GNSS_RX_SUBSYS_MAX\r
+} gnss_rx_subsys_id;\r
+\r
+typedef enum {\r
+    GNSS_PLT_SWITCH_GUART_BPS = 0,\r
+    GNSS_PLT_SWITCH_DBGUART_BPS,\r
+    GNSS_PLT_SWITCH_UART_SELECT,\r
+    GNSS_PLT_SWITCH_HSO_OR_SDT,\r
+    GNSS_PLT_SWITCH_DBGUART_SKIP,\r
+    GNSS_PLT_CMD_MAXSIZE\r
+} gnss_plt_cmd;\r
+\r
+typedef struct {\r
+    uint32_t bps;\r
+    uint32_t cr_crg;\r
+} tiot_plt_guart_para;\r
+\r
+typedef struct {\r
+    uint8_t frame_start;\r
+    uint8_t func_type;\r
+    uint8_t prime_id;\r
+    uint8_t reserved;\r
+    uint16_t frame_len;\r
+    uint16_t sn;\r
+} tiot_plt_om_header;\r
+\r
+typedef struct {\r
+    uint16_t cmd;\r
+    uint16_t para_len;\r
+} tiot_plt_cmd_header;\r
+\r
+#pragma pack(push, 1)\r
+typedef struct {\r
+    tiot_plt_om_header om_header;\r
+    tiot_plt_cmd_header cmd_header;\r
+    tiot_plt_guart_para para;\r
+    uint8_t tail;\r
+} tiot_plt_guart_cmd;\r
+#pragma pack(pop)\r
+\r
+#define tiot_plat_guart_baud_cmd(bps, flow_ctrl)                                \\r
+{                                                                               \\r
+    .om_header = { 0x7e, 0x0c, 0x00, 0x00, 0x15, 0x00 },                        \\r
+    .cmd_header = { GNSS_PLT_SWITCH_GUART_BPS, sizeof(tiot_plt_guart_para) },   \\r
+    .para = { (bps),                                                            \\r
+              ((flow_ctrl) == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ? 0xC301 : 0x301 \\r
+    },                                                                          \\r
+    .tail = 0x7e                                                                \\r
+}\r
+\r
+static tiot_controller g_gnss_controllers[CONFIG_GNSS_DEV_NUM] = { 0 };\r
+static tiot_packet_context g_gnss_pkt_ctx[CONFIG_GNSS_DEV_NUM];\r
+static tiot_packet g_gnss_pkt_queue_nodes[CONFIG_GNSS_DEV_NUM][GNSS_PACKET_QUEUE_NODES];\r
+static tiot_packet_queue g_gnss_pkt_queues[CONFIG_GNSS_DEV_NUM][GNSS_RX_SUBSYS_MAX];\r
+\r
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC\r
+static uint8_t g_gnss_common_buff_mem[CONFIG_GNSS_DEV_NUM][GNSS_COMMON_BUFF_MAX];\r
+#endif\r
+\r
+static uint16_t gnss_packet_manager_match_func(uint32_t subsys_code)\r
+{\r
+    if ((subsys_code == GNSS_FIRST_MSG) || (subsys_code == GNSS_COMMON_MSG) ||\r
+        (subsys_code == GNSS_LAST_MSG) || (subsys_code == MSG_BUTT)) {\r
+        return GNSS_RX_SUBSYS_0;\r
+    }\r
+    return GNSS_RX_SUBSYS_MAX;\r
+}\r
+\r
+static void gnss_device_wakeup_host_cb(uint32_t pin)\r
+{\r
+    (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_DISABLE);\r
+    tiot_controller *cur_ctrl = tiot_find_controller_by_pin(g_gnss_controllers, CONFIG_GNSS_DEV_NUM,\r
+                                                            pin, GNSS_PIN_DEVICE_WAKEUP_HOST);\r
+    if (cur_ctrl != NULL) {\r
+        tiot_pm_set_event(&cur_ctrl->pm, TIOT_PM_EVENT_WAKEUP_ACK);\r
+    }\r
+    (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_ENABLE);\r
+}\r
+\r
+static int32_t gnss_change_uart_config(tiot_xfer_manager *xfer, tiot_uart_config *uart_cfg)\r
+{\r
+    tiot_plt_guart_cmd uart_cmd = tiot_plat_guart_baud_cmd(uart_cfg->baudrate, uart_cfg->attr.flow_ctrl);\r
+    tiot_xfer_tx_param param = { SUBSYS_OM };\r
+    int32_t ret = tiot_xfer_send(xfer, (const uint8_t *)&uart_cmd, sizeof(tiot_plt_guart_cmd), &param);\r
+    if (ret != sizeof(tiot_plt_guart_cmd)) {\r
+        tiot_print_err("[TIOT]set user baudrate cmd fail.\r\n");\r
+        return -1;\r
+    }\r
+    ret = tiot_xfer_set_config(xfer, uart_cfg);\r
+    if (ret != 0) {\r
+        tiot_print_err("[TIOT]set user baudrate fail.\r\n");\r
+        return -1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+static inline int32_t gnss_send_host_need_wakeup(tiot_controller *ctrl)\r
+{\r
+    int32_t ret;\r
+    const uint8_t host_need_wakeup_cmd = SYS_PL_PM_SET_WAKEUP_HOST_VALID;\r
+    const tiot_xfer_tx_param param = { SUBSYS_SYS };\r
+    ret = tiot_xfer_send(&ctrl->transfer, &host_need_wakeup_cmd, sizeof(uint8_t), &param);\r
+    if (ret != sizeof(uint8_t)) {\r
+        tiot_print_err("[TIOT]set host need wakeup cmd fail.\r\n");\r
+        return -1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+static int32_t gnss_send_change_buadrate(tiot_controller *ctrl, uint32_t new_buadrate)\r
+{\r
+    const tiot_device_timings *timings = &ctrl->dev_info->timings;\r
+    tiot_uart_config uart_config = { 0 };\r
+    (void)tiot_xfer_get_config(&ctrl->transfer, &uart_config);\r
+    /* 配置用户波特率 */\r
+    if (uart_config.baudrate == new_buadrate) {\r
+        return 0;\r
+    }\r
+    uart_config.baudrate = new_buadrate;\r
+    if (gnss_change_uart_config(&ctrl->transfer, &uart_config) != 0) {\r
+        tiot_print_err("[TIoT]send change buadrate fail\n");\r
+        return -1;\r
+    }\r
+    /* 切换波特率后等待波特率稳定,device或host? */\r
+    tiot_board_udelay(timings->baud_change_wait_us);\r
+    return 0;\r
+}\r
+\r
+static int32_t gnss_service_packet_init(tiot_controller *ctrl, uint8_t dev_id)\r
+{\r
+    int32_t ret;\r
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC\r
+    tiot_packet_buffer pkt_buff = { g_gnss_common_buff_mem[dev_id], CONFIG_GNSS_PACKET_BUFF_MAX, 0 };\r
+#endif\r
+    tiot_packet_context_param param = {\r
+        .flags = TIOT_PKT_FLAGS_SUPPORT_ASCII,\r
+        .rx_manager_info = { g_gnss_pkt_queues[dev_id], GNSS_RX_SUBSYS_MAX, gnss_packet_manager_match_func },\r
+        .buff = NULL\r
+    };\r
+#ifndef CONFIG_BOARD_DYNAMIC_ALLOC\r
+    param.buff = &pkt_buff;\r
+#endif\r
+    g_gnss_pkt_queues[dev_id][GNSS_RX_SUBSYS_0].queue_nodes = g_gnss_pkt_queue_nodes[dev_id];\r
+    g_gnss_pkt_queues[dev_id][GNSS_RX_SUBSYS_0].queue_size = GNSS_PACKET_QUEUE_NODES;\r
+    tiot_packet_context *pkt_ctx = &g_gnss_pkt_ctx[dev_id];\r
+    ret = tiot_packet_init(pkt_ctx, &ctrl->transfer, &param);\r
+    if (ret != 0) {\r
+        tiot_print_err("[TIOT]packet init fail.\r\n");\r
+    }\r
+    return ret;\r
+}\r
+\r
+static int32_t gnss_service_install_packet(tiot_controller *ctrl, uint8_t dev_id)\r
+{\r
+    tiot_xfer_packet_ops gnss_packet_ops = {\r
+        .read_out = tiot_packet_read_out,\r
+        .rx_data_store = tiot_packet_rx_data_store,\r
+        .tx_push = tiot_packet_tx_push,\r
+    };\r
+    const tiot_device_timings *timings = &ctrl->dev_info->timings;\r
+    /* 收发模块注册包格式 */\r
+    if (tiot_xfer_install_packet(&ctrl->transfer, (tiot_xfer_packet_ops *)&gnss_packet_ops,\r
+                                 (uintptr_t)&g_gnss_pkt_ctx[dev_id]) != 0) {\r
+        tiot_print_err("[TIOT]packet install fail.\r\n");\r
+        return -1;\r
+    }\r
+    /* 必须等待device UART初始化后才能接收消息, 待确认时间. */\r
+    osal_msleep(timings->init_time_ms);\r
+    tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_REPORT_WORK);\r
+    return 0;\r
+}\r
+\r
+static inline int32_t gnss_service_custom_msg_send(tiot_controller *ctrl, uint32_t dev_wkup_host_pin,\r
+                                                   uint32_t custom_buadrate)\r
+{\r
+    /* 通过管脚有无判断host是否需要唤醒 */\r
+    if (dev_wkup_host_pin != TIOT_PIN_NONE) {\r
+        if (gnss_send_host_need_wakeup(ctrl) != 0) {\r
+            return -1;\r
+        }\r
+    }\r
+    /* 切换波特率 */\r
+    if (gnss_send_change_buadrate(ctrl, custom_buadrate) != 0) {\r
+        return -1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+static inline int32_t gnss_get_dev_id(tiot_controller *ctrl, uint8_t *dev_id)\r
+{\r
+    uint8_t i;\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        if (ctrl == &g_gnss_controllers[i]) {\r
+            *dev_id = i;\r
+            return 0;\r
+        }\r
+    }\r
+    tiot_print_err("[TIoT]invalid device\n");\r
+    return -1;\r
+}\r
+\r
+static inline void gnss_set_open_param(tiot_xfer_open_param *xfer_open_param, tiot_service_open_param *param)\r
+{\r
+    if (param == NULL) {\r
+        return;\r
+    }\r
+    xfer_open_param->rx_cbk_param.buff = param->buff;\r
+    xfer_open_param->rx_cbk_param.buff_len = param->buff_len;\r
+    xfer_open_param->rx_cbk_param.rx_callback = param->rx_callback;\r
+}\r
+\r
+static inline int32_t gnss_firmware_load(tiot_fw *firmware)\r
+{\r
+    int ret = -1;\r
+#ifdef CONFIG_FILE_BY_ARRAY\r
+    ret = tiot_firmware_load(firmware, gnss_fw_file_path_get(), TIOT_FW_FILE_ARRAY_CFG_NAME);\r
+#else\r
+    ret = tiot_firmware_load(firmware, NULL, gnss_board_get_info()->cfg_path);\r
+#endif\r
+    if (ret != 0) {\r
+        tiot_print_err("[TIoT]Gnss firmware load fail.\n");\r
+    }\r
+    return ret;\r
+}\r
+\r
+static int32_t gnss_service_open(tiot_controller *ctrl, void *param)\r
+{\r
+    int ret = -1;\r
+    uint8_t dev_id;\r
+    uint32_t dev_wkup_host_pin;\r
+    tiot_xfer_open_param xfer_open_param = { 0 };\r
+    if (gnss_get_dev_id(ctrl, &dev_id) != 0) {\r
+        return -1;\r
+    }\r
+    gnss_set_open_param(&xfer_open_param, param);\r
+    /* 传输启动 */\r
+    if (tiot_xfer_open(&ctrl->transfer, &xfer_open_param) != 0) {\r
+        /* 通信接口打开失败 */\r
+        tiot_print_err("[TIoT]Transfer port open fail\n");\r
+        goto xfer_open_fail;\r
+    }\r
+    /* 上电 */\r
+    if (tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWERON) != 0) {\r
+        /* 上电失败 */\r
+        tiot_print_err("[TIoT]Power on fail\n");\r
+        goto power_on_fail;\r
+    }\r
+    /* 加载固件 */\r
+    ret = gnss_firmware_load(&ctrl->firmware);\r
+    if (ret != 0) {\r
+        goto fw_load_fail;\r
+    }\r
+    /* 使能中断 */\r
+    dev_wkup_host_pin = ctrl->pm.pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];\r
+    tiot_pin_int_request(dev_wkup_host_pin, gnss_device_wakeup_host_cb);\r
+\r
+    ret = gnss_service_packet_init(ctrl, dev_id);\r
+    if (ret != 0) {\r
+        goto pkt_init_fail;\r
+    }\r
+    ret = gnss_service_install_packet(ctrl, dev_id);\r
+    if (ret != 0) {\r
+        goto pkt_install_fail;\r
+    }\r
+    ret = gnss_service_custom_msg_send(ctrl, dev_wkup_host_pin, CONFIG_GNSS_UART_BAUDRATE);\r
+    if (ret != 0) {\r
+        goto pkt_install_fail;\r
+    }\r
+    /* 打开OK */\r
+    tiot_print_suc("[TIoT]Controller open succ.\n");\r
+    return 0;\r
+\r
+pkt_install_fail:\r
+    tiot_packet_deinit(&g_gnss_pkt_ctx[dev_id]);\r
+pkt_init_fail:\r
+    tiot_pin_int_release(dev_wkup_host_pin);\r
+fw_load_fail:\r
+    (void)tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWEROFF);\r
+power_on_fail:\r
+    tiot_xfer_close(&ctrl->transfer);\r
+xfer_open_fail:\r
+    return ret;\r
+}\r
+\r
+static void gnss_service_close(tiot_controller *ctrl)\r
+{\r
+    uint8_t dev_id;\r
+    uint32_t dev_wkup_host_pin;\r
+    if (gnss_get_dev_id(ctrl, &dev_id) != 0) {\r
+        return;\r
+    }\r
+    dev_wkup_host_pin = ctrl->pm.pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST];\r
+    (void)tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWEROFF);\r
+    tiot_pin_int_release(dev_wkup_host_pin);\r
+    tiot_xfer_close(&ctrl->transfer);\r
+    tiot_xfer_uninstall_packet(&ctrl->transfer);\r
+    tiot_packet_deinit(&g_gnss_pkt_ctx[dev_id]);\r
+}\r
+\r
+static int32_t gnss_service_write(tiot_controller *ctrl, const uint8_t *data,\r
+                                  uint32_t len, const tiot_xfer_tx_param *param)\r
+{\r
+    tiot_unused(param);\r
+    uint8_t dev_id;\r
+    if (gnss_get_dev_id(ctrl, &dev_id) != 0) {\r
+        return -1;\r
+    }\r
+    const tiot_xfer_tx_param tx_param = { SUBSYS_GNSS };\r
+    tiot_pm *pm = &ctrl->pm;\r
+    (void)tiot_pm_set_event(pm, TIOT_PM_EVENT_WORK_VOTE_UP);\r
+    /* 尝试唤醒device */\r
+    int32_t ret = tiot_pm_set_event(pm, TIOT_PM_EVENT_WAKEUP);\r
+    if (ret != 0) {\r
+        tiot_print_err("[TIoT]wake up error\n");\r
+        goto vote_down;\r
+    }\r
+    /* 等待成功唤醒device */\r
+    ret = tiot_pm_wait_state(&ctrl->pm, TIOT_PM_STATE_WORK, ctrl->dev_info->timings.wakeup_wait_ms);\r
+    if (ret <= 0) {\r
+        tiot_print_warning("[TIoT]wakeup device fail, pm state is 0x%x.\n", pm->state);\r
+    }\r
+    ret = tiot_xfer_send(&ctrl->transfer, data, len, &tx_param);\r
+vote_down:\r
+    (void)tiot_pm_set_event(pm, TIOT_PM_EVENT_WORK_VOTE_DOWN);\r
+    return ret;\r
+}\r
+\r
+static int32_t gnss_service_read(tiot_controller *ctrl, uint8_t *buff, uint32_t buff_len,\r
+                                 const tiot_xfer_rx_param *param)\r
+{\r
+    uint8_t dev_id;\r
+    if (gnss_get_dev_id(ctrl, &dev_id) != 0) {\r
+        return -1;\r
+    }\r
+    return tiot_xfer_recv(&ctrl->transfer, buff, buff_len, param);\r
+}\r
+\r
+int32_t gnss_service_init(void)\r
+{\r
+    uint8_t i;\r
+    int32_t ret;\r
+    tiot_board_info per_board_info;\r
+    tiot_controller_info ctrl_info;\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        if (gnss_board_init(&i) != 0) {\r
+            tiot_print_err("[TIoT]board init fail\n");\r
+            return -1;\r
+        }\r
+    }\r
+    const gnss_board_info *board_info = gnss_board_get_info();\r
+    if (board_info == NULL) {\r
+        tiot_print_err("[TIoT]no board info.\n");\r
+        goto deinit;\r
+    }\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        per_board_info.hw_info.xmit_id = board_info->hw_infos[i].xmit_id;\r
+        per_board_info.hw_info.pm_info = board_info->hw_infos[i].pm_info;\r
+        ctrl_info.board_info = &per_board_info;\r
+        ctrl_info.dev_info = gnss_device_get_info();\r
+        ctrl_info.dev_cus = 0;\r
+        ret = tiot_controller_init(&g_gnss_controllers[i], &ctrl_info);\r
+        if (ret != 0) {\r
+            tiot_print_err("[TIoT]controller init fail\n");\r
+            goto deinit;\r
+        }\r
+    }\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        g_gnss_controllers[i].ops.open = gnss_service_open;\r
+        g_gnss_controllers[i].ops.close = gnss_service_close;\r
+        g_gnss_controllers[i].ops.write = gnss_service_write;\r
+        g_gnss_controllers[i].ops.read = gnss_service_read;\r
+        g_gnss_controllers[i].ops.pm_ctrl = NULL;\r
+    }\r
+    return 0;\r
+deinit:\r
+    gnss_service_deinit();\r
+    return -1;\r
+}\r
+\r
+void gnss_service_deinit(void)\r
+{\r
+    uint8_t i;\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        tiot_controller_deinit(&g_gnss_controllers[i]);\r
+    }\r
+    for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) {\r
+        gnss_board_deinit(&i);\r
+    }\r
+}\r
+\r
+uintptr_t gnss_service_get_ctrl(uint8_t dev_id)\r
+{\r
+    return (uintptr_t)&g_gnss_controllers[dev_id];\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.h
new file mode 100644 (file)
index 0000000..3d37a81
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: GNSS service interface. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+#ifndef GNSS_SERVICE_H
+#define GNSS_SERVICE_H
+
+#include "tiot_types.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * @defgroup tiot_device_gnss_service_if  GNSS Service Interface
+ * @ingroup  tiot_device_gnss
+ * @{
+ */
+
+/**
+ * @brief  GNSS service init.
+ * @return zero if OK, -1 if failed.
+ */
+int32_t gnss_service_init(void);
+
+/**
+ * @brief  GNSS service deinit.
+ */
+void gnss_service_deinit(void);
+
+/**
+ * @brief  GNSS service get ctrl.
+ * @param  dev_id Device id.
+ * @return Tiot controller instace.
+ */
+uintptr_t gnss_service_get_ctrl(uint8_t dev_id);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7149394
--- /dev/null
@@ -0,0 +1,12 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+add_subdirectory(porting)  # 替换成对应porting目录
+
+set(
+    tiot_product_header_list
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${tiot_product_header_list}" CACHE INTERNAL "tiot header list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/Makefile b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/Makefile
new file mode 100644 (file)
index 0000000..c3b9dbf
--- /dev/null
@@ -0,0 +1,4 @@
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/product_porting
+TIOT_HEADER_LIST += -I$(TIOT_DRIVER_PATH)/product_porting/porting
+include $(TIOT_DRIVER_PATH)/product_porting/porting/porting.mk
+tiot-porting-objs := $(addprefix product_porting/porting/,$(tiot-porting-objs))
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/readme.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/readme.txt
new file mode 100644 (file)
index 0000000..dd5b907
--- /dev/null
@@ -0,0 +1 @@
+TCXO时钟26M + 硬件流控悬空 + 无文件系统及动态内存
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_autoconfig.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_autoconfig.h
new file mode 100644 (file)
index 0000000..aad6a4e
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. */
+#define CONFIG_DEV_GNSS 1
+#define CONFIG_GNSS_DEV_NUM 1
+#define CONFIG_GNSS_WAKEUP_TYPE_UART 1
+#define CONFIG_GNSS_TCXO_FREQ_26M 1
+#define CONFIG_GNSS_UART_BAUDRATE 115200
+#define CONFIG_GNSS_PACKET_BUFF_MAX 10000
+#define CONFIG_FILE_BY_ARRAY 1
+#define CONFIG_FIRMWARE_CFG_HANDLE_PRIV 1
+#define CONFIG_FIRMWARE_FILE_READ_BUF_LEN 1029
+#define CONFIG_PM_WAKEUP_BY_UART 1
+#define CONFIG_PM_MANAGE_LOWPOWER 1
+#define CONFIG_XMIT_WITH_UART 1
+#define CONFIG_UART_RX_MODE_BUFFED 1
+#define CONFIG_XFER_PACKET_TIOT 1
+#define CONFIG_XFER_DEFAULT_RX_BUFF 1
+#define CONFIG_XFER_RX_BUFF_SIZE 512
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_defconfig b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_defconfig
new file mode 100644 (file)
index 0000000..6816a9b
--- /dev/null
@@ -0,0 +1,101 @@
+# Generated by HiCFBB Kconfig Tool.
+# Note: !!!This file can not be modify manually!!!
+
+#
+# Devices
+#
+
+#
+# Config the devices.
+#
+CONFIG_DEV_GNSS=y
+CONFIG_GNSS_DEV_NUM=1
+CONFIG_GNSS_WAKEUP_TYPE_UART=y
+# CONFIG_GNSS_WAKEUP_TYPE_GPIO is not set
+CONFIG_GNSS_TCXO_FREQ_26M=y
+# CONFIG_GNSS_TCXO_FREQ_38P4M is not set
+CONFIG_GNSS_UART_BAUDRATE=115200
+# CONFIG_GNSS_UART_WITH_FLOWCTRL is not set
+CONFIG_GNSS_PACKET_BUFF_MAX=10000
+# CONFIG_DEV_W33 is not set
+# CONFIG_DEV_CA01 is not set
+# end of Devices
+
+#
+# Common
+#
+
+#
+# Config common modules.
+#
+
+#
+# Misc
+#
+CONFIG_FILE_BY_ARRAY=y
+# CONFIG_OSAL_DEFINED is not set
+# CONFIG_LIBBOUNDSCHECK_IMPLEMENTED is not set
+# CONFIG_BOARD_DYNAMIC_ALLOC is not set
+# end of Misc
+
+#
+# Firmware Load
+#
+
+#
+# Firmware load module.
+#
+CONFIG_FIRMWARE_CFG_HANDLE_PRIV=y
+# CONFIG_FIRMWARE_CFG_HANDLE_XCI is not set
+CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029
+# end of Firmware Load
+
+#
+# Power Management
+#
+
+#
+# Power management module.
+#
+CONFIG_PM_WAKEUP_BY_UART=y
+CONFIG_PM_MANAGE_LOWPOWER=y
+# end of Power Management
+
+#
+# Transfer
+#
+
+#
+# Transfer module.
+#
+
+#
+# Transmit Type Support
+#
+
+#
+# Transmit type support.
+#
+CONFIG_XMIT_WITH_UART=y
+# CONFIG_XMIT_WITH_SPI is not set
+# CONFIG_XMIT_WITH_I2C is not set
+CONFIG_UART_RX_MODE_BUFFED=y
+# CONFIG_UART_RX_MODE_BLOCK is not set
+# end of Transmit Type Support
+
+#
+# Packet Handle Support
+#
+
+#
+# Pakcet handle support.
+#
+CONFIG_XFER_PACKET_TIOT=y
+# CONFIG_XFER_PACKET_NCI is not set
+# end of Packet Handle Support
+
+CONFIG_XFER_DEFAULT_RX_BUFF=y
+CONFIG_XFER_RX_BUFF_SIZE=512
+# CONFIG_XFER_TX_SUPPORT_TASK is not set
+# end of Transfer
+# end of Common
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/readme.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/readme.txt
new file mode 100644 (file)
index 0000000..98f9a54
--- /dev/null
@@ -0,0 +1 @@
+TCXO时钟38.4M + 硬件流控连接 + 有文件系统及动态内存
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_autoconfig.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_autoconfig.h
new file mode 100644 (file)
index 0000000..0fc0878
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. */
+#define CONFIG_DEV_GNSS 1
+#define CONFIG_GNSS_DEV_NUM 1
+#define CONFIG_GNSS_WAKEUP_TYPE_UART 1
+#define CONFIG_GNSS_TCXO_FREQ_38P4M 1
+#define CONFIG_GNSS_UART_BAUDRATE 115200
+#define CONFIG_GNSS_UART_WITH_FLOWCTRL 1
+#define CONFIG_BOARD_DYNAMIC_ALLOC 1
+#define CONFIG_FIRMWARE_CFG_HANDLE_PRIV 1
+#define CONFIG_FIRMWARE_FILE_READ_BUF_LEN 1029
+#define CONFIG_PM_WAKEUP_BY_UART 1
+#define CONFIG_PM_MANAGE_LOWPOWER 1
+#define CONFIG_XMIT_WITH_UART 1
+#define CONFIG_UART_RX_MODE_BUFFED 1
+#define CONFIG_XFER_PACKET_TIOT 1
+#define CONFIG_XFER_DEFAULT_RX_BUFF 1
+#define CONFIG_XFER_RX_BUFF_SIZE 512
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_defconfig b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_defconfig
new file mode 100644 (file)
index 0000000..e1935a2
--- /dev/null
@@ -0,0 +1,100 @@
+# Generated by HiCFBB Kconfig Tool.
+# Note: !!!This file can not be modify manually!!!
+
+#
+# Devices
+#
+
+#
+# Config the devices.
+#
+CONFIG_DEV_GNSS=y
+CONFIG_GNSS_DEV_NUM=1
+CONFIG_GNSS_WAKEUP_TYPE_UART=y
+# CONFIG_GNSS_WAKEUP_TYPE_GPIO is not set
+# CONFIG_GNSS_TCXO_FREQ_26M is not set
+CONFIG_GNSS_TCXO_FREQ_38P4M=y
+CONFIG_GNSS_UART_BAUDRATE=115200
+CONFIG_GNSS_UART_WITH_FLOWCTRL=y
+# CONFIG_DEV_W33 is not set
+# CONFIG_DEV_CA01 is not set
+# end of Devices
+
+#
+# Common
+#
+
+#
+# Config common modules.
+#
+
+#
+# Misc
+#
+# CONFIG_FILE_BY_ARRAY is not set
+# CONFIG_OSAL_DEFINED is not set
+# CONFIG_LIBBOUNDSCHECK_IMPLEMENTED is not set
+CONFIG_BOARD_DYNAMIC_ALLOC=y
+# end of Misc
+
+#
+# Firmware Load
+#
+
+#
+# Firmware load module.
+#
+CONFIG_FIRMWARE_CFG_HANDLE_PRIV=y
+# CONFIG_FIRMWARE_CFG_HANDLE_XCI is not set
+CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029
+# end of Firmware Load
+
+#
+# Power Management
+#
+
+#
+# Power management module.
+#
+CONFIG_PM_WAKEUP_BY_UART=y
+CONFIG_PM_MANAGE_LOWPOWER=y
+# end of Power Management
+
+#
+# Transfer
+#
+
+#
+# Transfer module.
+#
+
+#
+# Transmit Type Support
+#
+
+#
+# Transmit type support.
+#
+CONFIG_XMIT_WITH_UART=y
+# CONFIG_XMIT_WITH_SPI is not set
+# CONFIG_XMIT_WITH_I2C is not set
+CONFIG_UART_RX_MODE_BUFFED=y
+# CONFIG_UART_RX_MODE_BLOCK is not set
+# end of Transmit Type Support
+
+#
+# Packet Handle Support
+#
+
+#
+# Pakcet handle support.
+#
+CONFIG_XFER_PACKET_TIOT=y
+# CONFIG_XFER_PACKET_NCI is not set
+# end of Packet Handle Support
+
+CONFIG_XFER_DEFAULT_RX_BUFF=y
+CONFIG_XFER_RX_BUFF_SIZE=512
+# CONFIG_XFER_TX_SUPPORT_TASK is not set
+# end of Transfer
+# end of Common
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/readme.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/readme.txt
new file mode 100644 (file)
index 0000000..ecdac47
--- /dev/null
@@ -0,0 +1 @@
+TCXO时钟26M + 硬件流控连接
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_autoconfig.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_autoconfig.h
new file mode 100644 (file)
index 0000000..ee02803
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. */
+#define CONFIG_DEV_GNSS 1
+#define CONFIG_GNSS_DEV_NUM 1
+#define CONFIG_GNSS_WAKEUP_TYPE_UART 1
+#define CONFIG_GNSS_TCXO_FREQ_26M 1
+#define CONFIG_GNSS_UART_BAUDRATE 115200
+#define CONFIG_FILE_BY_ARRAY 1
+#define CONFIG_OSAL_DEFINED 1
+#define CONFIG_LIBBOUNDSCHECK_IMPLEMENTED 1
+#define CONFIG_BOARD_DYNAMIC_ALLOC 1
+#define CONFIG_FIRMWARE_CFG_HANDLE_PRIV 1
+#define CONFIG_FIRMWARE_FILE_READ_BUF_LEN 1029
+#define CONFIG_PM_WAKEUP_BY_UART 1
+#define CONFIG_PM_MANAGE_LOWPOWER 1
+#define CONFIG_XMIT_WITH_UART 1
+#define CONFIG_UART_RX_MODE_BUFFED 1
+#define CONFIG_XFER_PACKET_TIOT 1
+#define CONFIG_XFER_DEFAULT_RX_BUFF 1
+#define CONFIG_XFER_RX_BUFF_SIZE 512
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_defconfig b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_defconfig
new file mode 100644 (file)
index 0000000..4de7aff
--- /dev/null
@@ -0,0 +1,100 @@
+# Generated by HiCFBB Kconfig Tool.
+# Note: !!!This file can not be modify manually!!!
+
+#
+# Devices
+#
+
+#
+# Config the devices.
+#
+CONFIG_DEV_GNSS=y
+CONFIG_GNSS_DEV_NUM=1
+CONFIG_GNSS_WAKEUP_TYPE_UART=y
+# CONFIG_GNSS_WAKEUP_TYPE_GPIO is not set
+CONFIG_GNSS_TCXO_FREQ_26M=y
+# CONFIG_GNSS_TCXO_FREQ_38P4M is not set
+CONFIG_GNSS_UART_BAUDRATE=115200
+# CONFIG_GNSS_UART_WITH_FLOWCTRL is not set
+# CONFIG_DEV_W33 is not set
+# CONFIG_DEV_CA01 is not set
+# end of Devices
+
+#
+# Common
+#
+
+#
+# Config common modules.
+#
+
+#
+# Misc
+#
+CONFIG_FILE_BY_ARRAY=y
+CONFIG_OSAL_DEFINED=y
+CONFIG_LIBBOUNDSCHECK_IMPLEMENTED=y
+CONFIG_BOARD_DYNAMIC_ALLOC=y
+# end of Misc
+
+#
+# Firmware Load
+#
+
+#
+# Firmware load module.
+#
+CONFIG_FIRMWARE_CFG_HANDLE_PRIV=y
+# CONFIG_FIRMWARE_CFG_HANDLE_XCI is not set
+CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029
+# end of Firmware Load
+
+#
+# Power Management
+#
+
+#
+# Power management module.
+#
+CONFIG_PM_WAKEUP_BY_UART=y
+CONFIG_PM_MANAGE_LOWPOWER=y
+# end of Power Management
+
+#
+# Transfer
+#
+
+#
+# Transfer module.
+#
+
+#
+# Transmit Type Support
+#
+
+#
+# Transmit type support.
+#
+CONFIG_XMIT_WITH_UART=y
+# CONFIG_XMIT_WITH_SPI is not set
+# CONFIG_XMIT_WITH_I2C is not set
+CONFIG_UART_RX_MODE_BUFFED=y
+# CONFIG_UART_RX_MODE_BLOCK is not set
+# end of Transmit Type Support
+
+#
+# Packet Handle Support
+#
+
+#
+# Pakcet handle support.
+#
+CONFIG_XFER_PACKET_TIOT=y
+# CONFIG_XFER_PACKET_NCI is not set
+# end of Packet Handle Support
+
+CONFIG_XFER_DEFAULT_RX_BUFF=y
+CONFIG_XFER_RX_BUFF_SIZE=512
+# CONFIG_XFER_TX_SUPPORT_TASK is not set
+# end of Transfer
+# end of Common
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/readme.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/readme.txt
new file mode 100644 (file)
index 0000000..fbcaf37
--- /dev/null
@@ -0,0 +1 @@
+TCXO时钟38.4M + 硬件流控悬空
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_autoconfig.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_autoconfig.h
new file mode 100644 (file)
index 0000000..96e4f76
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. */
+#define CONFIG_DEV_GNSS 1
+#define CONFIG_GNSS_DEV_NUM 1
+#define CONFIG_GNSS_WAKEUP_TYPE_UART 1
+#define CONFIG_GNSS_TCXO_FREQ_38P4M 1
+#define CONFIG_GNSS_UART_BAUDRATE 115200
+#define CONFIG_GNSS_UART_WITH_FLOWCTRL 1
+#define CONFIG_FILE_BY_ARRAY 1
+#define CONFIG_OSAL_DEFINED 1
+#define CONFIG_LIBBOUNDSCHECK_IMPLEMENTED 1
+#define CONFIG_BOARD_DYNAMIC_ALLOC 1
+#define CONFIG_FIRMWARE_CFG_HANDLE_PRIV 1
+#define CONFIG_FIRMWARE_FILE_READ_BUF_LEN 1029
+#define CONFIG_PM_WAKEUP_BY_UART 1
+#define CONFIG_PM_MANAGE_LOWPOWER 1
+#define CONFIG_XMIT_WITH_UART 1
+#define CONFIG_UART_RX_MODE_BUFFED 1
+#define CONFIG_XFER_PACKET_TIOT 1
+#define CONFIG_XFER_DEFAULT_RX_BUFF 1
+#define CONFIG_XFER_RX_BUFF_SIZE 512
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_defconfig b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_defconfig
new file mode 100644 (file)
index 0000000..243c5bc
--- /dev/null
@@ -0,0 +1,100 @@
+# Generated by HiCFBB Kconfig Tool.
+# Note: !!!This file can not be modify manually!!!
+
+#
+# Devices
+#
+
+#
+# Config the devices.
+#
+CONFIG_DEV_GNSS=y
+CONFIG_GNSS_DEV_NUM=1
+CONFIG_GNSS_WAKEUP_TYPE_UART=y
+# CONFIG_GNSS_WAKEUP_TYPE_GPIO is not set
+# CONFIG_GNSS_TCXO_FREQ_26M is not set
+CONFIG_GNSS_TCXO_FREQ_38P4M=y
+CONFIG_GNSS_UART_BAUDRATE=115200
+CONFIG_GNSS_UART_WITH_FLOWCTRL=y
+# CONFIG_DEV_W33 is not set
+# CONFIG_DEV_CA01 is not set
+# end of Devices
+
+#
+# Common
+#
+
+#
+# Config common modules.
+#
+
+#
+# Misc
+#
+CONFIG_FILE_BY_ARRAY=y
+CONFIG_OSAL_DEFINED=y
+CONFIG_LIBBOUNDSCHECK_IMPLEMENTED=y
+CONFIG_BOARD_DYNAMIC_ALLOC=y
+# end of Misc
+
+#
+# Firmware Load
+#
+
+#
+# Firmware load module.
+#
+CONFIG_FIRMWARE_CFG_HANDLE_PRIV=y
+# CONFIG_FIRMWARE_CFG_HANDLE_XCI is not set
+CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029
+# end of Firmware Load
+
+#
+# Power Management
+#
+
+#
+# Power management module.
+#
+CONFIG_PM_WAKEUP_BY_UART=y
+CONFIG_PM_MANAGE_LOWPOWER=y
+# end of Power Management
+
+#
+# Transfer
+#
+
+#
+# Transfer module.
+#
+
+#
+# Transmit Type Support
+#
+
+#
+# Transmit type support.
+#
+CONFIG_XMIT_WITH_UART=y
+# CONFIG_XMIT_WITH_SPI is not set
+# CONFIG_XMIT_WITH_I2C is not set
+CONFIG_UART_RX_MODE_BUFFED=y
+# CONFIG_UART_RX_MODE_BLOCK is not set
+# end of Transmit Type Support
+
+#
+# Packet Handle Support
+#
+
+#
+# Pakcet handle support.
+#
+CONFIG_XFER_PACKET_TIOT=y
+# CONFIG_XFER_PACKET_NCI is not set
+# end of Packet Handle Support
+
+CONFIG_XFER_DEFAULT_RX_BUFF=y
+CONFIG_XFER_RX_BUFF_SIZE=512
+# CONFIG_XFER_TX_SUPPORT_TASK is not set
+# end of Transfer
+# end of Common
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/readme.md b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/readme.md
new file mode 100644 (file)
index 0000000..cf3aecf
--- /dev/null
@@ -0,0 +1,20 @@
+# menu_configs配置项
+menu_configs提供两套基础配置`config0`和`config1`,可以参考对应配置项,同时修改tiot_defconfig和tiot_autoconfig.h文件,适配产品环境。
+
+选择或修改tiot_defconfig和tiot_autoconfig.h文件后,将tiot_defconfig和tiot_autoconfig.h两文件拷贝至tiot_driver/product_porting目录,替换该目录下原有文件即可。
+
+# menu_configs配置项(Sparta)
+适配Sparta时,提供另外两套基础配置`config2`和`config3`,可以参考对应配置项,同时修改tiot_defconfig和tiot_autoconfig.h文件,适配产品环境。
+与`config0`、`config1`差异:
+- 配置项`CONFIG_OSAL_DEFINED`: Sparta SDK环境已自带OSAL(OS适配层)实现。
+- 配置项`CONFIG_LIBBOUNDSCHECK_IMPLEMENTED`:Sparta SDK环境已自带libboundscheck实现。
+
+## UART硬件流控
+配置项:`CONFIG_GNSS_UART_WITH_FLOWCTRL`
+- config0对应UART硬件流控悬空
+- config1对应UART硬件流控连接
+
+## TCXO时钟
+配置项:`CONFIG_GNSS_TCXO_FREQ_26M`、`CONFIG_GNSS_TCXO_FREQ_38P4M`
+- config0对应TCXO时钟为26M
+- config1对应TCXO时钟为38.4M
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3658375
--- /dev/null
@@ -0,0 +1,20 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    tiot_product_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_osal_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/gnss_board_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_uart_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_pin_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_misc_port.c
+)
+
+set(
+    tiot_product_header_list
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${tiot_product_header_list}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_product_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/gnss_board_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/gnss_board_port.c
new file mode 100644 (file)
index 0000000..b024455
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: GNSS board port. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+
+#include "gnss_board_port.h"
+
+static const gnss_board_hw_info g_gnss_board_hw_info;
+static const gnss_board_info g_gnss_board_info = {
+    .cfg_path = NULL,
+    .hw_infos = (gnss_board_hw_info *)&g_gnss_board_hw_info
+};
+
+int32_t gnss_board_init(void *param)
+{
+    tiot_unused(param);
+    return 0;
+}
+
+void gnss_board_deinit(void *param)
+{
+    tiot_unused(param);
+}
+
+const gnss_board_info *gnss_board_get_info(void)
+{
+    return &g_gnss_board_info;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/porting.mk b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/porting.mk
new file mode 100644 (file)
index 0000000..015284d
--- /dev/null
@@ -0,0 +1,5 @@
+tiot-porting-objs += tiot_board_uart_port.o
+tiot-porting-objs += tiot_board_pin_port.o
+tiot-porting-objs += tiot_board_misc_port.o
+tiot-porting-objs += gnss_board_port.o
+tiot-porting-objs += tiot_osal_port.o
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_log_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_log_port.h
new file mode 100644 (file)
index 0000000..690be5d
--- /dev/null
@@ -0,0 +1,49 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board log port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-05-06, Create file. \n\r
+ */\r
+#ifndef BOARD_LOG_PORT_H\r
+#define BOARD_LOG_PORT_H\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_board_port_log LOG port\r
+ * @ingroup  tiot_board_port\r
+ * @{\r
+ */\r
+#define TIOT_LOG_ALERT    0   /*!< Log level alert. */\r
+#define TIOT_LOG_ERR      1   /*!< Log level error. */\r
+#define TIOT_LOG_WARNING  2   /*!< Log level warning. */\r
+#define TIOT_LOG_INFO     3   /*!< Log level info. */\r
+#define TIOT_LOG_DEBUG    4   /*!< Log level debug. */\r
+\r
+#define TIOT_BOARD_LOG_LEVEL  TIOT_LOG_INFO    /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */\r
+\r
+#define BOARD_PRINT_FUNCTION_NAME       /* 此处替换为板级打印接口. */\r
+#define board_print_dbg(s, ...)         /* 此处替换为板级打印接口. */\r
+#define board_print_info(s, ...)        /* 此处替换为板级打印接口. */\r
+#define board_print_suc(s, ...)         /* 此处替换为板级打印接口. */\r
+#define board_print_warning(s, ...)     /* 此处替换为板级打印接口. */\r
+#define board_print_err(s, ...)         /* 此处替换为板级打印接口. */\r
+#define board_print_alter(s, ...)       /* 此处替换为板级打印接口. */\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_misc_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_misc_port.c
new file mode 100644 (file)
index 0000000..5b9470c
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Board misc port. \n
+ *
+ * History: \n
+ * 2023-12-07, Create file. \n
+ */
+#include "tiot_board_misc_port.h"
+
+int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+    return 0;
+}
+
+void tiot_board_wake_lock(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+}
+
+void tiot_board_wake_unlock(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+}
+
+void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+}
+
+void tiot_board_udelay(uint32_t us)
+{
+    tiot_unused(us);
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_pin_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_pin_port.c
new file mode 100644 (file)
index 0000000..4d0d62d
--- /dev/null
@@ -0,0 +1,37 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board PIN port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-04-20, Create file. \n\r
+ */\r
+#include "tiot_board_pin_port.h"\r
+\r
+int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level)\r
+{\r
+    tiot_unused(pin);\r
+    tiot_unused(level);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level)\r
+{\r
+    tiot_unused(pin);\r
+    tiot_unused(level);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable)\r
+{\r
+    tiot_unused(pin);\r
+    tiot_unused(int_enable);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb)\r
+{\r
+    tiot_unused(pin);\r
+    tiot_unused(int_cb);\r
+    return 0;\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_uart_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_uart_port.c
new file mode 100644 (file)
index 0000000..7e1bcfb
--- /dev/null
@@ -0,0 +1,45 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board UART port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_log.h"\r
+\r
+int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs)\r
+{\r
+    tiot_unused(xmit);\r
+    tiot_unused(cbs);\r
+    return 0;\r
+}\r
+\r
+void tiot_board_uart_close(tiot_xmit *xmit)\r
+{\r
+    tiot_unused(xmit);\r
+}\r
+\r
+int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len)\r
+{\r
+    tiot_unused(xmit);\r
+    tiot_unused(buff);\r
+    tiot_unused(len);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len)\r
+{\r
+    tiot_unused(xmit);\r
+    tiot_unused(buff);\r
+    tiot_unused(len);\r
+    return -1;\r
+}\r
+\r
+int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config)\r
+{\r
+    tiot_unused(xmit);\r
+    tiot_unused(config);\r
+    return 0;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_osal_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_osal_port.c
new file mode 100644 (file)
index 0000000..0307c3d
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: osal port demo. \n
+ *
+ * History: \n
+ * 2023-10-23, Create file. \n
+ */
+
+#include "tiot_osal.h"
+
+/* 仅用于编译,需要参照demo实现. */
+
+unsigned long osal_msleep(unsigned int msecs)
+{
+    tiot_unused(msecs);
+    return OSAL_SUCCESS;
+}
+
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag)
+{
+    tiot_unused(size);
+    tiot_unused(osal_gfp_flag);
+    return NULL;
+}
+
+void osal_kfree(void *addr)
+{
+    tiot_unused(addr);
+}
+
+int osal_spin_lock_init(osal_spinlock *lock)
+{
+    tiot_unused(lock);
+    return OSAL_SUCCESS;
+}
+
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags)
+{
+    tiot_unused(lock);
+    tiot_unused(flags);
+}
+
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags)
+{
+    tiot_unused(lock);
+    tiot_unused(flags);
+}
+
+void osal_spin_lock_destroy(osal_spinlock *lock)
+{
+    tiot_unused(lock);
+}
+
+int osal_mutex_init(osal_mutex *mutex)
+{
+    tiot_unused(mutex);
+    return OSAL_SUCCESS;
+}
+
+int osal_mutex_lock(osal_mutex *mutex)
+{
+    tiot_unused(mutex);
+    return OSAL_SUCCESS;
+}
+
+void osal_mutex_unlock(osal_mutex *mutex)
+{
+    tiot_unused(mutex);
+}
+
+void osal_mutex_destroy(osal_mutex *mutex)
+{
+    tiot_unused(mutex);
+}
+
+int osal_wait_init(osal_wait *wait)
+{
+    tiot_unused(wait);
+    return OSAL_SUCCESS;
+}
+
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,
+                                    unsigned long ms)
+{
+    tiot_unused(wait);
+    tiot_unused(func);
+    tiot_unused(param);
+    tiot_unused(ms);
+    return OSAL_SUCCESS;
+}
+
+void osal_wait_wakeup_interruptible(osal_wait *wait)
+{
+    tiot_unused(wait);
+}
+
+void osal_wait_destroy(osal_wait *wait)
+{
+    tiot_unused(wait);
+}
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+#error "need implement."
+#endif
+
+#ifndef CONFIG_FILE_BY_ARRAY
+#error "need implement."
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_board_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_board_port.c
new file mode 100644 (file)
index 0000000..fcff910
--- /dev/null
@@ -0,0 +1,189 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2024-01-04, Create file. \n\r
+ */\r
+#include "gnss_board_port.h"\r
+#include <linux/device.h>\r
+#include <linux/of_gpio.h>\r
+#include <linux/irq.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/gpio.h>\r
+#include <linux/tty.h>\r
+#include "tiot_board_pin_port.h"\r
+#include "tiot_board_pin_irq_helper.h"\r
+#include "tiot_board_log.h"\r
+#include "tiot_dts_node.h"\r
+#include "securec.h"\r
+\r
+#define DTS_NODE_COMPATIBLE "tiot,gnss"\r
+\r
+#define TTY_NAME_MAX   20\r
+#define CFG_PATH_MAX   200\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))\r
+#define WAKEIN_IRQF    (IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND)\r
+#else\r
+#define WAKEIN_IRQF    (IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND)\r
+#endif\r
+\r
+typedef struct {\r
+    bool optional;     /* 是否为可选管脚 */\r
+    const char *prop;  /* dts prop  */\r
+    const char *name;  /* gpio request name */\r
+    int gpio_flags;    /* gpio request 初始配置 */\r
+} tiot_kernel_pin_info;\r
+\r
+static gnss_board_hw_info g_board_hw_info = { 0 };\r
+static gnss_board_info g_board_info = {\r
+    .cfg_path = NULL,                 /* 如果有文件系统,指向gnss加载配置文件完整路径/相对路径\r
+                                          例如:linux下"/sys/xxx/xxx/xxx_config.bin",\r
+                                          windows下".\\config_file_path\\xxx_config.bin"\r
+                                          如果无文件系统,设为NULL. */\r
+    .hw_infos = &g_board_hw_info\r
+};\r
+\r
+static const tiot_kernel_pin_info g_board_pin_infos[GNSS_PIN_NUM] = {\r
+    { false, DTS_PROP_GPIO_POWEN_ON, NULL, GPIOF_OUT_INIT_LOW },\r
+    { true, DTS_PROP_GPIO_WAKEOUT, NULL, GPIOF_OUT_INIT_LOW },\r
+    { true, DTS_PROP_GPIO_WAKEIN, NULL, GPIOF_IN }\r
+};\r
+\r
+const gnss_board_info *gnss_board_get_info(void)\r
+{\r
+    return &g_board_info;\r
+}\r
+\r
+static struct device_node *board_find_device_node(uint8_t dev_id)\r
+{\r
+    /* 只使用单个, 忽略dev_id. */\r
+    tiot_unused(dev_id);\r
+    struct device_node *np = NULL;\r
+    struct device_node *dev_np = NULL;\r
+    /* 获取 top dts节点 */\r
+    np = of_find_compatible_node(NULL, NULL, DTS_NODE_TIOT);\r
+    if (np == NULL) {\r
+        printk("no compatible node.\r\n");\r
+        return NULL;\r
+    }\r
+    /* 获取子dts节点 */\r
+    dev_np = of_find_compatible_node(np, NULL, DTS_NODE_COMPATIBLE);\r
+    if (dev_np == NULL) {\r
+        printk("no device compatible node.\r\n");\r
+        return NULL;\r
+    }\r
+    return dev_np;\r
+}\r
+\r
+static int board_gpio_pins_init(struct device_node *dev_np, uint32_t *pins)\r
+{\r
+    uint8_t i;\r
+    int ret;\r
+    int gpio_nr;\r
+    const tiot_kernel_pin_info *pin_infos = (const tiot_kernel_pin_info *)&g_board_pin_infos;\r
+    /* 设置GPIO 初始pinmux. */\r
+    for (i = 0; i < GNSS_PIN_NUM; i++) {\r
+        gpio_nr = of_get_named_gpio(dev_np, pin_infos[i].prop, 0);\r
+        if (!pin_infos[i].optional && (gpio_nr < 0)) {\r
+            printk("non optional gpio no found: [%d].", i);\r
+            return -1;\r
+        }\r
+        if (gpio_nr < 0) {\r
+            pins[i] = TIOT_PIN_NONE;\r
+            continue;\r
+        }\r
+        printk("=================== tiot gpio [%d]: [%d].", i, gpio_nr);\r
+        ret = gpio_request_one(gpio_nr, pin_infos[i].gpio_flags, NULL);\r
+        if (ret != 0) {\r
+            printk("gpio request one failed [%d].\r\n", gpio_nr);\r
+            return -1;\r
+        }\r
+        if (pin_infos[i].gpio_flags == GPIOF_IN) {\r
+            /* 通过helper管理 irq gpio。 */\r
+            ret = tiot_board_irq_pin_register(gpio_nr, WAKEIN_IRQF);\r
+        }\r
+        if (ret != 0) {\r
+            printk("irq gpio register failed [%d].\r\n", gpio_nr);\r
+            return -1;\r
+        }\r
+        pins[i] = gpio_nr;\r
+    }\r
+    return ret;\r
+}\r
+\r
+static int board_node_get_prop_string(struct device_node *dev_np, const char *prop,\r
+                                      char *buff, uint32_t buff_len)\r
+{\r
+    errno_t err;\r
+    int ret = 0;\r
+    int str_len;\r
+    const char *str = NULL;\r
+    ret = of_property_read_string(dev_np, prop, &str);\r
+    if (ret < 0) {\r
+        printk("prop %s get failed.\r\n", prop);\r
+        return -1;\r
+    } else {\r
+        printk("prop %s get succ: %s.\r\n", prop, str);\r
+    }\r
+    str_len = strlen(str);\r
+    if (str_len >= buff_len) {\r
+        printk("prop %s too long, %d.\r\n", prop, str_len);\r
+        return -1;\r
+    }\r
+    err = memcpy_s(buff, str_len, str, str_len);\r
+    if (err != EOK) {\r
+        printk("tty_name memcpy fail.\r\n");\r
+        return -1;\r
+    }\r
+    return ret;\r
+}\r
+\r
+/* gnss板级UART、管脚初始化接口 */\r
+int32_t gnss_board_init(void *param)\r
+{\r
+    uint8_t dev_id;\r
+    int ret;\r
+    static char tty_name_backup[TTY_NAME_MAX] = { 0 };\r
+    static char cfg_path_backup[CFG_PATH_MAX] = { 0 };\r
+    struct device_node *dev_np = NULL;\r
+\r
+    dev_id = *(uint8_t *)param;\r
+    dev_np = board_find_device_node(dev_id);\r
+    if (dev_np == NULL) {\r
+        return -1;\r
+    }\r
+    /* 获取tty name. */\r
+    if (board_node_get_prop_string(dev_np, DTS_PROP_TTY_DEV_NAME, tty_name_backup, TTY_NAME_MAX) != 0) {\r
+        return -1;\r
+    }\r
+    g_board_hw_info.xmit_id = (uintptr_t)tty_name_backup;\r
+    /* 获取cfg固件文件路径. */\r
+    if (board_node_get_prop_string(dev_np, DTS_PROP_CFG_PATH, cfg_path_backup, CFG_PATH_MAX) != 0) {\r
+        return -1;\r
+    }\r
+    g_board_info.cfg_path = cfg_path_backup;\r
+    /* 获取gpio管脚. */\r
+    if (board_gpio_pins_init(dev_np, (uint32_t *)g_board_hw_info.pm_info) != 0) {\r
+        /* 失败时释放管脚. */\r
+        gnss_board_deinit(param);\r
+        return -1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+void gnss_board_deinit(void *param)\r
+{\r
+    (void)param;\r
+    uint8_t i;\r
+    uint32_t *pins = g_board_hw_info.pm_info;\r
+    for (i = 0; i < GNSS_PIN_NUM; i++) {\r
+        if (pins[i] == TIOT_PIN_NONE) {\r
+            continue;\r
+        }\r
+        gpio_free(pins[i]);\r
+    }\r
+    tiot_board_irq_pin_release();\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_misc_device.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_misc_device.c
new file mode 100644 (file)
index 0000000..7e6ba34
--- /dev/null
@@ -0,0 +1,149 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2023-12-26, Create file. \n\r
+ */\r
+#include <linux/module.h>\r
+#include <linux/fs.h>\r
+#include <linux/init.h>\r
+#include <linux/cdev.h>\r
+#include <linux/slab.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/of_gpio.h>\r
+#include "tiot_service_interface.h"\r
+#include "tiot_dts_node.h"\r
+\r
+#define DTS_NODE_COMPATIBLE "tiot,gnss"\r
+#define READ_TIMEOUT   1000\r
+#define TRX_DATA_MAX   9300\r
+\r
+struct tiot_dev {\r
+    struct miscdevice misc;\r
+    tiot_handle handle;\r
+} *g_misc_devp;\r
+\r
+static const char *g_device_node_name = NULL;\r
+static const char *g_misc_dev_name = NULL;\r
+static char g_misc_tx_data[TRX_DATA_MAX] = { 0 };\r
+static char g_misc_rx_data[TRX_DATA_MAX] = { 0 };\r
+\r
+static struct device_node *misc_find_device_node(void)\r
+{\r
+    struct device_node *np = NULL;\r
+    struct device_node *dev_np = NULL;\r
+    /* 获取 top dts节点 */\r
+    np = of_find_compatible_node(NULL, NULL, DTS_NODE_TIOT);\r
+    if (np == NULL) {\r
+        printk("no compatible node.\r\n");\r
+        return NULL;\r
+    }\r
+    /* 获取子dts节点 */\r
+    dev_np = of_find_compatible_node(np, NULL, DTS_NODE_COMPATIBLE);\r
+    if (dev_np == NULL) {\r
+        printk("no device compatible node.\r\n");\r
+        return NULL;\r
+    }\r
+    return dev_np;\r
+}\r
+\r
+static int misc_dev_open(struct inode *inode, struct file *filp)\r
+{\r
+    struct tiot_dev *dev = container_of(filp->private_data, struct tiot_dev, misc);\r
+    tiot_handle handle = tiot_service_open("gn71", NULL);\r
+    if (handle == 0) {\r
+        return -1;\r
+    }\r
+    dev->handle = handle;\r
+    filp->private_data = dev;\r
+    return 0;\r
+}\r
+\r
+static int misc_dev_close(struct inode *inode, struct file *filp)\r
+{\r
+    struct tiot_dev *dev = filp->private_data;\r
+    tiot_service_close(dev->handle);\r
+    dev->handle = 0;\r
+    return 0;\r
+}\r
+\r
+static ssize_t misc_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)\r
+{\r
+    int read_count;\r
+    struct tiot_dev *dev = filp->private_data;\r
+    if (count > sizeof(g_misc_rx_data)) {\r
+        return -ERANGE;\r
+    }\r
+    read_count = tiot_service_read(dev->handle, g_misc_rx_data,\r
+                                   sizeof(g_misc_rx_data), READ_TIMEOUT);\r
+    if (copy_to_user(buf, g_misc_rx_data, read_count)) {\r
+        return -ERANGE;\r
+    }\r
+    return read_count;\r
+}\r
+\r
+static ssize_t misc_dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)\r
+{\r
+    struct tiot_dev *dev = filp->private_data;\r
+    if (count > sizeof(g_misc_tx_data)) {\r
+        return -ERANGE;\r
+    }\r
+    if (copy_from_user(g_misc_tx_data, buf, count)) {\r
+        return -ERANGE;\r
+    }\r
+    return tiot_service_write(dev->handle, g_misc_tx_data, count);\r
+}\r
+\r
+static const struct file_operations tiot_gnss_fops = {\r
+    .owner = THIS_MODULE,\r
+    .read = misc_dev_read,\r
+    .write = misc_dev_write,\r
+    .open = misc_dev_open,\r
+    .release = misc_dev_close\r
+};\r
+\r
+static int __init tiot_module_init(void)\r
+{\r
+    int ret;\r
+    if (tiot_service_init() != 0) {\r
+        return -1;\r
+    }\r
+    struct device_node *dev_node = NULL;\r
+    dev_node = misc_find_device_node();\r
+    if (dev_node == NULL) {\r
+        return -1;\r
+    }\r
+    g_device_node_name = dev_node->name;\r
+    ret = of_property_read_string(dev_node, DTS_PROP_MISC_DEV_NAME, &g_misc_dev_name);\r
+    of_node_put(dev_node);\r
+\r
+    if (g_misc_dev_name) {\r
+        g_misc_devp = kzalloc(sizeof(struct tiot_dev), GFP_KERNEL);\r
+        if (!g_misc_devp)\r
+            return -ENOMEM;\r
+        g_misc_devp->misc.minor = MISC_DYNAMIC_MINOR;\r
+        g_misc_devp->misc.name = g_misc_dev_name;\r
+        g_misc_devp->misc.fops = &tiot_gnss_fops;\r
+        ret = misc_register(&g_misc_devp->misc);\r
+        if (ret != 0) {\r
+            return -1;\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+module_init(tiot_module_init);\r
+\r
+static void __exit tiot_module_exit(void)\r
+{\r
+    misc_deregister(&g_misc_devp->misc);\r
+    tiot_service_deinit();\r
+    kfree(g_misc_devp);\r
+    g_misc_devp = NULL;\r
+}\r
+\r
+module_exit(tiot_module_exit);\r
+MODULE_LICENSE("GPL v2");\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/porting.mk b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/porting.mk
new file mode 100644 (file)
index 0000000..0f18aa8
--- /dev/null
@@ -0,0 +1,7 @@
+tiot-porting-objs += tiot_osal_port.o\r
+tiot-porting-objs += tiot_board_uart_port.o\r
+tiot-porting-objs += tiot_board_pin_irq_helper.o\r
+tiot-porting-objs += tiot_board_pin_port.o\r
+tiot-porting-objs += tiot_board_misc_port.o\r
+tiot-porting-objs += gnss_board_port.o\r
+tiot-porting-objs += gnss_misc_device.o
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_log_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_log_port.h
new file mode 100644 (file)
index 0000000..6636380
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: kernel board log port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-05-06, Create file. \n\r
+ */\r
+#ifndef BOARD_LOG_PORT_H\r
+#define BOARD_LOG_PORT_H\r
+\r
+#include <linux/kernel.h>\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_board_port_log LOG port\r
+ * @ingroup  tiot_board_port\r
+ * @{\r
+ */\r
+\r
+#define TIOT_LOG_ALERT    0   /*!< Log level alert. */\r
+#define TIOT_LOG_ERR      1   /*!< Log level error. */\r
+#define TIOT_LOG_WARNING  2   /*!< Log level warning. */\r
+#define TIOT_LOG_INFO     3   /*!< Log level info. */\r
+#define TIOT_LOG_DEBUG    4   /*!< Log level debug. */\r
+\r
+#define TIOT_BOARD_LOG_LEVEL  TIOT_LOG_INFO    /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */\r
+\r
+#define BOARD_PRINT_FUNCTION_NAME           printk(KERN_INFO KBUILD_MODNAME ":D]%s]", __func__)\r
+#define board_print_dbg(s, args...)         printk(KERN_INFO KBUILD_MODNAME ":D]%s]" s, __func__, ##args)\r
+#define board_print_info(s, args...)        printk(KERN_INFO KBUILD_MODNAME ":I]%s]" s, __func__, ##args)\r
+#define board_print_suc(s, args...)         printk(KERN_INFO KBUILD_MODNAME ":S]%s]" s, __func__, ##args)\r
+#define board_print_warning(s, args...)     printk(KERN_WARNING KBUILD_MODNAME ":W]%s]" s, __func__, ##args)\r
+#define board_print_err(s, args...)         printk(KERN_ERR KBUILD_MODNAME ":E]%s]" s, __func__, ##args)\r
+#define board_print_alter(s, args...)       printk(KERN_ERR KBUILD_MODNAME ":A]%s]" s, __func__, ##args)\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_misc_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_misc_port.c
new file mode 100644 (file)
index 0000000..ad72d85
--- /dev/null
@@ -0,0 +1,113 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board misc port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-12-07, Create file. \n\r
+ */\r
+#include "tiot_board_misc_port.h"\r
+#include <linux/compiler.h>\r
+#include <linux/slab.h>\r
+#include <linux/spinlock.h>\r
+#include <linux/delay.h>\r
+#include <linux/version.h>\r
+#include <linux/device.h>\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))\r
+#include <linux/pm_wakeup.h>\r
+#endif\r
+#include "securec.h"\r
+\r
+#define TIOT_WAKEUP_LOCK_NAME    "tiot_wk"\r
+\r
+typedef struct {\r
+    struct wakeup_source ws;\r
+    spinlock_t ws_lock;\r
+    unsigned long lock_count;\r
+} tiot_kernel_wakelock;\r
+\r
+int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))\r
+    if (unlikely(lock == NULL)) {\r
+        return -1;\r
+    }\r
+    tiot_kernel_wakelock *kwakelock = (tiot_kernel_wakelock *)kzalloc(sizeof(tiot_kernel_wakelock), GFP_KERNEL);\r
+    if (kwakelock == NULL) {\r
+        return -1;\r
+    }\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))\r
+    memset_s((void *)&kwakelock->ws, sizeof(struct wakeup_source), 0, sizeof(struct wakeup_source));\r
+    kwakelock->ws.name = TIOT_WAKEUP_LOCK_NAME;\r
+    wakeup_source_add(&kwakelock->ws);\r
+#else\r
+    wakeup_source_init(&kwakelock->ws, TIOT_WAKEUP_LOCK_NAME);\r
+#endif\r
+    spin_lock_init(&kwakelock->ws_lock);\r
+    lock->lock = kwakelock;\r
+#endif\r
+    return 0;\r
+}\r
+\r
+void tiot_board_wake_lock(tiot_board_wakelock *lock)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))\r
+    unsigned long flags;\r
+\r
+    if (unlikely((lock == NULL) || (lock->lock == NULL))) {\r
+        return;\r
+    }\r
+\r
+    tiot_kernel_wakelock *kwakelock = lock->lock;\r
+    spin_lock_irqsave(&kwakelock->ws_lock, flags);\r
+    if (!kwakelock->lock_count) {\r
+        __pm_stay_awake(&kwakelock->ws);\r
+    }\r
+    kwakelock->lock_count++;\r
+    spin_unlock_irqrestore(&kwakelock->ws_lock, flags);\r
+#endif\r
+}\r
+\r
+void tiot_board_wake_unlock(tiot_board_wakelock *lock)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))\r
+    unsigned long flags;\r
+\r
+    if (unlikely((lock == NULL) || (lock->lock == NULL))) {\r
+        return;\r
+    }\r
+\r
+    tiot_kernel_wakelock *kwakelock = lock->lock;\r
+    spin_lock_irqsave(&kwakelock->ws_lock, flags);\r
+    if (kwakelock->lock_count) {\r
+        kwakelock->lock_count--;\r
+        if (!kwakelock->lock_count) {\r
+            __pm_relax(&kwakelock->ws);\r
+        }\r
+    }\r
+    spin_unlock_irqrestore(&kwakelock->ws_lock, flags);\r
+#endif\r
+}\r
+\r
+void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))\r
+    if (unlikely((lock == NULL) || (lock->lock == NULL))) {\r
+        return;\r
+    }\r
+\r
+    tiot_kernel_wakelock *kwakelock = lock->lock;\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))\r
+    wakeup_source_remove(&kwakelock->ws);\r
+    __pm_relax(&kwakelock->ws);\r
+#else\r
+    wakeup_source_trash(&kwakelock->ws);\r
+#endif\r
+    kfree(kwakelock);\r
+#endif\r
+}\r
+\r
+void tiot_board_udelay(uint32_t us)\r
+{\r
+    udelay(us);\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.c
new file mode 100644 (file)
index 0000000..8b6f6cd
--- /dev/null
@@ -0,0 +1,51 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2023-12-26, Create file. \n\r
+ */\r
+\r
+#include "tiot_board_pin_irq_helper.h"\r
+#include <linux/gpio.h>\r
+#include <linux/interrupt.h>\r
+\r
+#define TIOT_PIN_IRQ_MAX   16  /* for now this is enough. */\r
+\r
+static tiot_irq_pin_node g_tiot_board_irq_pin_map[TIOT_PIN_IRQ_MAX] = {{ 0 }};\r
+static uint32_t g_tiot_board_irq_pin_num = 0;\r
+\r
+int32_t tiot_board_irq_pin_register(uint32_t irq_pin, uint32_t irq_flags)\r
+{\r
+    if (g_tiot_board_irq_pin_num >= TIOT_PIN_IRQ_MAX) {\r
+        return -1;\r
+    }\r
+    tiot_irq_pin_node *cur_node = &g_tiot_board_irq_pin_map[g_tiot_board_irq_pin_num];\r
+    cur_node->pin = irq_pin;\r
+    cur_node->irq = gpio_to_irq(irq_pin);\r
+    cur_node->irq_flags = irq_flags;\r
+    cur_node->callback = NULL;\r
+    cur_node->is_enabled = TIOT_PIN_INT_DISABLE;\r
+    spin_lock_init(&(cur_node->lock));\r
+    g_tiot_board_irq_pin_num++;\r
+    return 0;\r
+}\r
+\r
+tiot_irq_pin_node *tiot_board_irq_pin_node_by_pin(uint32_t pin)\r
+{\r
+    tiot_irq_pin_node *cur_node = NULL;\r
+    int i;\r
+    for (i = 0; i < g_tiot_board_irq_pin_num; i++) {\r
+        cur_node = &g_tiot_board_irq_pin_map[i];\r
+        if (cur_node->pin == pin) {\r
+            return cur_node;\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+void tiot_board_irq_pin_release(void)\r
+{\r
+    g_tiot_board_irq_pin_num = 0;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.h
new file mode 100644 (file)
index 0000000..c0bdc3d
--- /dev/null
@@ -0,0 +1,48 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description:  \n\r
+ *\r
+ * History: \n\r
+ * 2023-12-26, Create file. \n\r
+ */\r
+#ifndef TIOT_BOARD_PIN_IRQ_HELPER_H\r
+#define TIOT_BOARD_PIN_IRQ_HELPER_H\r
+\r
+#include <linux/spinlock.h>\r
+#include "tiot_types.h"\r
+#include "tiot_board_pin_port.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+typedef struct {\r
+    uint32_t pin;\r
+    uint32_t irq;\r
+    uint32_t irq_flags;\r
+    uint32_t is_enabled;\r
+    spinlock_t lock;\r
+    tiot_pin_int_callback callback;\r
+} tiot_irq_pin_node;\r
+\r
+int32_t tiot_board_irq_pin_register(uint32_t irq_pin, uint32_t irq_flags);\r
+\r
+tiot_irq_pin_node *tiot_board_irq_pin_node_by_pin(uint32_t pin);\r
+\r
+void tiot_board_irq_pin_release(void);\r
+\r
+/* FOR S4 */\r
+void tiot_board_irq_pin_suspend(void);\r
+/* FOR S4 */\r
+void tiot_board_irq_pin_resume(void);\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_port.c
new file mode 100644 (file)
index 0000000..34f5d05
--- /dev/null
@@ -0,0 +1,88 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Demo board PIN port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-04-20, Create file. \n\r
+ */\r
+\r
+#include "tiot_board_pin_port.h"\r
+#include <linux/gpio.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/spinlock.h>\r
+#include "tiot_board_pin_irq_helper.h"\r
+\r
+int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level)\r
+{\r
+    return gpio_direction_output(pin, (int)level);\r
+}\r
+\r
+int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level)\r
+{\r
+    int32_t gpio_level = gpio_get_value(pin);\r
+    if (gpio_level < 0) {\r
+        return gpio_level;\r
+    }\r
+    *level = (gpio_level == 0) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH;\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable)\r
+{\r
+    if (pin == TIOT_PIN_NONE) {\r
+        return -1;\r
+    }\r
+    tiot_irq_pin_node *irq_pin_node = tiot_board_irq_pin_node_by_pin(pin);\r
+    if (irq_pin_node == NULL) {\r
+        return -1;\r
+    }\r
+    unsigned long flags;\r
+    spin_lock_irqsave(&irq_pin_node->lock, flags);\r
+    if ((int_enable == TIOT_PIN_INT_ENABLE) && (irq_pin_node->is_enabled == TIOT_PIN_INT_DISABLE)) {\r
+        enable_irq(irq_pin_node->irq);\r
+        irq_pin_node->is_enabled = TIOT_PIN_INT_ENABLE;\r
+    } else if ((int_enable == TIOT_PIN_INT_DISABLE) && (irq_pin_node->is_enabled == TIOT_PIN_INT_ENABLE)) {\r
+        disable_irq_nosync(irq_pin_node->irq);\r
+        irq_pin_node->is_enabled = TIOT_PIN_INT_DISABLE;\r
+    }\r
+    spin_unlock_irqrestore(&irq_pin_node->lock, flags);\r
+    return 0;\r
+}\r
+\r
+static irqreturn_t tiot_board_gpio_irq_callback(int irq, void *node)\r
+{\r
+    (void)irq;\r
+    tiot_irq_pin_node *irq_pin_node = (tiot_irq_pin_node *)node;\r
+    /* RESUME TODO */\r
+    if ((irq_pin_node != NULL) && (irq_pin_node->callback != NULL)) {\r
+        irq_pin_node->callback(irq_pin_node->pin);\r
+    }\r
+    return IRQ_HANDLED;\r
+}\r
+\r
+int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb)\r
+{\r
+    int32_t ret;\r
+    tiot_irq_pin_node *irq_pin_node = tiot_board_irq_pin_node_by_pin(pin);\r
+    if (irq_pin_node == NULL) {\r
+        return -1;\r
+    }\r
+    irq_pin_node->callback = int_cb;\r
+    if (irq_pin_node->irq == 0) {\r
+        return -1;\r
+    }\r
+    if (int_cb != NULL) {\r
+        ret = request_irq(irq_pin_node->irq, tiot_board_gpio_irq_callback,\r
+                          irq_pin_node->irq_flags, NULL, irq_pin_node);\r
+        if (ret < 0) {\r
+            printk("gpio index [%d] irq request fail ret = %d\n", pin, ret);\r
+            return -1;\r
+        }\r
+        /* 默认先关闭中断,需要时再开启 */\r
+        disable_irq_nosync(irq_pin_node->irq);\r
+    } else {\r
+        free_irq(irq_pin_node->irq, irq_pin_node);\r
+    }\r
+    return 0;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_uart_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_uart_port.c
new file mode 100644 (file)
index 0000000..df469ae
--- /dev/null
@@ -0,0 +1,205 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Demo board UART port\n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_log.h"\r
+#include "securec.h"\r
+\r
+#include <linux/tty.h>\r
+#include <linux/platform_device.h>\r
+\r
+#define TTY_LDISC_MAGIC    0x5403\r
+\r
+#define TIOT_TTY_RX_ROOM   1024U\r
+\r
+#define TTY_SENT_WAIT_MS   100U\r
+\r
+typedef struct {\r
+    tiot_xmit_callbacks cbs;\r
+} tiot_tty_ctrl;\r
+\r
+static tiot_tty_ctrl g_tiot_tty_ctrl = { 0 };\r
+\r
+static int32_t tiot_tty_ldisc_open(struct tty_struct *tty);\r
+static void tiot_tty_ldisc_close(struct tty_struct *tty);\r
+static void tiot_tty_ldisc_receive(struct tty_struct *tty, const uint8_t *data, char *tty_flags, int32_t count);\r
+\r
+/* 使用内核未使用的LDISC */\r
+#define N_HW_TIOT           (NR_LDISCS - 1)\r
+static struct tty_ldisc_ops g_tiot_ldisc_ops = {\r
+    .magic = TTY_LDISC_MAGIC,\r
+    .name = "n_tiot", /* 必须以n_开头 */\r
+    .open = tiot_tty_ldisc_open,\r
+    .close = tiot_tty_ldisc_close,\r
+    .receive_buf = tiot_tty_ldisc_receive,\r
+    .owner = THIS_MODULE\r
+};\r
+\r
+static int32_t tiot_tty_ldisc_open(struct tty_struct *tty)\r
+{\r
+    tiot_print_info("%s enter\n", __func__);\r
+    tty->receive_room = TIOT_TTY_RX_ROOM;\r
+\r
+    /* Flush any pending characters in the driver and discipline. */\r
+    tty_ldisc_flush(tty);\r
+    tty_driver_flush_buffer(tty);\r
+    return 0;\r
+}\r
+\r
+static void tiot_tty_ldisc_close(struct tty_struct *tty)\r
+{\r
+    tiot_print_info("%s: entered\n", __func__);\r
+\r
+    if (tty->disc_data == NULL) {\r
+        tiot_print_err("tty or tty->disc_data is NULL\n");\r
+        return;\r
+    }\r
+\r
+    /* Flush any pending characters in the driver and discipline. */\r
+    tty_ldisc_flush(tty);\r
+    tty_driver_flush_buffer(tty);\r
+\r
+    tiot_print_info("tty close done!\n");\r
+}\r
+\r
+static void tiot_tty_ldisc_receive(struct tty_struct *tty, const uint8_t *data, char *tty_flags, int32_t count)\r
+{\r
+    if (data == NULL || count < 0) {\r
+        return;\r
+    }\r
+\r
+    tiot_xmit *xmit = tty->disc_data;\r
+    if (g_tiot_tty_ctrl.cbs.rx_notify) {\r
+        g_tiot_tty_ctrl.cbs.rx_notify(xmit, (uint8_t *)data, count);\r
+    }\r
+}\r
+\r
+int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cb)\r
+{\r
+    struct tty_struct *tty = NULL;\r
+    int ret;\r
+    dev_t dev_no;\r
+\r
+    tiot_print_info("%s\n", __func__);\r
+    ret = tty_dev_name_to_number((const char *)xmit->id, &dev_no);\r
+    if (ret != 0) {\r
+        tiot_print_err("can't found tty:%s ret=%d\n", (const char *)xmit->id, ret);\r
+        return -ENODEV;\r
+    }\r
+ \r
+    /* open tty */\r
+    tty = tty_kopen(dev_no);\r
+    if (!tty || IS_ERR(tty)) {\r
+        tiot_print_err("open tty %x failed ret=%d\n", dev_no, PTR_ERR_OR_ZERO(tty));\r
+        return -ENODEV;\r
+    }\r
+\r
+    if (tty->ops->open) {\r
+        ret = tty->ops->open(tty, NULL);\r
+    } else {\r
+        tiot_print_err("tty->ops->open is NULL\n");\r
+        ret = -ENODEV;\r
+    }\r
+\r
+    if (ret) {\r
+        tty_unlock(tty);\r
+        xmit->handle = NULL;\r
+        return ret;\r
+    }\r
+\r
+    /* 打开后再配置波特率 */\r
+    tty_unlock(tty);\r
+    /* 先注册ldisc再set ldisc */\r
+    tty_register_ldisc(N_HW_TIOT, &g_tiot_ldisc_ops);\r
+    tty_set_ldisc(tty, N_HW_TIOT);\r
+    /* set ldisc前可能tty已设置ldisc,释放旧ldisc时会同时释放disc_data, 必须在set ldisc后再设置tty->disc_data */\r
+    xmit->handle = tty;\r
+    tty->disc_data = xmit;\r
+    if (!g_tiot_tty_ctrl.cbs.rx_notify) {\r
+        g_tiot_tty_ctrl.cbs.rx_notify = cb->rx_notify;\r
+    }\r
+    return 0;\r
+}\r
+\r
+void tiot_board_uart_close(tiot_xmit *xmit)\r
+{\r
+    /* close tty */\r
+    struct tty_struct *tty =  (struct tty_struct *)xmit->handle;\r
+\r
+    tiot_print_info("%s\n", __func__);\r
+\r
+    /* close tty */\r
+    if (tty == NULL) {\r
+        tiot_print_err("tty is null, ignore\n");\r
+        return;\r
+    }\r
+\r
+    tty_lock(tty);\r
+    if (tty->ops->close) {\r
+        tty->ops->close(tty, NULL);\r
+    } else {\r
+        tiot_print_warning("tty->ops->close is null\n");\r
+    }\r
+    tty_unlock(tty);\r
+    tty_kclose(tty);\r
+    tty_unregister_ldisc(N_HW_TIOT);\r
+    (void)memset_s(&g_tiot_tty_ctrl, sizeof(tiot_tty_ctrl), 0, sizeof(tiot_tty_ctrl));\r
+}\r
+\r
+int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len)\r
+{\r
+    /* 异步接口,但是设置波特率前会自动flush */\r
+    struct tty_struct *tty = (struct tty_struct *)xmit->handle;\r
+    return tty->ops->write(tty, buff, len);\r
+}\r
+\r
+int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len)\r
+{\r
+    /* 内核tty无同步读取接口,只通过回调接收 */\r
+    return -1;\r
+}\r
+\r
+int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config)\r
+{\r
+    struct tty_struct *tty = (struct tty_struct *)xmit->handle;\r
+    tiot_uart_config *uart_config = config;\r
+    struct ktermios ktermios;\r
+\r
+    ktermios = tty->termios;\r
+    /* close soft flowctrl */\r
+    ktermios.c_iflag &= ~IXON;\r
+\r
+    /* set uart cts/rts flowctrl */\r
+    ktermios.c_cflag &= ~CRTSCTS;\r
+    /* on to ignore modem status change */\r
+    ktermios.c_cflag |= CLOCAL;\r
+    if (uart_config->attr.flow_ctrl == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) {\r
+        ktermios.c_cflag |= CRTSCTS;\r
+        /* off to respect modem status change */\r
+        ktermios.c_cflag &= ~CLOCAL;\r
+    }\r
+\r
+    /* set csize */\r
+    ktermios.c_cflag &= ~(CSIZE);\r
+    ktermios.c_cflag |= CS8;\r
+\r
+    /* set uart baudrate */\r
+    ktermios.c_cflag &= ~CBAUD;\r
+    ktermios.c_cflag |= BOTHER;\r
+\r
+    /* close parity */\r
+    ktermios.c_iflag &= ~INPCK;\r
+    ktermios.c_cflag &= ~PARENB;\r
+    ktermios.c_cflag &= ~PARODD;\r
+    tty_termios_encode_baud_rate(&ktermios, uart_config->baudrate, uart_config->baudrate);\r
+\r
+    /* UART硬件fifo清空后才能切换UART配置,通过tty_wait_until_sent等待 */\r
+    tty_wait_until_sent(tty, TTY_SENT_WAIT_MS);\r
+    tty_set_termios(tty, &ktermios);\r
+    return 0;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_dts_node.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_dts_node.h
new file mode 100644 (file)
index 0000000..f1eb5f4
--- /dev/null
@@ -0,0 +1,50 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ *\r
+ * Description: dts nodes. \n\r
+ *\r
+ * History: \n\r
+ * 2024-02-21, Create file. \n\r
+ */\r
+#ifndef TIOT_DTS_NODE_H\r
+#define TIOT_DTS_NODE_H\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+tiot {                                                   // 总节点名\r
+    compatible = "tiot";                                 // 匹配名,不可修改\r
+    gn71 {                                               // 子节点名,gn71, 对应tiot_service_open参数\r
+        compatible = "tiot,gnss";                        // 匹配名,与对应device匹配,不可修改\r
+        tiot,misc-dev-name = "gn71";                     // 默认设备节点名,可自定义\r
+        tiot,tty-dev-name = "ttyXXXN";                   // 使用的tty设备节点名\r
+        tiot,power-on-gpio = <xxx>;                      // power on gpio管脚\r
+        tiot,wake-out-gpio = <xxx>;                      // 唤醒对端 gpio管脚\r
+        tiot,wake-in-gpio = <xxx>;                       // 被唤醒 gpio管脚\r
+        tiot,cfg-path = "/path/to/cfg/xxx_cfg.bin";      // 固件文件完整路径(包含文件名)\r
+    };\r
+};\r
+*/\r
+\r
+#define DTS_NODE_TIOT               "tiot"\r
+\r
+#define DTS_PROP_MISC_DEV_NAME      "tiot,misc-dev-name"\r
+\r
+#define DTS_PROP_TTY_DEV_NAME       "tiot,tty-dev-name"\r
+#define DTS_PROP_GPIO_POWEN_ON      "tiot,power-on-gpio"\r
+#define DTS_PROP_GPIO_WAKEOUT       "tiot,wake-out-gpio"\r
+#define DTS_PROP_GPIO_WAKEIN        "tiot,wake-in-gpio"\r
+\r
+#define DTS_PROP_CFG_PATH           "tiot,cfg-path"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_osal_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_osal_port.c
new file mode 100644 (file)
index 0000000..d769250
--- /dev/null
@@ -0,0 +1,363 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ *\r
+ * Description: kernel osal port demo. \n\r
+ *\r
+ * History: \n\r
+ * 2024-01-04, Create file. \n\r
+ */\r
+\r
+#include <linux/kernel.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/version.h>\r
+#include <linux/delay.h>\r
+#include <linux/slab.h>\r
+#include <linux/spinlock.h>\r
+#include <linux/mutex.h>\r
+#include <linux/wait.h>\r
+#include <linux/fs.h>\r
+#include <linux/kthread.h>\r
+#include <linux/version.h>\r
+#include "tiot_osal.h"\r
+\r
+unsigned long osal_msleep(unsigned int msecs)\r
+{\r
+    return msleep_interruptible(msecs);\r
+}\r
+\r
+static unsigned int osal_convert_gfp_flag(unsigned int osal_gfp_flag)\r
+{\r
+    unsigned int gfp_flag = 0;\r
+\r
+    if (osal_gfp_flag & OSAL_GFP_KERNEL) {\r
+        gfp_flag = GFP_KERNEL;\r
+    } else if (osal_gfp_flag & OSAL_GFP_ATOMIC) {\r
+        gfp_flag = GFP_ATOMIC;\r
+    } else if (osal_gfp_flag & OSAL_GFP_DMA) {\r
+        gfp_flag = GFP_DMA;\r
+    } else {\r
+        gfp_flag = GFP_KERNEL;\r
+    }\r
+\r
+    if (osal_gfp_flag & OSAL_GFP_ZERO) {\r
+        gfp_flag |= __GFP_ZERO;\r
+    }\r
+    return gfp_flag;\r
+}\r
+\r
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag)\r
+{\r
+    unsigned int gfp_flag = osal_convert_gfp_flag(osal_gfp_flag);\r
+    return kmalloc(size, gfp_flag);\r
+}\r
+\r
+void osal_kfree(void *addr)\r
+{\r
+    if (addr != NULL) {\r
+        kfree(addr);\r
+    }\r
+}\r
+\r
+int osal_spin_lock_init(osal_spinlock *lock)\r
+{\r
+    spinlock_t *p = NULL;\r
+\r
+    if (lock == NULL || lock->lock != NULL) {\r
+        printk("parameter invalid!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+    p = (spinlock_t *)kmalloc(sizeof(spinlock_t), GFP_KERNEL); // 8 is malloc size\r
+    if (p == NULL) {\r
+        printk("kmalloc error!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+    spin_lock_init(p);\r
+    lock->lock = p;\r
+    return OSAL_SUCCESS;\r
+}\r
+\r
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags)\r
+{\r
+    spinlock_t *p = NULL;\r
+    unsigned long f;\r
+\r
+    if ((lock == NULL) || (flags == NULL) || (lock->lock == NULL)) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+\r
+    p = (spinlock_t *)(lock->lock);\r
+    spin_lock_irqsave(p, f);\r
+\r
+    *flags = f;\r
+}\r
+\r
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags)\r
+{\r
+    spinlock_t *p = NULL;\r
+\r
+    if ((lock == NULL) || (flags == NULL) || (lock->lock == NULL)) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+\r
+    p = (spinlock_t *)(lock->lock);\r
+    spin_unlock_irqrestore(p, *flags);\r
+}\r
+\r
+void osal_spin_lock_destroy(osal_spinlock *lock)\r
+{\r
+    spinlock_t *p = NULL;\r
+\r
+    if (lock == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+\r
+    p = (spinlock_t *)(lock->lock);\r
+    kfree(p);\r
+    lock->lock = NULL;\r
+}\r
+\r
+int osal_mutex_init(osal_mutex *mutex)\r
+{\r
+    struct mutex *p = NULL;\r
+\r
+    if (mutex == NULL || mutex->mutex != NULL) {\r
+        printk("parameter invalid!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    p = kmalloc(sizeof(struct mutex), GFP_KERNEL);\r
+    if (p == NULL) {\r
+        printk("kmalloc error!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    mutex_init(p);\r
+    mutex->mutex = p;\r
+\r
+    return OSAL_SUCCESS;\r
+}\r
+\r
+int osal_mutex_lock(osal_mutex *mutex)\r
+{\r
+    struct mutex *p = NULL;\r
+\r
+    if (mutex == NULL || mutex->mutex == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    p = (struct mutex *)(mutex->mutex);\r
+    mutex_lock(p);\r
+\r
+    return OSAL_SUCCESS;\r
+}\r
+\r
+void osal_mutex_unlock(osal_mutex *mutex)\r
+{\r
+    struct mutex *p = NULL;\r
+\r
+    if (mutex == NULL || mutex->mutex == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+\r
+    p = (struct mutex *)(mutex->mutex);\r
+\r
+    mutex_unlock(p);\r
+}\r
+\r
+void osal_mutex_destroy(osal_mutex *mutex)\r
+{\r
+    struct mutex *p = NULL;\r
+\r
+    if (mutex == NULL || mutex->mutex == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+    p = (struct mutex *)(mutex->mutex);\r
+    kfree(p);\r
+    mutex->mutex = NULL;\r
+}\r
+\r
+int osal_wait_init(osal_wait *wait)\r
+{\r
+    wait_queue_head_t *wq = NULL;\r
+    if (wait == NULL || wait->wait != NULL) {\r
+        printk("parameter invalid!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+    wq = (wait_queue_head_t *)kmalloc(sizeof(wait_queue_head_t), GFP_ATOMIC);\r
+    if (wq == NULL) {\r
+        printk("kmalloc error!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+    init_waitqueue_head(wq);\r
+    wait->wait = wq;\r
+    return OSAL_SUCCESS;\r
+}\r
+\r
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,\r
+    unsigned long ms)\r
+{\r
+    wait_queue_head_t *wq = NULL;\r
+\r
+    if (wait == NULL || wait->wait == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    wq = (wait_queue_head_t *)(wait->wait);\r
+\r
+    if (func == NULL) {\r
+        return wait_event_interruptible_timeout((*wq), OSAL_WAIT_CONDITION_TRUE, msecs_to_jiffies(ms));\r
+    }\r
+\r
+    return wait_event_interruptible_timeout((*wq), func(param), msecs_to_jiffies(ms));\r
+}\r
+\r
+void osal_wait_wakeup_interruptible(osal_wait *wait)\r
+{\r
+    wait_queue_head_t *wq = NULL;\r
+\r
+    if (wait == NULL || wait->wait == NULL) {\r
+        printk("wait is NULL!\n");\r
+        return;\r
+    }\r
+\r
+    wq = (wait_queue_head_t *)(wait->wait);\r
+\r
+    wake_up_interruptible(wq);\r
+}\r
+\r
+void osal_wait_destroy(osal_wait *wait)\r
+{\r
+    wait_queue_head_t *wq = NULL;\r
+\r
+    if (wait == NULL || wait->wait == NULL) {\r
+        printk("wait is NULL!\n");\r
+        return;\r
+    }\r
+\r
+    wq = (wait_queue_head_t *)(wait->wait);\r
+    kfree(wq);\r
+    wait->wait = NULL;\r
+}\r
+\r
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK\r
+/* 不需要发送线程可不实现。 */\r
+osal_task *osal_kthread_create(osal_kthread_handler handler, void *data, const char *name, unsigned int stack_size)\r
+{\r
+    struct task_struct *k = NULL;\r
+    osal_task *p = NULL;\r
+\r
+    if (handler == NULL) {\r
+        printk("task handler is null!\n");\r
+        return NULL;\r
+    }\r
+\r
+    p = (osal_task *)kzalloc(sizeof(osal_task), GFP_KERNEL);\r
+    if (p == NULL) {\r
+        printk("kmalloc error!\n");\r
+        return NULL;\r
+    }\r
+\r
+    k = kthread_run(handler, data, name);\r
+    if (IS_ERR(k)) {\r
+        printk("kthread create error! k = %#x!\n", k);\r
+        kfree(p);\r
+        p = NULL;\r
+        return NULL;\r
+    }\r
+    p->task = k;\r
+    return p;\r
+}\r
+\r
+void osal_kthread_destroy(osal_task *task, unsigned int stop_flag)\r
+{\r
+    if (task == NULL || task->task == NULL) {\r
+        printk("parameter invalid!\n");\r
+        return;\r
+    }\r
+    /* note: When you call the Kthread_stop function, the thread function cannot be finished, otherwise it will oops. */\r
+    if (stop_flag != 0 && task->task != NULL) {\r
+        kthread_stop((struct task_struct *)(task->task));\r
+    }\r
+    task->task = NULL;\r
+    kfree(task);\r
+}\r
+#endif\r
+\r
+#ifndef CONFIG_FILE_BY_ARRAY\r
+static struct file *klib_fopen(const char *file, int flags, int mode)\r
+{\r
+    struct file *filp = filp_open(file, flags, mode);\r
+    return (IS_ERR(filp)) ? NULL : filp;\r
+}\r
+\r
+static void klib_fclose(struct file *filp)\r
+{\r
+    if (filp != NULL) {\r
+        filp_close(filp, NULL);\r
+    }\r
+    return;\r
+}\r
+\r
+static int klib_fread(char *buf, unsigned long size, struct file *filp)\r
+{\r
+    int readlen;\r
+    readlen = kernel_read(filp, buf, size, &filp->f_pos);\r
+    return readlen;\r
+}\r
+\r
+void *osal_klib_fopen(const char *file, int flags, int mode)\r
+{\r
+    if (file == NULL) {\r
+        printk("file NULL!\n");\r
+        return NULL;\r
+    }\r
+\r
+    return (void *)klib_fopen(file, flags, mode);\r
+}\r
+\r
+void osal_klib_fclose(void *filp)\r
+{\r
+    if (filp == NULL) {\r
+        printk("filp NULL!\n");\r
+        return;\r
+    }\r
+\r
+    klib_fclose((struct file *)filp);\r
+}\r
+\r
+int osal_klib_fread(char *buf, unsigned long size, void *filp)\r
+{\r
+    if ((buf == NULL) || (filp == NULL)) {\r
+        printk("buf&filp NULL!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    return klib_fread(buf, size, (struct file *)filp);\r
+}\r
+\r
+int osal_klib_fseek(long long offset, int whence, void *filp)\r
+{\r
+    int ret;\r
+    loff_t res;\r
+\r
+    if (filp == NULL) {\r
+        printk("filp NULL!\n");\r
+        return OSAL_FAILURE;\r
+    }\r
+\r
+    res = vfs_llseek(filp, offset, whence);\r
+    ret = (int)res;\r
+    if (res != (loff_t)ret) {\r
+        ret = OSAL_EOVERFLOW;\r
+    }\r
+\r
+    return ret;\r
+}\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/gnss_board_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/gnss_board_port.c
new file mode 100644 (file)
index 0000000..0a4d2b4
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: GNSS board port. \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+
+#include "gnss_board_port.h"
+#include "tiot_board_pin_port.h"
+
+/* 根据板级MCU与GNSS两个芯片的硬件连接修改适配 */
+/* 1. MCU芯片连接到GNSS芯片的UART bus编号, 如UART_ID_0. */
+/* 2. MCU芯片连接到GNSS芯片PWREN管脚号,如GPIO_ID_10。必须. */
+/* 3. MCU芯片连接到GNSS芯片GPIO9(host唤醒gnss)管脚号,如GPIO_ID_11。
+      可选,如果未连接此管脚,必须设为TIOT_PIN_NONE宏. */
+/* 4. MCU芯片连接到GNSS芯片GPIO7(gnss唤醒host)管脚号,如GPIO_ID_12。
+      可选,如果未连接此管脚,必须设为TIOT_PIN_NONE宏. */
+const static gnss_board_hw_info g_gnss_board_hw_info = { UART_ID_0, { GPIO_ID_10, GPIO_ID_11, GPIO_ID_12 }};
+
+const static gnss_board_info g_gnss_board_info = {
+    .cfg_path = NULL,                  /* 如果有文件系统,指向gnss加载配置文件完整路径/相对路径
+                                          例如:linux下"/sys/xxx/xxx/xxx_config.bin",
+                                          windows下".\\config_file_path\\xxx_config.bin"
+                                          如果无文件系统,设为NULL. */
+    .hw_infos = &g_gnss_board_hw_info
+};
+
+const gnss_board_info *gnss_board_get_info(void)
+{
+    return &g_gnss_board_info;
+}
+
+/* gnss板级UART、管脚初始化接口 */
+int32_t gnss_board_init(void *param)
+{
+    (void)param;
+    /* 板级管脚初始化 demo */
+    /* 如果在打开gnss前,在统一板级初始化流程内已完成板级硬件初始化配置,此处可不实现,直接返回. */
+    const uint32_t *gnss_pins = g_gnss_board_hw_info.pm_info;
+
+    /* 按实际板机管脚接口设置对应管脚初始配置. */
+    board_pin_init(gnss_pins[gnss_PIN_POWER_CTRL], PINMUX_GPIO, PIN_PULL_DOWN, PIN_LEVEL_LOW,
+                   PIN_DIRECTION_OUTPUT);
+    board_pin_init(gnss_pins[gnss_PIN_HOST_WAKEUP_DEVICE], PINMUX_GPIO, PIN_PULL_DOWN, PIN_LEVEL_LOW,
+                   PIN_DIRECTION_OUTPUT);
+    board_pin_init(gnss_pins[gnss_PIN_DEVICE_WAKEUP_HOST], PINMUX_GPIO, PIN_PULL_DOWN, PIN_LEVEL_LOW,
+                   PIN_DIRECTION_INPUT);
+
+    /* 板级UART管脚初始化 demo */
+    board_uart_pinmux_init(g_gnss_board_hw_info.xmit_id);
+    return 0;
+}
+
+void gnss_board_deinit(void *param)
+{
+    (void)param;
+    /* 板级管脚去初始化 demo,关闭gnss功能时被调用,可在此处恢复板级管脚原本配置,如果不需要,则空实现即可. */
+    const uint32_t *gnss_pins = g_gnss_board_hw_info.pm_info;
+    board_pin_restore(gnss_pins[gnss_PIN_POWER_CTRL]);
+    board_pin_restore(gnss_pins[gnss_PIN_HOST_WAKEUP_DEVICE]);
+    board_pin_restore(gnss_pins[gnss_PIN_DEVICE_WAKEUP_HOST]);
+
+    /* 板级UART管脚去初始化 demo */
+    board_uart_pinmux_restore(g_gnss_board_hw_info.xmit_id);
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_log_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_log_port.h
new file mode 100644 (file)
index 0000000..3a9e604
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board log port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-05-06, Create file. \n\r
+ */\r
+#ifndef BOARD_LOG_PORT_H\r
+#define BOARD_LOG_PORT_H\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_board_port_log LOG port\r
+ * @ingroup  tiot_board_port\r
+ * @{\r
+ */\r
+\r
+#define TIOT_LOG_ALERT    0   /*!< Log level alert. */\r
+#define TIOT_LOG_ERR      1   /*!< Log level error. */\r
+#define TIOT_LOG_WARNING  2   /*!< Log level warning. */\r
+#define TIOT_LOG_INFO     3   /*!< Log level info. */\r
+#define TIOT_LOG_DEBUG    4   /*!< Log level debug. */\r
+\r
+#define TIOT_BOARD_LOG_LEVEL  TIOT_LOG_INFO    /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */\r
+\r
+/* 适配板级格式化日志接口 */\r
+#define BOARD_PRINT_FUNCTION_NAME           board_log_with_format("%s\r\n", __func__)\r
+#define board_print_dbg(s, args...)         board_log_with_format(s, ##args)\r
+#define board_print_info(s, args...)        board_log_with_format(s, ##args)\r
+#define board_print_info(s, args...)        board_log_with_format(s, ##args)\r
+#define board_print_suc(s, args...)         board_log_with_format(s, ##args)\r
+#define board_print_warning(s, args...)     board_log_with_format(s, ##args)\r
+#define board_print_err(s, args...)         board_log_with_format(s, ##args)\r
+#define board_print_alter(s, args...)       board_log_with_format(s, ##args)\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_misc_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_misc_port.c
new file mode 100644 (file)
index 0000000..4532ba6
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Board misc port. \n
+ *
+ * History: \n
+ * 2023-12-07, Create file. \n
+ */
+#include "tiot_board_misc_port.h"
+
+int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock)
+{
+    /* 板级唤醒锁初始化接口。 */
+    /* 如果板级不睡眠或仅进入wfi(不关闭通信接口),实现为空函数即可。 */
+    tiot_unused(lock);
+    return 0;
+}
+
+void tiot_board_wake_lock(tiot_board_wakelock *lock)
+{
+    /* 板级唤醒加锁接口。 */
+    /* 如果板级不睡眠或仅进入wfi(不关闭通信接口),实现为空函数即可。 */
+    tiot_unused(lock);
+}
+
+void tiot_board_wake_unlock(tiot_board_wakelock *lock)
+{
+    /* 板级唤醒解锁接口。 */
+    /* 如果板级不睡眠或仅进入wfi(不关闭通信接口),实现为空函数即可。 */
+    tiot_unused(lock);
+}
+
+void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock)
+{
+    /* 板级唤醒锁销毁接口。 */
+    /* 如果板级不睡眠或仅进入wfi(不关闭通信接口),实现为空函数即可。 */
+    tiot_unused(lock);
+}
+
+void tiot_board_udelay(uint32_t us)
+{
+    /* 按板级微秒级delay接口适配. */
+    delay_us(us);
+    /* 如果板级没有微秒级delay接口,可使用循环代替实现. */
+#define LOOP_COUNT_FOR_USECOND  xxx   /* 1微秒循环次数, 依赖CPU频率. */
+    int count = 0;
+    for (uint32_t i = 0; i < us; i++) {
+        while (count < LOOP_COUNT_FOR_USECOND) {
+            count++;
+        }
+    }
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_pin_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_pin_port.c
new file mode 100644 (file)
index 0000000..0cee236
--- /dev/null
@@ -0,0 +1,69 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board PIN port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-04-20, Create file. \n\r
+ */\r
+#include "tiot_board_pin_port.h"\r
+\r
+#define err2ret(errcode)      (((errcode) == ERRCODE_SUCC) ? 0 : -1)\r
+\r
+static tiot_pin_int_callback g_tiot_gpio_callback = NULL;\r
+\r
+int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level)\r
+{\r
+    errcode_t errcode;\r
+    uint32_t gpio_level = level == TIOT_PIN_LEVEL_LOW ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH;\r
+    errcode = board_gpio_set_level(pin, gpio_level);\r
+    return err2ret(errcode);\r
+}\r
+\r
+int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level)\r
+{\r
+    uint32_t gpio_level = board_gpio_get_level(pin);\r
+    *level = (gpio_level == GPIO_LEVEL_LOW) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH;\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable)\r
+{\r
+    errcode_t errcode;\r
+    if (int_enable == TIOT_PIN_INT_ENABLE) {\r
+        errcode = board_gpio_enable_interrupt(pin);\r
+    } else {\r
+        errcode = board_gpio_disable_interrupt(pin);\r
+    }\r
+    return err2ret(errcode);\r
+}\r
+\r
+/* 必须向回调内传入触发中断的管脚id. */\r
+static void board_gpio_callback_adapter(uint32_t pin, uintptr_t param)\r
+{\r
+    (void)param;\r
+    board_gpio_clear_interrupt(pin);\r
+    if (g_tiot_gpio_callback != NULL) {\r
+        g_tiot_gpio_callback(pin);\r
+    }\r
+}\r
+\r
+int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb)\r
+{\r
+    /* 仅GNSS唤醒板级管脚使用此接口,必须为上升沿中断. */\r
+    errcode_t errcode;\r
+    if (int_cb != NULL) {\r
+        errcode = board_gpio_register_isr_func((pin_t)pin,\r
+                                               GPIO_INTERRUPT_RISING_EDGE,\r
+                                               board_gpio_callback_adapter);\r
+    } else {\r
+        errcode = board_gpio_unregister_isr_func((pin_t)pin);\r
+    }\r
+\r
+    if (errcode == ERRCODE_SUCC) {\r
+        if (g_tiot_gpio_callback == NULL) {\r
+            g_tiot_gpio_callback = int_cb;\r
+        }\r
+    }\r
+    return err2ret(errcode);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_uart_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_uart_port.c
new file mode 100644 (file)
index 0000000..1980af3
--- /dev/null
@@ -0,0 +1,146 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board UART port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_log.h"\r
+\r
+/* 记录xmit指针,用于板级回调无法传入指针情况. */\r
+static tiot_xmit *g_tiot_uart_xmit_backup;\r
+\r
+static tiot_xmit_callbacks g_tiot_uart_rx_cbs;\r
+\r
+/* 板级回调内向驱动回调传入UART接收到的数据. */\r
+static void tiot_uart_rx_callback_demo(const void *buff, uint16_t length)\r
+{\r
+    /* 必须传入xmit指针,此处使用open时备份值. */\r
+    g_tiot_uart_rx_cbs.rx_notify(g_tiot_uart_xmit_backup, (uint8_t *)buff, length);\r
+}\r
+\r
+static void tiot_uart_rx_callback_demo2(const void *ptr, const void *buff, uint16_t length)\r
+{\r
+    /* 必须传入xmit指针,此处板级回调接口传入值. */\r
+    g_tiot_uart_rx_cbs.rx_notify(ptr, (uint8_t *)buff, length);\r
+}\r
+\r
+int32_t tiot_board_uart_open_demo(tiot_xmit *xmit, tiot_xmit_callbacks *cbs)\r
+{\r
+    /* xmit->id即为板级信息配置的UART id, 可按板级接口需要转为 其他区分UART通道方式. */\r
+    errcode_t ret = board_uart_open(xmit->id);\r
+    if (ret != ERRCODE_SUCC) {\r
+        return -1;\r
+    }\r
+    g_tiot_uart_rx_cbs = *cbs;\r
+    /* 记录xmit指针,用于板级回调无法传入指针情况. */\r
+    g_tiot_uart_xmit_backup = xmit;\r
+    board_uart_register_rx_callback(xmit->id, tiot_uart_rx_callback_demo);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_uart_open_demo2(tiot_xmit *xmit, tiot_xmit_callbacks *cbs)\r
+{\r
+    /* xmit->id即为板级信息配置的UART id, 可按板级接口需要转为 其他区分UART通道方式. */\r
+    board_uart_handle *handle = board_uart_open_as_handle(xmit->id);\r
+    if (handle == NULL) {\r
+        return -1;\r
+    }\r
+    g_tiot_uart_rx_cbs = *cbs;\r
+    xmit->handle = handle;\r
+    /* 板级注册回调可传入指针情况. */\r
+    board_uart_register_rx_callback_withptr(xmit->id, tiot_uart_rx_callback_demo2, xmit);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs)\r
+{\r
+    return tiot_board_uart_open_demo(xmit, cbs);\r
+}\r
+\r
+void tiot_board_uart_close(tiot_xmit *xmit)\r
+{\r
+    board_uart_unregister_rx_callback(xmit->id);\r
+    board_uart_close(xmit->id);\r
+}\r
+\r
+int32_t tiot_board_uart_write_demo2(tiot_xmit *xmit, const uint8_t *buff, uint32_t len)\r
+{\r
+    if (xmit->handle == NULL) {\r
+        return -1;\r
+    }\r
+    return board_uart_write(xmit->handle, buff, len);\r
+}\r
+\r
+int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len)\r
+{\r
+    return board_uart_write(xmit->id, buff, len);\r
+}\r
+\r
+int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len)\r
+{\r
+    /* 如果通过回调方式将UART接收数据传入驱动回调,此接口可空实现. */\r
+    return board_uart_read(xmit->id, buff, len);\r
+}\r
+\r
+int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config)\r
+{\r
+    /* TIOT UART接口使用的UART配置枚举定义可能和板级定义不同, 在配置时可以进行转换. */\r
+    const uint8_t board_uart_data_bits_map[TIOT_UART_ATTR_DATABIT_BUTT] = {\r
+        BOARD_UART_DATA_BIT_8,\r
+        BOARD_UART_DATA_BIT_7,\r
+        BOARD_UART_DATA_BIT_6,\r
+        BOARD_UART_DATA_BIT_5\r
+    };\r
+    const uint8_t board_uart_stop_bits_map[TIOT_UART_ATTR_STOPBIT_BUTT] = {\r
+        BOARD_UART_STOP_BIT_1,\r
+        BOARD_UART_STOP_BIT_2 + 1,   /* Invalid stop bits. */\r
+        BOARD_UART_STOP_BIT_2\r
+    };\r
+    const uint8_t board_uart_parity_map[TIOT_UART_ATTR_PARITY_BUTT] = {\r
+        BOARD_UART_PARITY_NONE,\r
+        BOARD_UART_PARITY_ODD,\r
+        BOARD_UART_PARITY_EVEN,\r
+        BOARD_UART_PARITY_EVEN + 1,   /* Invalid parity bits. */\r
+        BOARD_UART_PARITY_EVEN + 1    /* Invalid parity bits. */\r
+    };\r
+    errcode_t ret;\r
+    if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) ||\r
+        (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) ||\r
+        (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) {\r
+        return -1;\r
+    }\r
+    /* 切换UART配置时,必须确保切换配置前的UART数据已从FIFO发送完成. */\r
+    while (board_uart_has_pending_transmissions(xmit->id) == true) {;}\r
+\r
+    board_uart_cfg_t cfg = { config->baudrate,\r
+                             board_uart_data_bits_map[config->attr.data_bits],\r
+                             board_uart_stop_bits_map[config->attr.stop_bits],\r
+                             board_uart_parity_map[config->attr.parity],\r
+                             config->attr.flow_ctrl };\r
+    ret = board_uart_set_config(xmit->id, &cfg);\r
+    return (ret == ERRCODE_SUCC) ? 0 : -1;\r
+}\r
+\r
+/* GNSS UART固定使用 data_bit=8, stop_bit=1, parity=None. */\r
+int32_t tiot_board_uart_set_config_simple(tiot_xmit *xmit, tiot_uart_config *config)\r
+{\r
+    errcode_t ret;\r
+    if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) ||\r
+        (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) ||\r
+        (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) {\r
+        return -1;\r
+    }\r
+    /* 切换UART配置时,必须确保切换配置前的UART数据已从FIFO发送完成. */\r
+    while (board_uart_has_pending_transmissions(xmit->id) == true) {;}\r
+\r
+    board_uart_cfg_t cfg = { config->baudrate,\r
+                             BOARD_UART_DATA_BIT_8,\r
+                             BOARD_UART_STOP_BIT_1,\r
+                             BOARD_UART_PARITY_NONE,\r
+                             config->attr.flow_ctrl };\r
+    ret = board_uart_set_config(xmit->id, &cfg);\r
+    return (ret == ERRCODE_SUCC) ? 0 : -1;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_freertos_demo.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_freertos_demo.c
new file mode 100644 (file)
index 0000000..318cc81
--- /dev/null
@@ -0,0 +1,312 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: FreeRTOS osal port demo. \n
+ *
+ * History: \n
+ * 2023-10-23, Create file. \n
+ */
+
+#include "tiot_osal.h"
+
+#include <unistd.h>
+#include "FreeRTOS.h"
+#include "portable.h"
+#include "task.h"
+#include "hwi.h"
+#include "semphr.h"
+#include "event_groups.h"
+#include "poll_adapt.h"
+
+unsigned long osal_msleep(unsigned int msecs)
+{
+    vTaskDelay(pdMS_TO_TICKS(msecs));
+    return OSAL_SUCCESS;
+}
+
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag)
+{
+    tiot_unused(osal_gfp_flag);
+    return pvPortMalloc(size);
+}
+
+void osal_kfree(void *addr)
+{
+    vPortFree(addr);
+}
+
+int osal_spin_lock_init(osal_spinlock *lock)
+{
+    RTOS_SpinInit((spinlock_t *)lock);
+    return OSAL_SUCCESS;
+}
+
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags)
+{
+    if (flags == NULL) {
+        return;
+    }
+    tiot_unused(lock);
+    *flags = (unsigned long)uxHwiLock();
+}
+
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags)
+{
+    if (flags == NULL) {
+        return;
+    }
+    tiot_unused(lock);
+    vHwiRestore(*flags);
+}
+
+void osal_spin_lock_destroy(osal_spinlock *lock)
+{
+    tiot_unused(lock);
+}
+
+int osal_mutex_init(osal_mutex *mutex)
+{
+    if (mutex == NULL || mutex->mutex != NULL) {
+        return OSAL_FAILURE;
+    }
+    #if defined(configUSE_RECURSIVE_MUTEXES) && (configUSE_RECURSIVE_MUTEXES == 1)
+    SemaphoreHandle_t handle = xSemaphoreCreateRecursiveMutex();
+    #else
+    SemaphoreHandle_t handle = xSemaphoreCreateMutex();
+    #endif
+    if (handle == NULL) {
+        return OSAL_FAILURE;
+    }
+    mutex->mutex = handle;
+    vQueueAddToRegistry(handle, "Mutex");
+    return OSAL_SUCCESS;
+}
+
+int osal_mutex_lock(osal_mutex *mutex)
+{
+    if (mutex == NULL || mutex->mutex == NULL) {
+        return OSAL_FAILURE;
+    }
+    #if defined(configUSE_RECURSIVE_MUTEXES) && (configUSE_RECURSIVE_MUTEXES == 1)
+    BaseType_t ret = xSemaphoreTakeRecursive((SemaphoreHandle_t)mutex->mutex, portMAX_DELAY);
+    #else
+    BaseType_t ret = xSemaphoreTake((SemaphoreHandle_t)mutex->mutex, portMAX_DELAY);
+    #endif
+    return ret == pdTRUE ? OSAL_SUCCESS : OSAL_FAILURE;
+}
+
+void osal_mutex_unlock(osal_mutex *mutex)
+{
+    if (mutex == NULL || mutex->mutex == NULL) {
+        return;
+    }
+    #if defined(configUSE_RECURSIVE_MUTEXES) && (configUSE_RECURSIVE_MUTEXES == 1)
+    (void)xSemaphoreGiveRecursive((SemaphoreHandle_t)mutex->mutex);
+    #else
+    (void)xSemaphoreGive((SemaphoreHandle_t)mutex->mutex);
+    #endif
+}
+
+void osal_mutex_destroy(osal_mutex *mutex)
+{
+    if (mutex == NULL || mutex->mutex == NULL) {
+        return;
+    }
+    vQueueUnregisterQueue((SemaphoreHandle_t)mutex->mutex);
+    vSemaphoreDelete((SemaphoreHandle_t)mutex->mutex);
+    mutex->mutex = NULL;
+}
+
+int osal_wait_init(osal_wait *wait)
+{
+    if (wait == NULL || wait->wait != NULL) {
+        return OSAL_FAILURE;
+    }
+
+    wait_queue_head_t *wq = (wait_queue_head_t *)pvPortMalloc(sizeof(wait_queue_head_t));
+    if (wq == NULL) {
+        return OSAL_FAILURE;
+    }
+    EventGroupHandle_t handler = xEventGroupCreate();
+    if (handler == NULL) {
+        vPortFree(wq);
+        return OSAL_FAILURE;
+    }
+    wq->stEvent.handler = handler;
+    RTOS_SpinInit(&wq->lock);
+    RTOS_ListInit(&wq->poll_queue);
+    wait->wait = wq;
+    return OSAL_SUCCESS;
+}
+
+static inline int is_timeout(unsigned int ret, unsigned int mask, int mode)
+{
+    return ((ret == 0) || (ret != mask && mode == OSAL_WAITMODE_AND));
+}
+
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,
+                                    unsigned long ms)
+{
+    if (wait == NULL || wait->wait == NULL) {
+        return OSAL_FAILURE;
+    }
+    wait_queue_head_t *wq = (wait_queue_head_t *)(wait->wait);
+    EventGroupHandle_t handler = wq->stEvent.handler;
+    unsigned int ticksnow = (unsigned int)xTaskGetTickCount();
+    unsigned int timetick = pdMS_TO_TICKS(ms);
+    if (timetick > INT32_MAX) {
+        return OSAL_FAILURE;
+    }
+    int timeout = (int)timetick;
+    int tmp_timeout = timeout;
+    int ret = timeout;
+    if (func == NULL) {
+        return ret;
+    }
+    if (ms == 0 && func(param)) {
+        return 1;
+    }
+    while (!func(param)) {
+        unsigned int event_ret = xEventGroupWaitBits(handler, 0x1U, OSAL_WAITMODE_CLR, OSAL_WAITMODE_AND, tmp_timeout);
+        if (ms == OSAL_WAIT_FOREVER) {
+            if (!func(param)) {
+                continue;
+            }
+            break;
+        }
+
+        tmp_timeout = (int)(timeout - (unsigned int)(xTaskGetTickCount() - ticksnow));
+        if (tmp_timeout <= 0 || is_timeout(event_ret, OSAL_WAITMODE_AND, 0x1U)) {
+            ret = (func(param) == FALSE) ? FALSE : TRUE;
+            break;
+        }
+        if (func(param)) {
+            ret = tmp_timeout;
+            break;
+        }
+    }
+    return ret;
+}
+
+void osal_wait_wakeup_interruptible(osal_wait *wait)
+{
+    if (wait == NULL || wait->wait == NULL) {
+        return;
+    }
+
+    wait_queue_head_t *wq = (wait_queue_head_t *)(wait->wait);
+    EventGroupHandle_t handler = wq->stEvent.handler;
+    if (xHwiGetInterruptId() == configHWI_INVALID_IRQ_ID) {
+        (void)xEventGroupSetBits(handler, 0x1U);
+        return;
+    }
+
+    BaseType_t taskwoken = pdFALSE;
+    BaseType_t result = xEventGroupSetBitsFromISR(handler, 0x1U, &taskwoken);
+    if (result != pdFAIL) {
+        portYIELD_FROM_ISR(taskwoken);
+    }
+}
+
+void osal_wait_destroy(osal_wait *wait)
+{
+    if (wait == NULL || wait->wait == NULL) {
+        return;
+    }
+    wait_queue_head_t *wq = (wait_queue_head_t *)(wait->wait);
+    EventGroupHandle_t handler = wq->stEvent.handler;
+    vEventGroupDelete(handler);
+    RTOS_ListDelInit(&wq->poll_queue);
+    vPortFree(wq);
+    wait->wait = NULL;
+}
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+osal_task *osal_kthread_create(osal_kthread_handler handler, void *data, const char *name, unsigned int stack_size)
+{
+    if (handler == NULL) {
+        return NULL;
+    }
+    TaskHandle_t taskhandle = NULL;
+    osal_task *pthread = (osal_task *)pvPortMalloc(sizeof(osal_task));
+    if (pthread == NULL) {
+        return NULL;
+    }
+    unsigned int stacksize = (stack_size <= MINIMAL_STACK_SIZE) ? MINIMAL_STACK_SIZE : stack_size;
+    unsigned short stackwordsize = (unsigned short)(stacksize / BYTE_PER_WORD);
+    unsigned long ret = xTaskCreate((TaskFunction_t)handler, name, stackwordsize, data,
+                                    (tskIDLE_PRIORITY + 1), &taskhandle);
+    if (ret != pdPASS) {
+        vPortFree(pthread);
+        return NULL;
+    }
+    pthread->task = taskhandle;
+    return pthread;
+}
+
+void osal_kthread_destroy(osal_task *task, unsigned int stop_flag)
+{
+    if (task == NULL || task->task == NULL) {
+        return;
+    }
+    tiot_unused(stop_flag);
+    TaskHandle_t task_del = (TaskHandle_t)task->task;
+    eTaskState state = eTaskGetState(task_del);
+    vPortFree((void*)task);
+    if (state == eDeleted) {
+        return;
+    }
+    vTaskDelete(task_del);
+}
+#endif
+
+#ifndef CONFIG_FILE_BY_ARRAY
+void *osal_klib_fopen(const char *file, int flags, int mode)
+{
+    int *filp = NULL;
+    int fd = open(file, flags, mode);
+    if (fd < 0) {
+        return NULL;
+    } else {
+        filp = (int *)pvPortMalloc(sizeof(int));
+        if (filp == NULL) {
+            close(fd);
+            return NULL;
+        }
+        *filp = fd;
+    }
+    return (void *)filp;
+}
+
+void osal_klib_fclose(void *filp)
+{
+    if (filp == NULL) {
+        return;
+    }
+    close(*(int *)filp);
+    vPortFree(filp);
+}
+
+int osal_klib_fread(char *buf, unsigned long size, void *filp)
+{
+    if (filp == NULL) {
+        return OSAL_FAILURE;
+    }
+    return read(*(int *)filp, buf, size);
+}
+
+int osal_klib_fseek(long long offset, int whence, void *filp)
+{
+    int ret;
+    off_t res;
+    if (filp == NULL || offset > INT32_MAX) {
+        return OSAL_FAILURE;
+    }
+    res = lseek(*(int *)filp, (off_t)offset, whence);
+    ret = (int)res;
+    if (res != (off_t)ret) {
+        ret = OSAL_FAILURE;
+    }
+    return ret;
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_nonos_demo.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_nonos_demo.c
new file mode 100644 (file)
index 0000000..34e934c
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: non-os osal port demo. \n
+ *
+ * History: \n
+ * 2023-10-23, Create file. \n
+ */
+
+#include "tiot_osal.h"
+
+unsigned long osal_msleep(unsigned int msecs)
+{
+    /* 无操作系统, 调用板级毫秒级delay接口。 */
+    delay_ms(msecs);
+    return OSAL_SUCCESS;
+}
+
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag)
+{
+    /* 无动态内存申请时,选择CONFIG_BOARD_DYNAMIC_ALLOC配置宏为n,可空实现。 */
+    return NULL;
+}
+
+void osal_kfree(void *addr)
+{
+    /* 无动态内存申请时,选择CONFIG_BOARD_DYNAMIC_ALLOC配置宏为n,可空实现。 */
+}
+
+int osal_spin_lock_init(osal_spinlock *lock)
+{
+    /* 此接口仅用于驱动内锁中断。 */
+    /* 无操作系统,不包含spinlock接口时,无需创建,返回OSAL_SUCCESS即可。 */
+    return OSAL_SUCCESS;
+}
+
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags)
+{
+    /* 无操作系统,不包含spinlock接口时,需要锁中断。 */
+    *flags = irq_save();
+}
+
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags)
+{
+    /* 无操作系统,不包含spinlock接口时,需要恢复中断。 */
+    irq_restore(*flags);
+}
+
+void osal_spin_lock_destroy(osal_spinlock *lock)
+{
+    /* 无操作系统,不包含spinlock接口时,可空实现。 */
+}
+
+int osal_mutex_init(osal_mutex *mutex)
+{
+    /* 此接口用于多线程保护. */
+    /* 无操作系统时,锁中断即可,此处返回OSAL_SUCCESS即可。 */
+    return OSAL_SUCCESS;
+}
+
+int osal_mutex_lock(osal_mutex *mutex)
+{
+    /* 无操作系统,不包含mutex接口时,只需要锁中断。 */
+    tiot_unused(mutex);
+    irq_disable();
+    return OSAL_SUCCESS;
+}
+
+void osal_mutex_unlock(osal_mutex *mutex)
+{
+    tiot_unused(mutex);
+    /* 无操作系统,不包含mutex接口时,只需要锁中断。 */
+    irq_enable();
+}
+
+void osal_mutex_destroy(osal_mutex *mutex)
+{
+    /* 无操作系统,不包含mutex接口时,可空实现。 */
+}
+
+int osal_wait_init(osal_wait *wait)
+{
+    /* wait接口用于接收等待。 */
+    /* 无操作系统event/wait_queue接口可用循环代替等待,此处返回OSAL_SUCCESS即可. */
+    tiot_unused(wait);
+    return OSAL_SUCCESS;
+}
+
+/* 无event/wait_queue接口可用循环代替等待。 */
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,
+                                    unsigned long ms)
+{
+    tiot_unused(wait);
+    /* 板级无毫秒延时接口,忽略传入毫秒参数,读接口传入的timeout_ms参数无效。 */
+    tiot_unused(ms);
+    /* 循环等待条件。 */
+    while (!func(param)) {
+        /* 如果板级有watchdog看门狗,需要在此处调用喂狗操作。 */
+        watchdog_feed();
+    }
+    return 1;
+}
+
+int osal_wait_timeout_interruptible_with_ms(osal_wait *wait, osal_wait_condition_func func, const void *param,
+                                            unsigned long ms)
+{
+    tiot_unused(wait);
+    /* 板级有毫秒延时接口,可选择此实现。 */
+    /* 循环等待条件。 */
+    unsigned long cnt = 0;
+    int ret = ms;
+    if ((ms == 0) && func(param)) {
+        return 1;
+    }
+    while (cnt < ms) {
+        ret = func(param);
+        if (ret == 1) {
+            break;
+        }
+        /* 板级有毫秒延时接口。 */
+        osal_msleep(1);
+        /* 如果板级有watchdog看门狗,需要在此处调用喂狗操作。 */
+        watchdog_feed();
+        cnt++;
+    }
+    if (cnt == ms) {
+        /* 超时情况。 */
+        ret = func(param);
+    } else {
+        ret = ms - cnt;
+    }
+    return ret;
+}
+
+void osal_wait_wakeup_interruptible(osal_wait *wait)
+{
+    /* 无操作系统event/wait_queue接口, 可空实现。 */
+    tiot_unused(wait);
+}
+
+void osal_wait_destroy(osal_wait *wait)
+{
+    /* 无操作系统event/wait_queue接口, 可空实现。 */
+    tiot_unused(wait);
+}
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+/* 无操作系统不支持task。 */
+#error "Not support task."
+#endif
+
+#ifndef CONFIG_FILE_BY_ARRAY
+/* 无操作系统不支持文件系统操作。 */
+#error "Not support filesystem."
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_rtos_demo.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_rtos_demo.c
new file mode 100644 (file)
index 0000000..32af73e
--- /dev/null
@@ -0,0 +1,265 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: RTOS osal port demo. \n
+ *
+ * History: \n
+ * 2023-10-23, Create file. \n
+ */
+
+#include "tiot_osal.h"
+
+/* 替换为对应RTOS接口头文件. */
+#include "rtos_interface.h"
+
+unsigned long osal_msleep(unsigned int msecs)
+{
+    /* 系统msleep,让出当前线程. */
+    rtos_msleep(msecs);
+    return OSAL_SUCCESS;
+}
+
+void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag)
+{
+    /* 无动态内存申请时,选择CONFIG_BOARD_DYNAMIC_ALLOC配置宏为n,可空实现。 */
+    return rtos_malloc(size);
+}
+
+void osal_kfree(void *addr)
+{
+    /* 无动态内存申请时,选择CONFIG_BOARD_DYNAMIC_ALLOC配置宏为n,可空实现。 */
+    rtos_free(addr);
+}
+
+int osal_spin_lock_init(osal_spinlock *lock)
+{
+    /* 此接口仅用于驱动内锁中断. */
+    /* 操作系统包含spinlock接口,调用spinlock接口创建. */
+    /* 操作系统不包含spinlock接口时,无需创建,返回OSAL_SUCCESS即可. */
+    rtos_spinlock *os_lock = rtos_spin_lock_create();
+    if (os_lock == NULL) {
+        return OSAL_FAILURE;
+    }
+    lock->lock = os_lock;
+    return OSAL_SUCCESS;
+}
+
+void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags)
+{
+    if ((lock == NULL) || (lock->lock == NULL)) {
+        return;
+    }
+    *flags = rtos_spin_lock_irqsave(lock->lock);
+    /* 操作系统不包含spinlock接口时,只需要锁中断. */
+}
+
+void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags)
+{
+    if ((lock == NULL) || (lock->lock == NULL)) {
+        return;
+    }
+    *flags = rtos_spin_lock_irqrestore(lock->lock);
+    /* 操作系统不包含spinlock接口时,只需要恢复锁中断. */
+}
+
+void osal_spin_lock_destroy(osal_spinlock *lock)
+{
+    /* 操作系统不包含spinlock接口时,可空实现. */
+    rtos_spinlock *os_lock = lock->lock;
+    lock->lock = NULL;
+    rtos_spin_lock_destroy(os_lock);
+}
+
+int osal_mutex_init(osal_mutex *mutex)
+{
+    /* 此接口用于多线程操作保护. */
+    /* 操作系统包含mutex接口,调用mutex接口创建. */
+    /* 操作系统不包含mutex接口或无多线程场景,锁中断即可,此处返回OSAL_SUCCESS. */
+    rtos_mutex *os_mutex = rtos_mutex_create();
+    if (os_mutex == NULL) {
+        return OSAL_FAILURE;
+    }
+    mutex->mutex = os_mutex;
+    return OSAL_SUCCESS;
+}
+
+int osal_mutex_lock(osal_mutex *mutex)
+{
+    if ((mutex == NULL) || (mutex->mutex == NULL)) {
+        return OSAL_FAILURE;
+    }
+    rtos_mutex_lock(mutex->mutex);
+    /* 操作系统不包含mutex接口时,只需要锁中断. */
+    return OSAL_SUCCESS;
+}
+
+void osal_mutex_unlock(osal_mutex *mutex)
+{
+    if ((mutex == NULL) || (mutex->mutex == NULL)) {
+        return OSAL_FAILURE;
+    }
+    rtos_mutex_unlock(mutex->mutex);
+    /* 操作系统不包含mutex接口时,只需要恢复锁中断. */
+}
+
+void osal_mutex_destroy(osal_mutex *mutex)
+{
+    /* 操作系统不包含mutex接口时,可空实现. */
+    rtos_mutex *os_mutex = mutex->mutex;
+    mutex->mutex = NULL;
+    rtos_spin_lock_destroy(os_mutex);
+}
+
+int osal_wait_init(osal_wait *wait)
+{
+    /* wait接口用于接收等待. */
+    /* 无event接口可用循环代替等待,返回OSAL_SUCCESS即可. */
+    rtos_event *event = rtos_event_create();
+    if (event == NULL) {
+        return OSAL_FAILURE;
+    }
+    wait->wait = event;
+    return OSAL_SUCCESS;
+}
+
+int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param,
+    unsigned long ms)
+{
+    if (wait == NULL || wait->wait == NULL) {
+        return OSAL_FAILURE;
+    }
+    wait_queue_head_t *wq = (wait_queue_head_t *)(wait->wait);
+
+    unsigned long long ticksnow = rtos_tick_count_get64();
+    unsigned int timetick = rtos_ms_to_tick(ms);
+    if ((ms != OSAL_WAIT_FOREVER) && (timetick > INT32_MAX)) {
+        return OSAL_FAILURE;
+    }
+    int timeout = (int)timetick;
+    int tmp_timeout = timeout;
+    int ret = timeout;
+    if (func == NULL) {
+        return ret; /* default return timeout if condition func NULL */
+    }
+    if (ms == 0 && func(param)) {
+        return 1;
+    }
+    while (!func(param)) {
+        unsigned int event_ret = rtos_event_wait((rtos_event *)wait->wait, 0x1U,
+                                                 RTOS_WAITMODE_AND | RTOS_WAITMODE_CLR, (tmp_timeout));
+        if (ms == OSAL_WAIT_FOREVER) {
+            if (!func(param)) {
+                continue;
+            }
+            break;
+        }
+        tmp_timeout = (int)(timeout - (unsigned int)(rtos_tick_count_get64() - ticksnow));
+        if (tmp_timeout <= 0 || event_ret == RTOS_EVENT_WAIT_TIMEOUT) {
+            ret = (func(param) == FALSE) ? FALSE : TRUE;
+            break;
+        }
+        if (func(param) != 0) {
+            ret = tmp_timeout;
+            break;
+        }
+    }
+    return ret;
+}
+
+/* 无event接口可用循环代替实现. */
+int osal_wait_timeout_interruptible_without_event(osal_wait *wait, osal_wait_condition_func func, const void *param,
+                                                  unsigned long ms)
+{
+    tiot_unused(wait);
+    /* 板级有毫秒延时接口,可选择此实现。 */
+    /* 循环等待条件。 */
+    unsigned long cnt = 0;
+    int ret = ms;
+    if ((ms == 0) && func(param)) {
+        return 1;
+    }
+    while (cnt < ms) {
+        ret = func(param);
+        if (ret == 1) {
+            break;
+        }
+        /* 板级有毫秒延时接口。 */
+        osal_msleep(1);
+        cnt++;
+    }
+    if (cnt == ms) {
+        /* 超时情况。 */
+        ret = func(param);
+    } else {
+        ret = ms - cnt;
+    }
+    return ret;
+}
+
+void osal_wait_wakeup_interruptible(osal_wait *wait)
+{
+    /* 无event接口可空实现. */
+    if ((wait == NULL) || (wait->wait == NULL)) {
+        return;
+    }
+    rtos_event_set((rtos_event *)wait->wait);
+}
+
+void osal_wait_destroy(osal_wait *wait)
+{
+    /* 无event接口可空实现. */
+    rtos_event *event = wait->wait;
+    wait->wait = NULL;
+    rtos_event_destroy(event);
+}
+
+#ifdef CONFIG_XFER_TX_SUPPORT_TASK
+/* 不需要发送线程可不实现。 */
+osal_task *osal_kthread_create(osal_kthread_handler handler, void *data, const char *name, unsigned int stack_size)
+{
+    rtos_task task_param = {
+        .entry = handler,
+        .arg[0] = data,
+        .name = name,
+        .stack_size = stack_size
+    };
+    uint32_t task_id = rtos_task_create(&task_param);
+    if (task_id != RTOS_INVALID_TASK_ID) {
+        return NULL;
+    }
+    osal_task *new_task = rtos_malloc(sizeof(osal_task));
+    new_task->task = (void *)(uintptr_t)task_id;
+    return new_task;
+}
+
+void osal_kthread_destroy(osal_task *task, unsigned int stop_flag)
+{
+    uint32_t task_id = (uint32_t)(uintptr_t)new_task->task;
+    rtos_free(task);
+    rtos_task_destroy(task_id, stop_flag);
+}
+#endif
+
+#ifndef CONFIG_FILE_BY_ARRAY
+/* 无文件系统可不实现。 */
+void *osal_klib_fopen(const char *file, int flags, int mode)
+{
+    /* 此接口仅用于打开配置文件, 参数参照tiot_osal.h. */
+    return rtos_fopen(file, flags, mode);
+}
+
+void osal_klib_fclose(void *filp)
+{
+    rtos_fclose(filp);
+}
+
+int osal_klib_fread(char *buf, unsigned long size, void *filp)
+{
+    rtos_fread(buf, size, filp);
+}
+
+int osal_klib_fseek(long long offset, int whence, void *filp)
+{
+    rtos_fseek(buf, size, filp);
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b5e1185
--- /dev/null
@@ -0,0 +1,19 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+#===============================================================================
+set(
+    tiot_product_src_list
+    ${CMAKE_CURRENT_SOURCE_DIR}/gnss_board_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_uart_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_pin_port.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/tiot_board_misc_port.c
+)
+
+set(
+    tiot_product_header_list
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${tiot_product_header_list}" CACHE INTERNAL "tiot header list" FORCE)
+set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_product_src_list}" CACHE INTERNAL "tiot src list" FORCE)
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/gnss_board_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/gnss_board_port.c
new file mode 100644 (file)
index 0000000..a13d388
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description:  \n
+ *
+ * History: \n
+ * 2023-06-13, Create file. \n
+ */
+
+#include "gnss_board_port.h"
+#include "tiot_board_pin_port.h"
+#include "gpio.h"
+#include "uart.h"
+#include "pinctrl.h"
+#include "soc_osal.h"
+
+/* 根据板级MCU与gnss两个芯片的硬件连接修改适配 */
+/* 1. MCU芯片连接到gnss芯片的UART bus编号, 如UART_BUS_0. */
+/* 2. MCU芯片连接到gnss芯片PWREN管脚号,如S_AGPIO_L30。必须. */
+/* 3. MCU芯片连接到gnss芯片GPIO9(host唤醒gnss)管脚号,如S_AGPIO_R1。
+      可选,如果板级未连接此管脚,必须设为TIOT_PIN_NONE宏. */
+/* 4. MCU芯片连接到gnss芯片GPIO7(gnss唤醒host)管脚号,如S_AGPIO_R0。
+      可选,如果板级未连接此管脚,必须设为TIOT_PIN_NONE宏. */
+static const gnss_board_hw_info g_gnss_board_hw_info = { UART_BUS_0, { S_AGPIO_L30, S_AGPIO_R1, TIOT_PIN_NONE } };
+static const gnss_board_info g_gnss_board_info = {
+    .cfg_path = NULL,  /* 如果使用文件系统,此处填写固件cfg文件完整路径,
+                          例如 .cfg_path = "user/gnss_firmware/gnss_fw_cfg";
+                          否则, 填写NULL,并替换源码目录tiot_driver/device/gnss/firmware下的固件数组文件。 */
+    .hw_infos = (gnss_board_hw_info *)&g_gnss_board_hw_info
+};
+
+int32_t gnss_board_init(void *param)
+{
+    tiot_unused(param);
+    const uint32_t *gnss_pins = g_gnss_board_hw_info.pm_info;
+    /* power en */
+    uint32_t power_ctrl_pin = gnss_pins[GNSS_PIN_POWER_CTRL];
+    (void)uapi_pin_set_mode((pin_t)power_ctrl_pin, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+    (void)uapi_pin_set_pull((pin_t)power_ctrl_pin, PIN_PULL_DOWN);
+    (void)uapi_gpio_set_val((pin_t)power_ctrl_pin, GPIO_LEVEL_LOW);
+    (void)uapi_gpio_set_dir((pin_t)power_ctrl_pin, GPIO_DIRECTION_OUTPUT);
+    (void)uapi_pin_set_ds((pin_t)power_ctrl_pin, (pin_drive_strength_t)(PIN_DS_MAX - 1));
+
+    /* host wakeup dev */
+    uint32_t host_wakeup_device_pin = gnss_pins[GNSS_PIN_HOST_WAKEUP_DEVICE];
+    if (host_wakeup_device_pin != TIOT_PIN_NONE) {
+        (void)uapi_pin_set_mode((pin_t)host_wakeup_device_pin, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+        (void)uapi_pin_set_ds((pin_t)host_wakeup_device_pin, (pin_drive_strength_t)(PIN_DS_MAX - 1));
+        (void)uapi_pin_set_pull((pin_t)host_wakeup_device_pin, PIN_PULL_DOWN);
+        (void)uapi_gpio_set_val((pin_t)host_wakeup_device_pin, GPIO_LEVEL_LOW);
+        (void)uapi_gpio_set_dir((pin_t)host_wakeup_device_pin, GPIO_DIRECTION_OUTPUT);
+    }
+
+    /* device wakeup host */
+    uint32_t device_wakeup_host_pin = gnss_pins[GNSS_PIN_DEVICE_WAKEUP_HOST];
+    if (device_wakeup_host_pin != TIOT_PIN_NONE) {
+        (void)uapi_pin_set_mode((pin_t)device_wakeup_host_pin, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+        (void)uapi_pin_set_pull((pin_t)device_wakeup_host_pin, PIN_PULL_DOWN);
+        (void)uapi_gpio_set_val((pin_t)device_wakeup_host_pin, GPIO_LEVEL_LOW);
+        (void)uapi_gpio_set_dir((pin_t)device_wakeup_host_pin, GPIO_DIRECTION_INPUT);
+    }
+    /* UART1 pinmux已经在板级完成初始化, 或在UART open时进行初始化。 */
+    return 0;
+}
+
+void gnss_board_deinit(void *param)
+{
+    tiot_unused(param);
+    const uint32_t *gnss_pins = g_gnss_board_hw_info.pm_info;
+    /* 确保PWREN管脚下拉 */
+    (void)uapi_gpio_set_val((pin_t)gnss_pins[GNSS_PIN_POWER_CTRL], GPIO_LEVEL_LOW);
+}
+
+const gnss_board_info *gnss_board_get_info(void)
+{
+    return &g_gnss_board_info;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_log_port.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_log_port.h
new file mode 100644 (file)
index 0000000..8a87996
--- /dev/null
@@ -0,0 +1,46 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board log port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-05-06, Create file. \n\r
+ */\r
+#ifndef BOARD_LOG_PORT_H\r
+#define BOARD_LOG_PORT_H\r
+\r
+#include <stdio.h>\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+/**\r
+ * @defgroup tiot_board_port_log LOG port\r
+ * @ingroup  tiot_board_port\r
+ * @{\r
+ */\r
+\r
+/* 通过printf直接打印,不需要日志时需要注释掉define后半部分. */\r
+#define BOARD_PRINT_FUNCTION_NAME           printf("%s\r\n", __func__)\r
+#define board_print_dbg(s, args...)         printf(s, ##args)\r
+#define board_print_info(s, args...)        printf(s, ##args)\r
+#define board_print_info(s, args...)        printf(s, ##args)\r
+#define board_print_suc(s, args...)         printf(s, ##args)\r
+#define board_print_warning(s, args...)     printf(s, ##args)\r
+#define board_print_err(s, args...)         printf(s, ##args)\r
+#define board_print_alter(s, args...)       printf(s, ##args)\r
+\r
+/**\r
+ * @}\r
+ */\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_misc_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_misc_port.c
new file mode 100644 (file)
index 0000000..a7a6e43
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
+ *
+ * Description: Board Misc port. \n
+ *
+ * History: \n
+ * 2023-12-04, Create file. \n
+ */
+#include "tiot_board_misc_port.h"
+#include "soc_osal.h"
+#include "pm_veto.h"
+
+#define TIOT_WAKEUP_LOCK_ID  PM_ID_SYS
+
+int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+    return 0;
+}
+
+void tiot_board_wake_lock(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+#if ENABLE_LOW_POWER == YES
+    (void)uapi_pm_add_sleep_veto(TIOT_WAKEUP_LOCK_ID);
+#endif
+}
+
+void tiot_board_wake_unlock(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+#if ENABLE_LOW_POWER == YES
+    (void)uapi_pm_remove_sleep_veto(TIOT_WAKEUP_LOCK_ID);
+#endif
+}
+
+void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock)
+{
+    tiot_unused(lock);
+}
+
+void tiot_board_udelay(uint32_t us)
+{
+    osal_udelay(us);
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_pin_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_pin_port.c
new file mode 100644 (file)
index 0000000..aebb1c2
--- /dev/null
@@ -0,0 +1,112 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board PIN port. \n\r
+ *\r
+ * History: \n\r
+ * 2023-04-20, Create file. \n\r
+ */\r
+#include "tiot_board_pin_port.h"\r
+#include "gpio.h"\r
+\r
+#define uapi_err2ret(errcode)      (((errcode) == ERRCODE_SUCC) ? 0 : -1)\r
+\r
+/* TIoT驱动使用中断管脚个数,需要按实际板级情况适配修改。 */\r
+#define TIOT_INT_PIN_NUMBER    1\r
+typedef struct {\r
+    uint32_t pin;\r
+    tiot_pin_int_callback callback;\r
+} tiot_int_pin_map;\r
+/* TIoT驱动使用中断管脚配置,需要按实际使用的中断管脚适配修改。 */\r
+static tiot_int_pin_map g_tiot_int_pin_map[TIOT_INT_PIN_NUMBER] = {\r
+    /* 例如使用XXX唤醒MCU管脚,对应GPIO ID为S_AGPIO_R0. */\r
+    { S_AGPIO_R0, NULL }\r
+};\r
+\r
+/**\r
+ * @brief  Board set pin level interface.\r
+ * @param  [in] pin   Pin id.\r
+ * @param  [in] level Pin level, see @ref tiot_pin_level.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level)\r
+{\r
+    errcode_t errcode;\r
+    gpio_level_t gpio_level = (level == TIOT_PIN_LEVEL_LOW) ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH;\r
+    errcode = uapi_gpio_set_val((pin_t)pin, gpio_level);\r
+    return uapi_err2ret(errcode);\r
+}\r
+\r
+/**\r
+ * @brief  Board get current pin level interface.\r
+ * @param  [in]  pin   Pin id.\r
+ * @param  [out] level Current pin level, see @ref tiot_pin_level.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level)\r
+{\r
+    gpio_level_t gpio_level = uapi_gpio_get_val((pin_t)pin);\r
+    *level = (gpio_level == GPIO_LEVEL_LOW) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH;\r
+    return 0;\r
+}\r
+\r
+/**\r
+ * @brief  Board pin interrupt enable interface.\r
+ * @param  [in] pin         Pin id.\r
+ * @param  [in] int_enable  Interrupt enable or disable, see @ref tiot_pin_int_enable.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable)\r
+{\r
+    errcode_t errcode;\r
+    if (int_enable == TIOT_PIN_INT_ENABLE) {\r
+        errcode = uapi_gpio_enable_interrupt((pin_t)pin);\r
+    } else {\r
+        errcode = uapi_gpio_disable_interrupt((pin_t)pin);\r
+    }\r
+    return uapi_err2ret(errcode);\r
+}\r
+\r
+\r
+static void tiot_board_gpio_callback(pin_t pin, uintptr_t param)\r
+{\r
+    (void)param;\r
+    uapi_gpio_clear_interrupt(pin);\r
+    for (uint8_t index = 0; index < TIOT_INT_PIN_NUMBER; index++) {\r
+        if ((pin == g_tiot_int_pin_map[index].pin) && (g_tiot_int_pin_map[index].callback != NULL)) {\r
+            g_tiot_int_pin_map[index].callback(pin);\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+/**\r
+ * @brief  Board pin interrupt callback register interface.\r
+ * @note   Porting should ensure this callback is called when enters pin irq if interrupt enabled.\r
+ * @param  [in] pin     Pin id.\r
+ * @param  [in] int_cb  Registed interrupt callback, see @ref tiot_pin_int_callback.\r
+ * @return zero if OK;\r
+ *         non-zero if FAIL.\r
+ */\r
+int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb)\r
+{\r
+    errcode_t errcode;\r
+    if (int_cb != NULL) {\r
+        errcode = uapi_gpio_register_isr_func((pin_t)pin, GPIO_INTERRUPT_RISING_EDGE, tiot_board_gpio_callback);\r
+    } else {\r
+        errcode = uapi_gpio_unregister_isr_func((pin_t)pin);\r
+    }\r
+    if (errcode != ERRCODE_SUCC) {\r
+        return -1;\r
+    }\r
+    for (uint8_t index = 0; index < TIOT_INT_PIN_NUMBER; index++) {\r
+        if (pin == g_tiot_int_pin_map[index].pin) {\r
+            g_tiot_int_pin_map[index].callback = int_cb;\r
+            break;\r
+        }\r
+    }\r
+    return 0;\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_uart_port.c b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_uart_port.c
new file mode 100644 (file)
index 0000000..b622e29
--- /dev/null
@@ -0,0 +1,193 @@
+/**\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ *\r
+ * Description: Board UART port\n\r
+ *\r
+ * History: \n\r
+ * 2023-03-25, Create file. \n\r
+ */\r
+#include "tiot_board_uart_port.h"\r
+#include "tiot_board_log.h"\r
+\r
+#include "uart.h"\r
+#include "uart_porting.h"\r
+#include "pinctrl.h"\r
+#include "pinctrl_porting.h"\r
+\r
+#define TIOT_UAPI_RW_TIMEOUT    0xFFFFFFFF\r
+#define UART_RX_BUFFER_SIZE     56\r
+\r
+#define TIOT_UAPI_UART_RX_MAX   1024\r
+\r
+/* TIoT驱动使用MCU UART个数. */\r
+enum tiot_uart_port {\r
+    TIOT_UART_PORT0,\r
+    TIOT_UART_NUM,\r
+    TIOT_UART_NONE = TIOT_UART_NUM\r
+};\r
+\r
+enum tiot_uart_pin_type {\r
+    UART_PIN_TYPE_TX,\r
+    UART_PIN_TYPE_RX,\r
+    UART_PIN_TYPE_CTS,\r
+    UART_PIN_TYPE_RTS,\r
+    UART_PIN_TYPE_NUM\r
+};\r
+\r
+typedef struct {\r
+    tiot_xmit *xmit;\r
+    uint8_t flow_ctrl_bk;\r
+    uint8_t rx_buff[UART_RX_BUFFER_SIZE];\r
+    const uart_pin_config_t pin_config_orig;\r
+    uart_pin_config_t pin_config;\r
+    hal_pio_func_t pinmux[UART_PIN_TYPE_NUM];\r
+    uart_rx_callback_t rx_callback;\r
+} tiot_board_uart_port;\r
+\r
+static tiot_xmit_callbacks g_tiot_xmit_cbs;\r
+\r
+/* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加 */\r
+static void tiot_board_rx_callback0(const void *buff, uint16_t length, bool error);\r
+/* TIoT驱动使用的UART初始信息,需要按实际板级情况适配。 */\r
+static tiot_board_uart_port g_tiot_board_uart_port[TIOT_UART_NUM] = {\r
+    /* TIOT_UART_PORT0. */\r
+    {\r
+        .flow_ctrl_bk = TIOT_UART_ATTR_FLOW_CTRL_ENABLE,   /* MCU UART默认是否开启流控。 */\r
+        .rx_buff = { 0 },\r
+        .pin_config_orig = { S_MGPIO19, S_MGPIO20, S_MGPIO21, S_MGPIO22 },   /* MCU UART管脚,按实际板级情况适配。 */\r
+        /* MCU UART管脚pinmux,按实际板级情况适配。 */\r
+        .pinmux = {\r
+            HAL_PIO_FUNC_UART1, HAL_PIO_FUNC_UART1,\r
+            HAL_PIO_FUNC_UART1, HAL_PIO_FUNC_UART1\r
+        },\r
+        .rx_callback = tiot_board_rx_callback0             /* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加。 */\r
+    }\r
+    /* TIOT_UART_PORTx... */\r
+};\r
+\r
+/* MCU UART bus号与TIoT驱动使用的UART 对应关系,需要按实际情况适配。 */\r
+static inline enum tiot_uart_port tiot_board_uart_bus_convert_port(uart_bus_t bus)\r
+{\r
+    /* 例如 UART_BUS_0 对应 TIoT驱动使用的第一个UART。 */\r
+    if (bus == UART_BUS_0) {\r
+        return TIOT_UART_PORT0;\r
+    }\r
+    return TIOT_UART_NONE;\r
+}\r
+\r
+static inline void tiot_board_rx_callback_common(tiot_board_uart_port *port, const void *buff, uint16_t length)\r
+{\r
+    g_tiot_xmit_cbs.rx_notify(port->xmit, (uint8_t *)buff, length);\r
+}\r
+\r
+/* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加 */\r
+static void tiot_board_rx_callback0(const void *buff, uint16_t length, bool error)\r
+{\r
+    if (error == false) {\r
+        tiot_board_rx_callback_common(&g_tiot_board_uart_port[TIOT_UART_PORT0], buff, length);\r
+    } else {\r
+        tiot_print_err("[TIoT]uart port0 receive error.\r\n");\r
+    }\r
+}\r
+\r
+static void tiot_board_uart_txrx_pinmux_init(tiot_board_uart_port *port)\r
+{\r
+    /* 防止板级未初始化. */\r
+    uapi_pin_set_mode(port->pin_config.tx_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_TX]);\r
+    uapi_pin_set_mode(port->pin_config.rx_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_RX]);\r
+}\r
+\r
+static void tiot_board_uart_switch_flowctrl(tiot_board_uart_port *port)\r
+{\r
+    /* 板级uart初始化不会初始化ctsrts pinmux... */\r
+    if (port->flow_ctrl_bk == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) {\r
+        port->pin_config.cts_pin = port->pin_config_orig.cts_pin;\r
+        port->pin_config.rts_pin = port->pin_config_orig.rts_pin;\r
+        uapi_pin_set_mode(port->pin_config.cts_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_CTS]);\r
+        uapi_pin_set_mode(port->pin_config.rts_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_RTS]);\r
+    } else {\r
+        port->pin_config.cts_pin = PIN_NONE;\r
+        port->pin_config.rts_pin = PIN_NONE;\r
+    }\r
+}\r
+\r
+static int32_t tiot_board_uart_reopen(uart_bus_t bus, tiot_board_uart_port *port, const uart_attr_t *attr)\r
+{\r
+    uart_buffer_config_t buff_cfg = { (uint8_t *)port->rx_buff, UART_RX_BUFFER_SIZE };\r
+    (void)uapi_uart_deinit(bus);\r
+    tiot_board_uart_txrx_pinmux_init(port);\r
+    tiot_board_uart_switch_flowctrl(port);\r
+    errcode_t ret = uapi_uart_init(bus, &(port->pin_config), attr, NULL, &buff_cfg);\r
+    if (ret != ERRCODE_SUCC) {\r
+        return -1;\r
+    }\r
+    uapi_uart_register_rx_callback(bus, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,\r
+                                   TIOT_UAPI_UART_RX_MAX, port->rx_callback);\r
+    return 0;\r
+}\r
+\r
+int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs)\r
+{\r
+    enum tiot_uart_port port_type = tiot_board_uart_bus_convert_port((uart_bus_t)xmit->id);\r
+    if (port_type == TIOT_UART_NONE) {\r
+        return -1;\r
+    }\r
+    tiot_board_uart_port *port = &g_tiot_board_uart_port[port_type];\r
+    const uart_attr_t init_attr = { 115200, UART_DATA_BIT_8, UART_STOP_BIT_1, UART_PARITY_NONE,\r
+                                    ((port->flow_ctrl_bk == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ?\r
+                                    UART_FLOW_CTRL_RTS_CTS : UART_FLOW_CTRL_NONE) };\r
+    port->pin_config.tx_pin = port->pin_config_orig.tx_pin;\r
+    port->pin_config.rx_pin = port->pin_config_orig.rx_pin;\r
+    if (tiot_board_uart_reopen((uart_bus_t)xmit->id, port, &init_attr) != 0) {\r
+        return -1;\r
+    }\r
+    g_tiot_xmit_cbs = *cbs;\r
+    port->xmit = xmit;\r
+    xmit->handle = port;\r
+    return 0;\r
+}\r
+\r
+void tiot_board_uart_close(tiot_xmit *xmit)\r
+{\r
+    uapi_uart_unregister_rx_callback(xmit->id);\r
+    (void)uapi_uart_deinit(xmit->id);\r
+}\r
+\r
+int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len)\r
+{\r
+    return uapi_uart_write_nolock(xmit->id, buff, len, TIOT_UAPI_RW_TIMEOUT);\r
+}\r
+\r
+int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len)\r
+{\r
+    return uapi_uart_read(xmit->id, buff, len, TIOT_UAPI_RW_TIMEOUT);\r
+}\r
+\r
+int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config)\r
+{\r
+    errcode_t ret;\r
+    tiot_board_uart_port *port = xmit->handle;\r
+    if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) ||\r
+        (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) ||\r
+        (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) {\r
+        return -1;\r
+    }\r
+    if (port == NULL) {\r
+        return -1;\r
+    }\r
+    /* 确保当前无数据正在FIFO内传输,才能修改配置. */\r
+    while (uapi_uart_has_pending_transmissions(xmit->id) == true) {;}\r
+\r
+    const uart_attr_t attr = { config->baudrate, UART_DATA_BIT_8, UART_STOP_BIT_1, UART_PARITY_NONE,\r
+                               ((config->attr.flow_ctrl == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ?\r
+                               UART_FLOW_CTRL_RTS_CTS : UART_FLOW_CTRL_NONE) };\r
+    /* 调整流控需要重新init. */\r
+    if (config->attr.flow_ctrl != port->flow_ctrl_bk) {\r
+        port->flow_ctrl_bk = config->attr.flow_ctrl;\r
+        if (tiot_board_uart_reopen((uart_bus_t)xmit->id, port, &attr) != 0) {\r
+            return -1;\r
+        }\r
+    }\r
+    ret = uapi_uart_set_attr(xmit->id, &attr);\r
+    return (ret == ERRCODE_SUCC) ? 0 : -1;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_autoconfig.h b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_autoconfig.h
new file mode 100644 (file)
index 0000000..aad6a4e
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. */
+#define CONFIG_DEV_GNSS 1
+#define CONFIG_GNSS_DEV_NUM 1
+#define CONFIG_GNSS_WAKEUP_TYPE_UART 1
+#define CONFIG_GNSS_TCXO_FREQ_26M 1
+#define CONFIG_GNSS_UART_BAUDRATE 115200
+#define CONFIG_GNSS_PACKET_BUFF_MAX 10000
+#define CONFIG_FILE_BY_ARRAY 1
+#define CONFIG_FIRMWARE_CFG_HANDLE_PRIV 1
+#define CONFIG_FIRMWARE_FILE_READ_BUF_LEN 1029
+#define CONFIG_PM_WAKEUP_BY_UART 1
+#define CONFIG_PM_MANAGE_LOWPOWER 1
+#define CONFIG_XMIT_WITH_UART 1
+#define CONFIG_UART_RX_MODE_BUFFED 1
+#define CONFIG_XFER_PACKET_TIOT 1
+#define CONFIG_XFER_DEFAULT_RX_BUFF 1
+#define CONFIG_XFER_RX_BUFF_SIZE 512
diff --git a/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_defconfig b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_defconfig
new file mode 100644 (file)
index 0000000..6816a9b
--- /dev/null
@@ -0,0 +1,101 @@
+# Generated by HiCFBB Kconfig Tool.
+# Note: !!!This file can not be modify manually!!!
+
+#
+# Devices
+#
+
+#
+# Config the devices.
+#
+CONFIG_DEV_GNSS=y
+CONFIG_GNSS_DEV_NUM=1
+CONFIG_GNSS_WAKEUP_TYPE_UART=y
+# CONFIG_GNSS_WAKEUP_TYPE_GPIO is not set
+CONFIG_GNSS_TCXO_FREQ_26M=y
+# CONFIG_GNSS_TCXO_FREQ_38P4M is not set
+CONFIG_GNSS_UART_BAUDRATE=115200
+# CONFIG_GNSS_UART_WITH_FLOWCTRL is not set
+CONFIG_GNSS_PACKET_BUFF_MAX=10000
+# CONFIG_DEV_W33 is not set
+# CONFIG_DEV_CA01 is not set
+# end of Devices
+
+#
+# Common
+#
+
+#
+# Config common modules.
+#
+
+#
+# Misc
+#
+CONFIG_FILE_BY_ARRAY=y
+# CONFIG_OSAL_DEFINED is not set
+# CONFIG_LIBBOUNDSCHECK_IMPLEMENTED is not set
+# CONFIG_BOARD_DYNAMIC_ALLOC is not set
+# end of Misc
+
+#
+# Firmware Load
+#
+
+#
+# Firmware load module.
+#
+CONFIG_FIRMWARE_CFG_HANDLE_PRIV=y
+# CONFIG_FIRMWARE_CFG_HANDLE_XCI is not set
+CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029
+# end of Firmware Load
+
+#
+# Power Management
+#
+
+#
+# Power management module.
+#
+CONFIG_PM_WAKEUP_BY_UART=y
+CONFIG_PM_MANAGE_LOWPOWER=y
+# end of Power Management
+
+#
+# Transfer
+#
+
+#
+# Transfer module.
+#
+
+#
+# Transmit Type Support
+#
+
+#
+# Transmit type support.
+#
+CONFIG_XMIT_WITH_UART=y
+# CONFIG_XMIT_WITH_SPI is not set
+# CONFIG_XMIT_WITH_I2C is not set
+CONFIG_UART_RX_MODE_BUFFED=y
+# CONFIG_UART_RX_MODE_BLOCK is not set
+# end of Transmit Type Support
+
+#
+# Packet Handle Support
+#
+
+#
+# Pakcet handle support.
+#
+CONFIG_XFER_PACKET_TIOT=y
+# CONFIG_XFER_PACKET_NCI is not set
+# end of Packet Handle Support
+
+CONFIG_XFER_DEFAULT_RX_BUFF=y
+CONFIG_XFER_RX_BUFF_SIZE=512
+# CONFIG_XFER_TX_SUPPORT_TASK is not set
+# end of Transfer
+# end of Common
diff --git a/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_cfg.bin b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_cfg.bin
new file mode 100644 (file)
index 0000000..e11d8f2
--- /dev/null
@@ -0,0 +1,905 @@
+0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x30, 0x78, 0x30, 0x30,
+0x30, 0x39, 0x38, 0x30, 0x30, 0x30, 0x20, 0x05, 0x04, 0x01, 0x01, 0xfe, 0xef, 0xb2, 0x48, 0x6a,
+0xae, 0x84, 0x2a, 0x84, 0xef, 0x02, 0xd9, 0x0d, 0x40, 0x99, 0x2a, 0x84, 0xef, 0x82, 0x54, 0x4a,
+0x08, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x00, 0xef, 0x12, 0x92, 0x18, 0xef, 0x42, 0x42, 0x16,
+0x01, 0x8a, 0x13, 0x01, 0x82, 0x80, 0x00, 0x00, 0xef, 0x02, 0xd4, 0x69, 0x70, 0x6e, 0x00, 0x00,
+0xef, 0xa2, 0x11, 0x53, 0xef, 0x82, 0x44, 0x3c, 0x22, 0x2c, 0x31, 0xcd, 0x82, 0x80, 0x00, 0x00,
+0xef, 0x72, 0xd5, 0x68, 0xef, 0x92, 0x56, 0x10, 0x03, 0x45, 0xc5, 0xd9, 0xef, 0x92, 0xd6, 0x10,
+0x03, 0x45, 0xc5, 0xd9, 0xef, 0x32, 0xd5, 0x24, 0x53, 0x15, 0x05, 0xc2, 0x3c, 0x99, 0x00, 0x00,
+0xef, 0x12, 0x56, 0x57, 0xef, 0x22, 0x06, 0x02, 0xef, 0xe0, 0x40, 0x37, 0xef, 0xf2, 0x92, 0x35,
+0x03, 0x06, 0xa6, 0xb4, 0xa0, 0x99, 0x00, 0x00, 0xef, 0xf2, 0x01, 0x57, 0x20, 0x99, 0x00, 0x00,
+0xef, 0xf2, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf2, 0xc1, 0x3e, 0x20, 0x99, 0x00, 0x00,
+0xef, 0xf2, 0xc1, 0x33, 0xef, 0xa2, 0x41, 0x4c, 0x13, 0xb6, 0x16, 0x00, 0xef, 0xa2, 0x01, 0x2a,
+0x01, 0xdb, 0x27, 0x30, 0x20, 0x99, 0x00, 0x00, 0xef, 0x92, 0x51, 0x48, 0xef, 0xb2, 0xc1, 0x40,
+0xae, 0x84, 0x2a, 0x89, 0xef, 0x22, 0x93, 0x5d, 0xb5, 0x00, 0x03, 0x26, 0x82, 0x80, 0x00, 0x00,
+0xef, 0xb2, 0xd2, 0x1f, 0xef, 0xb2, 0x52, 0x04, 0x2e, 0x86, 0x2a, 0x84, 0xa4, 0x99, 0x00, 0x00,
+0xef, 0xb2, 0xd2, 0x21, 0x82, 0x80, 0x00, 0x00, 0xef, 0x72, 0xc6, 0x47, 0xef, 0x42, 0x06, 0x5f,
+0x8b, 0xdb, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xef, 0x42, 0xc6, 0x42, 0x3f, 0xf9, 0x00, 0x00,
+0xef, 0xe2, 0x45, 0x09, 0xef, 0xe2, 0x05, 0x63, 0x8b, 0x84, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
+0xef, 0xe2, 0x85, 0x7b, 0xef, 0xe2, 0x45, 0x7a, 0x23, 0x10, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xef, 0xd2, 0xd5, 0x7c, 0xef, 0xe2, 0x55, 0x19, 0x05, 0x07, 0x2e, 0x85, 0x00, 0x00, 0x00, 0x00,
+0xef, 0x42, 0xd6, 0x2a, 0xef, 0x52, 0xc6, 0x4d, 0x37, 0xc5, 0x08, 0x00, 0x82, 0x80, 0x00, 0x00,
+0xef, 0xc2, 0xd3, 0x53, 0x82, 0x80, 0x00, 0x00, 0xef, 0xc2, 0x13, 0x51, 0xef, 0x82, 0x13, 0x5e,
+0x04, 0x20, 0x13, 0x04, 0xef, 0xe2, 0xc8, 0x07, 0x7f, 0x9f, 0x13, 0x84, 0xef, 0x12, 0x15, 0x69,
+0xb0, 0x42, 0x11, 0xc1, 0xef, 0xa2, 0xd6, 0x18, 0x2a, 0x89, 0x37, 0x44, 0xef, 0x62, 0x44, 0x32,
+0x15, 0x02, 0x2a, 0x86, 0xef, 0x52, 0x94, 0x43, 0xef, 0xd0, 0xcf, 0x90, 0xef, 0x42, 0x84, 0x70,
+0xef, 0x50, 0xd2, 0x44, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf2, 0x54, 0x46, 0x00, 0x00, 0x00, 0x00,
+0xef, 0x22, 0xc1, 0x61, 0xef, 0x62, 0x50, 0x4c, 0x37, 0x35, 0x09, 0x00, 0x82, 0x80, 0x00, 0x00,
+0xef, 0xe2, 0xc5, 0x37, 0xef, 0xe2, 0xd6, 0x01, 0xaa, 0x84, 0xef, 0xe0, 0xef, 0x72, 0x86, 0x71,
+0x05, 0x44, 0xef, 0xd0, 0xef, 0x32, 0xd6, 0x69, 0x37, 0xd5, 0x08, 0x00, 0xef, 0x22, 0x43, 0x55,
+0x83, 0xd6, 0x86, 0xb2, 0xa0, 0x98, 0x00, 0x00, 0xef, 0x62, 0x94, 0x29, 0x00, 0x00, 0x00, 0x00,
+0xef, 0xd2, 0x51, 0x16, 0xef, 0xe2, 0xd2, 0x75, 0x26, 0xa0, 0x2a, 0x84, 0xef, 0xf2, 0x52, 0x0b,
+0x32, 0x89, 0x8b, 0x87, 0xef, 0x22, 0x54, 0x2a, 0x2a, 0x86, 0x0d, 0x45, 0x00, 0x00, 0x00, 0x00,
+0xef, 0xf2, 0xc7, 0x6b, 0xef, 0x92, 0x11, 0x65, 0x04, 0x20, 0x07, 0x30, 0xef, 0xa2, 0xc3, 0x76,
+0xb7, 0xb5, 0x04, 0x20, 0x20, 0x98, 0x00, 0x00, 0xef, 0x62, 0x54, 0x48, 0xef, 0x72, 0x03, 0x6c,
+0xef, 0xe0, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0xef, 0x72, 0x88, 0x07, 0xef, 0x82, 0x98, 0x32,
+0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x31, 0x05, 0x04,
+0x01, 0x02, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x43, 0x00, 0x00, 0x00, 0x09,
+0xd0, 0x00, 0x00, 0x31, 0x7d, 0x00, 0x00, 0xe9, 0x09, 0x05, 0x00, 0x79, 0x8e, 0x07, 0x00, 0xe1,
+0x65, 0x07, 0x00, 0xa9, 0x8d, 0x05, 0x00, 0x99, 0x01, 0x08, 0x00, 0xd1, 0x13, 0x05, 0x00, 0x09,
+0x16, 0x04, 0x00, 0xd1, 0xf0, 0x02, 0x00, 0x21, 0xf1, 0x02, 0x00, 0xd1, 0x5a, 0x04, 0x00, 0x39,
+0x72, 0x03, 0x00, 0x09, 0x70, 0x03, 0x00, 0xe9, 0xa5, 0x06, 0x00, 0x91, 0xb4, 0x07, 0x00, 0x71,
+0xb5, 0x07, 0x00, 0xf1, 0xb6, 0x07, 0x00, 0x11, 0xb8, 0x07, 0x00, 0x91, 0x07, 0x08, 0x00, 0xa9,
+0x0a, 0x08, 0x00, 0x71, 0x14, 0x08, 0x00, 0x71, 0xfb, 0x07, 0x00, 0x59, 0x71, 0x06, 0x00, 0xc9,
+0xec, 0x06, 0x00, 0x61, 0xeb, 0x06, 0x00, 0xf1, 0xeb, 0x06, 0x00, 0x31, 0x16, 0x03, 0x00, 0x29,
+0x46, 0x03, 0x00, 0x41, 0x48, 0x03, 0x00, 0x99, 0xb0, 0x03, 0x00, 0xd1, 0xab, 0x03, 0x00, 0x41,
+0xa9, 0x03, 0x00, 0x31, 0xa9, 0x03, 0x00, 0x81, 0xb2, 0x03, 0x00, 0x59, 0xa9, 0x03, 0x00, 0x79,
+0x42, 0x03, 0x00, 0xe9, 0x39, 0x03, 0x00, 0xe9, 0xcf, 0x05, 0x00, 0x79, 0xd0, 0x05, 0x00, 0xb1,
+0x10, 0x06, 0x00, 0x09, 0xa6, 0x00, 0x00, 0x09, 0x77, 0x04, 0x00, 0x31, 0xdf, 0x02, 0x00, 0xe1,
+0x34, 0x05, 0x00, 0x49, 0x3c, 0x05, 0x00, 0x61, 0x53, 0x05, 0x00, 0x39, 0x99, 0x04, 0x00, 0xd1,
+0x8b, 0x08, 0x00, 0x09, 0x27, 0x09, 0x00, 0x99, 0xaf, 0x03, 0x00, 0x29, 0x9f, 0x02, 0x00, 0xc9,
+0x13, 0x03, 0x00, 0x61, 0x50, 0x03, 0x00, 0x61, 0x7a, 0x06, 0x00, 0x21, 0x2e, 0x05, 0x00, 0xb9,
+0xd2, 0x07, 0x00, 0xd1, 0xb2, 0x06, 0x00, 0x01, 0xa9, 0x06, 0x00, 0xa1, 0x70, 0x05, 0x00, 0x11,
+0x90, 0x01, 0x00, 0x71, 0x13, 0x08, 0x00, 0x81, 0x0a, 0x06, 0x00, 0xd9, 0x2c, 0x05, 0x00, 0x09,
+0x28, 0x06, 0x00, 0xe1, 0x15, 0x01, 0x00, 0x49, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+0x98, 0xef, 0xf0, 0x66, 0xee, 0xb7, 0x25, 0x00, 0x40, 0x03, 0xd5, 0xc5, 0x54, 0x13, 0x76, 0x15,
+0x00, 0x13, 0x85, 0x01, 0x24, 0x01, 0xc6, 0x23, 0x9a, 0x05, 0x60, 0x7a, 0x1d, 0x19, 0x46, 0x23,
+0xa0, 0xc1, 0x3c, 0x93, 0x85, 0x81, 0xf7, 0x85, 0x46, 0x23, 0x93, 0xd5, 0x00, 0x23, 0x97, 0xd5,
+0x00, 0x23, 0x9b, 0xc5, 0x00, 0x93, 0x85, 0x81, 0x05, 0xf2, 0x15, 0xe2, 0x19, 0xf2, 0x1d, 0xe6,
+0x11, 0xc1, 0x65, 0x93, 0x85, 0x15, 0x9c, 0x6c, 0xc1, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0x7b,
+0xe8, 0x00, 0x70, 0x37, 0x25, 0x00, 0x40, 0x85, 0x45, 0x23, 0x10, 0xb5, 0x20, 0x82, 0x80, 0x00,
+0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0xef, 0x40, 0x57, 0x84, 0x7b, 0xe8, 0xa0, 0x70, 0xfb,
+0xca, 0x81, 0x9e, 0xa0, 0x98, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x10, 0xb7, 0xf7, 0x2a, 0x84, 0xef,
+0xf0, 0x56, 0x97, 0x03, 0x55, 0x44, 0x01, 0x0c, 0x48, 0x10, 0x4c, 0x2e, 0x95, 0x08, 0xc8, 0x02,
+0x96, 0xef, 0xf0, 0xf6, 0x93, 0x5c, 0x4c, 0x22, 0x85, 0x80, 0x98, 0x82, 0x87, 0x00, 0x00, 0xc0,
+0x99, 0x32, 0x89, 0xae, 0x84, 0x2a, 0x84, 0xef, 0xf0, 0xd6, 0x94, 0x22, 0x85, 0xa6, 0x85, 0x4a,
+0x86, 0xef, 0x30, 0xb7, 0xdd, 0x2a, 0x84, 0xef, 0xf0, 0x96, 0x91, 0x22, 0x85, 0xa0, 0x99, 0x00,
+0x00, 0x00, 0x00, 0xc4, 0x99, 0x83, 0x44, 0xc5, 0x01, 0x2e, 0x84, 0x01, 0x46, 0xd4, 0x4d, 0xa9,
+0x45, 0xb3, 0xf5, 0xb4, 0x02, 0x13, 0x07, 0xc0, 0x17, 0xb3, 0x37, 0xd7, 0x00, 0x13, 0xb7, 0x15,
+0x00, 0xf9, 0x8f, 0x9d, 0x90, 0xa9, 0xe7, 0x03, 0x46, 0x05, 0x00, 0x93, 0x07, 0xc0, 0x12, 0xb3,
+0xb6, 0xd7, 0x00, 0x64, 0x9f, 0xf9, 0x8e, 0x79, 0x16, 0x33, 0x36, 0xc0, 0x00, 0x55, 0x8e, 0x1d,
+0xe6, 0x03, 0x49, 0x15, 0x00, 0x2e, 0x85, 0xef, 0x10, 0x08, 0xd6, 0x0d, 0xc1, 0x13, 0x05, 0xf1,
+0x00, 0xef, 0x10, 0xe8, 0xbb, 0x01, 0xcd, 0x03, 0x46, 0xf1, 0x00, 0x26, 0x85, 0xa2, 0x85, 0xca,
+0x86, 0xef, 0x10, 0xa8, 0xa9, 0x7d, 0x15, 0x13, 0x36, 0x15, 0x00, 0x11, 0xa0, 0x01, 0x46, 0x32,
+0x85, 0xa4, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x9a, 0x39, 0xcd, 0xaa, 0x84, 0xef, 0x00, 0xa9,
+0x99, 0x2a, 0x84, 0x13, 0x86, 0x44, 0x00, 0x0a, 0x85, 0x91, 0x45, 0xa2, 0x86, 0xef, 0x50, 0xe7,
+0xb5, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d,
+0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x24, 0x93,
+0x85, 0x25, 0x64, 0xef, 0x60, 0x97, 0xa2, 0xb7, 0xf9, 0x01, 0x20, 0x03, 0xc5, 0x89, 0xad, 0x05,
+0x4a, 0x93, 0x84, 0x89, 0xad, 0x05, 0xc9, 0x8b, 0x18, 0x15, 0x01, 0x03, 0x45, 0x11, 0x00, 0xcc,
+0x50, 0x4d, 0x8d, 0x39, 0xe9, 0xb1, 0xa8, 0x7b, 0x25, 0x00, 0x81, 0x19, 0xc9, 0x37, 0x05, 0x23,
+0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x18, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0xb7,
+0x99, 0x01, 0x44, 0xd5, 0xa8, 0x03, 0x45, 0x01, 0x00, 0x0b, 0x1c, 0x05, 0x01, 0x7b, 0x25, 0x00,
+0x81, 0xa3, 0x83, 0x44, 0x01, 0x0b, 0x49, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23,
+0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x28, 0x93, 0x85, 0x25, 0x6c, 0xef, 0x60, 0xf7,
+0x9b, 0x03, 0xc5, 0x89, 0xad, 0x8b, 0x09, 0xe5, 0x01, 0x03, 0xc5, 0x84, 0x00, 0x8b, 0x1b, 0x05,
+0x03, 0xef, 0x70, 0xf3, 0xc0, 0x05, 0x04, 0x01, 0x03, 0xfc, 0x69, 0xe2, 0x7b, 0x25, 0x00, 0x81,
+0x0b, 0x48, 0x05, 0x03, 0x03, 0xc6, 0x84, 0x00, 0xfb, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00,
+0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x32, 0x93, 0x85, 0x25, 0x6c, 0xef, 0x60, 0xf7, 0x9d,
+0x92, 0x10, 0x83, 0x46, 0x01, 0x00, 0x03, 0x05, 0x11, 0x00, 0x03, 0x56, 0x21, 0x00, 0x23, 0x8c,
+0xd9, 0xac, 0x23, 0x85, 0xa4, 0x00, 0x8b, 0x49, 0x06, 0x04, 0x7b, 0x25, 0x00, 0x81, 0x09, 0xcd,
+0x7b, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x39,
+0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0x37, 0xa0, 0x01, 0x46, 0x29, 0x90, 0x83, 0xa5, 0x41, 0x7a,
+0x81, 0xc5, 0x32, 0x85, 0x82, 0x95, 0x19, 0xa0, 0x13, 0x05, 0x60, 0x22, 0xef, 0x60, 0xe9, 0xdf,
+0x26, 0x85, 0xef, 0x20, 0x89, 0xe3, 0x7b, 0x25, 0x00, 0x81, 0xa3, 0x8c, 0x49, 0xad, 0x0b, 0x4c,
+0x05, 0x03, 0x03, 0xc6, 0x89, 0xad, 0xfb, 0x25, 0x09, 0xf6, 0xfb, 0x26, 0x0f, 0x26, 0x7b, 0x27,
+0x09, 0xf6, 0x83, 0x57, 0x21, 0x00, 0xb3, 0x86, 0xd5, 0x40, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05,
+0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x49, 0x93, 0x85, 0x25, 0x6c, 0xef, 0x60, 0xd7, 0xa0, 0x22, 0x85,
+0xa0, 0x9a, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x9a, 0xae, 0x89, 0x2a, 0x89, 0x37, 0x44, 0x02, 0x40,
+0x13, 0x05, 0x44, 0x20, 0x89, 0x45, 0xef, 0x50, 0x89, 0xe1, 0x13, 0x05, 0x44, 0x23, 0xc1, 0x45,
+0xef, 0x50, 0xe9, 0xe0, 0x13, 0x04, 0x04, 0x20, 0x93, 0x05, 0x00, 0x0a, 0x22, 0x85, 0xef, 0x50,
+0x09, 0xe1, 0x93, 0x05, 0x00, 0x0a, 0x22, 0x85, 0xef, 0x50, 0x69, 0xdf, 0x37, 0x45, 0x10, 0x40,
+0x4c, 0x55, 0x41, 0x66, 0xd1, 0x8d, 0x4c, 0xd5, 0x37, 0x6a, 0x02, 0x40, 0x13, 0x04, 0x4a, 0x20,
+0x93, 0x05, 0x00, 0x20, 0x22, 0x85, 0xef, 0x50, 0x89, 0xde, 0x93, 0x04, 0x0a, 0x12, 0x93, 0x05,
+0x00, 0x10, 0x26, 0x85, 0xef, 0x50, 0xa9, 0xdd, 0x83, 0xd5, 0x41, 0x56, 0x26, 0x85, 0xef, 0x50,
+0x09, 0xdc, 0x93, 0x05, 0x00, 0x10, 0x26, 0x85, 0xef, 0x50, 0x69, 0xdb, 0x93, 0x75, 0xf9, 0x03,
+0x13, 0x05, 0x0a, 0x20, 0xef, 0x50, 0x29, 0xda, 0x8d, 0x45, 0x22, 0x85, 0xef, 0x50, 0x29, 0xdb,
+0x93, 0x95, 0x09, 0x01, 0xc1, 0x81, 0x13, 0x05, 0x8a, 0x20, 0xef, 0x50, 0xc9, 0xd8, 0x93, 0xd5,
+0x09, 0x01, 0x13, 0x05, 0xca, 0x20, 0xef, 0x50, 0x09, 0xd8, 0x83, 0xd5, 0x81, 0x56, 0x13, 0x05,
+0x0a, 0x21, 0xef, 0x50, 0x49, 0xd7, 0x83, 0xd5, 0xa1, 0x56, 0x13, 0x05, 0x4a, 0x21, 0xef, 0x50,
+0x89, 0xd6, 0x83, 0xd5, 0xc1, 0x56, 0x13, 0x05, 0x8a, 0x21, 0xef, 0x50, 0xc9, 0xd5, 0x83, 0xd5,
+0xe1, 0x56, 0x13, 0x05, 0xca, 0x21, 0xef, 0x50, 0x09, 0xd5, 0x93, 0x05, 0x00, 0x08, 0x22, 0x85,
+0xef, 0x50, 0xe9, 0xd4, 0x93, 0x05, 0x00, 0x20, 0x22, 0x85, 0xef, 0x50, 0x49, 0xd4, 0x93, 0x05,
+0x00, 0x10, 0x22, 0x85, 0xef, 0x50, 0xa9, 0xd3, 0x7b, 0x25, 0x00, 0x81, 0x19, 0xcd, 0x83, 0x56,
+0x4a, 0x20, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x49, 0x93, 0x85,
+0x25, 0x54, 0x22, 0x86, 0x80, 0x9a, 0x6f, 0x60, 0x57, 0x83, 0xa0, 0x9a, 0x00, 0x00, 0x37, 0x55,
+0x03, 0x20, 0x03, 0x45, 0xc5, 0xd9, 0xb7, 0xb5, 0x09, 0x00, 0x83, 0xc5, 0x45, 0x70, 0x4d, 0x8d,
+0x11, 0xcd, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x4f, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05,
+0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x16, 0x05, 0xa0, 0x7b, 0x25, 0x00, 0x81,
+0x09, 0x46, 0x7b, 0x66, 0xcf, 0x2e, 0x0b, 0x47, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05,
+0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x14, 0x93, 0x85, 0x25, 0x4c, 0x6f, 0x60,
+0x47, 0xf8, 0x82, 0x80, 0x00, 0x00, 0x37, 0x55, 0x03, 0x20, 0x03, 0x45, 0xc5, 0xd9, 0xb7, 0xb5,
+0x09, 0x00, 0x83, 0xc5, 0x45, 0x70, 0x7d, 0x15, 0x33, 0x35, 0xa0, 0x00, 0xfd, 0x15, 0xb3, 0x35,
+0xb0, 0x00, 0x6d, 0x8d, 0x0d, 0xed, 0x37, 0xf5, 0x01, 0x20, 0x93, 0x05, 0x85, 0xad, 0x03, 0x85,
+0x65, 0x00, 0x7b, 0x26, 0x00, 0x81, 0x85, 0x46, 0xd4, 0xc9, 0x05, 0x05, 0x23, 0x83, 0xa5, 0x00,
+0x0b, 0x41, 0x16, 0x03, 0x08, 0x92, 0xfb, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05,
+0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x20, 0x93, 0x85, 0x25, 0x4c, 0x6f, 0x60, 0x07, 0xf8, 0x7b, 0x25,
+0x00, 0x81, 0x09, 0x46, 0x7b, 0x66, 0xcf, 0x2e, 0x0b, 0x47, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6,
+0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x23, 0x93, 0x85, 0x25, 0x4c,
+0x6f, 0x60, 0x27, 0xf0, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x15, 0x08, 0x91, 0x8b, 0x54,
+0x05, 0x02, 0x03, 0x45, 0x86, 0x00, 0x0b, 0x15, 0x05, 0x01, 0x33, 0x35, 0xb0, 0x00, 0x82, 0x80,
+0xa3, 0x15, 0x06, 0x00, 0x93, 0x05, 0xd6, 0x00, 0x21, 0xa0, 0x1a, 0x12, 0x93, 0x05, 0xb6, 0x00,
+0x05, 0x45, 0x82, 0x11, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x9b, 0xaa, 0x84, 0x05, 0x44,
+0xef, 0x60, 0xa9, 0xbf, 0x01, 0xe5, 0x03, 0xc5, 0x24, 0x00, 0x19, 0xc1, 0x22, 0x85, 0xa8, 0x9b,
+0x03, 0x95, 0x04, 0x00, 0x2c, 0x08, 0x10, 0x08, 0x34, 0x00, 0x13, 0x07, 0xf1, 0x01, 0xef, 0x80,
+0x49, 0xa1, 0x2a, 0x89, 0x32, 0x45, 0xa2, 0x45, 0x92, 0x1c, 0x13, 0x06, 0x09, 0xfe, 0x05, 0x44,
+0x0b, 0x23, 0x06, 0x00, 0x81, 0x4a, 0x33, 0x1a, 0xc4, 0x00, 0x21, 0xa0, 0x01, 0x4a, 0xb3, 0x1a,
+0x24, 0x01, 0xb3, 0xf5, 0x55, 0x01, 0x33, 0x75, 0x45, 0x01, 0x4d, 0x8d, 0x61, 0xd1, 0x37, 0x55,
+0x00, 0x20, 0x13, 0x05, 0x85, 0x88, 0x54, 0x51, 0x10, 0x51, 0x7b, 0x25, 0x09, 0xf6, 0xe2, 0x47,
+0x1d, 0x8d, 0x93, 0x05, 0xc0, 0x44, 0x63, 0x4c, 0xb5, 0x06, 0x7b, 0x25, 0x00, 0x81, 0xb7, 0x45,
+0x01, 0x20, 0x93, 0x84, 0x05, 0xa3, 0x8b, 0x4a, 0x05, 0x03, 0x03, 0x45, 0xf1, 0x01, 0x2b, 0x85,
+0xa4, 0x06, 0x18, 0x41, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x57,
+0x93, 0x85, 0x25, 0x7c, 0x01, 0x46, 0xca, 0x86, 0xef, 0x60, 0xe7, 0xf3, 0x7b, 0x25, 0x00, 0x81,
+0x83, 0x45, 0xf1, 0x01, 0xab, 0x85, 0xb4, 0x06, 0xd0, 0x41, 0x94, 0x41, 0x13, 0xc7, 0xfa, 0xff,
+0x93, 0x47, 0xfa, 0xff, 0x7d, 0x8e, 0x75, 0x8f, 0x98, 0xc1, 0xd0, 0xc1, 0x0b, 0x44, 0xd5, 0x03,
+0xfb, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x5a,
+0x93, 0x85, 0x25, 0x7c, 0x01, 0x46, 0xca, 0x86, 0xef, 0x60, 0xe7, 0xef, 0x05, 0xbf, 0xd2, 0x45,
+0x42, 0x45, 0x33, 0xc8, 0xb6, 0x00, 0xb3, 0x37, 0xa6, 0x00, 0xe4, 0x9f, 0x33, 0xb7, 0xb6, 0x00,
+0x64, 0x9f, 0x2b, 0xe7, 0x07, 0x21, 0x0d, 0xe7, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x44, 0xc5, 0x02,
+0x83, 0x96, 0x04, 0x00, 0x7b, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17,
+0xb7, 0xb5, 0x00, 0x60, 0x93, 0x85, 0x25, 0x78, 0x01, 0x46, 0x02, 0x72, 0x05, 0x04, 0x01, 0x04,
+0xfb, 0xef, 0x60, 0xc7, 0xe5, 0xfd, 0xb5, 0x26, 0x87, 0xef, 0x80, 0x49, 0xef, 0x7d, 0x15, 0x13,
+0x34, 0x15, 0x00, 0xc5, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x83, 0x45, 0x25, 0x00, 0x8b, 0xdc, 0x05,
+0x06, 0x05, 0x46, 0xb3, 0x15, 0xb6, 0x00, 0x93, 0xf5, 0x55, 0x02, 0x95, 0xc1, 0x83, 0x05, 0x05,
+0x07, 0xfd, 0x15, 0x8c, 0x91, 0x8b, 0xd4, 0x05, 0x02, 0x83, 0x45, 0xd5, 0x03, 0x13, 0xf6, 0x35,
+0x00, 0x19, 0xce, 0x5e, 0x1d, 0x39, 0xa0, 0x3e, 0x1d, 0xa3, 0x1e, 0x05, 0x02, 0x39, 0xa0, 0x83,
+0x45, 0xd5, 0x03, 0x93, 0xf5, 0x75, 0x0e, 0xa3, 0x0e, 0xb5, 0x02, 0x01, 0x45, 0x82, 0x80, 0x83,
+0x45, 0xc5, 0x03, 0xe5, 0xfd, 0x03, 0x45, 0xb5, 0x03, 0x13, 0x35, 0x15, 0x00, 0x82, 0x80, 0x00,
+0x00, 0x40, 0x99, 0x2a, 0x84, 0x83, 0x44, 0x25, 0x00, 0xef, 0xb0, 0x59, 0xb8, 0x0b, 0x0a, 0x15,
+0x01, 0x03, 0x25, 0x44, 0x09, 0x83, 0x25, 0x44, 0x08, 0x83, 0x06, 0x04, 0x07, 0xa3, 0x0c, 0x04,
+0x06, 0x13, 0x06, 0x15, 0x00, 0x03, 0x25, 0x04, 0x0b, 0xfd, 0x16, 0x94, 0x92, 0x23, 0x2a, 0xc4,
+0x08, 0x8b, 0xdf, 0x06, 0x02, 0x2b, 0x86, 0xb5, 0xbe, 0xab, 0x35, 0xb6, 0xbe, 0x15, 0x46, 0xef,
+0xb0, 0xf9, 0xeb, 0xb7, 0xb5, 0x09, 0x00, 0x93, 0x85, 0xc5, 0x20, 0xab, 0x85, 0x95, 0x04, 0x8c,
+0x41, 0x23, 0x28, 0xa4, 0x0a, 0x63, 0x60, 0xb5, 0x02, 0x23, 0x08, 0x04, 0x06, 0x0d, 0x45, 0xa3,
+0x0c, 0xa4, 0x06, 0x23, 0x28, 0x04, 0x0a, 0x23, 0x2a, 0x04, 0x08, 0x3a, 0x1c, 0x20, 0x99, 0x01,
+0xc5, 0x23, 0x28, 0x04, 0x0a, 0x20, 0x99, 0x8b, 0x4e, 0x06, 0x32, 0x22, 0x85, 0xef, 0xb0, 0x99,
+0xc0, 0x75, 0xf9, 0x09, 0x45, 0x23, 0x08, 0xa4, 0x06, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x05, 0xc5,
+0x20, 0x2b, 0x05, 0x95, 0x04, 0x08, 0x41, 0x85, 0x45, 0x03, 0x06, 0xd4, 0x03, 0xa3, 0x0c, 0xb4,
+0x06, 0x05, 0x81, 0x23, 0x28, 0xa4, 0x0a, 0x13, 0x65, 0x06, 0x02, 0xa3, 0x0e, 0xa4, 0x02, 0x20,
+0x99, 0x23, 0x08, 0x04, 0x06, 0x20, 0x99, 0x00, 0x00, 0x40, 0x99, 0xae, 0x84, 0x2a, 0x84, 0x13,
+0x05, 0x00, 0x20, 0x2a, 0xc0, 0x0a, 0x85, 0xef, 0xb0, 0x29, 0xd3, 0x03, 0x45, 0x04, 0x07, 0x8b,
+0x03, 0x15, 0x02, 0x0b, 0x12, 0x35, 0x01, 0x82, 0x45, 0x13, 0x05, 0x90, 0x6c, 0x2e, 0x86, 0x83,
+0x26, 0x84, 0x09, 0x77, 0x96, 0xa4, 0xc4, 0x13, 0x07, 0x00, 0x40, 0x33, 0x45, 0xe6, 0x02, 0x36,
+0x95, 0x05, 0x66, 0x13, 0x06, 0xd6, 0x24, 0xae, 0x86, 0xf7, 0x96, 0xc4, 0xc4, 0x03, 0x26, 0xc4,
+0x09, 0x23, 0x2c, 0xa4, 0x08, 0xb3, 0xc6, 0xe6, 0x02, 0x36, 0x95, 0x32, 0x95, 0x23, 0x2e, 0xa4,
+0x08, 0x19, 0x66, 0x13, 0x06, 0x66, 0x1e, 0xf7, 0x95, 0xc4, 0xc4, 0xa1, 0xa8, 0x82, 0x45, 0x13,
+0x05, 0x90, 0x6c, 0x2e, 0x86, 0x77, 0x96, 0xa4, 0xc4, 0x03, 0x25, 0x84, 0x09, 0x85, 0x66, 0x13,
+0x87, 0x06, 0xa0, 0x33, 0x46, 0xe6, 0x02, 0x32, 0x95, 0x23, 0x2c, 0xa4, 0x08, 0x13, 0x86, 0xd6,
+0x24, 0xae, 0x86, 0xf7, 0x96, 0xc4, 0xc4, 0x13, 0x06, 0x00, 0x40, 0xb3, 0xc6, 0xc6, 0x02, 0x36,
+0x95, 0x83, 0x26, 0xc4, 0x09, 0x0a, 0x05, 0x29, 0x47, 0x33, 0x45, 0xe5, 0x02, 0x36, 0x95, 0x23,
+0x2e, 0xa4, 0x08, 0x99, 0x66, 0x93, 0x86, 0x66, 0x1e, 0xf7, 0x95, 0xd4, 0xc4, 0xb3, 0xc5, 0xc5,
+0x02, 0x8a, 0x05, 0xb3, 0xc5, 0xe5, 0x02, 0x50, 0x48, 0x2e, 0x95, 0x93, 0x55, 0xf6, 0x41, 0xc2,
+0x05, 0xab, 0xa5, 0xc5, 0x60, 0x93, 0x16, 0x06, 0x01, 0xab, 0x85, 0xa5, 0xbe, 0x2b, 0x05, 0xc5,
+0x20, 0x33, 0x36, 0xd5, 0x00, 0xb2, 0x95, 0x08, 0xcc, 0x4c, 0xcc, 0x20, 0x99, 0x00, 0x00, 0x00,
+0x00, 0x5c, 0x98, 0x79, 0x71, 0xef, 0x10, 0x50, 0x5e, 0xfb, 0x05, 0x2f, 0x2e, 0x64, 0x9d, 0xfd,
+0x15, 0xb3, 0x35, 0xb0, 0x00, 0x4d, 0x8d, 0x29, 0xe5, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0x85,
+0x22, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xe6, 0xed, 0x37, 0x65, 0x02, 0x20, 0x13,
+0x05, 0x85, 0xd9, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0xd7,
+0xc6, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d,
+0x8d, 0x39, 0xed, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0xf2, 0xa1,
+0xa0, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0xa5, 0x2c, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef,
+0x80, 0x66, 0xe9, 0x37, 0x65, 0x02, 0x20, 0x13, 0x05, 0x85, 0xd9, 0x93, 0x05, 0x20, 0x0a, 0x30,
+0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0x57, 0xc2, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13,
+0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23, 0x00, 0x13,
+0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x05, 0x1d, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0xe7, 0xae, 0x45,
+0x61, 0x3c, 0x98, 0x00, 0x00, 0x5c, 0x98, 0x79, 0x71, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0xc5,
+0x36, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xe6, 0xe3, 0x37, 0x65, 0x02, 0x20, 0x13,
+0x05, 0xa5, 0xe3, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0xd7,
+0xbc, 0x05, 0x37, 0x01, 0x45, 0xef, 0xf0, 0x98, 0x9d, 0x45, 0x61, 0x3c, 0x98, 0x5c, 0x98, 0x79,
+0x71, 0xef, 0x10, 0x90, 0x4f, 0xfb, 0x05, 0x2f, 0x2e, 0x64, 0x9d, 0xfd, 0x15, 0xb3, 0x35, 0xb0,
+0x00, 0x4d, 0x8d, 0x29, 0xe5, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0xe5, 0x40, 0x28, 0x00, 0x13,
+0x06, 0x20, 0x0a, 0xef, 0x80, 0x26, 0xdf, 0x37, 0x65, 0x02, 0x20, 0x13, 0x05, 0xc5, 0xed, 0x93,
+0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0x17, 0xb8, 0xfb, 0x25, 0x00,
+0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x39, 0xed, 0x37,
+0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x42, 0xa1, 0xa0, 0x37, 0xb5, 0x09,
+0x00, 0x93, 0x05, 0x05, 0x4b, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xa6, 0xda, 0x37,
+0x65, 0x02, 0x20, 0x13, 0x05, 0xc5, 0xed, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20,
+0x0a, 0xef, 0x40, 0x97, 0xb3, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93,
+0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7,
+0xb5, 0x00, 0x6d, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0x27, 0xa0, 0x45, 0x61, 0x3c, 0x98, 0x00,
+0x00, 0xc0, 0x98, 0x37, 0x54, 0x03, 0x20, 0x03, 0x45, 0xc4, 0xd9, 0x8b, 0x18, 0x15, 0x01, 0xef,
+0xa0, 0xba, 0x84, 0x37, 0x05, 0x03, 0x20, 0x83, 0x45, 0x05, 0x24, 0x8b, 0x91, 0x15, 0x01, 0x23,
+0x00, 0x05, 0x24, 0x13, 0x06, 0x05, 0x24, 0x37, 0x05, 0x03, 0x20, 0x13, 0x05, 0x05, 0x2a, 0x93,
+0x05, 0x00, 0x06, 0x93, 0x06, 0x00, 0x06, 0xef, 0x40, 0x37, 0xad, 0xfb, 0x25, 0x00, 0x81, 0x2a,
+0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23,
+0x00, 0xec, 0x7d, 0x05, 0x04, 0x01, 0x05, 0xfa, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x03, 0x2d,
+0x93, 0x85, 0x25, 0x44, 0xef, 0x60, 0xc7, 0x99, 0x23, 0x0e, 0x04, 0xd8, 0x37, 0xb5, 0x09, 0x00,
+0x23, 0x02, 0x05, 0x70, 0x37, 0x55, 0x03, 0x20, 0xa3, 0x0e, 0x05, 0xd8, 0xa0, 0x98, 0x00, 0x00,
+0x44, 0x99, 0x37, 0xb5, 0x09, 0x00, 0x85, 0x45, 0x23, 0x02, 0xb5, 0x70, 0x08, 0x08, 0xef, 0xc0,
+0xaa, 0xb4, 0xef, 0xd0, 0xb9, 0xd4, 0xef, 0xe0, 0x69, 0x86, 0xef, 0xd0, 0x79, 0xcf, 0x37, 0x54,
+0x03, 0x20, 0x03, 0x26, 0x44, 0xdb, 0xb7, 0x54, 0x03, 0x20, 0x03, 0xa5, 0xc4, 0xdb, 0x83, 0x25,
+0x44, 0xdb, 0x63, 0x64, 0xc5, 0x00, 0x0d, 0x8d, 0x19, 0xa0, 0x33, 0x85, 0xa5, 0x40, 0x93, 0x05,
+0x00, 0x10, 0x63, 0x6a, 0xb5, 0x02, 0x37, 0x55, 0x03, 0x20, 0x03, 0x25, 0x85, 0xdb, 0x03, 0x26,
+0x44, 0xdb, 0x83, 0x25, 0x44, 0xdb, 0x63, 0x67, 0xa6, 0x00, 0x33, 0x85, 0xa5, 0x40, 0x0b, 0x53,
+0x05, 0x3c, 0x11, 0xa8, 0x0d, 0x8d, 0x0b, 0x44, 0x05, 0x3c, 0xef, 0x20, 0x29, 0x83, 0x03, 0x25,
+0x44, 0xdb, 0x23, 0xae, 0xa4, 0xda, 0xef, 0xd0, 0x79, 0xef, 0x68, 0x00, 0xef, 0xc0, 0xca, 0xad,
+0x42, 0x45, 0xb2, 0x45, 0xef, 0xc0, 0x0a, 0xb2, 0xb7, 0x55, 0x03, 0x20, 0x93, 0x85, 0x85, 0xe0,
+0x90, 0x4d, 0x63, 0x73, 0xa6, 0x00, 0x88, 0xcd, 0xb7, 0x55, 0x03, 0x20, 0x03, 0xa6, 0x85, 0xdf,
+0x32, 0x95, 0x23, 0xac, 0xa5, 0xde, 0x24, 0x99, 0x00, 0x00, 0x00, 0x00, 0x40, 0x99, 0x2e, 0x84,
+0xaa, 0x84, 0xef, 0x30, 0xbc, 0xc6, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x05, 0x60, 0x0e, 0x13, 0x06,
+0x30, 0x11, 0x2b, 0xe6, 0xa5, 0x20, 0x23, 0x90, 0xc4, 0x00, 0x09, 0x45, 0x23, 0x10, 0xa4, 0x00,
+0x20, 0x99, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x89, 0xaa, 0x84, 0xef, 0x10, 0x70, 0x2f, 0x93, 0x05,
+0x20, 0x1c, 0x13, 0x04, 0x00, 0x14, 0x2b, 0xe4, 0xa5, 0x22, 0xef, 0x30, 0x3c, 0xc3, 0x03, 0x45,
+0xc5, 0x0e, 0x93, 0x05, 0x60, 0x0e, 0x2b, 0xe4, 0xa5, 0x20, 0x23, 0x90, 0x84, 0x00, 0x0d, 0x45,
+0x23, 0x10, 0xa9, 0x00, 0xa0, 0x99, 0x00, 0x00, 0x40, 0x9a, 0x69, 0xc5, 0x2a, 0x84, 0xef, 0x10,
+0x30, 0x2c, 0x83, 0x05, 0x04, 0x07, 0xaa, 0x89, 0x03, 0x29, 0xc4, 0x2a, 0x13, 0x85, 0xf5, 0xff,
+0x88, 0x91, 0x13, 0x05, 0xf0, 0x0f, 0x8b, 0xcd, 0x05, 0x02, 0x83, 0x44, 0xa4, 0x03, 0xef, 0x30,
+0xfc, 0xbe, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x35, 0x15, 0x00, 0x8b, 0x93, 0x04, 0x01, 0x13, 0x06,
+0x60, 0x0e, 0x13, 0x05, 0x30, 0x11, 0x09, 0xa8, 0x13, 0x06, 0x20, 0x1c, 0x13, 0x05, 0x00, 0x14,
+0x2b, 0x65, 0x36, 0x23, 0x13, 0x06, 0x60, 0x0e, 0x2b, 0x65, 0xb6, 0x22, 0x83, 0x55, 0x44, 0x27,
+0x63, 0x6c, 0xb5, 0x02, 0x03, 0x45, 0x14, 0x03, 0x0b, 0x1c, 0x05, 0x01, 0x03, 0x45, 0x04, 0x2a,
+0x0b, 0x1a, 0x05, 0x01, 0x03, 0x45, 0x14, 0x2a, 0x05, 0xe1, 0x03, 0x25, 0x44, 0x08, 0xab, 0x05,
+0xa5, 0xbe, 0x2b, 0xb5, 0xa5, 0xbe, 0x95, 0x65, 0x93, 0x85, 0x65, 0x55, 0x23, 0x20, 0x04, 0x0a,
+0x63, 0x64, 0xb5, 0x00, 0x23, 0x22, 0x04, 0x08, 0x03, 0x45, 0xc4, 0x07, 0x0b, 0x19, 0x05, 0x01,
+0x09, 0x45, 0x23, 0x0e, 0xa4, 0x06, 0x23, 0x20, 0x04, 0x08, 0x23, 0x22, 0x04, 0x08, 0x13, 0x05,
+0x44, 0x23, 0x93, 0x05, 0x40, 0x03, 0x93, 0x06, 0x40, 0x03, 0x01, 0x46, 0xef, 0x40, 0xd7, 0xee,
+0x63, 0x0a, 0x09, 0x00, 0x03, 0x45, 0x39, 0x00, 0x0b, 0x13, 0x05, 0x05, 0x23, 0x20, 0x04, 0x08,
+0x23, 0x22, 0x04, 0x08, 0x20, 0x9a, 0x00, 0x00, 0xc0, 0x9a, 0x32, 0x8a, 0x2e, 0x89, 0xaa, 0x84,
+0xef, 0x10, 0x10, 0x1f, 0x13, 0x04, 0x40, 0x15, 0x93, 0x09, 0xa0, 0x0f, 0x0b, 0x87, 0x04, 0x03,
+0x93, 0x05, 0x40, 0x1f, 0x13, 0x04, 0xe0, 0x15, 0x2b, 0xe4, 0xa5, 0x22, 0xef, 0x30, 0x1c, 0xb2,
+0x03, 0x45, 0xc5, 0x0e, 0x2b, 0xe4, 0xa9, 0x20, 0x23, 0x10, 0x8a, 0x00, 0x0b, 0x16, 0x09, 0x01,
+0xef, 0x30, 0xdc, 0xb0, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x05, 0xb0, 0x12, 0xab, 0xe5, 0xa9, 0x20,
+0x23, 0x10, 0xba, 0x00, 0xa0, 0x9a, 0x00, 0x00, 0x40, 0x9a, 0x49, 0xc5, 0xae, 0x89, 0x2a, 0x84,
+0xef, 0x10, 0x10, 0x1a, 0x93, 0x05, 0x20, 0x1c, 0x03, 0x29, 0x44, 0x02, 0x93, 0x04, 0x00, 0x14,
+0xab, 0xe4, 0xa5, 0x22, 0xa3, 0x0c, 0x34, 0x03, 0xef, 0x30, 0x5c, 0xad, 0x03, 0x45, 0xc5, 0x0e,
+0x93, 0x05, 0x60, 0x0e, 0xab, 0xe4, 0xa5, 0x20, 0x63, 0x77, 0x99, 0x02, 0x09, 0x45, 0xa3, 0x08,
+0xa4, 0x02, 0x8b, 0x59, 0x09, 0xfb, 0x93, 0x05, 0x04, 0x03, 0x11, 0x45, 0xa3, 0x08, 0xa4, 0x02,
+0x8b, 0x81, 0x19, 0x02, 0x0b, 0x93, 0x09, 0x01, 0x2e, 0x85, 0xca, 0x85, 0xef, 0x10, 0x5a, 0xfb,
+0xef, 0x50, 0xd9, 0xc5, 0x25, 0xa0, 0x22, 0x1c, 0xef, 0x50, 0x59, 0xc5, 0x64, 0x9d, 0x93, 0x85,
+0xe9, 0xff, 0xb3, 0x35, 0xb0, 0x00, 0x4d, 0x8d, 0x11, 0xe9, 0x03, 0x45, 0x14, 0x03, 0x0b, 0x02,
+0x05, 0x04, 0x8b, 0x12, 0x05, 0x02, 0x05, 0x05, 0xa3, 0x08, 0xa4, 0x02, 0xef, 0x10, 0x19, 0xfe,
+0x11, 0xc1, 0x22, 0x1c, 0x20, 0x9a, 0x22, 0x85, 0x4a, 0x86, 0xef, 0x10, 0x7a, 0xf8, 0xe9, 0xb7,
+0x00, 0x00, 0x00, 0x00, 0xaa, 0x86, 0x03, 0x05, 0x05, 0x07, 0x7d, 0x15, 0x08, 0x93, 0x2e, 0x85,
+0x8b, 0x52, 0x07, 0x02, 0xb2, 0x85, 0x6f, 0x10, 0xea, 0xe1, 0x83, 0xc5, 0xa6, 0x03, 0x8b, 0x92,
+0x05, 0x01, 0xb2, 0x85, 0x6f, 0x10, 0x4a, 0xe2, 0xb2, 0x85, 0x6f, 0x10, 0x2a, 0xe3, 0x00, 0x00,
+0x40, 0x9a, 0xb6, 0x84, 0xb2, 0x89, 0x2e, 0x89, 0x2a, 0x84, 0xef, 0x50, 0xf9, 0xbb, 0x4d, 0xc1,
+0x8b, 0x9b, 0x04, 0x01, 0x0b, 0x47, 0x24, 0x03, 0xef, 0x70, 0x19, 0x9d, 0x7b, 0x06, 0x2f, 0x2e,
+0x93, 0x05, 0xc0, 0x12, 0x0b, 0x05, 0x06, 0x01, 0x13, 0x45, 0xc5, 0x2b, 0x13, 0x06, 0x40, 0x06,
+0x93, 0x05, 0x80, 0x0c, 0xab, 0x65, 0xa6, 0x20, 0x23, 0x10, 0xb9, 0x00, 0x20, 0x9a, 0xef, 0x70,
+0xb9, 0x9a, 0x13, 0x05, 0x45, 0xd4, 0x33, 0x35, 0xa0, 0x00, 0x93, 0x35, 0x34, 0x00, 0x4d, 0x8d,
+0x11, 0xe5, 0x8b, 0x11, 0x14, 0x03, 0x13, 0x05, 0x00, 0x05, 0x89, 0xa0, 0xef, 0x70, 0xd9, 0x98,
+0x13, 0x45, 0x65, 0x22, 0x93, 0x45, 0x34, 0x00, 0x4d, 0x8d, 0x1d, 0xe9, 0x83, 0xd5, 0xa9, 0x00,
+0x13, 0x06, 0x20, 0x12, 0x09, 0x45, 0x63, 0x65, 0xb6, 0x00, 0x05, 0x45, 0x0b, 0xc4, 0x05, 0xf1,
+0x83, 0x55, 0x09, 0x00, 0x33, 0xd5, 0xa5, 0x00, 0x23, 0x10, 0xa9, 0x00, 0xef, 0x10, 0x50, 0x05,
+0x01, 0xc9, 0x13, 0x05, 0x00, 0x14, 0x19, 0xa0, 0x13, 0x05, 0x00, 0x0a, 0x23, 0x10, 0xa9, 0x00,
+0x7b, 0x05, 0x2f, 0x2e, 0x0b, 0x13, 0x05, 0x01, 0x13, 0x05, 0x00, 0x14, 0x23, 0x10, 0xa9, 0x00,
+0x20, 0x9a, 0x00, 0x00, 0xc0, 0x99, 0x01, 0x44, 0x37, 0x35, 0x09, 0x00, 0x13, 0x09, 0x05, 0xa7,
+0x37, 0x86, 0x02, 0x40, 0xb7, 0x84, 0x02, 0x40, 0x03, 0x25, 0x09, 0x00, 0x5b, 0xa2, 0xa4, 0xc0,
+0xdb, 0x26, 0x49, 0x80, 0x01, 0x45, 0xa2, 0x85, 0xef, 0x50, 0x0a, 0xa9, 0x05, 0x04, 0x26, 0x86,
+0x0b, 0x1a, 0xf4, 0x46, 0x37, 0x85, 0x02, 0x40, 0x18, 0x99, 0x05, 0x04, 0x01, 0x06, 0xf9, 0x93,
+0x05, 0x10, 0x10, 0x23, 0x28, 0xb5, 0x0e, 0x85, 0x65, 0x93, 0x85, 0xa5, 0xa0, 0x23, 0x2a, 0xb5,
+0x0e, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0x03, 0x45, 0x65, 0x00, 0x8b,
+0x1e, 0x05, 0x02, 0x03, 0x47, 0x44, 0x00, 0xa3, 0x01, 0xe4, 0x00, 0x10, 0x5c, 0x54, 0x5c, 0x7b,
+0x25, 0x00, 0x81, 0x10, 0xd8, 0x54, 0xd8, 0x72, 0x1c, 0x7a, 0x1c, 0x0b, 0x47, 0x05, 0x04, 0xfb,
+0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x25, 0x93,
+0x85, 0x25, 0x4c, 0xef, 0x50, 0x97, 0xe6, 0x0e, 0x10, 0xa0, 0x98, 0x00, 0x00, 0x00, 0x00, 0x03,
+0x47, 0x45, 0x00, 0xa3, 0x01, 0xe5, 0x00, 0x10, 0x5d, 0x54, 0x5d, 0xfb, 0x25, 0x00, 0x81, 0x10,
+0xd9, 0x54, 0xd9, 0x72, 0x1d, 0x7a, 0x1d, 0x0b, 0xc7, 0x05, 0x03, 0xfb, 0x27, 0x09, 0xf6, 0x37,
+0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x34, 0x93, 0x85, 0x25, 0x4c, 0x6f,
+0x50, 0xd7, 0xe2, 0x82, 0x80, 0x00, 0x00, 0xc0, 0x99, 0x37, 0x05, 0x00, 0x04, 0xb7, 0x45, 0x10,
+0x40, 0xec, 0x55, 0x37, 0x16, 0x03, 0x20, 0x13, 0x04, 0x06, 0xb1, 0x50, 0x54, 0x13, 0x09, 0xf5,
+0xff, 0x2b, 0xe5, 0x05, 0x74, 0x48, 0xd0, 0xb3, 0x24, 0xc5, 0x00, 0x22, 0x85, 0xa9, 0x3f, 0x03,
+0x45, 0x64, 0x00, 0x0b, 0x16, 0x05, 0x01, 0x03, 0x45, 0x54, 0x00, 0x13, 0x35, 0x15, 0x00, 0x65,
+0x8d, 0x93, 0x15, 0x15, 0x00, 0xa9, 0x8c, 0x23, 0x03, 0xb4, 0x00, 0x48, 0x50, 0x2a, 0x10, 0x48,
+0xd4, 0x37, 0x86, 0x12, 0x40, 0x03, 0x25, 0x06, 0x0b, 0x83, 0x25, 0x46, 0x0b, 0x03, 0x26, 0xc6,
+0x0b, 0x69, 0x82, 0xb3, 0xe6, 0xa5, 0x00, 0xb3, 0xf6, 0x26, 0x01, 0x23, 0x02, 0xc4, 0x00, 0x99,
+0xc6, 0xb3, 0xf5, 0x25, 0x01, 0x33, 0x75, 0x25, 0x01, 0x08, 0xdc, 0x4c, 0xdc, 0x81, 0xc4, 0x22,
+0x85, 0x80, 0x99, 0xb1, 0xb7, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0x40, 0x98, 0x22, 0xa0, 0x53,
+0x15, 0x05, 0xc2, 0x53, 0x00, 0x05, 0xd2, 0x53, 0x74, 0x05, 0x0a, 0xef, 0x30, 0x8e, 0xb0, 0x31,
+0xc1, 0xef, 0x30, 0x2e, 0xb0, 0x13, 0x45, 0x45, 0x00, 0x93, 0x05, 0x40, 0x06, 0x13, 0x06, 0x80,
+0x0c, 0x2b, 0xe6, 0xa5, 0x20, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x5a, 0x53, 0x15, 0x04,
+0xc2, 0xd3, 0x00, 0x05, 0xd2, 0xd3, 0x70, 0x14, 0x0a, 0xd3, 0xf0, 0x00, 0x12, 0x53, 0x95, 0x00,
+0xc2, 0xb3, 0x65, 0xc5, 0x02, 0x0d, 0x8d, 0x53, 0x01, 0x05, 0xd2, 0xd3, 0xf0, 0x20, 0x0a, 0x53,
+0xf4, 0x00, 0x1a, 0xef, 0xf0, 0x5d, 0xd5, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x55, 0x53,
+0x15, 0x85, 0xa2, 0x43, 0x70, 0x05, 0x42, 0x2b, 0x64, 0xa0, 0x3a, 0x53, 0x05, 0x84, 0x22, 0x02,
+0x24, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xd0, 0x8a, 0xea, 0x00, 0x00, 0x00, 0x00, 0xcc,
+0x9a, 0x22, 0xb8, 0x26, 0xb4, 0x36, 0x89, 0x32, 0x84, 0x53, 0x84, 0xb5, 0x22, 0xae, 0x89, 0xd3,
+0x04, 0xa5, 0x22, 0xaa, 0x84, 0xef, 0xe0, 0xea, 0xb0, 0x2a, 0x8a, 0x03, 0x55, 0x05, 0x0d, 0x69,
+0xc1, 0x13, 0x06, 0x84, 0x07, 0x93, 0x06, 0x94, 0x07, 0xa4, 0x91, 0x0d, 0x45, 0xef, 0xd0, 0xeb,
+0xe6, 0x02, 0xd2, 0x02, 0xd0, 0x08, 0x10, 0x53, 0x85, 0x94, 0x22, 0xef, 0xe0, 0x9e, 0xe5, 0x26,
+0x85, 0xef, 0x30, 0xec, 0xf6, 0x02, 0x35, 0x8b, 0x13, 0x05, 0x01, 0x52, 0x85, 0xa2, 0x85, 0xef,
+0xe0, 0xda, 0xa4, 0x29, 0xa0, 0x52, 0x85, 0xa2, 0x85, 0xef, 0xe0, 0xba, 0x9c, 0x07, 0x30, 0x84,
+0x01, 0x82, 0x30, 0x53, 0xf0, 0x00, 0x0a, 0x02, 0xb0, 0x53, 0x05, 0x84, 0x22, 0x22, 0x85, 0xce,
+0x85, 0x4a, 0x86, 0xef, 0x00, 0x0b, 0x94, 0x13, 0x05, 0x84, 0x03, 0x13, 0x06, 0xc4, 0x02, 0x93,
+0x06, 0x84, 0x02, 0xce, 0x85, 0xef, 0x80, 0xfe, 0xa6, 0x08, 0xa0, 0xef, 0xa0, 0x0c, 0xf8, 0x48,
+0x74, 0x0c, 0x74, 0x02, 0x36, 0x53, 0x05, 0x05, 0x42, 0xd3, 0x85, 0x05, 0x42, 0xce, 0x85, 0xef,
+0x80, 0x4e, 0xf6, 0x53, 0x04, 0xa5, 0x22, 0x0a, 0x85, 0x93, 0x05, 0x00, 0x02, 0x93, 0x06, 0x00,
+0x02, 0x01, 0x46, 0xef, 0x40, 0xd7, 0xa7, 0x8a, 0x85, 0x4e, 0x85, 0xef, 0x50, 0x1b, 0xc0, 0x08,
+0x74, 0xc2, 0x25, 0x53, 0x05, 0x05, 0x42, 0xef, 0x80, 0x5e, 0x9b, 0xd3, 0x05, 0xa5, 0x22, 0x37,
+0xb5, 0x09, 0x00, 0x07, 0x36, 0x05, 0x56, 0x22, 0x85, 0x53, 0x05, 0x84, 0x22, 0xef, 0x00, 0x2b,
+0x8a, 0xa2, 0x34, 0x42, 0x34, 0xac, 0x9a, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x99, 0x37, 0xb5, 0x09,
+0x00, 0x93, 0x05, 0x85, 0x56, 0x13, 0x05, 0x51, 0x02, 0x6d, 0x46, 0x13, 0x04, 0x51, 0x02, 0xef,
+0x70, 0x56, 0xe7, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0x35, 0x58, 0x13, 0x05, 0xa1, 0x00, 0x6d,
+0x46, 0x93, 0x04, 0xa1, 0x00, 0xef, 0x70, 0xf6, 0xe5, 0xef, 0x30, 0xbc, 0x97, 0xab, 0x64, 0xa4,
+0x20, 0x37, 0xb5, 0x00, 0x20, 0x13, 0x04, 0x05, 0xf2, 0x93, 0x05, 0x40, 0x02, 0x93, 0x06, 0x40,
+0x02, 0x13, 0x09, 0x40, 0x02, 0x22, 0x85, 0x01, 0x46, 0xef, 0x40, 0x77, 0x9f, 0x26, 0x85, 0xef,
+0x80, 0x46, 0xb9, 0xaa, 0x86, 0x93, 0x05, 0x40, 0x02, 0x22, 0x85, 0x26, 0x86, 0xef, 0x40, 0xa7,
+0xbc, 0x19, 0xcd, 0x7b, 0x25, 0x00, 0x81, 0x41, 0xcd, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5,
+0x17, 0xb7, 0xb5, 0x01, 0x38, 0x93, 0x85, 0x25, 0x34, 0xef, 0x50, 0xb7, 0xa4, 0xb0, 0x99, 0x26,
+0x85, 0xef, 0x80, 0x26, 0xb6, 0xaa, 0x84, 0x8b, 0x28, 0x05, 0x1f, 0x7b, 0x25, 0x00, 0x81, 0x25,
+0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x3d, 0x93, 0x85, 0x25,
+0x34, 0x26, 0x86, 0xef, 0x50, 0x57, 0xa7, 0xb0, 0x99, 0xef, 0x80, 0x67, 0xa4, 0xaa, 0x86, 0x33,
+0x85, 0x84, 0x00, 0xb3, 0x05, 0x99, 0x40, 0x37, 0xb6, 0x09, 0x00, 0x13, 0x06, 0xe6, 0x59, 0xef,
+0x10, 0x57, 0xb3, 0x0b, 0x22, 0x05, 0x00, 0xaa, 0x94, 0x31, 0xa8, 0x7b, 0x25, 0x00, 0x81, 0x19,
+0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x44, 0x93, 0x85, 0x25,
+0x34, 0xef, 0x50, 0x37, 0x9e, 0x13, 0x06, 0x40, 0x02, 0x22, 0x85, 0xa6, 0x85, 0xef, 0x70, 0x7e,
+0x87, 0x93, 0x85, 0x34, 0x00, 0x13, 0x06, 0x40, 0x02, 0x22, 0x85, 0xef, 0x70, 0x1e, 0x8f, 0xb0,
+0x99, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x20, 0xfe, 0xef, 0x3d, 0xc1, 0x2a, 0x84, 0x37, 0xb5, 0x00,
+0x20, 0x03, 0x15, 0x85, 0x6a, 0x85, 0x65, 0x95, 0x05, 0x23, 0x10, 0xb4, 0x00, 0x93, 0x05, 0x85,
+0x00, 0x23, 0x13, 0xb4, 0x00, 0x13, 0x05, 0x84, 0x00, 0xac, 0x91, 0xef, 0xf0, 0xdd, 0xae, 0x23,
+0x11, 0xa4, 0x00, 0xef, 0xf0, 0x9d, 0x91, 0xfb, 0x25, 0x00, 0x81, 0x23, 0x12, 0xa4, 0x00, 0x0b,
+0xc8, 0x05, 0x03, 0x03, 0x56, 0x64, 0x00, 0x83, 0x56, 0x24, 0x00, 0x37, 0x05, 0x23, 0x00, 0x13,
+0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x25, 0x93, 0x85, 0x25, 0x4c, 0xef, 0x50, 0x57, 0xa1, 0x03,
+0x55, 0x64, 0x00, 0x93, 0x05, 0x85, 0x00, 0x22, 0x85, 0x80, 0x98, 0x6f, 0xf0, 0xdd, 0x96, 0x9f,
+0x1f, 0x05, 0x04, 0x01, 0x07, 0xf8, 0xa0, 0x98, 0x00, 0x00, 0x40, 0x98, 0x0b, 0x94, 0x15, 0x01,
+0x2a, 0x86, 0x13, 0x05, 0xb1, 0x00, 0x85, 0x45, 0x85, 0x46, 0xef, 0x40, 0x47, 0xaa, 0x03, 0x46,
+0xb1, 0x00, 0x8b, 0x1f, 0x06, 0x01, 0x37, 0x55, 0x00, 0x20, 0x13, 0x05, 0x85, 0x88, 0x0c, 0x51,
+0x48, 0x51, 0xfb, 0x26, 0x00, 0x81, 0x37, 0xb7, 0x09, 0x00, 0x23, 0x26, 0xa7, 0x70, 0x23, 0x24,
+0xb7, 0x70, 0x0b, 0xc6, 0x06, 0x03, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5,
+0x02, 0x30, 0x93, 0x85, 0x25, 0x5c, 0xef, 0x50, 0x97, 0x95, 0x20, 0x98, 0x85, 0x45, 0x39, 0xa8,
+0x7b, 0x25, 0x00, 0x81, 0x19, 0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5,
+0x02, 0x2b, 0x93, 0x85, 0x25, 0x54, 0xef, 0x50, 0x97, 0x93, 0x89, 0x45, 0x7b, 0x6e, 0xb5, 0x6c,
+0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0xef, 0x70, 0x4b, 0xcd, 0xaa, 0x85,
+0x05, 0x45, 0x85, 0xc5, 0x0b, 0x54, 0x04, 0x0a, 0x85, 0x45, 0xb3, 0x95, 0x85, 0x00, 0x93, 0xf5,
+0x85, 0x23, 0x81, 0xed, 0xfd, 0x75, 0xfd, 0x15, 0xa2, 0x95, 0x8b, 0xd4, 0x05, 0x09, 0x05, 0x46,
+0xb3, 0x15, 0xb6, 0x00, 0x93, 0xf5, 0x15, 0x14, 0x91, 0xc1, 0xa0, 0x98, 0x01, 0x45, 0xa0, 0x98,
+0x00, 0x00, 0xc0, 0x98, 0x8b, 0x9f, 0x05, 0x02, 0x2a, 0x86, 0x0a, 0x85, 0x89, 0x45, 0x89, 0x46,
+0x09, 0x44, 0xef, 0x40, 0xc7, 0x9e, 0x03, 0x46, 0x01, 0x00, 0x0b, 0x4c, 0x06, 0x02, 0x7b, 0x25,
+0x00, 0x81, 0x09, 0xcd, 0x83, 0x46, 0x11, 0x00, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17,
+0xb7, 0xb5, 0x02, 0x4b, 0x93, 0x85, 0x25, 0x54, 0xef, 0x50, 0xf7, 0x90, 0x7b, 0x6e, 0x85, 0x6c,
+0xa0, 0x98, 0x85, 0x45, 0x7b, 0x6e, 0xb5, 0x6c, 0xa0, 0x98, 0xef, 0x30, 0x0c, 0xc4, 0x2a, 0x84,
+0x83, 0x45, 0x01, 0x00, 0x03, 0x25, 0x45, 0x11, 0x2c, 0xc8, 0x0b, 0x97, 0x05, 0x01, 0x13, 0x65,
+0x05, 0x04, 0x23, 0x2a, 0xa4, 0x10, 0xef, 0x30, 0x4c, 0xf1, 0x13, 0x35, 0x15, 0x00, 0x05, 0x05,
+0x23, 0x0a, 0xa4, 0x04, 0x29, 0xa0, 0x13, 0x75, 0xf5, 0xfb, 0x23, 0x2a, 0xa4, 0x10, 0x7b, 0x25,
+0x00, 0x81, 0x0b, 0x48, 0x05, 0x03, 0x03, 0x46, 0x01, 0x00, 0x83, 0x46, 0x11, 0x00, 0x37, 0x05,
+0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x5a, 0x93, 0x85, 0x25, 0x5c, 0xef, 0x50,
+0x97, 0x8a, 0xa0, 0x98, 0x00, 0x00, 0x4c, 0x98, 0x0b, 0x92, 0x25, 0x1c, 0x2a, 0x86, 0x08, 0x10,
+0xf1, 0x45, 0xf1, 0x46, 0xef, 0x40, 0xa7, 0x94, 0x83, 0x46, 0x01, 0x02, 0x37, 0xb5, 0x09, 0x00,
+0x83, 0x05, 0x15, 0x6d, 0x36, 0x86, 0x2b, 0xe6, 0xd5, 0x20, 0xa3, 0x08, 0xc5, 0x6c, 0x03, 0x47,
+0x11, 0x02, 0x83, 0x47, 0x21, 0x02, 0x7b, 0x25, 0x00, 0x81, 0xb7, 0xb5, 0x09, 0x00, 0x23, 0x88,
+0xe5, 0x70, 0x93, 0x85, 0x05, 0x71, 0xa3, 0x80, 0xf5, 0x00, 0x0b, 0x41, 0x15, 0x03, 0x03, 0x48,
+0x31, 0x02, 0x83, 0x58, 0x41, 0x02, 0x83, 0x52, 0x61, 0x02, 0x03, 0x53, 0x81, 0x02, 0x83, 0x53,
+0xa1, 0x02, 0x32, 0x5e, 0x42, 0x55, 0xd2, 0x55, 0x62, 0x56, 0x32, 0xcc, 0x2e, 0xca, 0x2a, 0xc8,
+0x72, 0xc6, 0x1e, 0xc4, 0x1a, 0xc2, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5,
+0x02, 0x73, 0x93, 0x85, 0x25, 0x5c, 0x31, 0x46, 0x16, 0xc0, 0xef, 0x50, 0xd7, 0x93, 0x2c, 0x98,
+0x85, 0x45, 0x7b, 0x6e, 0xb5, 0x6c, 0x2c, 0x98, 0x00, 0x00, 0x40, 0x98, 0x22, 0xa0, 0x33, 0xc8,
+0xb6, 0x00, 0xb3, 0x38, 0xc5, 0x00, 0x33, 0xb7, 0xd5, 0x00, 0x2b, 0xe7, 0x08, 0x21, 0x33, 0x38,
+0xa6, 0x00, 0xb3, 0x87, 0xb6, 0x40, 0xb3, 0x87, 0x07, 0x41, 0x33, 0x08, 0xa6, 0x40, 0x95, 0x8d,
+0xb3, 0x85, 0x15, 0x41, 0x11, 0x8d, 0xab, 0xe5, 0xe7, 0x22, 0x2b, 0x65, 0xe8, 0x22, 0x41, 0x81,
+0x2b, 0x26, 0xb5, 0x20, 0x93, 0xd6, 0x05, 0x01, 0x33, 0x35, 0xc0, 0x00, 0x2b, 0x05, 0xb5, 0x60,
+0xe8, 0x8d, 0x70, 0x8d, 0x2b, 0x65, 0xe6, 0x22, 0xab, 0xe5, 0xe6, 0x22, 0xef, 0xd0, 0xa6, 0xbf,
+0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x5a, 0x53, 0x74, 0x05, 0x12, 0xef, 0x50, 0xeb, 0xe5,
+0xef, 0xd0, 0x66, 0xbe, 0x53, 0x75, 0xa4, 0x1a, 0x02, 0x24, 0x20, 0x98, 0x00, 0x00, 0xc0, 0x98,
+0xef, 0x10, 0x6e, 0xd4, 0x2a, 0x84, 0xef, 0x50, 0x5e, 0xc4, 0x37, 0xb6, 0x09, 0x00, 0x83, 0x25,
+0xc6, 0x70, 0x03, 0x27, 0x86, 0x70, 0x33, 0x66, 0xb7, 0x00, 0x01, 0xca, 0x74, 0x49, 0x30, 0x49,
+0x3a, 0x85, 0xa5, 0x37, 0x53, 0x15, 0x15, 0xc2, 0x11, 0xa0, 0x01, 0x45, 0x08, 0xc0, 0xef, 0xb0,
+0x4e, 0xd5, 0x23, 0x02, 0xa4, 0x00, 0xef, 0x50, 0x4e, 0xbc, 0xb7, 0xc5, 0x04, 0x20, 0x93, 0x85,
+0x85, 0xf6, 0x07, 0xb0, 0x05, 0x73, 0x53, 0x75, 0x10, 0x40, 0x53, 0x06, 0x05, 0xe0, 0xa3, 0x28,
+0xc4, 0x00, 0x07, 0xb0, 0x05, 0x14, 0x53, 0x75, 0x10, 0x40, 0x53, 0x06, 0x05, 0xe0, 0xa3, 0x26,
+0xc4, 0x00, 0x03, 0xa6, 0x85, 0x71, 0x83, 0xa5, 0x05, 0x1d, 0x23, 0x03, 0xa4, 0x00, 0xa3, 0x13,
+0xc4, 0x00, 0xa3, 0x24, 0xb4, 0x00, 0xef, 0x10, 0x4e, 0xcc, 0x2a, 0x84, 0x05, 0x65, 0x2d, 0x05,
+0x23, 0x10, 0xa4, 0x00, 0x55, 0x45, 0x23, 0x13, 0xa4, 0x00, 0xef, 0xf0, 0x8d, 0xde, 0x83, 0x55,
+0x64, 0x00, 0x23, 0x12, 0xa4, 0x00, 0x13, 0x05, 0x84, 0x00, 0xef, 0xf0, 0x4d, 0xfa, 0x2a, 0x87,
+0x23, 0x11, 0xa4, 0x00, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x48, 0x05, 0x03, 0x03, 0x56, 0x04, 0x00,
+0x83, 0x56, 0x64, 0x00, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x03, 0x45,
+0x93, 0x85, 0x25, 0x5c, 0xef, 0x50, 0xe7, 0xf2, 0x03, 0x55, 0x64, 0x00, 0x93, 0x05, 0x85, 0x00,
+0x22, 0x85, 0x80, 0x98, 0x6f, 0xf0, 0xad, 0xe2, 0x00, 0x00, 0x40, 0x99, 0x03, 0xc6, 0xb5, 0x00,
+0x2a, 0x84, 0x0d, 0x45, 0x0b, 0x03, 0x16, 0x01, 0x83, 0xc4, 0x95, 0x00, 0x33, 0x85, 0xb4, 0x00,
+0x03, 0x45, 0x25, 0x00, 0x0b, 0xcf, 0x04, 0x03, 0x0b, 0x0e, 0x05, 0x02, 0x0b, 0x0d, 0x05, 0x04,
+0xef, 0x10, 0xe0, 0x08, 0x4c, 0x44, 0x53, 0x80, 0x05, 0xd2, 0xd3, 0x80, 0x14, 0xd2, 0x11, 0xc5,
+0x37, 0xb5, 0x09, 0x00, 0x07, 0x31, 0x85, 0x5b, 0x29, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x31,
+0x05, 0x5b, 0xd3, 0xf0, 0x20, 0x12, 0xd3, 0x85, 0x00, 0xa2, 0x15, 0x45, 0x91, 0xe1, 0x11, 0x45,
+0x20, 0x99, 0x00, 0x00, 0x00, 0x00, 0x83, 0x45, 0xf5, 0x02, 0x13, 0xf6, 0x05, 0x02, 0x53, 0x05,
+0x00, 0xd2, 0x59, 0xca, 0x54, 0x45, 0x18, 0x45, 0x37, 0xb6, 0x09, 0x00, 0x07, 0x30, 0x06, 0x5c,
+0x03, 0x46, 0x15, 0x02, 0xd3, 0x80, 0x16, 0xd2, 0x53, 0x01, 0x17, 0xd2, 0x43, 0x70, 0x01, 0x0a,
+0x0b, 0x53, 0x16, 0x06, 0x85, 0x46, 0xb3, 0x96, 0xc6, 0x00, 0x93, 0xf6, 0x96, 0x02, 0x9d, 0xce,
+0xab, 0xe6, 0x35, 0x44, 0x11, 0xca, 0x03, 0x05, 0x05, 0x02, 0x0b, 0x17, 0x06, 0x03, 0x37, 0x07,
+0x04, 0x20, 0x13, 0x07, 0x07, 0xde, 0x21, 0xa8, 0x03, 0x05, 0x05, 0x02, 0x37, 0x57, 0x04, 0x20,
+0x13, 0x07, 0x07, 0xcf, 0x29, 0xa0, 0xdf, 0xbc, 0x05, 0x04, 0x01, 0x08, 0xf7, 0x37, 0x57, 0x04,
+0x20, 0x13, 0x07, 0x07, 0xcc, 0x3a, 0x95, 0x89, 0xca, 0x03, 0x45, 0x05, 0x00, 0x11, 0xc5, 0x63,
+0x82, 0xa6, 0x02, 0x53, 0x05, 0x00, 0x22, 0x82, 0x80, 0x01, 0x45, 0x13, 0x36, 0x16, 0x00, 0x8d,
+0x89, 0x93, 0xc6, 0x35, 0x00, 0xab, 0x65, 0xd0, 0x20, 0x2b, 0xe5, 0xc5, 0x22, 0x09, 0xc9, 0x0b,
+0x19, 0xf5, 0x01, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85, 0x5c, 0x53, 0x75, 0x10, 0x02, 0x82,
+0x80, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x99, 0x2a, 0x84, 0x03, 0x06, 0x05, 0x02, 0x03, 0x45, 0x15,
+0x02, 0xae, 0x84, 0x23, 0x90, 0xc5, 0x02, 0xa3, 0x86, 0xa5, 0x02, 0xb2, 0x85, 0xef, 0x90, 0xce,
+0xe6, 0x83, 0xd5, 0x04, 0x02, 0x03, 0xc6, 0xd4, 0x02, 0x23, 0x91, 0xa4, 0x02, 0x2e, 0x89, 0x8b,
+0x15, 0x06, 0x01, 0x37, 0x15, 0x00, 0x20, 0x13, 0x05, 0x85, 0x01, 0x2b, 0x05, 0xb5, 0x04, 0x08,
+0x41, 0x13, 0x09, 0x75, 0x00, 0x03, 0x05, 0x04, 0x03, 0x23, 0x88, 0xa4, 0x02, 0xec, 0x91, 0x32,
+0x85, 0xef, 0xf0, 0x1e, 0xdf, 0xa3, 0x89, 0xa4, 0x02, 0x03, 0xc5, 0xd4, 0x02, 0x02, 0xc4, 0x02,
+0xc2, 0x02, 0xc0, 0x93, 0x15, 0x09, 0x01, 0xc1, 0x81, 0x0a, 0x86, 0xef, 0x80, 0x3e, 0xa4, 0x02,
+0x45, 0x83, 0x05, 0x44, 0x02, 0x03, 0x06, 0xb4, 0x02, 0x23, 0x83, 0xa4, 0x02, 0x23, 0x86, 0xb4,
+0x02, 0xa3, 0x82, 0xc4, 0x02, 0x03, 0x05, 0xe4, 0x01, 0x83, 0x05, 0x34, 0x02, 0x03, 0x06, 0x74,
+0x02, 0x83, 0x06, 0x24, 0x02, 0x23, 0x82, 0xa4, 0x02, 0xa3, 0x83, 0xb4, 0x02, 0xa3, 0x88, 0xc4,
+0x02, 0x13, 0x85, 0xd6, 0xff, 0x88, 0x91, 0x93, 0xb5, 0xa5, 0x00, 0x13, 0x06, 0x10, 0x21, 0x33,
+0x55, 0xa6, 0x00, 0x6d, 0x8d, 0x4c, 0x44, 0x10, 0x44, 0xb7, 0xb6, 0x09, 0x00, 0x07, 0xb0, 0x06,
+0x5c, 0x23, 0x8a, 0xa4, 0x02, 0xd3, 0x80, 0x05, 0xd2, 0x53, 0x01, 0x16, 0xd2, 0x43, 0x70, 0x01,
+0x0a, 0x27, 0xb8, 0x04, 0x00, 0x22, 0x85, 0x59, 0x35, 0x03, 0x05, 0xf4, 0x02, 0x88, 0xa8, 0x23,
+0x87, 0xa4, 0x02, 0xa4, 0x99, 0x40, 0x99, 0xef, 0x30, 0xac, 0x81, 0x2a, 0x84, 0x13, 0x05, 0xf0,
+0x0f, 0x23, 0x12, 0xa4, 0x00, 0xef, 0x30, 0xcc, 0xaf, 0x93, 0x05, 0x10, 0x24, 0x93, 0x04, 0x10,
+0x20, 0x13, 0x06, 0x10, 0x20, 0x2b, 0xe6, 0xa5, 0x20, 0x23, 0x2a, 0xc4, 0x10, 0xef, 0x30, 0x4c,
+0xae, 0x83, 0x25, 0x44, 0x11, 0x13, 0x35, 0x15, 0x00, 0x05, 0x05, 0x13, 0xf6, 0x05, 0x04, 0xa3,
+0x0a, 0xa4, 0x04, 0x09, 0xc6, 0x05, 0x46, 0x30, 0xc8, 0x23, 0x0a, 0xa4, 0x04, 0x13, 0xf5, 0x05,
+0x20, 0x23, 0x0b, 0x04, 0x04, 0x11, 0xc5, 0xef, 0x30, 0xac, 0xab, 0x19, 0xe1, 0x23, 0x1c, 0x94,
+0x04, 0x23, 0x01, 0x04, 0x14, 0x20, 0x99, 0x00, 0x00, 0x40, 0x98, 0xef, 0x20, 0x7c, 0xfb, 0x89,
+0x45, 0x23, 0x05, 0xb5, 0x00, 0xb7, 0xd5, 0x4c, 0x3f, 0x93, 0x85, 0xd5, 0xcc, 0x23, 0x26, 0xb5,
+0x12, 0x20, 0x98, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x50, 0x2d, 0xbb, 0x79, 0xed, 0x37, 0xb5, 0x04,
+0x20, 0x93, 0x05, 0x05, 0x6b, 0xc8, 0x49, 0x09, 0xc9, 0x07, 0xb0, 0x85, 0x00, 0x05, 0x05, 0xd3,
+0x00, 0x15, 0xd2, 0x53, 0x15, 0x10, 0xa2, 0x69, 0xe1, 0xef, 0x50, 0xce, 0x81, 0xb7, 0xc5, 0x04,
+0x20, 0x13, 0x84, 0x85, 0xf6, 0x83, 0x25, 0x04, 0x16, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15,
+0x00, 0x4d, 0x8d, 0x5d, 0xe1, 0xef, 0x20, 0xdc, 0xf5, 0x03, 0x45, 0xc5, 0x0e, 0x0b, 0x17, 0x25,
+0x01, 0xef, 0x50, 0x0e, 0x87, 0x07, 0x30, 0x84, 0x12, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb0, 0x05,
+0x66, 0xd3, 0x95, 0x00, 0xa2, 0x37, 0xb6, 0x09, 0x00, 0x13, 0x06, 0x86, 0x5d, 0xab, 0x05, 0xb6,
+0x06, 0x07, 0xb0, 0x05, 0x00, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb0, 0x05, 0x5d, 0xb7, 0xb5, 0x09,
+0x00, 0x83, 0xc5, 0x05, 0x71, 0x13, 0x35, 0x15, 0x00, 0x2b, 0xe0, 0xa0, 0x3a, 0x07, 0x25, 0x04,
+0x1d, 0x13, 0xb5, 0x15, 0x00, 0xd3, 0x80, 0x15, 0xd2, 0xab, 0x60, 0xa0, 0x3a, 0x53, 0x00, 0x05,
+0x42, 0x53, 0x95, 0x00, 0xa2, 0x05, 0xc9, 0x23, 0x20, 0x04, 0x16, 0x23, 0x20, 0x04, 0x18, 0x13,
+0x05, 0x84, 0x1f, 0x93, 0x05, 0x00, 0x29, 0x93, 0x06, 0x00, 0x29, 0x01, 0x46, 0xef, 0x40, 0x07,
+0xa7, 0x13, 0x05, 0x84, 0x48, 0x93, 0x05, 0x00, 0x29, 0x93, 0x06, 0x00, 0x29, 0x01, 0x46, 0x80,
+0x98, 0x6f, 0x40, 0xc7, 0xa5, 0x03, 0x45, 0x14, 0x72, 0x0b, 0x14, 0x05, 0x02, 0xef, 0x40, 0x5e,
+0xfe, 0x79, 0xd1, 0xef, 0x40, 0xbd, 0xa3, 0x61, 0xd1, 0xa0, 0x98, 0x00, 0x00, 0xc0, 0x98, 0x37,
+0x24, 0x04, 0x20, 0x83, 0x25, 0x44, 0xe3, 0x37, 0xb5, 0x09, 0x00, 0x03, 0x45, 0x15, 0x6d, 0xb3,
+0x35, 0xb0, 0x00, 0x13, 0x06, 0xd5, 0xfd, 0x13, 0x36, 0x16, 0x00, 0xd1, 0x8d, 0x99, 0xe5, 0xef,
+0x20, 0x3c, 0xd2, 0x13, 0x05, 0x44, 0xe3, 0x85, 0x45, 0x0c, 0xc1, 0xed, 0x35, 0x80, 0x98, 0x6f,
+0x00, 0x30, 0x54, 0x00, 0x00, 0x40, 0x99, 0x2a, 0x84, 0xef, 0x60, 0x1d, 0xbc, 0xaa, 0x84, 0xef,
+0x40, 0x7e, 0xf3, 0x05, 0xc1, 0x37, 0xb5, 0x09, 0x00, 0x03, 0x45, 0x15, 0x71, 0x93, 0x75, 0x05,
+0x08, 0x91, 0xe5, 0x13, 0x75, 0x05, 0x04, 0x11, 0xc5, 0x09, 0x45, 0x11, 0xa0, 0x05, 0x45, 0x23,
+0x8c, 0xa4, 0x00, 0x03, 0xc5, 0x84, 0x01, 0x93, 0x65, 0x25, 0x00, 0x8b, 0x93, 0x05, 0x02, 0x22,
+0x85, 0xef, 0x70, 0x0d, 0xc5, 0x03, 0xc5, 0x84, 0x01, 0x8b, 0x14, 0x05, 0x01, 0x09, 0x45, 0x23,
+0x8c, 0xa4, 0x00, 0x22, 0x85, 0xef, 0x70, 0xcd, 0xc3, 0x11, 0xc1, 0x20, 0x99, 0x05, 0x45, 0x23,
+0x8c, 0xa4, 0x00, 0x22, 0x85, 0x00, 0x99, 0x6f, 0x70, 0xad, 0xc2, 0x00, 0x00, 0x40, 0x99, 0x2a,
+0x84, 0x05, 0x65, 0xb3, 0x05, 0xa4, 0x00, 0x83, 0xa5, 0x85, 0xb0, 0x13, 0x05, 0x05, 0xb0, 0x0b,
+0x98, 0x05, 0x01, 0xb7, 0xd5, 0x4c, 0x3f, 0x93, 0x85, 0xd5, 0xcc, 0x23, 0x26, 0xb4, 0x0e, 0xb7,
+0x05, 0x40, 0x40, 0x23, 0x28, 0xb4, 0x0e, 0xb7, 0x05, 0x00, 0x40, 0x23, 0x24, 0xb4, 0x0e, 0xb3,
+0x04, 0xa4, 0x00, 0xef, 0x20, 0xfc, 0xdd, 0x03, 0x45, 0xc5, 0x0e, 0x15, 0xcd, 0xef, 0x20, 0x5c,
+0xdd, 0x03, 0x45, 0xc5, 0x0e, 0x0d, 0xe1, 0x07, 0x30, 0x84, 0x05, 0x37, 0xb5, 0x09, 0x00, 0x87,
+0x30, 0x85, 0x5e, 0x53, 0x15, 0x10, 0xa2, 0x01, 0xc9, 0x37, 0x05, 0x00, 0x40, 0x23, 0x26, 0xa4,
+0x0e, 0x37, 0x05, 0x80, 0x3f, 0x31, 0xa0, 0x88, 0x40, 0x0b, 0x15, 0x05, 0x01, 0x37, 0x05, 0x80,
+0x40, 0x23, 0x28, 0xa4, 0x0e, 0x21, 0xa0, 0x03, 0xc5, 0x84, 0x01, 0x69, 0xd1, 0x20, 0x99, 0x00,
+0x00, 0x50, 0x9e, 0xa2, 0xa0, 0x26, 0xbc, 0x4a, 0xb8, 0x4e, 0xb4, 0x52, 0xb0, 0x56, 0xac, 0x5a,
+0xa8, 0x5e, 0xa4, 0x32, 0x84, 0xae, 0x89, 0x2a, 0xc2, 0xef, 0x00, 0xd0, 0x42, 0x64, 0x9d, 0x93,
+0x25, 0x14, 0x00, 0x4d, 0x8d, 0x63, 0x19, 0x05, 0x14, 0x81, 0x44, 0x09, 0x65, 0x13, 0x05, 0x05,
+0x86, 0xb3, 0x8a, 0xa9, 0x00, 0x05, 0x65, 0x13, 0x0b, 0x85, 0xc6, 0xb3, 0x8b, 0x69, 0x01, 0x13,
+0x8c, 0x89, 0x12, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa4, 0x05, 0x5f, 0xb7, 0xb5, 0x78, 0x80, 0x05,
+0x04, 0x01, 0x09, 0xf6, 0x09, 0x00, 0x87, 0xa4, 0x45, 0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb9,
+0x05, 0x6a, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb9, 0x85, 0x60, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xaa,
+0x85, 0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xaa, 0xc5, 0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xbb,
+0x05, 0x60, 0x93, 0x0c, 0x05, 0xc6, 0x13, 0x0d, 0x45, 0xc6, 0xd3, 0x0b, 0x00, 0xf0, 0xab, 0x8d,
+0x99, 0x04, 0x13, 0x8a, 0x8d, 0x2a, 0x52, 0x85, 0x53, 0x05, 0x84, 0x20, 0xef, 0x40, 0x5d, 0xdd,
+0x13, 0x85, 0x8d, 0x36, 0x53, 0x85, 0x94, 0x20, 0xef, 0x40, 0x9d, 0xdc, 0x81, 0x45, 0x01, 0x45,
+0x01, 0x49, 0x2b, 0x86, 0x99, 0x0a, 0x33, 0x08, 0x96, 0x01, 0xb3, 0x08, 0xa6, 0x01, 0x33, 0x07,
+0x66, 0x01, 0xe2, 0x87, 0x5e, 0x86, 0x53, 0x05, 0x00, 0xf0, 0x63, 0x87, 0xb4, 0x04, 0xb3, 0x86,
+0xba, 0x00, 0x83, 0xc6, 0x06, 0x00, 0xa9, 0xc2, 0x87, 0x25, 0x08, 0x00, 0x07, 0x26, 0x86, 0xff,
+0x87, 0xa6, 0x08, 0x00, 0x07, 0x27, 0xc6, 0xff, 0x1c, 0x63, 0x07, 0x28, 0x06, 0x00, 0xd3, 0xf6,
+0xe6, 0x10, 0xc3, 0xf5, 0xc5, 0x68, 0xc3, 0xf5, 0x07, 0x59, 0x53, 0x80, 0x05, 0x42, 0xd3, 0x06,
+0x0b, 0xa2, 0x99, 0xc6, 0x90, 0x63, 0x05, 0x05, 0x53, 0x76, 0xb6, 0x18, 0x53, 0x75, 0xc5, 0x00,
+0xd3, 0x86, 0x75, 0xa1, 0x91, 0xc2, 0x05, 0x09, 0x85, 0x05, 0x13, 0x06, 0x06, 0x02, 0x91, 0x07,
+0xe3, 0x15, 0xb4, 0xfa, 0x1d, 0xc1, 0x87, 0xa5, 0x8d, 0x12, 0x53, 0x76, 0x05, 0xd0, 0x53, 0x75,
+0xc5, 0x18, 0x53, 0x75, 0x45, 0x01, 0x53, 0x15, 0xb5, 0xa0, 0x01, 0xc9, 0x53, 0xf5, 0xb5, 0x10,
+0x53, 0x75, 0x55, 0x11, 0x52, 0x85, 0xef, 0x40, 0xbd, 0xd2, 0x8b, 0x3b, 0x09, 0x03, 0x12, 0x45,
+0x2b, 0x75, 0x95, 0x58, 0x48, 0x75, 0x53, 0x00, 0x05, 0x42, 0x53, 0x70, 0x20, 0x13, 0x53, 0x15,
+0x30, 0xa3, 0x19, 0xc9, 0x07, 0xa5, 0x8d, 0x12, 0x53, 0x15, 0xaa, 0xa0, 0x11, 0xc5, 0x53, 0x75,
+0xa5, 0x10, 0x52, 0x85, 0xef, 0x40, 0xdd, 0xcf, 0x85, 0x04, 0xe3, 0x9a, 0x84, 0xf0, 0xa2, 0x2b,
+0x42, 0x2b, 0xe2, 0x2a, 0x02, 0x3a, 0xa2, 0x39, 0x42, 0x39, 0xe2, 0x34, 0x06, 0x24, 0x30, 0x9e,
+0x00, 0x00, 0x00, 0x00, 0x40, 0x99, 0x2e, 0x84, 0xaa, 0x84, 0xef, 0x20, 0xfc, 0xbf, 0x03, 0x45,
+0xc5, 0x0e, 0x25, 0xc1, 0x05, 0x65, 0x26, 0x95, 0x03, 0x05, 0xa5, 0xb4, 0x75, 0x15, 0x08, 0x91,
+0x8b, 0x54, 0x15, 0x02, 0x8b, 0x23, 0x14, 0x01, 0x01, 0x46, 0xb3, 0x25, 0x80, 0x00, 0x09, 0x65,
+0x93, 0x06, 0x05, 0x86, 0xa6, 0x96, 0x22, 0x87, 0x83, 0xc7, 0x06, 0x00, 0x81, 0xc7, 0x83, 0xc7,
+0x06, 0x03, 0x3e, 0x96, 0x7d, 0x17, 0x85, 0x06, 0x65, 0xfb, 0x13, 0x26, 0x86, 0x00, 0xe4, 0x9d,
+0xd1, 0x8d, 0x85, 0xe1, 0x13, 0x05, 0x05, 0x89, 0x26, 0x95, 0x83, 0x45, 0x05, 0xfd, 0x81, 0xc5,
+0x83, 0x45, 0x05, 0x00, 0x81, 0xe5, 0x23, 0x08, 0x05, 0xfc, 0x02, 0x11, 0x7d, 0x14, 0x05, 0x05,
+0x6d, 0xf4, 0x20, 0x99, 0x00, 0x00, 0x00, 0x00, 0x44, 0x9a, 0x22, 0xa8, 0x26, 0xa4, 0xb2, 0x89,
+0x8b, 0x86, 0x06, 0x02, 0x8b, 0x98, 0x16, 0x01, 0x89, 0x65, 0x93, 0x85, 0x05, 0x89, 0xb3, 0x04,
+0xb5, 0x00, 0x13, 0x04, 0x85, 0x1e, 0x21, 0x05, 0x01, 0xa8, 0x89, 0x65, 0x93, 0x85, 0x05, 0x86,
+0xb3, 0x04, 0xb5, 0x00, 0x13, 0x04, 0x85, 0x12, 0x00, 0x21, 0xef, 0x00, 0x30, 0x21, 0x0b, 0xae,
+0x09, 0x01, 0x2a, 0x89, 0xd3, 0x04, 0x00, 0xf0, 0x03, 0xc5, 0x04, 0x00, 0x05, 0xc1, 0x08, 0x60,
+0x53, 0x05, 0x05, 0x42, 0xef, 0x90, 0xa6, 0x80, 0x53, 0x15, 0xa4, 0xa2, 0x63, 0x06, 0x09, 0x00,
+0x11, 0xc5, 0x08, 0x60, 0x53, 0x95, 0xa4, 0xa0, 0x11, 0xc1, 0x82, 0x10, 0xfd, 0x19, 0x11, 0x04,
+0x85, 0x04, 0xe3, 0x9b, 0x09, 0xfc, 0xa2, 0x24, 0x42, 0x24, 0x24, 0x9a, 0x00, 0x00, 0x00, 0x00,
+0xc8, 0x99, 0x22, 0xac, 0x26, 0xa8, 0x4a, 0xa4, 0x2a, 0x84, 0x05, 0x65, 0x13, 0x05, 0xa5, 0xb2,
+0xb3, 0x04, 0xa4, 0x00, 0x07, 0xb0, 0x64, 0x0b, 0x87, 0xb0, 0xe4, 0x0a, 0x09, 0x65, 0x53, 0x75,
+0x10, 0x40, 0xd3, 0xf5, 0x10, 0x40, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb0, 0x05, 0x61, 0xb7, 0xb5,
+0x09, 0x00, 0x87, 0xb0, 0x85, 0x61, 0x83, 0xd5, 0x04, 0x00, 0x53, 0x81, 0x05, 0x42, 0x53, 0x71,
+0x01, 0x12, 0xd3, 0x01, 0x05, 0x42, 0x53, 0x82, 0x15, 0xd2, 0x53, 0x72, 0x12, 0x12, 0x43, 0xf0,
+0x01, 0x22, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa5, 0x85, 0x62, 0x87, 0x31, 0x04, 0x0a, 0x13, 0x05,
+0xd5, 0x8c, 0x53, 0x74, 0x10, 0x40, 0xd3, 0x05, 0x85, 0xa0, 0x43, 0xf0, 0x11, 0x12, 0x8d, 0xe9,
+0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa5, 0xc5, 0x62, 0x53, 0x06, 0xa4, 0xa0, 0xb7, 0xb5, 0x09, 0x00,
+0x0d, 0xe6, 0x37, 0xb6, 0x09, 0x00, 0x07, 0x25, 0x46, 0x63, 0x87, 0xa5, 0x05, 0x63, 0xb7, 0xb5,
+0x09, 0x00, 0x07, 0xa6, 0x85, 0x63, 0x53, 0x75, 0xa4, 0x00, 0x43, 0x75, 0xc5, 0x58, 0x01, 0xa8,
+0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa5, 0xc5, 0x67, 0x19, 0xa0, 0x07, 0xa5, 0x05, 0x63, 0x83, 0x85,
+0x04, 0x02, 0xd3, 0x74, 0x10, 0x40, 0xf5, 0x15, 0x8c, 0x91, 0x33, 0x09, 0xa4, 0x00, 0x8b, 0xc8,
+0x05, 0x02, 0x53, 0x79, 0x95, 0x10, 0xef, 0x00, 0x70, 0x10, 0x0d, 0xc1, 0x28, 0x34, 0xef, 0x80,
+0x16, 0xf1, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x62, 0x53, 0x15, 0x05, 0xa2, 0x19, 0xc5,
+0xef, 0x30, 0x5d, 0x8b, 0x07, 0x30, 0x05, 0x46, 0x53, 0x79, 0x10, 0x40, 0x37, 0xb5, 0x09, 0x00,
+0x07, 0x25, 0xc5, 0x63, 0x03, 0x45, 0x09, 0x00, 0xd3, 0x15, 0xa9, 0xa0, 0x37, 0xb6, 0x09, 0x00,
+0x07, 0x30, 0x86, 0x66, 0x13, 0x35, 0x65, 0x00, 0x6d, 0x8d, 0xd3, 0x00, 0x09, 0x42, 0xab, 0x60,
+0xa0, 0x3a, 0x27, 0x38, 0x14, 0x04, 0x53, 0x00, 0x04, 0x42, 0x27, 0xbb, 0x04, 0x0a, 0x27, 0xb3,
+0x14, 0x0a, 0x53, 0x80, 0x04, 0x42, 0x27, 0xb7, 0x04, 0x0a, 0xef, 0x40, 0xad, 0xd2, 0xaa, 0x84,
+0x48, 0x71, 0x0c, 0x61, 0x30, 0x65, 0x53, 0x75, 0xa5, 0x10, 0x43, 0xf5, 0xb5, 0x50, 0x43, 0x75,
+0xc6, 0x50, 0x53, 0x05, 0x05, 0x42, 0xef, 0xa0, 0x76, 0xac, 0x87, 0xa5, 0x84, 0x0d, 0x07, 0xa6,
+0x44, 0x0b, 0x87, 0xa6, 0xc4, 0x0f, 0x08, 0xb4, 0x53, 0xf5, 0xb5, 0x10, 0x43, 0x75, 0xc6, 0x50,
+0x43, 0xf5, 0xd6, 0x50, 0x53, 0x05, 0x05, 0x42, 0xef, 0xa0, 0x56, 0xaa, 0x08, 0xb0, 0x22, 0x29,
+0xc2, 0x24, 0x62, 0x24, 0xa8, 0x99, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x86, 0x2a, 0x84, 0x05, 0x65,
+0x07, 0x30, 0x84, 0x05, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb0, 0x05, 0x64, 0xb3, 0x05, 0xa4, 0x00,
+0x83, 0xc5, 0x85, 0xb1, 0x13, 0x05, 0x85, 0xb0, 0xd3, 0x96, 0x00, 0xa2, 0xb3, 0x04, 0xa4, 0x00,
+0x81, 0xc6, 0x99, 0xc1, 0x81, 0x45, 0x82, 0x14, 0x32, 0x85, 0xef, 0x40, 0xad, 0xee, 0xcc, 0x44,
+0x05, 0x49, 0x8b, 0x81, 0x05, 0x01, 0x2a, 0x89, 0x07, 0x30, 0x84, 0x05, 0x37, 0xb5, 0x09, 0x00,
+0x87, 0x30, 0x85, 0x65, 0x53, 0x15, 0x10, 0xa2, 0x01, 0xcd, 0xef, 0x20, 0xad, 0x93, 0x8b, 0x14,
+0x05, 0x01, 0xef, 0x40, 0x3d, 0xde, 0x05, 0x04, 0x01, 0x0a, 0xf5, 0x7d, 0xd7, 0x8b, 0x02, 0x05,
+0x02, 0x05, 0x49, 0x23, 0x88, 0x24, 0x01, 0x22, 0x85, 0xef, 0x40, 0xad, 0xef, 0xaa, 0x85, 0x01,
+0x45, 0x8b, 0x81, 0x05, 0x01, 0x4a, 0x85, 0x8c, 0x40, 0x0b, 0x96, 0x05, 0x01, 0x83, 0xc5, 0x24,
+0x04, 0x0b, 0x84, 0x05, 0x02, 0xef, 0x40, 0x3d, 0x86, 0x8b, 0x12, 0x05, 0x01, 0x01, 0x45, 0x82,
+0x14, 0xa0, 0x99, 0x01, 0x45, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x99, 0x22, 0xac, 0x26,
+0xa8, 0x4a, 0xa4, 0x32, 0x84, 0x08, 0x22, 0x2e, 0x89, 0xaa, 0x84, 0xef, 0x80, 0x66, 0x9d, 0x07,
+0x30, 0x04, 0x00, 0x53, 0x04, 0xa5, 0x22, 0x53, 0x05, 0x00, 0x22, 0xef, 0x80, 0x86, 0x82, 0x07,
+0x30, 0x84, 0x00, 0xd3, 0x04, 0xa5, 0x22, 0x53, 0x05, 0x00, 0x22, 0xef, 0x80, 0x66, 0x9b, 0x07,
+0x30, 0x84, 0x00, 0x53, 0x09, 0xa5, 0x22, 0x53, 0x05, 0x00, 0x22, 0xef, 0x80, 0x86, 0x80, 0x07,
+0xb0, 0x84, 0x00, 0x87, 0xb0, 0x04, 0x00, 0x53, 0x11, 0x84, 0x22, 0x87, 0xb1, 0x04, 0x01, 0x53,
+0x70, 0x20, 0x12, 0xd3, 0x70, 0x19, 0x12, 0xc7, 0x70, 0x05, 0x0a, 0x53, 0xf1, 0x34, 0x12, 0xc3,
+0x70, 0x25, 0x0a, 0x27, 0x30, 0x19, 0x00, 0x87, 0xb0, 0x04, 0x00, 0xd3, 0x70, 0x15, 0x12, 0x43,
+0x70, 0x09, 0x0a, 0x43, 0x70, 0x29, 0x02, 0x27, 0x34, 0x09, 0x00, 0x07, 0xb0, 0x84, 0x00, 0x88,
+0x4c, 0x53, 0xf0, 0x04, 0x12, 0x43, 0x70, 0x34, 0x02, 0x27, 0x38, 0x09, 0x00, 0x23, 0x2c, 0xa9,
+0x00, 0x22, 0x29, 0xc2, 0x24, 0x62, 0x24, 0xa8, 0x99, 0x00, 0x00, 0xdc, 0x99, 0x59, 0x71, 0xa2,
+0xad, 0xa6, 0xa9, 0x2a, 0x84, 0x07, 0x30, 0x05, 0x00, 0x87, 0x30, 0x85, 0x00, 0x07, 0x31, 0x05,
+0x01, 0x53, 0x84, 0xb5, 0x22, 0xd3, 0x04, 0xa5, 0x22, 0xae, 0x84, 0x02, 0xb9, 0x06, 0xbd, 0x8a,
+0xa1, 0x05, 0x49, 0xca, 0xc5, 0x08, 0x19, 0x8c, 0x18, 0xef, 0x40, 0xfb, 0xd4, 0x07, 0x30, 0x84,
+0x02, 0x87, 0x30, 0x04, 0x03, 0x07, 0x31, 0x84, 0x03, 0x02, 0xa9, 0x06, 0xad, 0x0a, 0xb1, 0x4a,
+0xd5, 0x28, 0x10, 0x0c, 0x09, 0x13, 0x06, 0x00, 0x02, 0xef, 0x60, 0x76, 0xfe, 0x28, 0x00, 0x8c,
+0x18, 0x13, 0x06, 0x00, 0x02, 0xef, 0x60, 0xb6, 0xfd, 0x28, 0x10, 0x2c, 0x00, 0x90, 0x08, 0xb4,
+0x00, 0xef, 0x40, 0x7b, 0xee, 0x46, 0x20, 0xe6, 0x20, 0x53, 0x70, 0x90, 0x12, 0x82, 0xa8, 0x53,
+0xf0, 0x90, 0x12, 0x82, 0xac, 0x88, 0x08, 0x0c, 0x09, 0x90, 0x18, 0xc5, 0x35, 0x4a, 0x20, 0xea,
+0x20, 0x0a, 0x31, 0x27, 0x34, 0x04, 0x02, 0x27, 0x38, 0x14, 0x02, 0x27, 0x3c, 0x24, 0x02, 0x07,
+0x30, 0x04, 0x00, 0x87, 0xb0, 0x04, 0x00, 0x53, 0x70, 0x10, 0x0a, 0x87, 0x30, 0x84, 0x00, 0x07,
+0xb1, 0x84, 0x00, 0x87, 0x31, 0x04, 0x01, 0x07, 0xb2, 0x04, 0x01, 0x02, 0xa9, 0x53, 0xf0, 0x20,
+0x0a, 0x02, 0xad, 0x53, 0xf0, 0x41, 0x0a, 0x02, 0xb1, 0x4a, 0xd5, 0x28, 0x10, 0x0c, 0x09, 0x13,
+0x06, 0x00, 0x02, 0xef, 0x60, 0xd6, 0xf6, 0x28, 0x00, 0x8c, 0x18, 0x13, 0x06, 0x00, 0x02, 0xef,
+0x60, 0x16, 0xf6, 0x28, 0x10, 0x2c, 0x00, 0x90, 0x08, 0xb4, 0x00, 0xef, 0x40, 0xdb, 0xe6, 0x46,
+0x20, 0xe6, 0x20, 0x53, 0x70, 0x80, 0x12, 0x82, 0xa8, 0x53, 0xf0, 0x80, 0x12, 0x82, 0xac, 0x88,
+0x08, 0x0c, 0x09, 0x90, 0x18, 0x9d, 0x35, 0x07, 0xb0, 0x04, 0x00, 0xca, 0x20, 0x53, 0x70, 0x10,
+0x02, 0x27, 0x30, 0x04, 0x00, 0x07, 0xb0, 0x84, 0x00, 0xea, 0x20, 0x53, 0x70, 0x10, 0x02, 0x27,
+0x34, 0x04, 0x00, 0x07, 0xb0, 0x04, 0x01, 0x8a, 0x30, 0x53, 0x70, 0x10, 0x02, 0x27, 0x38, 0x04,
+0x00, 0xce, 0x24, 0x6e, 0x24, 0x65, 0x61, 0xbc, 0x99, 0x00, 0x00, 0x40, 0x9b, 0x2e, 0x8a, 0xaa,
+0x84, 0x05, 0x64, 0x13, 0x05, 0x04, 0xb1, 0xb3, 0x89, 0xa4, 0x00, 0xef, 0x20, 0x4c, 0xf2, 0x83,
+0x2a, 0x85, 0x0e, 0xef, 0x30, 0x8d, 0xd9, 0xaa, 0x85, 0x26, 0x85, 0x95, 0x3b, 0xb3, 0x85, 0x84,
+0x00, 0x83, 0xa5, 0x85, 0xb3, 0x25, 0x46, 0xb3, 0x35, 0xb6, 0x00, 0x33, 0x35, 0xa0, 0x00, 0x6d,
+0x8d, 0x15, 0xe1, 0x13, 0x05, 0x84, 0xb7, 0x26, 0x95, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb5, 0x05,
+0x65, 0xd2, 0x85, 0xef, 0x40, 0x4d, 0xfd, 0x23, 0xa0, 0x09, 0x00, 0x37, 0x55, 0x04, 0x20, 0x23,
+0x2e, 0x05, 0x72, 0x20, 0x9b, 0x13, 0x05, 0x84, 0xb7, 0x33, 0x89, 0xa4, 0x00, 0x63, 0x8a, 0x0a,
+0x00, 0x53, 0x05, 0x00, 0xd2, 0x52, 0x85, 0xca, 0x85, 0xef, 0x40, 0xed, 0xfa, 0x05, 0x45, 0x2d,
+0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x35, 0x85, 0x5c, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x35, 0x85,
+0x64, 0x52, 0x85, 0xca, 0x85, 0x99, 0x35, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x35, 0x05, 0x65, 0x4a,
+0x85, 0xd2, 0x85, 0xef, 0x40, 0x4d, 0xf8, 0x01, 0x45, 0x23, 0xa0, 0xa9, 0x00, 0xb7, 0x55, 0x04,
+0x20, 0x23, 0xae, 0xa5, 0x72, 0x52, 0x85, 0xa6, 0x85, 0x00, 0x9b, 0x6f, 0xf0, 0x1c, 0x92, 0x00,
+0x00, 0x00, 0x00, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x65, 0x53, 0x95, 0x05, 0xa2, 0x11,
+0xc5, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x65, 0xb9, 0xa8, 0x53, 0x15, 0x05, 0xa2, 0x01,
+0xc9, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x5c, 0x53, 0x70, 0x05, 0x02, 0xa9, 0xa0, 0x37,
+0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x66, 0x53, 0x15, 0x05, 0xa2, 0x01, 0xcd, 0x37, 0xb5, 0x09,
+0x00, 0x07, 0x30, 0x85, 0x5c, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85, 0x5e, 0x43, 0x70, 0x15,
+0x02, 0x1d, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x66, 0x53, 0x15, 0x05, 0xa2, 0x01,
+0xc9, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x5c, 0x53, 0x70, 0x05, 0x12, 0x29, 0xa0, 0x37,
+0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x67, 0x53, 0x75, 0xc0, 0x12, 0x82, 0x80, 0x00, 0x00, 0xc0,
+0x9b, 0x37, 0xbb, 0x09, 0x00, 0x93, 0x04, 0x4b, 0x6d, 0xdc, 0x40, 0xba, 0x89, 0x36, 0x89, 0x32,
+0x8a, 0x2e, 0x84, 0xaa, 0x8a, 0x05, 0x65, 0x93, 0x05, 0x05, 0xa0, 0x3e, 0x85, 0x01, 0x46, 0xae,
+0x86, 0xef, 0x30, 0xb7, 0x96, 0x03, 0x25, 0x4b, 0x6d, 0x93, 0x05, 0x80, 0x2d, 0x93, 0x06, 0x80,
+0x2d, 0x01, 0x46, 0xef, 0x30, 0x97, 0x95, 0x22, 0x85, 0xef, 0xb0, 0xbd, 0xe1, 0x83, 0x26, 0x4b,
+0x6d, 0xd8, 0x40, 0x05, 0x45, 0xd6, 0x85, 0x22, 0x86, 0xef, 0x90, 0x2d, 0xd5, 0x05, 0xc5, 0x03,
+0x25, 0x4b, 0x6d, 0x93, 0x95, 0x29, 0x00, 0x13, 0x06, 0x05, 0x1e, 0x93, 0x06, 0x40, 0x0c, 0x52,
+0x85, 0xef, 0x30, 0x27, 0xb1, 0xd0, 0x40, 0x22, 0x85, 0xd2, 0x85, 0xca, 0x86, 0xef, 0x80, 0xbd,
+0xdd, 0x33, 0x35, 0xa0, 0x00, 0xa0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x2f, 0x05, 0x01, 0x81,
+0x48, 0x33, 0x28, 0xb0, 0x00, 0x13, 0x13, 0x25, 0x00, 0x93, 0x92, 0x25, 0x00, 0x63, 0x01, 0x08,
+0x02, 0xb2, 0x83, 0x36, 0x8e, 0xba, 0x8e, 0xae, 0x87, 0x5b, 0xa5, 0x43, 0xa0, 0xdb, 0x25, 0x4e,
+0xa0, 0x53, 0x75, 0xb5, 0x10, 0x27, 0xa0, 0xae, 0x00, 0xfd, 0x17, 0x9a, 0x9e, 0xf5, 0xf7, 0x85,
+0x08, 0x11, 0x07, 0x16, 0x96, 0xe3, 0x9c, 0xa8, 0xfc, 0x82, 0x80, 0x7e, 0x95, 0x05, 0x04, 0x01,
+0x0b, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x48, 0x9e, 0x22, 0xb0, 0x26, 0xac, 0x80, 0x10, 0x83, 0x2a,
+0x44, 0x00, 0x83, 0x2d, 0x04, 0x00, 0x2a, 0x89, 0x37, 0xb5, 0x09, 0x00, 0x63, 0xd5, 0xba, 0x01,
+0x07, 0x24, 0x85, 0x67, 0xa1, 0xaa, 0xc6, 0x89, 0xbe, 0x84, 0x36, 0x8c, 0x2e, 0x8b, 0x23, 0x24,
+0xe4, 0xfa, 0x23, 0x26, 0x04, 0xfb, 0x23, 0x28, 0xc4, 0xfa, 0x23, 0x2a, 0x24, 0xfa, 0x3d, 0x45,
+0xab, 0x05, 0x55, 0x05, 0xc1, 0x99, 0x33, 0x0a, 0xb1, 0x40, 0x52, 0x81, 0xb3, 0x85, 0xba, 0x03,
+0xab, 0x05, 0xb5, 0x04, 0xc1, 0x99, 0x33, 0x0d, 0xb1, 0x40, 0x6a, 0x81, 0xb3, 0x0c, 0xb1, 0x40,
+0x66, 0x81, 0xab, 0x05, 0xb5, 0x05, 0xc1, 0x99, 0xb3, 0x05, 0xb1, 0x40, 0x23, 0x22, 0xb4, 0xfa,
+0x2e, 0x81, 0xb3, 0x85, 0xbd, 0x03, 0x2b, 0x05, 0xb5, 0x04, 0x41, 0x99, 0xb3, 0x0b, 0xa1, 0x40,
+0x5e, 0x81, 0x93, 0x95, 0x2a, 0x00, 0x52, 0x85, 0x01, 0x46, 0xae, 0x86, 0xef, 0x30, 0x77, 0x84,
+0x6a, 0x85, 0xe2, 0x85, 0x56, 0x86, 0xee, 0x86, 0x5a, 0x87, 0xef, 0xe0, 0xcd, 0x95, 0x0b, 0xa9,
+0x0a, 0x01, 0x13, 0x05, 0xf9, 0xff, 0x13, 0x35, 0x15, 0x00, 0xd6, 0x85, 0x52, 0x86, 0x5b, 0xa5,
+0x44, 0xa0, 0xd3, 0x75, 0xa5, 0x10, 0xab, 0x65, 0xa5, 0x38, 0xfd, 0x15, 0x5b, 0x22, 0xb6, 0xe0,
+0xfd, 0xf5, 0x6e, 0x85, 0xd6, 0x85, 0x6a, 0x86, 0xd2, 0x86, 0x66, 0x87, 0xdd, 0x3d, 0x37, 0xb5,
+0x09, 0x00, 0x87, 0x24, 0xc5, 0x67, 0xd3, 0x05, 0x00, 0xf0, 0x53, 0x04, 0x00, 0xf0, 0x01, 0x45,
+0xee, 0x85, 0x6e, 0x86, 0xd6, 0x86, 0x53, 0x85, 0x94, 0x20, 0x66, 0x87, 0xea, 0x87, 0x5e, 0x88,
+0xef, 0xe0, 0xed, 0x8a, 0x5e, 0x85, 0xee, 0x85, 0xef, 0xe0, 0xad, 0xca, 0x11, 0xc5, 0x37, 0xb5,
+0x09, 0x00, 0x07, 0x24, 0x85, 0x67, 0xb1, 0xa8, 0x8b, 0xa7, 0x0d, 0x01, 0x11, 0x45, 0x2b, 0x05,
+0xb5, 0x05, 0x53, 0x04, 0x00, 0xf0, 0xde, 0x85, 0x6e, 0x86, 0x88, 0x61, 0x53, 0x74, 0xa4, 0x00,
+0x7d, 0x16, 0xaa, 0x95, 0x7d, 0xfa, 0x05, 0x46, 0xd3, 0x05, 0x00, 0xf0, 0x01, 0x45, 0xee, 0x85,
+0xd6, 0x86, 0x53, 0x85, 0x94, 0x20, 0x66, 0x87, 0x83, 0x27, 0x84, 0xfa, 0x83, 0x24, 0x44, 0xfa,
+0x26, 0x88, 0xef, 0xe0, 0xcd, 0x85, 0x05, 0x46, 0xd3, 0x05, 0x00, 0xf0, 0x01, 0x45, 0xee, 0x85,
+0xee, 0x86, 0x53, 0x85, 0x94, 0x20, 0x5e, 0x87, 0xa6, 0x87, 0x03, 0x28, 0xc4, 0xfa, 0xef, 0xe0,
+0x0d, 0x84, 0x83, 0x24, 0x44, 0xfb, 0x63, 0x8a, 0x09, 0x00, 0x5e, 0x85, 0xce, 0x85, 0x6e, 0x86,
+0xee, 0x86, 0x03, 0x27, 0x04, 0xfb, 0xef, 0xe0, 0x8d, 0x8b, 0x26, 0x81, 0x53, 0x05, 0x84, 0x20,
+0x13, 0x01, 0x04, 0xfa, 0xe2, 0x24, 0x02, 0x34, 0x28, 0x9e, 0xc0, 0x98, 0x2a, 0x84, 0xef, 0x20,
+0x8c, 0xbb, 0x81, 0x45, 0x37, 0xb6, 0x09, 0x00, 0x13, 0x06, 0xc6, 0x6d, 0xb3, 0x86, 0xc5, 0x00,
+0x83, 0xc6, 0x06, 0x00, 0x63, 0x86, 0x86, 0x00, 0xa1, 0x05, 0x8b, 0x9c, 0xf5, 0x28, 0x01, 0xa8,
+0x08, 0x41, 0xb2, 0x95, 0xcc, 0x41, 0xe9, 0x8d, 0x05, 0x45, 0x91, 0xc1, 0xa0, 0x98, 0x01, 0x45,
+0xa0, 0x98, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x84, 0xaa, 0x84, 0xef, 0xc0, 0x2b, 0x87,
+0x15, 0xc5, 0xef, 0x40, 0x0e, 0xae, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x25, 0x05, 0x68, 0x53, 0x85,
+0xa5, 0xa0, 0x05, 0x49, 0x09, 0xed, 0xe0, 0x91, 0x26, 0x85, 0xef, 0x70, 0x9e, 0x9e, 0x37, 0xb5,
+0x09, 0x00, 0x07, 0x30, 0x85, 0x68, 0x53, 0x15, 0x05, 0xa2, 0x11, 0xc1, 0x01, 0x49, 0x4a, 0x85,
+0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xc9, 0x15, 0xe4, 0xae, 0x89, 0x2a, 0x89,
+0x01, 0x45, 0xa5, 0x3f, 0x21, 0xcd, 0x31, 0x4a, 0x05, 0x44, 0x13, 0x0b, 0x40, 0x0e, 0xa0, 0x90,
+0x26, 0x85, 0xef, 0x90, 0xdc, 0xb2, 0xaa, 0x8a, 0x01, 0x45, 0xa6, 0x85, 0x69, 0x3f, 0x0b, 0x16,
+0x05, 0x01, 0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0d, 0x56, 0x86,
+0xef, 0x30, 0xa7, 0x87, 0x5a, 0x8a, 0x13, 0x35, 0x04, 0x02, 0x05, 0x04, 0x13, 0x0b, 0x8a, 0x0d,
+0xb3, 0xb5, 0x69, 0x01, 0xe4, 0x9d, 0x6d, 0x8d, 0x79, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x0d, 0x45,
+0x05, 0x46, 0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0x9e, 0x95, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85,
+0xa0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9b, 0x8b, 0xc8, 0x15, 0xe4, 0xae, 0x89, 0x2a, 0x89,
+0x0d, 0x45, 0x21, 0x37, 0x39, 0xc9, 0x31, 0x4a, 0x85, 0x44, 0x13, 0x04, 0x40, 0x0e, 0x64, 0x91,
+0xef, 0xc0, 0x7a, 0xe3, 0xaa, 0x8a, 0xa4, 0x91, 0x0d, 0x45, 0x35, 0x37, 0x0b, 0x16, 0x05, 0x01,
+0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0d, 0x56, 0x86, 0xef, 0x30,
+0xc7, 0x80, 0x22, 0x8a, 0x13, 0xb5, 0x24, 0x03, 0x85, 0x04, 0x13, 0x04, 0x8a, 0x0d, 0xb3, 0xb5,
+0x89, 0x00, 0xe4, 0x9d, 0x6d, 0x8d, 0x61, 0xf5, 0x93, 0x05, 0x4a, 0xff, 0x1d, 0x45, 0x05, 0x46,
+0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0xbe, 0x8e, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85, 0x20, 0x9b,
+0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xc9, 0x15, 0xd4, 0xae, 0x89, 0x2a, 0x89, 0x19, 0x45, 0x71, 0x3d,
+0x21, 0xcd, 0x31, 0x4a, 0x05, 0x44, 0x13, 0x0b, 0x40, 0x0d, 0xa0, 0x90, 0x26, 0x85, 0xef, 0xd0,
+0x9b, 0xa5, 0xaa, 0x8a, 0x19, 0x45, 0xa6, 0x85, 0x7d, 0x3d, 0x0b, 0x16, 0x05, 0x01, 0x33, 0x05,
+0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0c, 0x56, 0x86, 0xef, 0x20, 0xf7, 0xf9,
+0x5a, 0x8a, 0x13, 0x35, 0x44, 0x02, 0x05, 0x04, 0x13, 0x0b, 0x8a, 0x0c, 0xb3, 0xb5, 0x69, 0x01,
+0xe4, 0x9d, 0x6d, 0x8d, 0x79, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x39, 0x45, 0x05, 0x46, 0xca, 0x86,
+0x4e, 0x87, 0xef, 0x00, 0xde, 0x87, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85, 0xa0, 0x9b, 0x00, 0x00,
+0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xca, 0x15, 0xbc, 0xae, 0x89, 0x2a, 0x89, 0x05, 0x45, 0x05, 0x44,
+0x2d, 0x35, 0x29, 0xcd, 0x31, 0x4a, 0x13, 0x0b, 0xc0, 0x0b, 0xa0, 0x90, 0x26, 0x85, 0xef, 0xf0,
+0x0b, 0xdb, 0xaa, 0x8a, 0x05, 0x45, 0xa6, 0x85, 0xb9, 0x35, 0x0b, 0x17, 0x05, 0x01, 0x23, 0x96,
+0x8a, 0x0a, 0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x00, 0x0b, 0x56, 0x86,
+0xef, 0x20, 0xb7, 0xf2, 0x5a, 0x8a, 0x13, 0x35, 0x84, 0x01, 0x05, 0x04, 0x13, 0x0b, 0x0a, 0x0b,
+0xb3, 0xb5, 0x69, 0x01, 0xe4, 0x9d, 0x6d, 0x8d, 0x69, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x55, 0x45,
+0x05, 0x46, 0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0x9e, 0x80, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85,
+0xa0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x37, 0xc5, 0x04, 0x20, 0x13, 0x05, 0x85, 0xf6, 0x83, 0x25,
+0x05, 0x16, 0x07, 0x30, 0x85, 0x12, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85, 0x5c, 0x37, 0xb5,
+0x09, 0x00, 0x07, 0x31, 0x05, 0x69, 0x33, 0x35, 0xb0, 0x00, 0xd3, 0x85, 0x00, 0xa2, 0x6d, 0x8d,
+0xd3, 0x05, 0x20, 0xa2, 0x6d, 0x8d, 0x82, 0x80, 0x00, 0x00, 0x37, 0xb5, 0x09, 0x00, 0x03, 0x45,
+0x25, 0x71, 0x3a, 0x36, 0x05, 0x04, 0x01, 0x0c, 0xf3, 0x82, 0x80, 0x00, 0x00, 0xc0, 0x98, 0xef,
+0x20, 0xec, 0xc2, 0x01, 0xe5, 0x05, 0x44, 0x5d, 0x3f, 0x11, 0xe1, 0x01, 0x44, 0x37, 0xb5, 0x09,
+0x00, 0x23, 0x09, 0x85, 0x70, 0xa0, 0x98, 0x00, 0x00, 0x40, 0x98, 0x37, 0xb5, 0x09, 0x00, 0x03,
+0x45, 0x25, 0x71, 0x0d, 0xc1, 0xef, 0xe0, 0x1e, 0xf9, 0x85, 0x45, 0xa3, 0x00, 0xb5, 0x00, 0xef,
+0x20, 0xae, 0x90, 0xaa, 0x85, 0x35, 0x45, 0x0b, 0x84, 0x05, 0x01, 0xef, 0xe0, 0xbe, 0xf7, 0x8d,
+0x45, 0x23, 0x11, 0xb5, 0x00, 0x05, 0x45, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x9d, 0x13,
+0x01, 0x01, 0xdd, 0x27, 0x3c, 0x81, 0x28, 0x36, 0x84, 0xb2, 0x89, 0x2e, 0x89, 0x28, 0x00, 0x93,
+0x05, 0x00, 0x29, 0x7d, 0x56, 0x93, 0x06, 0x00, 0x29, 0x13, 0x0a, 0x81, 0x00, 0xef, 0x30, 0xc7,
+0xc5, 0x28, 0x00, 0x93, 0x05, 0x40, 0x0a, 0xef, 0x50, 0x7e, 0xd5, 0x37, 0x15, 0x09, 0x00, 0x13,
+0x05, 0x05, 0x98, 0xab, 0x05, 0x84, 0x04, 0x33, 0x86, 0xa5, 0x00, 0x83, 0x0a, 0x06, 0x00, 0x13,
+0xa6, 0x1a, 0x00, 0x93, 0xb6, 0x19, 0x00, 0x01, 0x4b, 0x55, 0x8e, 0x51, 0xea, 0x2e, 0x95, 0x93,
+0x0b, 0x15, 0x00, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x34, 0x85, 0x69, 0x05, 0x4c, 0x37, 0x15, 0x09,
+0x00, 0x93, 0x0c, 0x45, 0x9a, 0x81, 0x44, 0x33, 0x85, 0x9b, 0x00, 0x03, 0x44, 0x05, 0x00, 0x13,
+0x1d, 0x0c, 0x01, 0x13, 0x5d, 0x0d, 0x41, 0x0b, 0x5f, 0x04, 0x1b, 0x22, 0x85, 0xea, 0x85, 0xef,
+0x80, 0x6e, 0xdf, 0x0d, 0xc5, 0xab, 0x85, 0x8c, 0x04, 0x03, 0x94, 0x25, 0x00, 0x63, 0x40, 0x04,
+0x02, 0xab, 0x05, 0xaa, 0x04, 0x8c, 0x41, 0x8b, 0x85, 0x05, 0xff, 0xef, 0x70, 0x2e, 0xe7, 0x19,
+0xc5, 0x28, 0x69, 0x53, 0x00, 0x05, 0x42, 0x53, 0x05, 0x80, 0xa2, 0x19, 0xcd, 0x85, 0x04, 0x0b,
+0x9e, 0xe4, 0x04, 0x33, 0x25, 0x5d, 0x01, 0x93, 0x15, 0x0b, 0x01, 0xc1, 0x81, 0xb3, 0xb5, 0x35,
+0x01, 0x6d, 0x8d, 0x05, 0x0c, 0x45, 0xf1, 0x21, 0xa8, 0x33, 0x05, 0x84, 0x01, 0x93, 0x15, 0x0b,
+0x01, 0xc1, 0x81, 0x05, 0x0b, 0xab, 0x05, 0xb9, 0x02, 0x23, 0x90, 0xa5, 0x00, 0xd9, 0xbf, 0x13,
+0x15, 0x0b, 0x01, 0x41, 0x81, 0x07, 0x34, 0x81, 0x29, 0x13, 0x01, 0x01, 0x23, 0xbc, 0x9d, 0x00,
+0x00, 0x5c, 0x9e, 0x13, 0x01, 0x01, 0xdc, 0x27, 0x38, 0x81, 0x2a, 0x27, 0x34, 0x91, 0x2a, 0x27,
+0x30, 0x21, 0x2b, 0x2a, 0xc6, 0x63, 0x0d, 0x05, 0x14, 0x2e, 0x84, 0x01, 0x45, 0x93, 0x09, 0x01,
+0x01, 0xfd, 0x55, 0x13, 0x06, 0x00, 0x29, 0xb3, 0x86, 0xa9, 0x00, 0x11, 0x05, 0x8c, 0xc2, 0xe3,
+0x1c, 0xc5, 0xfe, 0x08, 0x08, 0x93, 0x05, 0x40, 0x0a, 0xef, 0x50, 0x5e, 0xc5, 0x13, 0x7a, 0xf4,
+0x0f, 0x63, 0x07, 0x0a, 0x12, 0x01, 0x45, 0x81, 0x4a, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb4, 0x85,
+0x69, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb4, 0x05, 0x6a, 0xb7, 0x15, 0x09, 0x00, 0x13, 0x8b, 0x45,
+0x9a, 0x53, 0x09, 0x00, 0xd2, 0xab, 0x05, 0xab, 0x04, 0x83, 0x9b, 0x05, 0x00, 0x0b, 0xae, 0x3b,
+0x01, 0x32, 0x46, 0x2b, 0x0c, 0xa6, 0x10, 0x93, 0x8c, 0x25, 0x00, 0x85, 0x44, 0x13, 0xf5, 0xfa,
+0x0f, 0xe4, 0x91, 0xef, 0x80, 0x2e, 0xd0, 0x2a, 0x84, 0x7d, 0x15, 0x28, 0x91, 0x8b, 0x53, 0x35,
+0xa3, 0x22, 0x85, 0xef, 0x70, 0xae, 0xd8, 0x83, 0x4d, 0x0c, 0x00, 0x0b, 0xd0, 0x3d, 0x24, 0x83,
+0x95, 0x0c, 0x00, 0x63, 0xcc, 0x05, 0x0a, 0x2a, 0x8d, 0x1d, 0xc1, 0x07, 0x25, 0x0d, 0x05, 0x53,
+0x00, 0x05, 0x42, 0x53, 0x05, 0x80, 0xa2, 0x55, 0xe1, 0x2b, 0x85, 0x89, 0x04, 0x08, 0x41, 0xa6,
+0x95, 0x2b, 0x06, 0xbc, 0x03, 0x23, 0x12, 0xb6, 0x00, 0x8b, 0x16, 0x05, 0xff, 0x15, 0xa8, 0x2b,
+0x85, 0x89, 0x04, 0x08, 0x41, 0x8b, 0x01, 0x25, 0xff, 0xa6, 0x95, 0x2b, 0x06, 0xbc, 0x03, 0x23,
+0x12, 0xb6, 0x00, 0x13, 0x34, 0x1d, 0x00, 0x33, 0x09, 0xbc, 0x01, 0x23, 0x0e, 0x09, 0x0c, 0xef,
+0x50, 0x3e, 0xc5, 0x93, 0x05, 0x15, 0x00, 0xab, 0x65, 0xa0, 0x20, 0x23, 0x0e, 0xb9, 0x0c, 0x0d,
+0xec, 0x07, 0x25, 0x0d, 0x05, 0x53, 0x00, 0x05, 0x42, 0x53, 0x15, 0x04, 0xa2, 0x53, 0x70, 0x90,
+0x12, 0xd3, 0x00, 0x29, 0x23, 0xab, 0x60, 0xa0, 0x3a, 0xd3, 0x95, 0x00, 0xc2, 0x2b, 0x06, 0xbc,
+0x03, 0x23, 0x16, 0xb6, 0x04, 0x53, 0x00, 0x29, 0x23, 0x11, 0xcd, 0x07, 0x25, 0x4d, 0x05, 0x53,
+0x00, 0x05, 0x42, 0x53, 0x70, 0x90, 0x12, 0x39, 0xa0, 0x2b, 0x05, 0xbc, 0x03, 0x23, 0x16, 0x05,
+0x04, 0x53, 0x00, 0x29, 0x23, 0x53, 0x15, 0x00, 0xc2, 0xab, 0x05, 0xbc, 0x03, 0x23, 0x9a, 0xa5,
+0x08, 0x03, 0x05, 0x0c, 0x00, 0x05, 0x05, 0x23, 0x00, 0xac, 0x00, 0x13, 0x85, 0x14, 0x00, 0xe8,
+0x90, 0xe3, 0xde, 0x9b, 0xf0, 0x85, 0x0a, 0x13, 0xf5, 0xfa, 0x0f, 0xe3, 0x6d, 0x45, 0xef, 0x07,
+0x39, 0x01, 0x2a, 0x87, 0x34, 0x81, 0x2a, 0x07, 0x34, 0x01, 0x2b, 0x13, 0x01, 0x01, 0x24, 0x3c,
+0x9e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x89, 0xaa, 0x84, 0x93, 0x06, 0xc5, 0x10, 0x37,
+0xb5, 0x09, 0x00, 0x13, 0x06, 0x85, 0x6a, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x00, 0x07,
+0xba, 0x63, 0x45, 0x05, 0x06, 0x13, 0x84, 0x04, 0x0d, 0x22, 0x85, 0xef, 0x60, 0x36, 0xb8, 0xaa,
+0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x22, 0x86, 0xef, 0x70, 0x97, 0x9e, 0x39, 0xe5, 0x93,
+0x84, 0x04, 0x0f, 0x26, 0x85, 0xef, 0x60, 0x96, 0xb6, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a,
+0x85, 0x26, 0x86, 0xef, 0x70, 0xf7, 0x9c, 0x15, 0xe9, 0x26, 0x85, 0xef, 0x60, 0x36, 0xb5, 0x8b,
+0x13, 0x05, 0x01, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x04, 0xf5, 0x6a, 0x29, 0xa0, 0x37, 0xb5, 0x09,
+0x00, 0x13, 0x04, 0x15, 0x6b, 0x22, 0x85, 0xef, 0x60, 0x76, 0xb3, 0xaa, 0x86, 0x93, 0x05, 0x00,
+0x08, 0x4a, 0x85, 0x22, 0x86, 0xef, 0x70, 0xd7, 0x99, 0x11, 0xc1, 0xa0, 0x99, 0x4a, 0x85, 0xef,
+0x60, 0xf6, 0xb1, 0xaa, 0x85, 0x13, 0x06, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x60, 0x2e, 0x89, 0x4a,
+0x85, 0xef, 0x60, 0xd6, 0xb0, 0x13, 0x06, 0x00, 0x08, 0xaa, 0x85, 0x4a, 0x85, 0x80, 0x99, 0x6f,
+0x60, 0x6e, 0x90, 0x00, 0x00, 0x40, 0x9a, 0x32, 0x89, 0xae, 0x89, 0x01, 0x45, 0x01, 0x44, 0x93,
+0x85, 0xa5, 0x1b, 0x33, 0x86, 0xa5, 0x00, 0x03, 0x16, 0x06, 0x00, 0x63, 0x43, 0xc0, 0x00, 0x01,
+0x46, 0x30, 0x92, 0x09, 0x05, 0x32, 0x94, 0x0b, 0x1b, 0xf5, 0x0c, 0x93, 0x86, 0xc9, 0x10, 0x37,
+0xb5, 0x09, 0x00, 0x13, 0x06, 0x85, 0x6b, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x00, 0x07,
+0xad, 0x63, 0x47, 0x05, 0x0a, 0x93, 0x84, 0x09, 0x0d, 0x26, 0x85, 0xef, 0x60, 0x36, 0xab, 0xaa,
+0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x26, 0x86, 0xef, 0x70, 0x97, 0x91, 0x49, 0xe9, 0x93,
+0x84, 0x09, 0x03, 0x26, 0x85, 0xef, 0x60, 0x96, 0xa9, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a,
+0x85, 0x26, 0x86, 0xef, 0x70, 0xf7, 0x8f, 0x25, 0xed, 0x93, 0x84, 0x09, 0x10, 0x26, 0x85, 0xef,
+0x60, 0xf6, 0xa7, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x85, 0x27, 0x05, 0x04, 0x01, 0x0d, 0xf2,
+0x4a, 0x85, 0x26, 0x86, 0xef, 0x70, 0x57, 0x8e, 0x39, 0xed, 0x93, 0x06, 0x00, 0x08, 0x22, 0x85,
+0x81, 0x45, 0x4a, 0x86, 0xef, 0x50, 0xde, 0xf1, 0x4e, 0x85, 0xef, 0x60, 0xb6, 0xa5, 0xaa, 0x86,
+0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x4e, 0x86, 0xef, 0x70, 0x17, 0x8c, 0x0d, 0xed, 0x13, 0x84,
+0x09, 0x05, 0x22, 0x85, 0xef, 0x60, 0x16, 0xa4, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85,
+0x22, 0x86, 0xef, 0x70, 0x77, 0x8a, 0x05, 0xe1, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x04, 0xf5, 0x6b,
+0x22, 0x85, 0xef, 0x60, 0x36, 0xa2, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x22, 0x86,
+0xef, 0x70, 0x97, 0x88, 0x11, 0xc1, 0x20, 0x9a, 0x4a, 0x85, 0xef, 0x60, 0xb6, 0xa0, 0xaa, 0x85,
+0x13, 0x06, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x50, 0xfe, 0xf7, 0x4a, 0x85, 0xef, 0x60, 0x96, 0x9f,
+0x13, 0x06, 0x00, 0x08, 0xaa, 0x85, 0x4a, 0x85, 0x00, 0x9a, 0x6f, 0x50, 0x3e, 0xff, 0x00, 0x00,
+0x40, 0x98, 0xef, 0x10, 0xae, 0xec, 0xb7, 0xc5, 0x04, 0x20, 0x03, 0xa6, 0x85, 0x0c, 0x81, 0x45,
+0x01, 0xe6, 0x85, 0x45, 0x0b, 0x52, 0x05, 0x05, 0x2e, 0x85, 0x20, 0x98, 0xef, 0xb0, 0x5b, 0xb0,
+0x13, 0x25, 0x55, 0x00, 0x8d, 0x45, 0x33, 0x85, 0xa5, 0x40, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00,
+0xc0, 0x99, 0x2a, 0x84, 0xf1, 0x37, 0xaa, 0x84, 0xef, 0xb0, 0x9b, 0xae, 0x2a, 0x89, 0x84, 0x92,
+0x37, 0xb5, 0x09, 0x00, 0x93, 0x04, 0xe5, 0x59, 0x91, 0x45, 0x22, 0x85, 0x26, 0x86, 0xef, 0x00,
+0x67, 0x9a, 0x63, 0x4a, 0x05, 0x00, 0x13, 0x05, 0x44, 0x00, 0xc1, 0x45, 0x26, 0x86, 0xca, 0x86,
+0x80, 0x99, 0x6f, 0x00, 0x27, 0x99, 0xa0, 0x99, 0xdc, 0x99, 0x7d, 0x71, 0x2e, 0x89, 0xaa, 0x84,
+0x08, 0x10, 0x93, 0x05, 0x00, 0x06, 0x93, 0x06, 0x00, 0x06, 0x01, 0x46, 0xef, 0x20, 0x57, 0xfc,
+0x28, 0x00, 0xd1, 0x45, 0xd1, 0x46, 0x01, 0x46, 0xef, 0x20, 0x97, 0xfb, 0x37, 0x05, 0x05, 0x20,
+0x13, 0x04, 0x85, 0xc3, 0x22, 0x85, 0xef, 0x60, 0x2e, 0xaf, 0x08, 0x10, 0xa2, 0x85, 0xef, 0x60,
+0x2e, 0xab, 0x28, 0x00, 0x71, 0x37, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x06, 0x25, 0x6c, 0x26, 0x85,
+0xca, 0x85, 0xef, 0x70, 0xa7, 0xbc, 0x3d, 0xe9, 0x10, 0x10, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70,
+0xe7, 0xbb, 0x2d, 0xe5, 0x10, 0x18, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x27, 0xbb, 0x39, 0xed,
+0x90, 0x00, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x67, 0xba, 0x29, 0xe9, 0x90, 0x08, 0x26, 0x85,
+0xca, 0x85, 0xef, 0x70, 0xa7, 0xb9, 0x39, 0xe1, 0x30, 0x00, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70,
+0xe7, 0xb8, 0x0d, 0xed, 0x90, 0x10, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x27, 0xb8, 0x1d, 0xe5,
+0x70, 0x00, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x67, 0xb7, 0x0d, 0xe1, 0x26, 0x85, 0xef, 0x60,
+0x76, 0x8d, 0xaa, 0x85, 0x26, 0x85, 0x4a, 0x86, 0xef, 0x50, 0xde, 0xe4, 0x26, 0x85, 0xef, 0x60,
+0x76, 0x8c, 0xaa, 0x85, 0x26, 0x85, 0x4a, 0x86, 0xef, 0x50, 0x5e, 0xec, 0x41, 0x61, 0xbc, 0x99,
+0x7d, 0x71, 0x37, 0xc6, 0x04, 0x20, 0x07, 0x25, 0x86, 0x13, 0xc8, 0xe5, 0x13, 0x05, 0x05, 0x03,
+0x53, 0x00, 0x05, 0x42, 0x02, 0xa4, 0x22, 0x47, 0xb2, 0x47, 0xb7, 0xb5, 0x09, 0x00, 0x13, 0x86,
+0xb5, 0x6c, 0xc1, 0x45, 0x41, 0x61, 0x6f, 0x00, 0xe7, 0x89, 0x00, 0x00, 0x82, 0x80, 0x00, 0x00,
+0x37, 0x45, 0x05, 0x20, 0x23, 0x2a, 0x05, 0x8c, 0x23, 0x28, 0x05, 0x8c, 0x37, 0xb5, 0x09, 0x00,
+0x23, 0x26, 0x05, 0x70, 0x23, 0x24, 0x05, 0x70, 0x82, 0x80, 0x00, 0x00, 0x49, 0x1f, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x49, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x49, 0x1f, 0x00, 0x00, 0xc7, 0x31, 0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51,
+0x47, 0x03, 0x08, 0x00, 0x87, 0x40, 0x04, 0x01, 0x04, 0x00, 0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00,
+0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0x88, 0x41, 0x64, 0x08, 0x06, 0x00, 0x88, 0x41, 0x32, 0x04,
+0x07, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65,
+0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xfd, 0x78, 0xc9, 0x01, 0x05, 0x00,
+0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00, 0x47, 0x6e, 0xcd, 0x03, 0x05, 0x00, 0x88, 0x41, 0x64, 0x08,
+0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44,
+0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00,
+0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0xaa, 0x79, 0x28, 0x01,
+0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44,
+0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00,
+0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xd3, 0x64, 0xed, 0x09, 0x02, 0x00, 0x43, 0x44, 0x35, 0x12,
+0x05, 0x00, 0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0xde, 0x7a, 0x7f, 0x1d, 0x06, 0x00, 0x88, 0x41,
+0x32, 0x04, 0x07, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00,
+0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xfd, 0x78, 0xc9, 0x01,
+0x05, 0x00, 0x43, 0x44, 0x35, 0x12, 0x05, 0x00, 0x47, 0x6e, 0xcd, 0x03, 0x05, 0x00, 0x88, 0x41,
+0x64, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00,
+0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03,
+0x08, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0xaa, 0x79,
+0x28, 0x01, 0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00,
+0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0x87, 0x40, 0x04, 0x01, 0x04, 0x00, 0x73, 0x4c,
+0x6b, 0x0b, 0x06, 0x00, 0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0x88, 0x41, 0x64, 0x08, 0x06, 0x00,
+0x88, 0x41, 0x32, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0xfd, 0x78,
+0xc9, 0x01, 0x05, 0x00, 0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00, 0x47, 0x6e, 0xcd, 0x03, 0x05, 0x00,
+0x88, 0x41, 0x64, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51,
+0x1c, 0x0d, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00,
+0xaa, 0x79, 0x28, 0x01, 0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x93, 0x71, 0x05, 0x04, 0x01, 0x0e, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12,
+0x00, 0xcd, 0x4f, 0x29, 0x00, 0x10, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x60, 0x52, 0xae,
+0x00, 0x11, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x43, 0x44, 0x2f, 0x02, 0x15, 0x00, 0x43,
+0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x21, 0x57, 0x61, 0x00, 0x0e,
+0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0xcd, 0x4f, 0x29, 0x00, 0x10, 0x00, 0x43, 0x44, 0xea,
+0x02, 0x14, 0x00, 0x60, 0x52, 0xae, 0x00, 0x11, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x43,
+0x44, 0x2f, 0x02, 0x15, 0x00, 0x43, 0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14,
+0x00, 0x21, 0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0x25, 0x66, 0x2a,
+0x00, 0x11, 0x00, 0x43, 0x44, 0x76, 0x05, 0x13, 0x00, 0x60, 0x52, 0xa3, 0x00, 0x11, 0x00, 0x43,
+0x44, 0xbb, 0x02, 0x14, 0x00, 0x43, 0x44, 0x2f, 0x02, 0x15, 0x00, 0x43, 0x44, 0x02, 0x06, 0x13,
+0x00, 0x43, 0x44, 0x35, 0x12, 0x13, 0x00, 0x0d, 0x5f, 0x3a, 0x00, 0x0f, 0x00, 0x43, 0x44, 0x5d,
+0x00, 0x13, 0x00, 0xcd, 0x4f, 0x7f, 0x00, 0x10, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x60,
+0x52, 0x1f, 0x02, 0x11, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x15,
+0x00, 0x43, 0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x0d, 0x5f, 0x3a,
+0x00, 0x0f, 0x00, 0x43, 0x44, 0x5d, 0x00, 0x13, 0x00, 0xcd, 0x4f, 0x7f, 0x00, 0x10, 0x00, 0x43,
+0x44, 0x1a, 0x09, 0x14, 0x00, 0x60, 0x52, 0x1f, 0x02, 0x11, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14,
+0x00, 0x43, 0x44, 0x8d, 0x04, 0x15, 0x00, 0x43, 0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d,
+0x04, 0x14, 0x00, 0x21, 0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0x25,
+0x66, 0xd1, 0x00, 0x11, 0x00, 0x43, 0x44, 0x35, 0x12, 0x13, 0x00, 0x60, 0x52, 0x1f, 0x02, 0x11,
+0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x15, 0x00, 0x43, 0x44, 0xe9,
+0x00, 0x14, 0x00, 0x43, 0x44, 0xd2, 0x01, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc4, 0x1d, 0x43, 0xd7, 0x41, 0x24,
+0x41, 0x63, 0x68, 0x69, 0x6c, 0x6c, 0x65, 0x73, 0x2c, 0x48, 0x37, 0x53, 0x31, 0x2c, 0x51, 0x33,
+0x35, 0x2c, 0x46, 0x31, 0x50, 0x32, 0x36, 0x2e, 0x30, 0x00, 0x24, 0x41, 0x63, 0x68, 0x69, 0x6c,
+0x6c, 0x65, 0x73, 0x2c, 0x48, 0x37, 0x53, 0x31, 0x2c, 0x51, 0x35, 0x30, 0x2c, 0x46, 0x31, 0x50,
+0x32, 0x36, 0x2e, 0x30, 0x00, 0x2c, 0x25, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x40, 0x8f, 0x40, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xe3, 0x3f, 0x9a,
+0x99, 0x99, 0x99, 0x99, 0x99, 0xd9, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x3e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xa0, 0x41, 0x0a, 0xd7, 0x23, 0x3d, 0x00,
+0x00, 0xa0, 0x40, 0x00, 0x00, 0x40, 0x40, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xeb, 0x3f, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0xe8, 0x6a, 0x2b, 0xf6, 0x97, 0xdd, 0xed, 0x3f, 0xc0,
+0xa8, 0xa4, 0x4e, 0x40, 0x13, 0xb1, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00,
+0x00, 0xf0, 0x41, 0x00, 0x00, 0xc8, 0x41, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0xc8, 0xc1, 0x9a,
+0x99, 0x99, 0xbe, 0x00, 0x00, 0xa0, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x9a,
+0x99, 0x99, 0x99, 0x99, 0x99, 0xb9, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x33,
+0x33, 0x33, 0x33, 0x33, 0x33, 0xd3, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
+0x00, 0x80, 0xbf, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x50, 0xc3, 0x47, 0x00, 0x00, 0x00, 0x00, 0x87,
+0x44, 0xe7, 0x4a, 0x18, 0x57, 0xc6, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x55,
+0x94, 0xe7, 0x4a, 0x18, 0x57, 0xb6, 0x3f, 0xf8, 0xc1, 0x63, 0x1a, 0xdc, 0xa5, 0x4c, 0x40, 0x24,
+0x25, 0x73, 0x5a, 0x44, 0x41, 0x00, 0x2c, 0x2c, 0x2c, 0x30, 0x30, 0x2c, 0x30, 0x30, 0x00, 0x24,
+0x25, 0x73, 0x47, 0x47, 0x41, 0x00, 0x2c, 0x2c, 0x00, 0x24, 0x50, 0x4e, 0x54, 0x48, 0x30, 0x30,
+0x31, 0x00, 0x2c, 0x25, 0x2e, 0x32, 0x66, 0x00, 0x23, 0x00, 0x00, 0x00, 0x70, 0x05, 0x20, 0xd8,
+0x72, 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08,
+0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x1b, 0x01, 0x00, 0x04, 0x00, 0x00, 0x05, 0x00,
+0x51, 0x55, 0x49, 0x54, 0x20
diff --git a/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.c b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.c
new file mode 100644 (file)
index 0000000..3e86a61
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description:  gnss firmware file arrays.
+ *
+ * History:
+ * 2024-07-20, Create file.
+ */
+#include "gnss_fw_file_array.h"
+
+#define GNSS_FW_ATTR
+
+#define GNSS_CFG_BIN  "gnss_cfg.bin"
+GNSS_FW_ATTR const char g_gnss_cfg_file[] = {
+#include GNSS_CFG_BIN
+};
+
+const tiot_file g_gnss_fw_files[] = {
+    { "cfg", sizeof(g_gnss_cfg_file), g_gnss_cfg_file },
+};
+
+const tiot_file_path g_gnss_fw_file_path = {
+    g_gnss_fw_files, sizeof(g_gnss_fw_files) / sizeof(tiot_file)
+};
+
+const tiot_file_path *gnss_fw_file_path_get(void)
+{
+    return &g_gnss_fw_file_path;
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.h b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.h
new file mode 100644 (file)
index 0000000..bb61c32
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description:  gnss firmware file arrays.
+ *
+ * History:
+ * 2024-07-20, Create file.
+ */
+
+#ifndef GNSS_FW_FILE_ARRAY_H
+#define GNSS_FW_FILE_ARRAY_H
+
+#include "tiot_fileops.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+const tiot_file_path *gnss_fw_file_path_get(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/gnss_config.bin b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/gnss_config.bin
new file mode 100644 (file)
index 0000000..9126639
Binary files /dev/null and b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/gnss_config.bin differ
diff --git a/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format2/gnss_config_array.c b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format2/gnss_config_array.c
new file mode 100644 (file)
index 0000000..e2fbc22
--- /dev/null
@@ -0,0 +1,1497 @@
+/**
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+ *
+ * Description: config array.
+ *
+ * History:
+ * 2024-07-20, Create file.
+ */
+
+struct cfg_cmd {
+    const char *content;
+    int len;
+};
+
+/*
+46 49 4c 45 53 20 30 78 30 30 30 39 38 30 30 30 20
+*/
+const char g_cfg_cmd0[] = {
+    0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x30, 0x78, 0x30, 0x30, 0x30, 0x39, 0x38, 0x30, 0x30, 0x30,
+    0x20
+};
+
+/*
+01 01 fe ef b2 48 6a ae 84 2a 84 ef 02 d9 0d 40 99 2a 84 ef 82 54 4a 08 00 93 05 00 00 00 00 ef
+12 92 18 ef 42 42 16 01 8a 13 01 82 80 00 00 ef 02 d4 69 70 6e 00 00 ef a2 11 53 ef 82 44 3c 22
+2c 31 cd 82 80 00 00 ef 72 d5 68 ef 92 56 10 03 45 c5 d9 ef 92 d6 10 03 45 c5 d9 ef 32 d5 24 53
+15 05 c2 3c 99 00 00 ef 12 56 57 ef 22 06 02 ef e0 40 37 ef f2 92 35 03 06 a6 b4 a0 99 00 00 ef
+f2 01 57 20 99 00 00 ef f2 01 50 00 00 00 00 ef f2 c1 3e 20 99 00 00 ef f2 c1 33 ef a2 41 4c 13
+b6 16 00 ef a2 01 2a 01 db 27 30 20 99 00 00 ef 92 51 48 ef b2 c1 40 ae 84 2a 89 ef 22 93 5d b5
+00 03 26 82 80 00 00 ef b2 d2 1f ef b2 52 04 2e 86 2a 84 a4 99 00 00 ef b2 d2 21 82 80 00 00 ef
+72 c6 47 ef 42 06 5f 8b db 05 06 00 00 00 00 ef 42 c6 42 3f f9 00 00 ef e2 45 09 ef e2 05 63 8b
+84 05 01 00 00 00 00 ef e2 85 7b ef e2 45 7a 23 10 c5 00 00 00 00 00 ef d2 d5 7c ef e2 55 19 05
+07 2e 85 00 00 00 00 ef 42 d6 2a ef 52 c6 4d 37 c5 08 00 82 80 00 00 ef c2 d3 53 82 80 00 00 ef
+c2 13 51 ef 82 13 5e 04 20 13 04 ef e2 c8 07 7f 9f 13 84 ef 12 15 69 b0 42 11 c1 ef a2 d6 18 2a
+89 37 44 ef 62 44 32 15 02 2a 86 ef 52 94 43 ef d0 cf 90 ef 42 84 70 ef 50 d2 44 00 00 00 00 ef
+f2 54 46 00 00 00 00 ef 22 c1 61 ef 62 50 4c 37 35 09 00 82 80 00 00 ef e2 c5 37 ef e2 d6 01 aa
+84 ef e0 ef 72 86 71 05 44 ef d0 ef 32 d6 69 37 d5 08 00 ef 22 43 55 83 d6 86 b2 a0 98 00 00 ef
+62 94 29 00 00 00 00 ef d2 51 16 ef e2 d2 75 26 a0 2a 84 ef f2 52 0b 32 89 8b 87 ef 22 54 2a 2a
+86 0d 45 00 00 00 00 ef f2 c7 6b ef 92 11 65 04 20 07 30 ef a2 c3 76 b7 b5 04 20 20 98 00 00 ef
+62 54 48 ef 72 03 6c ef e0 00 28 00 00 00 00 ef 72 88 07 ef 82 98 32 82 80 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 58 31
+*/
+const char g_cfg_cmd1[] = {
+    0x01, 0x01, 0xfe, 0xef, 0xb2, 0x48, 0x6a, 0xae, 0x84, 0x2a, 0x84, 0xef, 0x02, 0xd9, 0x0d, 0x40,
+    0x99, 0x2a, 0x84, 0xef, 0x82, 0x54, 0x4a, 0x08, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x00, 0xef,
+    0x12, 0x92, 0x18, 0xef, 0x42, 0x42, 0x16, 0x01, 0x8a, 0x13, 0x01, 0x82, 0x80, 0x00, 0x00, 0xef,
+    0x02, 0xd4, 0x69, 0x70, 0x6e, 0x00, 0x00, 0xef, 0xa2, 0x11, 0x53, 0xef, 0x82, 0x44, 0x3c, 0x22,
+    0x2c, 0x31, 0xcd, 0x82, 0x80, 0x00, 0x00, 0xef, 0x72, 0xd5, 0x68, 0xef, 0x92, 0x56, 0x10, 0x03,
+    0x45, 0xc5, 0xd9, 0xef, 0x92, 0xd6, 0x10, 0x03, 0x45, 0xc5, 0xd9, 0xef, 0x32, 0xd5, 0x24, 0x53,
+    0x15, 0x05, 0xc2, 0x3c, 0x99, 0x00, 0x00, 0xef, 0x12, 0x56, 0x57, 0xef, 0x22, 0x06, 0x02, 0xef,
+    0xe0, 0x40, 0x37, 0xef, 0xf2, 0x92, 0x35, 0x03, 0x06, 0xa6, 0xb4, 0xa0, 0x99, 0x00, 0x00, 0xef,
+    0xf2, 0x01, 0x57, 0x20, 0x99, 0x00, 0x00, 0xef, 0xf2, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0xef,
+    0xf2, 0xc1, 0x3e, 0x20, 0x99, 0x00, 0x00, 0xef, 0xf2, 0xc1, 0x33, 0xef, 0xa2, 0x41, 0x4c, 0x13,
+    0xb6, 0x16, 0x00, 0xef, 0xa2, 0x01, 0x2a, 0x01, 0xdb, 0x27, 0x30, 0x20, 0x99, 0x00, 0x00, 0xef,
+    0x92, 0x51, 0x48, 0xef, 0xb2, 0xc1, 0x40, 0xae, 0x84, 0x2a, 0x89, 0xef, 0x22, 0x93, 0x5d, 0xb5,
+    0x00, 0x03, 0x26, 0x82, 0x80, 0x00, 0x00, 0xef, 0xb2, 0xd2, 0x1f, 0xef, 0xb2, 0x52, 0x04, 0x2e,
+    0x86, 0x2a, 0x84, 0xa4, 0x99, 0x00, 0x00, 0xef, 0xb2, 0xd2, 0x21, 0x82, 0x80, 0x00, 0x00, 0xef,
+    0x72, 0xc6, 0x47, 0xef, 0x42, 0x06, 0x5f, 0x8b, 0xdb, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xef,
+    0x42, 0xc6, 0x42, 0x3f, 0xf9, 0x00, 0x00, 0xef, 0xe2, 0x45, 0x09, 0xef, 0xe2, 0x05, 0x63, 0x8b,
+    0x84, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xef, 0xe2, 0x85, 0x7b, 0xef, 0xe2, 0x45, 0x7a, 0x23,
+    0x10, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xd2, 0xd5, 0x7c, 0xef, 0xe2, 0x55, 0x19, 0x05,
+    0x07, 0x2e, 0x85, 0x00, 0x00, 0x00, 0x00, 0xef, 0x42, 0xd6, 0x2a, 0xef, 0x52, 0xc6, 0x4d, 0x37,
+    0xc5, 0x08, 0x00, 0x82, 0x80, 0x00, 0x00, 0xef, 0xc2, 0xd3, 0x53, 0x82, 0x80, 0x00, 0x00, 0xef,
+    0xc2, 0x13, 0x51, 0xef, 0x82, 0x13, 0x5e, 0x04, 0x20, 0x13, 0x04, 0xef, 0xe2, 0xc8, 0x07, 0x7f,
+    0x9f, 0x13, 0x84, 0xef, 0x12, 0x15, 0x69, 0xb0, 0x42, 0x11, 0xc1, 0xef, 0xa2, 0xd6, 0x18, 0x2a,
+    0x89, 0x37, 0x44, 0xef, 0x62, 0x44, 0x32, 0x15, 0x02, 0x2a, 0x86, 0xef, 0x52, 0x94, 0x43, 0xef,
+    0xd0, 0xcf, 0x90, 0xef, 0x42, 0x84, 0x70, 0xef, 0x50, 0xd2, 0x44, 0x00, 0x00, 0x00, 0x00, 0xef,
+    0xf2, 0x54, 0x46, 0x00, 0x00, 0x00, 0x00, 0xef, 0x22, 0xc1, 0x61, 0xef, 0x62, 0x50, 0x4c, 0x37,
+    0x35, 0x09, 0x00, 0x82, 0x80, 0x00, 0x00, 0xef, 0xe2, 0xc5, 0x37, 0xef, 0xe2, 0xd6, 0x01, 0xaa,
+    0x84, 0xef, 0xe0, 0xef, 0x72, 0x86, 0x71, 0x05, 0x44, 0xef, 0xd0, 0xef, 0x32, 0xd6, 0x69, 0x37,
+    0xd5, 0x08, 0x00, 0xef, 0x22, 0x43, 0x55, 0x83, 0xd6, 0x86, 0xb2, 0xa0, 0x98, 0x00, 0x00, 0xef,
+    0x62, 0x94, 0x29, 0x00, 0x00, 0x00, 0x00, 0xef, 0xd2, 0x51, 0x16, 0xef, 0xe2, 0xd2, 0x75, 0x26,
+    0xa0, 0x2a, 0x84, 0xef, 0xf2, 0x52, 0x0b, 0x32, 0x89, 0x8b, 0x87, 0xef, 0x22, 0x54, 0x2a, 0x2a,
+    0x86, 0x0d, 0x45, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf2, 0xc7, 0x6b, 0xef, 0x92, 0x11, 0x65, 0x04,
+    0x20, 0x07, 0x30, 0xef, 0xa2, 0xc3, 0x76, 0xb7, 0xb5, 0x04, 0x20, 0x20, 0x98, 0x00, 0x00, 0xef,
+    0x62, 0x54, 0x48, 0xef, 0x72, 0x03, 0x6c, 0xef, 0xe0, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0xef,
+    0x72, 0x88, 0x07, 0xef, 0x82, 0x98, 0x32, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x58, 0x31
+};
+
+/*
+01 02 fd 00 00 00 00 00 80 09 00 43 00 00 00 09 d0 00 00 31 7d 00 00 e9 09 05 00 79 8e 07 00 e1
+65 07 00 a9 8d 05 00 99 01 08 00 d1 13 05 00 09 16 04 00 d1 f0 02 00 21 f1 02 00 d1 5a 04 00 39
+72 03 00 09 70 03 00 e9 a5 06 00 91 b4 07 00 71 b5 07 00 f1 b6 07 00 11 b8 07 00 91 07 08 00 a9
+0a 08 00 71 14 08 00 71 fb 07 00 59 71 06 00 c9 ec 06 00 61 eb 06 00 f1 eb 06 00 31 16 03 00 29
+46 03 00 41 48 03 00 99 b0 03 00 d1 ab 03 00 41 a9 03 00 31 a9 03 00 81 b2 03 00 59 a9 03 00 79
+42 03 00 e9 39 03 00 e9 cf 05 00 79 d0 05 00 b1 10 06 00 09 a6 00 00 09 77 04 00 31 df 02 00 e1
+34 05 00 49 3c 05 00 61 53 05 00 39 99 04 00 d1 8b 08 00 09 27 09 00 99 af 03 00 29 9f 02 00 c9
+13 03 00 61 50 03 00 61 7a 06 00 21 2e 05 00 b9 d2 07 00 d1 b2 06 00 01 a9 06 00 a1 70 05 00 11
+90 01 00 71 13 08 00 81 0a 06 00 d9 2c 05 00 09 28 06 00 e1 15 01 00 49 fb 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 98 ef f0 66 ee b7 25 00 40 03 d5 c5 54 13 76 15
+00 13 85 01 24 01 c6 23 9a 05 60 7a 1d 19 46 23 a0 c1 3c 93 85 81 f7 85 46 23 93 d5 00 23 97 d5
+00 23 9b c5 00 93 85 81 05 f2 15 e2 19 f2 1d e6 11 c1 65 93 85 15 9c 6c c1 20 98 00 00 00 00 7b
+e8 00 70 37 25 00 40 85 45 23 10 b5 20 82 80 00 00 00 00 c0 98 2a 84 ef 40 57 84 7b e8 a0 70 fb
+ca 81 9e a0 98 00 00 c0 98 ef 10 b7 f7 2a 84 ef f0 56 97 03 55 44 01 0c 48 10 4c 2e 95 08 c8 02
+96 ef f0 f6 93 5c 4c 22 85 80 98 82 87 00 00 c0 99 32 89 ae 84 2a 84 ef f0 d6 94 22 85 a6 85 4a
+86 ef 30 b7 dd 2a 84 ef f0 96 91 22 85 a0 99 00 00 00 00 c4 99 83 44 c5 01 2e 84 01 46 d4 4d a9
+45 b3 f5 b4 02 13 07 c0 17 b3 37 d7 00 13 b7 15 00 f9 8f 9d 90 a9 e7 03 46 05 00 93 07 c0 12 b3
+b6 d7 00 64 9f f9 8e 79 16 33 36 c0 00 55 8e 1d e6 03 49 15 00 2e 85 ef 10 08 d6 0d c1 13 05 f1
+00 ef 10 e8 bb 01 cd 03 46 f1 00 26 85 a2 85 ca 86 ef 10 a8 a9 7d 15 13 36 15 00 11 a0 01 46 32
+85 a4 99 00 00 00 00 c0 9a 39 cd aa 84 ef 00 a9 99 2a 84 13 86 44 00 0a 85 91 45 a2 86 ef 50 e7
+b5 fb 25 00 81 2a 86 13 35 15 00 93 b5 15 00 4d 8d 19 e9 37 05 23 00 13 05 e5 17 b7 b5 02 24 93
+85 25 64 ef 60 97 a2 b7 f9 01 20 03 c5 89 ad 05 4a 93 84 89 ad 05 c9 8b 18 15 01 03 45 11 00 cc
+50 4d 8d 39 e9 b1 a8 7b 25 00 81 19 c9 37 05 23 00 13 05 e5 17 b7 b5 02 18 93 85 25 64 ef 60 b7
+99 01 44 d5 a8 03 45 01 00 0b 1c 05 01 7b 25 00 81 a3 83 44 01 0b 49 05 03 7b 26 09 f6 37 05 23
+00 13 05 e5 17 b7 b5 02 28 93 85 25 6c ef 60 f7 9b 03 c5 89 ad 8b 09 e5 01 03 c5 84 00 8b 1b 05
+03 ef 70 f3 c0
+*/
+const char g_cfg_cmd2[] = {
+    0x01, 0x02, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x43, 0x00, 0x00, 0x00, 0x09,
+    0xd0, 0x00, 0x00, 0x31, 0x7d, 0x00, 0x00, 0xe9, 0x09, 0x05, 0x00, 0x79, 0x8e, 0x07, 0x00, 0xe1,
+    0x65, 0x07, 0x00, 0xa9, 0x8d, 0x05, 0x00, 0x99, 0x01, 0x08, 0x00, 0xd1, 0x13, 0x05, 0x00, 0x09,
+    0x16, 0x04, 0x00, 0xd1, 0xf0, 0x02, 0x00, 0x21, 0xf1, 0x02, 0x00, 0xd1, 0x5a, 0x04, 0x00, 0x39,
+    0x72, 0x03, 0x00, 0x09, 0x70, 0x03, 0x00, 0xe9, 0xa5, 0x06, 0x00, 0x91, 0xb4, 0x07, 0x00, 0x71,
+    0xb5, 0x07, 0x00, 0xf1, 0xb6, 0x07, 0x00, 0x11, 0xb8, 0x07, 0x00, 0x91, 0x07, 0x08, 0x00, 0xa9,
+    0x0a, 0x08, 0x00, 0x71, 0x14, 0x08, 0x00, 0x71, 0xfb, 0x07, 0x00, 0x59, 0x71, 0x06, 0x00, 0xc9,
+    0xec, 0x06, 0x00, 0x61, 0xeb, 0x06, 0x00, 0xf1, 0xeb, 0x06, 0x00, 0x31, 0x16, 0x03, 0x00, 0x29,
+    0x46, 0x03, 0x00, 0x41, 0x48, 0x03, 0x00, 0x99, 0xb0, 0x03, 0x00, 0xd1, 0xab, 0x03, 0x00, 0x41,
+    0xa9, 0x03, 0x00, 0x31, 0xa9, 0x03, 0x00, 0x81, 0xb2, 0x03, 0x00, 0x59, 0xa9, 0x03, 0x00, 0x79,
+    0x42, 0x03, 0x00, 0xe9, 0x39, 0x03, 0x00, 0xe9, 0xcf, 0x05, 0x00, 0x79, 0xd0, 0x05, 0x00, 0xb1,
+    0x10, 0x06, 0x00, 0x09, 0xa6, 0x00, 0x00, 0x09, 0x77, 0x04, 0x00, 0x31, 0xdf, 0x02, 0x00, 0xe1,
+    0x34, 0x05, 0x00, 0x49, 0x3c, 0x05, 0x00, 0x61, 0x53, 0x05, 0x00, 0x39, 0x99, 0x04, 0x00, 0xd1,
+    0x8b, 0x08, 0x00, 0x09, 0x27, 0x09, 0x00, 0x99, 0xaf, 0x03, 0x00, 0x29, 0x9f, 0x02, 0x00, 0xc9,
+    0x13, 0x03, 0x00, 0x61, 0x50, 0x03, 0x00, 0x61, 0x7a, 0x06, 0x00, 0x21, 0x2e, 0x05, 0x00, 0xb9,
+    0xd2, 0x07, 0x00, 0xd1, 0xb2, 0x06, 0x00, 0x01, 0xa9, 0x06, 0x00, 0xa1, 0x70, 0x05, 0x00, 0x11,
+    0x90, 0x01, 0x00, 0x71, 0x13, 0x08, 0x00, 0x81, 0x0a, 0x06, 0x00, 0xd9, 0x2c, 0x05, 0x00, 0x09,
+    0x28, 0x06, 0x00, 0xe1, 0x15, 0x01, 0x00, 0x49, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+    0x98, 0xef, 0xf0, 0x66, 0xee, 0xb7, 0x25, 0x00, 0x40, 0x03, 0xd5, 0xc5, 0x54, 0x13, 0x76, 0x15,
+    0x00, 0x13, 0x85, 0x01, 0x24, 0x01, 0xc6, 0x23, 0x9a, 0x05, 0x60, 0x7a, 0x1d, 0x19, 0x46, 0x23,
+    0xa0, 0xc1, 0x3c, 0x93, 0x85, 0x81, 0xf7, 0x85, 0x46, 0x23, 0x93, 0xd5, 0x00, 0x23, 0x97, 0xd5,
+    0x00, 0x23, 0x9b, 0xc5, 0x00, 0x93, 0x85, 0x81, 0x05, 0xf2, 0x15, 0xe2, 0x19, 0xf2, 0x1d, 0xe6,
+    0x11, 0xc1, 0x65, 0x93, 0x85, 0x15, 0x9c, 0x6c, 0xc1, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0x7b,
+    0xe8, 0x00, 0x70, 0x37, 0x25, 0x00, 0x40, 0x85, 0x45, 0x23, 0x10, 0xb5, 0x20, 0x82, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0xef, 0x40, 0x57, 0x84, 0x7b, 0xe8, 0xa0, 0x70, 0xfb,
+    0xca, 0x81, 0x9e, 0xa0, 0x98, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x10, 0xb7, 0xf7, 0x2a, 0x84, 0xef,
+    0xf0, 0x56, 0x97, 0x03, 0x55, 0x44, 0x01, 0x0c, 0x48, 0x10, 0x4c, 0x2e, 0x95, 0x08, 0xc8, 0x02,
+    0x96, 0xef, 0xf0, 0xf6, 0x93, 0x5c, 0x4c, 0x22, 0x85, 0x80, 0x98, 0x82, 0x87, 0x00, 0x00, 0xc0,
+    0x99, 0x32, 0x89, 0xae, 0x84, 0x2a, 0x84, 0xef, 0xf0, 0xd6, 0x94, 0x22, 0x85, 0xa6, 0x85, 0x4a,
+    0x86, 0xef, 0x30, 0xb7, 0xdd, 0x2a, 0x84, 0xef, 0xf0, 0x96, 0x91, 0x22, 0x85, 0xa0, 0x99, 0x00,
+    0x00, 0x00, 0x00, 0xc4, 0x99, 0x83, 0x44, 0xc5, 0x01, 0x2e, 0x84, 0x01, 0x46, 0xd4, 0x4d, 0xa9,
+    0x45, 0xb3, 0xf5, 0xb4, 0x02, 0x13, 0x07, 0xc0, 0x17, 0xb3, 0x37, 0xd7, 0x00, 0x13, 0xb7, 0x15,
+    0x00, 0xf9, 0x8f, 0x9d, 0x90, 0xa9, 0xe7, 0x03, 0x46, 0x05, 0x00, 0x93, 0x07, 0xc0, 0x12, 0xb3,
+    0xb6, 0xd7, 0x00, 0x64, 0x9f, 0xf9, 0x8e, 0x79, 0x16, 0x33, 0x36, 0xc0, 0x00, 0x55, 0x8e, 0x1d,
+    0xe6, 0x03, 0x49, 0x15, 0x00, 0x2e, 0x85, 0xef, 0x10, 0x08, 0xd6, 0x0d, 0xc1, 0x13, 0x05, 0xf1,
+    0x00, 0xef, 0x10, 0xe8, 0xbb, 0x01, 0xcd, 0x03, 0x46, 0xf1, 0x00, 0x26, 0x85, 0xa2, 0x85, 0xca,
+    0x86, 0xef, 0x10, 0xa8, 0xa9, 0x7d, 0x15, 0x13, 0x36, 0x15, 0x00, 0x11, 0xa0, 0x01, 0x46, 0x32,
+    0x85, 0xa4, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x9a, 0x39, 0xcd, 0xaa, 0x84, 0xef, 0x00, 0xa9,
+    0x99, 0x2a, 0x84, 0x13, 0x86, 0x44, 0x00, 0x0a, 0x85, 0x91, 0x45, 0xa2, 0x86, 0xef, 0x50, 0xe7,
+    0xb5, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d,
+    0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x24, 0x93,
+    0x85, 0x25, 0x64, 0xef, 0x60, 0x97, 0xa2, 0xb7, 0xf9, 0x01, 0x20, 0x03, 0xc5, 0x89, 0xad, 0x05,
+    0x4a, 0x93, 0x84, 0x89, 0xad, 0x05, 0xc9, 0x8b, 0x18, 0x15, 0x01, 0x03, 0x45, 0x11, 0x00, 0xcc,
+    0x50, 0x4d, 0x8d, 0x39, 0xe9, 0xb1, 0xa8, 0x7b, 0x25, 0x00, 0x81, 0x19, 0xc9, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x18, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0xb7,
+    0x99, 0x01, 0x44, 0xd5, 0xa8, 0x03, 0x45, 0x01, 0x00, 0x0b, 0x1c, 0x05, 0x01, 0x7b, 0x25, 0x00,
+    0x81, 0xa3, 0x83, 0x44, 0x01, 0x0b, 0x49, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x28, 0x93, 0x85, 0x25, 0x6c, 0xef, 0x60, 0xf7,
+    0x9b, 0x03, 0xc5, 0x89, 0xad, 0x8b, 0x09, 0xe5, 0x01, 0x03, 0xc5, 0x84, 0x00, 0x8b, 0x1b, 0x05,
+    0x03, 0xef, 0x70, 0xf3, 0xc0
+};
+
+/*
+01 03 fc 69 e2 7b 25 00 81 0b 48 05 03 03 c6 84 00 fb 26 09 f6 37 05 23 00 13 05 e5 17 b7 b5 02
+32 93 85 25 6c ef 60 f7 9d 92 10 83 46 01 00 03 05 11 00 03 56 21 00 23 8c d9 ac 23 85 a4 00 8b
+49 06 04 7b 25 00 81 09 cd 7b 27 09 f6 37 05 23 00 13 05 e5 17 b7 b5 02 39 93 85 25 64 ef 60 37
+a0 01 46 29 90 83 a5 41 7a 81 c5 32 85 82 95 19 a0 13 05 60 22 ef 60 e9 df 26 85 ef 20 89 e3 7b
+25 00 81 a3 8c 49 ad 0b 4c 05 03 03 c6 89 ad fb 25 09 f6 fb 26 0f 26 7b 27 09 f6 83 57 21 00 b3
+86 d5 40 37 05 23 00 13 05 e5 17 b7 b5 02 49 93 85 25 6c ef 60 d7 a0 22 85 a0 9a 00 00 00 00 c0
+9a ae 89 2a 89 37 44 02 40 13 05 44 20 89 45 ef 50 89 e1 13 05 44 23 c1 45 ef 50 e9 e0 13 04 04
+20 93 05 00 0a 22 85 ef 50 09 e1 93 05 00 0a 22 85 ef 50 69 df 37 45 10 40 4c 55 41 66 d1 8d 4c
+d5 37 6a 02 40 13 04 4a 20 93 05 00 20 22 85 ef 50 89 de 93 04 0a 12 93 05 00 10 26 85 ef 50 a9
+dd 83 d5 41 56 26 85 ef 50 09 dc 93 05 00 10 26 85 ef 50 69 db 93 75 f9 03 13 05 0a 20 ef 50 29
+da 8d 45 22 85 ef 50 29 db 93 95 09 01 c1 81 13 05 8a 20 ef 50 c9 d8 93 d5 09 01 13 05 ca 20 ef
+50 09 d8 83 d5 81 56 13 05 0a 21 ef 50 49 d7 83 d5 a1 56 13 05 4a 21 ef 50 89 d6 83 d5 c1 56 13
+05 8a 21 ef 50 c9 d5 83 d5 e1 56 13 05 ca 21 ef 50 09 d5 93 05 00 08 22 85 ef 50 e9 d4 93 05 00
+20 22 85 ef 50 49 d4 93 05 00 10 22 85 ef 50 a9 d3 7b 25 00 81 19 cd 83 56 4a 20 37 05 23 00 13
+05 e5 17 b7 b5 01 49 93 85 25 54 22 86 80 9a 6f 60 57 83 a0 9a 00 00 37 55 03 20 03 45 c5 d9 b7
+b5 09 00 83 c5 45 70 4d 8d 11 cd 7b 25 00 81 0b 4f 05 03 7b 26 09 f6 37 05 23 00 13 05 e5 17 b7
+b5 02 16 05 a0 7b 25 00 81 09 46 7b 66 cf 2e 0b 47 05 03 7b 26 09 f6 37 05 23 00 13 05 e5 17 b7
+b5 02 14 93 85 25 4c 6f 60 47 f8 82 80 00 00 37 55 03 20 03 45 c5 d9 b7 b5 09 00 83 c5 45 70 7d
+15 33 35 a0 00 fd 15 b3 35 b0 00 6d 8d 0d ed 37 f5 01 20 93 05 85 ad 03 85 65 00 7b 26 00 81 85
+46 d4 c9 05 05 23 83 a5 00 0b 41 16 03 08 92 fb 26 09 f6 37 05 23 00 13 05 e5 17 b7 b5 02 20 93
+85 25 4c 6f 60 07 f8 7b 25 00 81 09 46 7b 66 cf 2e 0b 47 05 03 7b 26 09 f6 37 05 23 00 13 05 e5
+17 b7 b5 02 23 93 85 25 4c 6f 60 27 f0 82 80 00 00 00 00 7d 15 08 91 8b 54 05 02 03 45 86 00 0b
+15 05 01 33 35 b0 00 82 80 a3 15 06 00 93 05 d6 00 21 a0 1a 12 93 05 b6 00 05 45 82 11 82 80 00
+00 00 00 c8 9b aa 84 05 44 ef 60 a9 bf 01 e5 03 c5 24 00 19 c1 22 85 a8 9b 03 95 04 00 2c 08 10
+08 34 00 13 07 f1 01 ef 80 49 a1 2a 89 32 45 a2 45 92 1c 13 06 09 fe 05 44 0b 23 06 00 81 4a 33
+1a c4 00 21 a0 01 4a b3 1a 24 01 b3 f5 55 01 33 75 45 01 4d 8d 61 d1 37 55 00 20 13 05 85 88 54
+51 10 51 7b 25 09 f6 e2 47 1d 8d 93 05 c0 44 63 4c b5 06 7b 25 00 81 b7 45 01 20 93 84 05 a3 8b
+4a 05 03 03 45 f1 01 2b 85 a4 06 18 41 37 05 23 00 13 05 e5 17 b7 b5 00 57 93 85 25 7c 01 46 ca
+86 ef 60 e7 f3 7b 25 00 81 83 45 f1 01 ab 85 b4 06 d0 41 94 41 13 c7 fa ff 93 47 fa ff 7d 8e 75
+8f 98 c1 d0 c1 0b 44 d5 03 fb 27 09 f6 37 05 23 00 13 05 e5 17 b7 b5 00 5a 93 85 25 7c 01 46 ca
+86 ef 60 e7 ef 05 bf d2 45 42 45 33 c8 b6 00 b3 37 a6 00 e4 9f 33 b7 b6 00 64 9f 2b e7 07 21 0d
+e7 7b 25 00 81 0b 44 c5 02 83 96 04 00 7b 27 09 f6 37 05 23 00 13 05 e5 17 b7 b5 00 60 93 85 25
+78 01 46 02 72
+*/
+const char g_cfg_cmd3[] = {
+    0x01, 0x03, 0xfc, 0x69, 0xe2, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x48, 0x05, 0x03, 0x03, 0xc6, 0x84,
+    0x00, 0xfb, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02,
+    0x32, 0x93, 0x85, 0x25, 0x6c, 0xef, 0x60, 0xf7, 0x9d, 0x92, 0x10, 0x83, 0x46, 0x01, 0x00, 0x03,
+    0x05, 0x11, 0x00, 0x03, 0x56, 0x21, 0x00, 0x23, 0x8c, 0xd9, 0xac, 0x23, 0x85, 0xa4, 0x00, 0x8b,
+    0x49, 0x06, 0x04, 0x7b, 0x25, 0x00, 0x81, 0x09, 0xcd, 0x7b, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x39, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0x37,
+    0xa0, 0x01, 0x46, 0x29, 0x90, 0x83, 0xa5, 0x41, 0x7a, 0x81, 0xc5, 0x32, 0x85, 0x82, 0x95, 0x19,
+    0xa0, 0x13, 0x05, 0x60, 0x22, 0xef, 0x60, 0xe9, 0xdf, 0x26, 0x85, 0xef, 0x20, 0x89, 0xe3, 0x7b,
+    0x25, 0x00, 0x81, 0xa3, 0x8c, 0x49, 0xad, 0x0b, 0x4c, 0x05, 0x03, 0x03, 0xc6, 0x89, 0xad, 0xfb,
+    0x25, 0x09, 0xf6, 0xfb, 0x26, 0x0f, 0x26, 0x7b, 0x27, 0x09, 0xf6, 0x83, 0x57, 0x21, 0x00, 0xb3,
+    0x86, 0xd5, 0x40, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x49, 0x93,
+    0x85, 0x25, 0x6c, 0xef, 0x60, 0xd7, 0xa0, 0x22, 0x85, 0xa0, 0x9a, 0x00, 0x00, 0x00, 0x00, 0xc0,
+    0x9a, 0xae, 0x89, 0x2a, 0x89, 0x37, 0x44, 0x02, 0x40, 0x13, 0x05, 0x44, 0x20, 0x89, 0x45, 0xef,
+    0x50, 0x89, 0xe1, 0x13, 0x05, 0x44, 0x23, 0xc1, 0x45, 0xef, 0x50, 0xe9, 0xe0, 0x13, 0x04, 0x04,
+    0x20, 0x93, 0x05, 0x00, 0x0a, 0x22, 0x85, 0xef, 0x50, 0x09, 0xe1, 0x93, 0x05, 0x00, 0x0a, 0x22,
+    0x85, 0xef, 0x50, 0x69, 0xdf, 0x37, 0x45, 0x10, 0x40, 0x4c, 0x55, 0x41, 0x66, 0xd1, 0x8d, 0x4c,
+    0xd5, 0x37, 0x6a, 0x02, 0x40, 0x13, 0x04, 0x4a, 0x20, 0x93, 0x05, 0x00, 0x20, 0x22, 0x85, 0xef,
+    0x50, 0x89, 0xde, 0x93, 0x04, 0x0a, 0x12, 0x93, 0x05, 0x00, 0x10, 0x26, 0x85, 0xef, 0x50, 0xa9,
+    0xdd, 0x83, 0xd5, 0x41, 0x56, 0x26, 0x85, 0xef, 0x50, 0x09, 0xdc, 0x93, 0x05, 0x00, 0x10, 0x26,
+    0x85, 0xef, 0x50, 0x69, 0xdb, 0x93, 0x75, 0xf9, 0x03, 0x13, 0x05, 0x0a, 0x20, 0xef, 0x50, 0x29,
+    0xda, 0x8d, 0x45, 0x22, 0x85, 0xef, 0x50, 0x29, 0xdb, 0x93, 0x95, 0x09, 0x01, 0xc1, 0x81, 0x13,
+    0x05, 0x8a, 0x20, 0xef, 0x50, 0xc9, 0xd8, 0x93, 0xd5, 0x09, 0x01, 0x13, 0x05, 0xca, 0x20, 0xef,
+    0x50, 0x09, 0xd8, 0x83, 0xd5, 0x81, 0x56, 0x13, 0x05, 0x0a, 0x21, 0xef, 0x50, 0x49, 0xd7, 0x83,
+    0xd5, 0xa1, 0x56, 0x13, 0x05, 0x4a, 0x21, 0xef, 0x50, 0x89, 0xd6, 0x83, 0xd5, 0xc1, 0x56, 0x13,
+    0x05, 0x8a, 0x21, 0xef, 0x50, 0xc9, 0xd5, 0x83, 0xd5, 0xe1, 0x56, 0x13, 0x05, 0xca, 0x21, 0xef,
+    0x50, 0x09, 0xd5, 0x93, 0x05, 0x00, 0x08, 0x22, 0x85, 0xef, 0x50, 0xe9, 0xd4, 0x93, 0x05, 0x00,
+    0x20, 0x22, 0x85, 0xef, 0x50, 0x49, 0xd4, 0x93, 0x05, 0x00, 0x10, 0x22, 0x85, 0xef, 0x50, 0xa9,
+    0xd3, 0x7b, 0x25, 0x00, 0x81, 0x19, 0xcd, 0x83, 0x56, 0x4a, 0x20, 0x37, 0x05, 0x23, 0x00, 0x13,
+    0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x49, 0x93, 0x85, 0x25, 0x54, 0x22, 0x86, 0x80, 0x9a, 0x6f,
+    0x60, 0x57, 0x83, 0xa0, 0x9a, 0x00, 0x00, 0x37, 0x55, 0x03, 0x20, 0x03, 0x45, 0xc5, 0xd9, 0xb7,
+    0xb5, 0x09, 0x00, 0x83, 0xc5, 0x45, 0x70, 0x4d, 0x8d, 0x11, 0xcd, 0x7b, 0x25, 0x00, 0x81, 0x0b,
+    0x4f, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7,
+    0xb5, 0x02, 0x16, 0x05, 0xa0, 0x7b, 0x25, 0x00, 0x81, 0x09, 0x46, 0x7b, 0x66, 0xcf, 0x2e, 0x0b,
+    0x47, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7,
+    0xb5, 0x02, 0x14, 0x93, 0x85, 0x25, 0x4c, 0x6f, 0x60, 0x47, 0xf8, 0x82, 0x80, 0x00, 0x00, 0x37,
+    0x55, 0x03, 0x20, 0x03, 0x45, 0xc5, 0xd9, 0xb7, 0xb5, 0x09, 0x00, 0x83, 0xc5, 0x45, 0x70, 0x7d,
+    0x15, 0x33, 0x35, 0xa0, 0x00, 0xfd, 0x15, 0xb3, 0x35, 0xb0, 0x00, 0x6d, 0x8d, 0x0d, 0xed, 0x37,
+    0xf5, 0x01, 0x20, 0x93, 0x05, 0x85, 0xad, 0x03, 0x85, 0x65, 0x00, 0x7b, 0x26, 0x00, 0x81, 0x85,
+    0x46, 0xd4, 0xc9, 0x05, 0x05, 0x23, 0x83, 0xa5, 0x00, 0x0b, 0x41, 0x16, 0x03, 0x08, 0x92, 0xfb,
+    0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x20, 0x93,
+    0x85, 0x25, 0x4c, 0x6f, 0x60, 0x07, 0xf8, 0x7b, 0x25, 0x00, 0x81, 0x09, 0x46, 0x7b, 0x66, 0xcf,
+    0x2e, 0x0b, 0x47, 0x05, 0x03, 0x7b, 0x26, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5,
+    0x17, 0xb7, 0xb5, 0x02, 0x23, 0x93, 0x85, 0x25, 0x4c, 0x6f, 0x60, 0x27, 0xf0, 0x82, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0x7d, 0x15, 0x08, 0x91, 0x8b, 0x54, 0x05, 0x02, 0x03, 0x45, 0x86, 0x00, 0x0b,
+    0x15, 0x05, 0x01, 0x33, 0x35, 0xb0, 0x00, 0x82, 0x80, 0xa3, 0x15, 0x06, 0x00, 0x93, 0x05, 0xd6,
+    0x00, 0x21, 0xa0, 0x1a, 0x12, 0x93, 0x05, 0xb6, 0x00, 0x05, 0x45, 0x82, 0x11, 0x82, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0xc8, 0x9b, 0xaa, 0x84, 0x05, 0x44, 0xef, 0x60, 0xa9, 0xbf, 0x01, 0xe5, 0x03,
+    0xc5, 0x24, 0x00, 0x19, 0xc1, 0x22, 0x85, 0xa8, 0x9b, 0x03, 0x95, 0x04, 0x00, 0x2c, 0x08, 0x10,
+    0x08, 0x34, 0x00, 0x13, 0x07, 0xf1, 0x01, 0xef, 0x80, 0x49, 0xa1, 0x2a, 0x89, 0x32, 0x45, 0xa2,
+    0x45, 0x92, 0x1c, 0x13, 0x06, 0x09, 0xfe, 0x05, 0x44, 0x0b, 0x23, 0x06, 0x00, 0x81, 0x4a, 0x33,
+    0x1a, 0xc4, 0x00, 0x21, 0xa0, 0x01, 0x4a, 0xb3, 0x1a, 0x24, 0x01, 0xb3, 0xf5, 0x55, 0x01, 0x33,
+    0x75, 0x45, 0x01, 0x4d, 0x8d, 0x61, 0xd1, 0x37, 0x55, 0x00, 0x20, 0x13, 0x05, 0x85, 0x88, 0x54,
+    0x51, 0x10, 0x51, 0x7b, 0x25, 0x09, 0xf6, 0xe2, 0x47, 0x1d, 0x8d, 0x93, 0x05, 0xc0, 0x44, 0x63,
+    0x4c, 0xb5, 0x06, 0x7b, 0x25, 0x00, 0x81, 0xb7, 0x45, 0x01, 0x20, 0x93, 0x84, 0x05, 0xa3, 0x8b,
+    0x4a, 0x05, 0x03, 0x03, 0x45, 0xf1, 0x01, 0x2b, 0x85, 0xa4, 0x06, 0x18, 0x41, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x57, 0x93, 0x85, 0x25, 0x7c, 0x01, 0x46, 0xca,
+    0x86, 0xef, 0x60, 0xe7, 0xf3, 0x7b, 0x25, 0x00, 0x81, 0x83, 0x45, 0xf1, 0x01, 0xab, 0x85, 0xb4,
+    0x06, 0xd0, 0x41, 0x94, 0x41, 0x13, 0xc7, 0xfa, 0xff, 0x93, 0x47, 0xfa, 0xff, 0x7d, 0x8e, 0x75,
+    0x8f, 0x98, 0xc1, 0xd0, 0xc1, 0x0b, 0x44, 0xd5, 0x03, 0xfb, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x5a, 0x93, 0x85, 0x25, 0x7c, 0x01, 0x46, 0xca,
+    0x86, 0xef, 0x60, 0xe7, 0xef, 0x05, 0xbf, 0xd2, 0x45, 0x42, 0x45, 0x33, 0xc8, 0xb6, 0x00, 0xb3,
+    0x37, 0xa6, 0x00, 0xe4, 0x9f, 0x33, 0xb7, 0xb6, 0x00, 0x64, 0x9f, 0x2b, 0xe7, 0x07, 0x21, 0x0d,
+    0xe7, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x44, 0xc5, 0x02, 0x83, 0x96, 0x04, 0x00, 0x7b, 0x27, 0x09,
+    0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x60, 0x93, 0x85, 0x25,
+    0x78, 0x01, 0x46, 0x02, 0x72
+};
+
+/*
+01 04 fb ef 60 c7 e5 fd b5 26 87 ef 80 49 ef 7d 15 13 34 15 00 c5 b5 00 00 00 00 83 45 25 00 8b
+dc 05 06 05 46 b3 15 b6 00 93 f5 55 02 95 c1 83 05 05 07 fd 15 8c 91 8b d4 05 02 83 45 d5 03 13
+f6 35 00 19 ce 5e 1d 39 a0 3e 1d a3 1e 05 02 39 a0 83 45 d5 03 93 f5 75 0e a3 0e b5 02 01 45 82
+80 83 45 c5 03 e5 fd 03 45 b5 03 13 35 15 00 82 80 00 00 40 99 2a 84 83 44 25 00 ef b0 59 b8 0b
+0a 15 01 03 25 44 09 83 25 44 08 83 06 04 07 a3 0c 04 06 13 06 15 00 03 25 04 0b fd 16 94 92 23
+2a c4 08 8b df 06 02 2b 86 b5 be ab 35 b6 be 15 46 ef b0 f9 eb b7 b5 09 00 93 85 c5 20 ab 85 95
+04 8c 41 23 28 a4 0a 63 60 b5 02 23 08 04 06 0d 45 a3 0c a4 06 23 28 04 0a 23 2a 04 08 3a 1c 20
+99 01 c5 23 28 04 0a 20 99 8b 4e 06 32 22 85 ef b0 99 c0 75 f9 09 45 23 08 a4 06 37 b5 09 00 13
+05 c5 20 2b 05 95 04 08 41 85 45 03 06 d4 03 a3 0c b4 06 05 81 23 28 a4 0a 13 65 06 02 a3 0e a4
+02 20 99 23 08 04 06 20 99 00 00 40 99 ae 84 2a 84 13 05 00 20 2a c0 0a 85 ef b0 29 d3 03 45 04
+07 8b 03 15 02 0b 12 35 01 82 45 13 05 90 6c 2e 86 83 26 84 09 77 96 a4 c4 13 07 00 40 33 45 e6
+02 36 95 05 66 13 06 d6 24 ae 86 f7 96 c4 c4 03 26 c4 09 23 2c a4 08 b3 c6 e6 02 36 95 32 95 23
+2e a4 08 19 66 13 06 66 1e f7 95 c4 c4 a1 a8 82 45 13 05 90 6c 2e 86 77 96 a4 c4 03 25 84 09 85
+66 13 87 06 a0 33 46 e6 02 32 95 23 2c a4 08 13 86 d6 24 ae 86 f7 96 c4 c4 13 06 00 40 b3 c6 c6
+02 36 95 83 26 c4 09 0a 05 29 47 33 45 e5 02 36 95 23 2e a4 08 99 66 93 86 66 1e f7 95 d4 c4 b3
+c5 c5 02 8a 05 b3 c5 e5 02 50 48 2e 95 93 55 f6 41 c2 05 ab a5 c5 60 93 16 06 01 ab 85 a5 be 2b
+05 c5 20 33 36 d5 00 b2 95 08 cc 4c cc 20 99 00 00 00 00 5c 98 79 71 ef 10 50 5e fb 05 2f 2e 64
+9d fd 15 b3 35 b0 00 4d 8d 29 e5 37 b5 09 00 93 05 85 22 28 00 13 06 20 0a ef 80 e6 ed 37 65 02
+20 13 05 85 d9 93 05 20 0a 30 00 93 06 20 0a ef 40 d7 c6 fb 25 00 81 2a 86 13 35 15 00 93 b5 15
+00 4d 8d 39 ed 37 05 23 00 13 05 e5 17 b7 b5 01 f2 a1 a0 37 b5 09 00 93 05 a5 2c 28 00 13 06 20
+0a ef 80 66 e9 37 65 02 20 13 05 85 d9 93 05 20 0a 30 00 93 06 20 0a ef 40 57 c2 fb 25 00 81 2a
+86 13 35 15 00 93 b5 15 00 4d 8d 19 e9 37 05 23 00 13 05 e5 17 b7 b5 05 1d 93 85 25 64 ef 60 e7
+ae 45 61 3c 98 00 00 5c 98 79 71 37 b5 09 00 93 05 c5 36 28 00 13 06 20 0a ef 80 e6 e3 37 65 02
+20 13 05 a5 e3 93 05 20 0a 30 00 93 06 20 0a ef 40 d7 bc 05 37 01 45 ef f0 98 9d 45 61 3c 98 5c
+98 79 71 ef 10 90 4f fb 05 2f 2e 64 9d fd 15 b3 35 b0 00 4d 8d 29 e5 37 b5 09 00 93 05 e5 40 28
+00 13 06 20 0a ef 80 26 df 37 65 02 20 13 05 c5 ed 93 05 20 0a 30 00 93 06 20 0a ef 40 17 b8 fb
+25 00 81 2a 86 13 35 15 00 93 b5 15 00 4d 8d 39 ed 37 05 23 00 13 05 e5 17 b7 b5 00 42 a1 a0 37
+b5 09 00 93 05 05 4b 28 00 13 06 20 0a ef 80 a6 da 37 65 02 20 13 05 c5 ed 93 05 20 0a 30 00 93
+06 20 0a ef 40 97 b3 fb 25 00 81 2a 86 13 35 15 00 93 b5 15 00 4d 8d 19 e9 37 05 23 00 13 05 e5
+17 b7 b5 00 6d 93 85 25 64 ef 60 27 a0 45 61 3c 98 00 00 c0 98 37 54 03 20 03 45 c4 d9 8b 18 15
+01 ef a0 ba 84 37 05 03 20 83 45 05 24 8b 91 15 01 23 00 05 24 13 06 05 24 37 05 03 20 13 05 05
+2a 93 05 00 06 93 06 00 06 ef 40 37 ad fb 25 00 81 2a 86 13 35 15 00 93 b5 15 00 4d 8d 19 e9 37
+05 23 00 ec 7d
+*/
+const char g_cfg_cmd4[] = {
+    0x01, 0x04, 0xfb, 0xef, 0x60, 0xc7, 0xe5, 0xfd, 0xb5, 0x26, 0x87, 0xef, 0x80, 0x49, 0xef, 0x7d,
+    0x15, 0x13, 0x34, 0x15, 0x00, 0xc5, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x83, 0x45, 0x25, 0x00, 0x8b,
+    0xdc, 0x05, 0x06, 0x05, 0x46, 0xb3, 0x15, 0xb6, 0x00, 0x93, 0xf5, 0x55, 0x02, 0x95, 0xc1, 0x83,
+    0x05, 0x05, 0x07, 0xfd, 0x15, 0x8c, 0x91, 0x8b, 0xd4, 0x05, 0x02, 0x83, 0x45, 0xd5, 0x03, 0x13,
+    0xf6, 0x35, 0x00, 0x19, 0xce, 0x5e, 0x1d, 0x39, 0xa0, 0x3e, 0x1d, 0xa3, 0x1e, 0x05, 0x02, 0x39,
+    0xa0, 0x83, 0x45, 0xd5, 0x03, 0x93, 0xf5, 0x75, 0x0e, 0xa3, 0x0e, 0xb5, 0x02, 0x01, 0x45, 0x82,
+    0x80, 0x83, 0x45, 0xc5, 0x03, 0xe5, 0xfd, 0x03, 0x45, 0xb5, 0x03, 0x13, 0x35, 0x15, 0x00, 0x82,
+    0x80, 0x00, 0x00, 0x40, 0x99, 0x2a, 0x84, 0x83, 0x44, 0x25, 0x00, 0xef, 0xb0, 0x59, 0xb8, 0x0b,
+    0x0a, 0x15, 0x01, 0x03, 0x25, 0x44, 0x09, 0x83, 0x25, 0x44, 0x08, 0x83, 0x06, 0x04, 0x07, 0xa3,
+    0x0c, 0x04, 0x06, 0x13, 0x06, 0x15, 0x00, 0x03, 0x25, 0x04, 0x0b, 0xfd, 0x16, 0x94, 0x92, 0x23,
+    0x2a, 0xc4, 0x08, 0x8b, 0xdf, 0x06, 0x02, 0x2b, 0x86, 0xb5, 0xbe, 0xab, 0x35, 0xb6, 0xbe, 0x15,
+    0x46, 0xef, 0xb0, 0xf9, 0xeb, 0xb7, 0xb5, 0x09, 0x00, 0x93, 0x85, 0xc5, 0x20, 0xab, 0x85, 0x95,
+    0x04, 0x8c, 0x41, 0x23, 0x28, 0xa4, 0x0a, 0x63, 0x60, 0xb5, 0x02, 0x23, 0x08, 0x04, 0x06, 0x0d,
+    0x45, 0xa3, 0x0c, 0xa4, 0x06, 0x23, 0x28, 0x04, 0x0a, 0x23, 0x2a, 0x04, 0x08, 0x3a, 0x1c, 0x20,
+    0x99, 0x01, 0xc5, 0x23, 0x28, 0x04, 0x0a, 0x20, 0x99, 0x8b, 0x4e, 0x06, 0x32, 0x22, 0x85, 0xef,
+    0xb0, 0x99, 0xc0, 0x75, 0xf9, 0x09, 0x45, 0x23, 0x08, 0xa4, 0x06, 0x37, 0xb5, 0x09, 0x00, 0x13,
+    0x05, 0xc5, 0x20, 0x2b, 0x05, 0x95, 0x04, 0x08, 0x41, 0x85, 0x45, 0x03, 0x06, 0xd4, 0x03, 0xa3,
+    0x0c, 0xb4, 0x06, 0x05, 0x81, 0x23, 0x28, 0xa4, 0x0a, 0x13, 0x65, 0x06, 0x02, 0xa3, 0x0e, 0xa4,
+    0x02, 0x20, 0x99, 0x23, 0x08, 0x04, 0x06, 0x20, 0x99, 0x00, 0x00, 0x40, 0x99, 0xae, 0x84, 0x2a,
+    0x84, 0x13, 0x05, 0x00, 0x20, 0x2a, 0xc0, 0x0a, 0x85, 0xef, 0xb0, 0x29, 0xd3, 0x03, 0x45, 0x04,
+    0x07, 0x8b, 0x03, 0x15, 0x02, 0x0b, 0x12, 0x35, 0x01, 0x82, 0x45, 0x13, 0x05, 0x90, 0x6c, 0x2e,
+    0x86, 0x83, 0x26, 0x84, 0x09, 0x77, 0x96, 0xa4, 0xc4, 0x13, 0x07, 0x00, 0x40, 0x33, 0x45, 0xe6,
+    0x02, 0x36, 0x95, 0x05, 0x66, 0x13, 0x06, 0xd6, 0x24, 0xae, 0x86, 0xf7, 0x96, 0xc4, 0xc4, 0x03,
+    0x26, 0xc4, 0x09, 0x23, 0x2c, 0xa4, 0x08, 0xb3, 0xc6, 0xe6, 0x02, 0x36, 0x95, 0x32, 0x95, 0x23,
+    0x2e, 0xa4, 0x08, 0x19, 0x66, 0x13, 0x06, 0x66, 0x1e, 0xf7, 0x95, 0xc4, 0xc4, 0xa1, 0xa8, 0x82,
+    0x45, 0x13, 0x05, 0x90, 0x6c, 0x2e, 0x86, 0x77, 0x96, 0xa4, 0xc4, 0x03, 0x25, 0x84, 0x09, 0x85,
+    0x66, 0x13, 0x87, 0x06, 0xa0, 0x33, 0x46, 0xe6, 0x02, 0x32, 0x95, 0x23, 0x2c, 0xa4, 0x08, 0x13,
+    0x86, 0xd6, 0x24, 0xae, 0x86, 0xf7, 0x96, 0xc4, 0xc4, 0x13, 0x06, 0x00, 0x40, 0xb3, 0xc6, 0xc6,
+    0x02, 0x36, 0x95, 0x83, 0x26, 0xc4, 0x09, 0x0a, 0x05, 0x29, 0x47, 0x33, 0x45, 0xe5, 0x02, 0x36,
+    0x95, 0x23, 0x2e, 0xa4, 0x08, 0x99, 0x66, 0x93, 0x86, 0x66, 0x1e, 0xf7, 0x95, 0xd4, 0xc4, 0xb3,
+    0xc5, 0xc5, 0x02, 0x8a, 0x05, 0xb3, 0xc5, 0xe5, 0x02, 0x50, 0x48, 0x2e, 0x95, 0x93, 0x55, 0xf6,
+    0x41, 0xc2, 0x05, 0xab, 0xa5, 0xc5, 0x60, 0x93, 0x16, 0x06, 0x01, 0xab, 0x85, 0xa5, 0xbe, 0x2b,
+    0x05, 0xc5, 0x20, 0x33, 0x36, 0xd5, 0x00, 0xb2, 0x95, 0x08, 0xcc, 0x4c, 0xcc, 0x20, 0x99, 0x00,
+    0x00, 0x00, 0x00, 0x5c, 0x98, 0x79, 0x71, 0xef, 0x10, 0x50, 0x5e, 0xfb, 0x05, 0x2f, 0x2e, 0x64,
+    0x9d, 0xfd, 0x15, 0xb3, 0x35, 0xb0, 0x00, 0x4d, 0x8d, 0x29, 0xe5, 0x37, 0xb5, 0x09, 0x00, 0x93,
+    0x05, 0x85, 0x22, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xe6, 0xed, 0x37, 0x65, 0x02,
+    0x20, 0x13, 0x05, 0x85, 0xd9, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef,
+    0x40, 0xd7, 0xc6, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15,
+    0x00, 0x4d, 0x8d, 0x39, 0xed, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01,
+    0xf2, 0xa1, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0xa5, 0x2c, 0x28, 0x00, 0x13, 0x06, 0x20,
+    0x0a, 0xef, 0x80, 0x66, 0xe9, 0x37, 0x65, 0x02, 0x20, 0x13, 0x05, 0x85, 0xd9, 0x93, 0x05, 0x20,
+    0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0x57, 0xc2, 0xfb, 0x25, 0x00, 0x81, 0x2a,
+    0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x05, 0x1d, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0xe7,
+    0xae, 0x45, 0x61, 0x3c, 0x98, 0x00, 0x00, 0x5c, 0x98, 0x79, 0x71, 0x37, 0xb5, 0x09, 0x00, 0x93,
+    0x05, 0xc5, 0x36, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xe6, 0xe3, 0x37, 0x65, 0x02,
+    0x20, 0x13, 0x05, 0xa5, 0xe3, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef,
+    0x40, 0xd7, 0xbc, 0x05, 0x37, 0x01, 0x45, 0xef, 0xf0, 0x98, 0x9d, 0x45, 0x61, 0x3c, 0x98, 0x5c,
+    0x98, 0x79, 0x71, 0xef, 0x10, 0x90, 0x4f, 0xfb, 0x05, 0x2f, 0x2e, 0x64, 0x9d, 0xfd, 0x15, 0xb3,
+    0x35, 0xb0, 0x00, 0x4d, 0x8d, 0x29, 0xe5, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0xe5, 0x40, 0x28,
+    0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0x26, 0xdf, 0x37, 0x65, 0x02, 0x20, 0x13, 0x05, 0xc5,
+    0xed, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93, 0x06, 0x20, 0x0a, 0xef, 0x40, 0x17, 0xb8, 0xfb,
+    0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x39,
+    0xed, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x42, 0xa1, 0xa0, 0x37,
+    0xb5, 0x09, 0x00, 0x93, 0x05, 0x05, 0x4b, 0x28, 0x00, 0x13, 0x06, 0x20, 0x0a, 0xef, 0x80, 0xa6,
+    0xda, 0x37, 0x65, 0x02, 0x20, 0x13, 0x05, 0xc5, 0xed, 0x93, 0x05, 0x20, 0x0a, 0x30, 0x00, 0x93,
+    0x06, 0x20, 0x0a, 0xef, 0x40, 0x97, 0xb3, 0xfb, 0x25, 0x00, 0x81, 0x2a, 0x86, 0x13, 0x35, 0x15,
+    0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5,
+    0x17, 0xb7, 0xb5, 0x00, 0x6d, 0x93, 0x85, 0x25, 0x64, 0xef, 0x60, 0x27, 0xa0, 0x45, 0x61, 0x3c,
+    0x98, 0x00, 0x00, 0xc0, 0x98, 0x37, 0x54, 0x03, 0x20, 0x03, 0x45, 0xc4, 0xd9, 0x8b, 0x18, 0x15,
+    0x01, 0xef, 0xa0, 0xba, 0x84, 0x37, 0x05, 0x03, 0x20, 0x83, 0x45, 0x05, 0x24, 0x8b, 0x91, 0x15,
+    0x01, 0x23, 0x00, 0x05, 0x24, 0x13, 0x06, 0x05, 0x24, 0x37, 0x05, 0x03, 0x20, 0x13, 0x05, 0x05,
+    0x2a, 0x93, 0x05, 0x00, 0x06, 0x93, 0x06, 0x00, 0x06, 0xef, 0x40, 0x37, 0xad, 0xfb, 0x25, 0x00,
+    0x81, 0x2a, 0x86, 0x13, 0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x19, 0xe9, 0x37,
+    0x05, 0x23, 0x00, 0xec, 0x7d
+};
+
+/*
+01 05 fa 13 05 e5 17 b7 b5 03 2d 93 85 25 44 ef 60 c7 99 23 0e 04 d8 37 b5 09 00 23 02 05 70 37
+55 03 20 a3 0e 05 d8 a0 98 00 00 44 99 37 b5 09 00 85 45 23 02 b5 70 08 08 ef c0 aa b4 ef d0 b9
+d4 ef e0 69 86 ef d0 79 cf 37 54 03 20 03 26 44 db b7 54 03 20 03 a5 c4 db 83 25 44 db 63 64 c5
+00 0d 8d 19 a0 33 85 a5 40 93 05 00 10 63 6a b5 02 37 55 03 20 03 25 85 db 03 26 44 db 83 25 44
+db 63 67 a6 00 33 85 a5 40 0b 53 05 3c 11 a8 0d 8d 0b 44 05 3c ef 20 29 83 03 25 44 db 23 ae a4
+da ef d0 79 ef 68 00 ef c0 ca ad 42 45 b2 45 ef c0 0a b2 b7 55 03 20 93 85 85 e0 90 4d 63 73 a6
+00 88 cd b7 55 03 20 03 a6 85 df 32 95 23 ac a5 de 24 99 00 00 00 00 40 99 2e 84 aa 84 ef 30 bc
+c6 03 45 c5 0e 93 05 60 0e 13 06 30 11 2b e6 a5 20 23 90 c4 00 09 45 23 10 a4 00 20 99 00 00 c0
+99 2e 89 aa 84 ef 10 70 2f 93 05 20 1c 13 04 00 14 2b e4 a5 22 ef 30 3c c3 03 45 c5 0e 93 05 60
+0e 2b e4 a5 20 23 90 84 00 0d 45 23 10 a9 00 a0 99 00 00 40 9a 69 c5 2a 84 ef 10 30 2c 83 05 04
+07 aa 89 03 29 c4 2a 13 85 f5 ff 88 91 13 05 f0 0f 8b cd 05 02 83 44 a4 03 ef 30 fc be 03 45 c5
+0e 93 35 15 00 8b 93 04 01 13 06 60 0e 13 05 30 11 09 a8 13 06 20 1c 13 05 00 14 2b 65 36 23 13
+06 60 0e 2b 65 b6 22 83 55 44 27 63 6c b5 02 03 45 14 03 0b 1c 05 01 03 45 04 2a 0b 1a 05 01 03
+45 14 2a 05 e1 03 25 44 08 ab 05 a5 be 2b b5 a5 be 95 65 93 85 65 55 23 20 04 0a 63 64 b5 00 23
+22 04 08 03 45 c4 07 0b 19 05 01 09 45 23 0e a4 06 23 20 04 08 23 22 04 08 13 05 44 23 93 05 40
+03 93 06 40 03 01 46 ef 40 d7 ee 63 0a 09 00 03 45 39 00 0b 13 05 05 23 20 04 08 23 22 04 08 20
+9a 00 00 c0 9a 32 8a 2e 89 aa 84 ef 10 10 1f 13 04 40 15 93 09 a0 0f 0b 87 04 03 93 05 40 1f 13
+04 e0 15 2b e4 a5 22 ef 30 1c b2 03 45 c5 0e 2b e4 a9 20 23 10 8a 00 0b 16 09 01 ef 30 dc b0 03
+45 c5 0e 93 05 b0 12 ab e5 a9 20 23 10 ba 00 a0 9a 00 00 40 9a 49 c5 ae 89 2a 84 ef 10 10 1a 93
+05 20 1c 03 29 44 02 93 04 00 14 ab e4 a5 22 a3 0c 34 03 ef 30 5c ad 03 45 c5 0e 93 05 60 0e ab
+e4 a5 20 63 77 99 02 09 45 a3 08 a4 02 8b 59 09 fb 93 05 04 03 11 45 a3 08 a4 02 8b 81 19 02 0b
+93 09 01 2e 85 ca 85 ef 10 5a fb ef 50 d9 c5 25 a0 22 1c ef 50 59 c5 64 9d 93 85 e9 ff b3 35 b0
+00 4d 8d 11 e9 03 45 14 03 0b 02 05 04 8b 12 05 02 05 05 a3 08 a4 02 ef 10 19 fe 11 c1 22 1c 20
+9a 22 85 4a 86 ef 10 7a f8 e9 b7 00 00 00 00 aa 86 03 05 05 07 7d 15 08 93 2e 85 8b 52 07 02 b2
+85 6f 10 ea e1 83 c5 a6 03 8b 92 05 01 b2 85 6f 10 4a e2 b2 85 6f 10 2a e3 00 00 40 9a b6 84 b2
+89 2e 89 2a 84 ef 50 f9 bb 4d c1 8b 9b 04 01 0b 47 24 03 ef 70 19 9d 7b 06 2f 2e 93 05 c0 12 0b
+05 06 01 13 45 c5 2b 13 06 40 06 93 05 80 0c ab 65 a6 20 23 10 b9 00 20 9a ef 70 b9 9a 13 05 45
+d4 33 35 a0 00 93 35 34 00 4d 8d 11 e5 8b 11 14 03 13 05 00 05 89 a0 ef 70 d9 98 13 45 65 22 93
+45 34 00 4d 8d 1d e9 83 d5 a9 00 13 06 20 12 09 45 63 65 b6 00 05 45 0b c4 05 f1 83 55 09 00 33
+d5 a5 00 23 10 a9 00 ef 10 50 05 01 c9 13 05 00 14 19 a0 13 05 00 0a 23 10 a9 00 7b 05 2f 2e 0b
+13 05 01 13 05 00 14 23 10 a9 00 20 9a 00 00 c0 99 01 44 37 35 09 00 13 09 05 a7 37 86 02 40 b7
+84 02 40 03 25 09 00 5b a2 a4 c0 db 26 49 80 01 45 a2 85 ef 50 0a a9 05 04 26 86 0b 1a f4 46 37
+85 02 40 18 99
+*/
+const char g_cfg_cmd5[] = {
+    0x01, 0x05, 0xfa, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x03, 0x2d, 0x93, 0x85, 0x25, 0x44, 0xef,
+    0x60, 0xc7, 0x99, 0x23, 0x0e, 0x04, 0xd8, 0x37, 0xb5, 0x09, 0x00, 0x23, 0x02, 0x05, 0x70, 0x37,
+    0x55, 0x03, 0x20, 0xa3, 0x0e, 0x05, 0xd8, 0xa0, 0x98, 0x00, 0x00, 0x44, 0x99, 0x37, 0xb5, 0x09,
+    0x00, 0x85, 0x45, 0x23, 0x02, 0xb5, 0x70, 0x08, 0x08, 0xef, 0xc0, 0xaa, 0xb4, 0xef, 0xd0, 0xb9,
+    0xd4, 0xef, 0xe0, 0x69, 0x86, 0xef, 0xd0, 0x79, 0xcf, 0x37, 0x54, 0x03, 0x20, 0x03, 0x26, 0x44,
+    0xdb, 0xb7, 0x54, 0x03, 0x20, 0x03, 0xa5, 0xc4, 0xdb, 0x83, 0x25, 0x44, 0xdb, 0x63, 0x64, 0xc5,
+    0x00, 0x0d, 0x8d, 0x19, 0xa0, 0x33, 0x85, 0xa5, 0x40, 0x93, 0x05, 0x00, 0x10, 0x63, 0x6a, 0xb5,
+    0x02, 0x37, 0x55, 0x03, 0x20, 0x03, 0x25, 0x85, 0xdb, 0x03, 0x26, 0x44, 0xdb, 0x83, 0x25, 0x44,
+    0xdb, 0x63, 0x67, 0xa6, 0x00, 0x33, 0x85, 0xa5, 0x40, 0x0b, 0x53, 0x05, 0x3c, 0x11, 0xa8, 0x0d,
+    0x8d, 0x0b, 0x44, 0x05, 0x3c, 0xef, 0x20, 0x29, 0x83, 0x03, 0x25, 0x44, 0xdb, 0x23, 0xae, 0xa4,
+    0xda, 0xef, 0xd0, 0x79, 0xef, 0x68, 0x00, 0xef, 0xc0, 0xca, 0xad, 0x42, 0x45, 0xb2, 0x45, 0xef,
+    0xc0, 0x0a, 0xb2, 0xb7, 0x55, 0x03, 0x20, 0x93, 0x85, 0x85, 0xe0, 0x90, 0x4d, 0x63, 0x73, 0xa6,
+    0x00, 0x88, 0xcd, 0xb7, 0x55, 0x03, 0x20, 0x03, 0xa6, 0x85, 0xdf, 0x32, 0x95, 0x23, 0xac, 0xa5,
+    0xde, 0x24, 0x99, 0x00, 0x00, 0x00, 0x00, 0x40, 0x99, 0x2e, 0x84, 0xaa, 0x84, 0xef, 0x30, 0xbc,
+    0xc6, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x05, 0x60, 0x0e, 0x13, 0x06, 0x30, 0x11, 0x2b, 0xe6, 0xa5,
+    0x20, 0x23, 0x90, 0xc4, 0x00, 0x09, 0x45, 0x23, 0x10, 0xa4, 0x00, 0x20, 0x99, 0x00, 0x00, 0xc0,
+    0x99, 0x2e, 0x89, 0xaa, 0x84, 0xef, 0x10, 0x70, 0x2f, 0x93, 0x05, 0x20, 0x1c, 0x13, 0x04, 0x00,
+    0x14, 0x2b, 0xe4, 0xa5, 0x22, 0xef, 0x30, 0x3c, 0xc3, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x05, 0x60,
+    0x0e, 0x2b, 0xe4, 0xa5, 0x20, 0x23, 0x90, 0x84, 0x00, 0x0d, 0x45, 0x23, 0x10, 0xa9, 0x00, 0xa0,
+    0x99, 0x00, 0x00, 0x40, 0x9a, 0x69, 0xc5, 0x2a, 0x84, 0xef, 0x10, 0x30, 0x2c, 0x83, 0x05, 0x04,
+    0x07, 0xaa, 0x89, 0x03, 0x29, 0xc4, 0x2a, 0x13, 0x85, 0xf5, 0xff, 0x88, 0x91, 0x13, 0x05, 0xf0,
+    0x0f, 0x8b, 0xcd, 0x05, 0x02, 0x83, 0x44, 0xa4, 0x03, 0xef, 0x30, 0xfc, 0xbe, 0x03, 0x45, 0xc5,
+    0x0e, 0x93, 0x35, 0x15, 0x00, 0x8b, 0x93, 0x04, 0x01, 0x13, 0x06, 0x60, 0x0e, 0x13, 0x05, 0x30,
+    0x11, 0x09, 0xa8, 0x13, 0x06, 0x20, 0x1c, 0x13, 0x05, 0x00, 0x14, 0x2b, 0x65, 0x36, 0x23, 0x13,
+    0x06, 0x60, 0x0e, 0x2b, 0x65, 0xb6, 0x22, 0x83, 0x55, 0x44, 0x27, 0x63, 0x6c, 0xb5, 0x02, 0x03,
+    0x45, 0x14, 0x03, 0x0b, 0x1c, 0x05, 0x01, 0x03, 0x45, 0x04, 0x2a, 0x0b, 0x1a, 0x05, 0x01, 0x03,
+    0x45, 0x14, 0x2a, 0x05, 0xe1, 0x03, 0x25, 0x44, 0x08, 0xab, 0x05, 0xa5, 0xbe, 0x2b, 0xb5, 0xa5,
+    0xbe, 0x95, 0x65, 0x93, 0x85, 0x65, 0x55, 0x23, 0x20, 0x04, 0x0a, 0x63, 0x64, 0xb5, 0x00, 0x23,
+    0x22, 0x04, 0x08, 0x03, 0x45, 0xc4, 0x07, 0x0b, 0x19, 0x05, 0x01, 0x09, 0x45, 0x23, 0x0e, 0xa4,
+    0x06, 0x23, 0x20, 0x04, 0x08, 0x23, 0x22, 0x04, 0x08, 0x13, 0x05, 0x44, 0x23, 0x93, 0x05, 0x40,
+    0x03, 0x93, 0x06, 0x40, 0x03, 0x01, 0x46, 0xef, 0x40, 0xd7, 0xee, 0x63, 0x0a, 0x09, 0x00, 0x03,
+    0x45, 0x39, 0x00, 0x0b, 0x13, 0x05, 0x05, 0x23, 0x20, 0x04, 0x08, 0x23, 0x22, 0x04, 0x08, 0x20,
+    0x9a, 0x00, 0x00, 0xc0, 0x9a, 0x32, 0x8a, 0x2e, 0x89, 0xaa, 0x84, 0xef, 0x10, 0x10, 0x1f, 0x13,
+    0x04, 0x40, 0x15, 0x93, 0x09, 0xa0, 0x0f, 0x0b, 0x87, 0x04, 0x03, 0x93, 0x05, 0x40, 0x1f, 0x13,
+    0x04, 0xe0, 0x15, 0x2b, 0xe4, 0xa5, 0x22, 0xef, 0x30, 0x1c, 0xb2, 0x03, 0x45, 0xc5, 0x0e, 0x2b,
+    0xe4, 0xa9, 0x20, 0x23, 0x10, 0x8a, 0x00, 0x0b, 0x16, 0x09, 0x01, 0xef, 0x30, 0xdc, 0xb0, 0x03,
+    0x45, 0xc5, 0x0e, 0x93, 0x05, 0xb0, 0x12, 0xab, 0xe5, 0xa9, 0x20, 0x23, 0x10, 0xba, 0x00, 0xa0,
+    0x9a, 0x00, 0x00, 0x40, 0x9a, 0x49, 0xc5, 0xae, 0x89, 0x2a, 0x84, 0xef, 0x10, 0x10, 0x1a, 0x93,
+    0x05, 0x20, 0x1c, 0x03, 0x29, 0x44, 0x02, 0x93, 0x04, 0x00, 0x14, 0xab, 0xe4, 0xa5, 0x22, 0xa3,
+    0x0c, 0x34, 0x03, 0xef, 0x30, 0x5c, 0xad, 0x03, 0x45, 0xc5, 0x0e, 0x93, 0x05, 0x60, 0x0e, 0xab,
+    0xe4, 0xa5, 0x20, 0x63, 0x77, 0x99, 0x02, 0x09, 0x45, 0xa3, 0x08, 0xa4, 0x02, 0x8b, 0x59, 0x09,
+    0xfb, 0x93, 0x05, 0x04, 0x03, 0x11, 0x45, 0xa3, 0x08, 0xa4, 0x02, 0x8b, 0x81, 0x19, 0x02, 0x0b,
+    0x93, 0x09, 0x01, 0x2e, 0x85, 0xca, 0x85, 0xef, 0x10, 0x5a, 0xfb, 0xef, 0x50, 0xd9, 0xc5, 0x25,
+    0xa0, 0x22, 0x1c, 0xef, 0x50, 0x59, 0xc5, 0x64, 0x9d, 0x93, 0x85, 0xe9, 0xff, 0xb3, 0x35, 0xb0,
+    0x00, 0x4d, 0x8d, 0x11, 0xe9, 0x03, 0x45, 0x14, 0x03, 0x0b, 0x02, 0x05, 0x04, 0x8b, 0x12, 0x05,
+    0x02, 0x05, 0x05, 0xa3, 0x08, 0xa4, 0x02, 0xef, 0x10, 0x19, 0xfe, 0x11, 0xc1, 0x22, 0x1c, 0x20,
+    0x9a, 0x22, 0x85, 0x4a, 0x86, 0xef, 0x10, 0x7a, 0xf8, 0xe9, 0xb7, 0x00, 0x00, 0x00, 0x00, 0xaa,
+    0x86, 0x03, 0x05, 0x05, 0x07, 0x7d, 0x15, 0x08, 0x93, 0x2e, 0x85, 0x8b, 0x52, 0x07, 0x02, 0xb2,
+    0x85, 0x6f, 0x10, 0xea, 0xe1, 0x83, 0xc5, 0xa6, 0x03, 0x8b, 0x92, 0x05, 0x01, 0xb2, 0x85, 0x6f,
+    0x10, 0x4a, 0xe2, 0xb2, 0x85, 0x6f, 0x10, 0x2a, 0xe3, 0x00, 0x00, 0x40, 0x9a, 0xb6, 0x84, 0xb2,
+    0x89, 0x2e, 0x89, 0x2a, 0x84, 0xef, 0x50, 0xf9, 0xbb, 0x4d, 0xc1, 0x8b, 0x9b, 0x04, 0x01, 0x0b,
+    0x47, 0x24, 0x03, 0xef, 0x70, 0x19, 0x9d, 0x7b, 0x06, 0x2f, 0x2e, 0x93, 0x05, 0xc0, 0x12, 0x0b,
+    0x05, 0x06, 0x01, 0x13, 0x45, 0xc5, 0x2b, 0x13, 0x06, 0x40, 0x06, 0x93, 0x05, 0x80, 0x0c, 0xab,
+    0x65, 0xa6, 0x20, 0x23, 0x10, 0xb9, 0x00, 0x20, 0x9a, 0xef, 0x70, 0xb9, 0x9a, 0x13, 0x05, 0x45,
+    0xd4, 0x33, 0x35, 0xa0, 0x00, 0x93, 0x35, 0x34, 0x00, 0x4d, 0x8d, 0x11, 0xe5, 0x8b, 0x11, 0x14,
+    0x03, 0x13, 0x05, 0x00, 0x05, 0x89, 0xa0, 0xef, 0x70, 0xd9, 0x98, 0x13, 0x45, 0x65, 0x22, 0x93,
+    0x45, 0x34, 0x00, 0x4d, 0x8d, 0x1d, 0xe9, 0x83, 0xd5, 0xa9, 0x00, 0x13, 0x06, 0x20, 0x12, 0x09,
+    0x45, 0x63, 0x65, 0xb6, 0x00, 0x05, 0x45, 0x0b, 0xc4, 0x05, 0xf1, 0x83, 0x55, 0x09, 0x00, 0x33,
+    0xd5, 0xa5, 0x00, 0x23, 0x10, 0xa9, 0x00, 0xef, 0x10, 0x50, 0x05, 0x01, 0xc9, 0x13, 0x05, 0x00,
+    0x14, 0x19, 0xa0, 0x13, 0x05, 0x00, 0x0a, 0x23, 0x10, 0xa9, 0x00, 0x7b, 0x05, 0x2f, 0x2e, 0x0b,
+    0x13, 0x05, 0x01, 0x13, 0x05, 0x00, 0x14, 0x23, 0x10, 0xa9, 0x00, 0x20, 0x9a, 0x00, 0x00, 0xc0,
+    0x99, 0x01, 0x44, 0x37, 0x35, 0x09, 0x00, 0x13, 0x09, 0x05, 0xa7, 0x37, 0x86, 0x02, 0x40, 0xb7,
+    0x84, 0x02, 0x40, 0x03, 0x25, 0x09, 0x00, 0x5b, 0xa2, 0xa4, 0xc0, 0xdb, 0x26, 0x49, 0x80, 0x01,
+    0x45, 0xa2, 0x85, 0xef, 0x50, 0x0a, 0xa9, 0x05, 0x04, 0x26, 0x86, 0x0b, 0x1a, 0xf4, 0x46, 0x37,
+    0x85, 0x02, 0x40, 0x18, 0x99
+};
+
+/*
+01 06 f9 93 05 10 10 23 28 b5 0e 85 65 93 85 a5 a0 23 2a b5 0e a0 99 00 00 00 00 c0 98 2a 84 03
+45 65 00 8b 1e 05 02 03 47 44 00 a3 01 e4 00 10 5c 54 5c 7b 25 00 81 10 d8 54 d8 72 1c 7a 1c 0b
+47 05 04 fb 27 09 f6 37 05 23 00 13 05 e5 17 b7 b5 01 25 93 85 25 4c ef 50 97 e6 0e 10 a0 98 00
+00 00 00 03 47 45 00 a3 01 e5 00 10 5d 54 5d fb 25 00 81 10 d9 54 d9 72 1d 7a 1d 0b c7 05 03 fb
+27 09 f6 37 05 23 00 13 05 e5 17 b7 b5 01 34 93 85 25 4c 6f 50 d7 e2 82 80 00 00 c0 99 37 05 00
+04 b7 45 10 40 ec 55 37 16 03 20 13 04 06 b1 50 54 13 09 f5 ff 2b e5 05 74 48 d0 b3 24 c5 00 22
+85 a9 3f 03 45 64 00 0b 16 05 01 03 45 54 00 13 35 15 00 65 8d 93 15 15 00 a9 8c 23 03 b4 00 48
+50 2a 10 48 d4 37 86 12 40 03 25 06 0b 83 25 46 0b 03 26 c6 0b 69 82 b3 e6 a5 00 b3 f6 26 01 23
+02 c4 00 99 c6 b3 f5 25 01 33 75 25 01 08 dc 4c dc 81 c4 22 85 80 99 b1 b7 a0 99 00 00 00 00 40
+98 22 a0 53 15 05 c2 53 00 05 d2 53 74 05 0a ef 30 8e b0 31 c1 ef 30 2e b0 13 45 45 00 93 05 40
+06 13 06 80 0c 2b e6 a5 20 37 b5 09 00 07 30 85 5a 53 15 04 c2 d3 00 05 d2 d3 70 14 0a d3 f0 00
+12 53 95 00 c2 b3 65 c5 02 0d 8d 53 01 05 d2 d3 f0 20 0a 53 f4 00 1a ef f0 5d d5 37 b5 09 00 07
+30 85 55 53 15 85 a2 43 70 05 42 2b 64 a0 3a 53 05 84 22 02 24 20 98 00 00 00 00 6f d0 8a ea 00
+00 00 00 cc 9a 22 b8 26 b4 36 89 32 84 53 84 b5 22 ae 89 d3 04 a5 22 aa 84 ef e0 ea b0 2a 8a 03
+55 05 0d 69 c1 13 06 84 07 93 06 94 07 a4 91 0d 45 ef d0 eb e6 02 d2 02 d0 08 10 53 85 94 22 ef
+e0 9e e5 26 85 ef 30 ec f6 02 35 8b 13 05 01 52 85 a2 85 ef e0 da a4 29 a0 52 85 a2 85 ef e0 ba
+9c 07 30 84 01 82 30 53 f0 00 0a 02 b0 53 05 84 22 22 85 ce 85 4a 86 ef 00 0b 94 13 05 84 03 13
+06 c4 02 93 06 84 02 ce 85 ef 80 fe a6 08 a0 ef a0 0c f8 48 74 0c 74 02 36 53 05 05 42 d3 85 05
+42 ce 85 ef 80 4e f6 53 04 a5 22 0a 85 93 05 00 02 93 06 00 02 01 46 ef 40 d7 a7 8a 85 4e 85 ef
+50 1b c0 08 74 c2 25 53 05 05 42 ef 80 5e 9b d3 05 a5 22 37 b5 09 00 07 36 05 56 22 85 53 05 84
+22 ef 00 2b 8a a2 34 42 34 ac 9a 00 00 00 00 d0 99 37 b5 09 00 93 05 85 56 13 05 51 02 6d 46 13
+04 51 02 ef 70 56 e7 37 b5 09 00 93 05 35 58 13 05 a1 00 6d 46 93 04 a1 00 ef 70 f6 e5 ef 30 bc
+97 ab 64 a4 20 37 b5 00 20 13 04 05 f2 93 05 40 02 93 06 40 02 13 09 40 02 22 85 01 46 ef 40 77
+9f 26 85 ef 80 46 b9 aa 86 93 05 40 02 22 85 26 86 ef 40 a7 bc 19 cd 7b 25 00 81 41 cd 37 05 23
+00 13 05 e5 17 b7 b5 01 38 93 85 25 34 ef 50 b7 a4 b0 99 26 85 ef 80 26 b6 aa 84 8b 28 05 1f 7b
+25 00 81 25 c9 37 05 23 00 13 05 e5 17 b7 b5 01 3d 93 85 25 34 26 86 ef 50 57 a7 b0 99 ef 80 67
+a4 aa 86 33 85 84 00 b3 05 99 40 37 b6 09 00 13 06 e6 59 ef 10 57 b3 0b 22 05 00 aa 94 31 a8 7b
+25 00 81 19 c9 37 05 23 00 13 05 e5 17 b7 b5 01 44 93 85 25 34 ef 50 37 9e 13 06 40 02 22 85 a6
+85 ef 70 7e 87 93 85 34 00 13 06 40 02 22 85 ef 70 1e 8f b0 99 00 00 c0 98 ef 20 fe ef 3d c1 2a
+84 37 b5 00 20 03 15 85 6a 85 65 95 05 23 10 b4 00 93 05 85 00 23 13 b4 00 13 05 84 00 ac 91 ef
+f0 dd ae 23 11 a4 00 ef f0 9d 91 fb 25 00 81 23 12 a4 00 0b c8 05 03 03 56 64 00 83 56 24 00 37
+05 23 00 13 05 e5 17 b7 b5 00 25 93 85 25 4c ef 50 57 a1 03 55 64 00 93 05 85 00 22 85 80 98 6f
+f0 dd 96 9f 1f
+*/
+const char g_cfg_cmd6[] = {
+    0x01, 0x06, 0xf9, 0x93, 0x05, 0x10, 0x10, 0x23, 0x28, 0xb5, 0x0e, 0x85, 0x65, 0x93, 0x85, 0xa5,
+    0xa0, 0x23, 0x2a, 0xb5, 0x0e, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0x03,
+    0x45, 0x65, 0x00, 0x8b, 0x1e, 0x05, 0x02, 0x03, 0x47, 0x44, 0x00, 0xa3, 0x01, 0xe4, 0x00, 0x10,
+    0x5c, 0x54, 0x5c, 0x7b, 0x25, 0x00, 0x81, 0x10, 0xd8, 0x54, 0xd8, 0x72, 0x1c, 0x7a, 0x1c, 0x0b,
+    0x47, 0x05, 0x04, 0xfb, 0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7,
+    0xb5, 0x01, 0x25, 0x93, 0x85, 0x25, 0x4c, 0xef, 0x50, 0x97, 0xe6, 0x0e, 0x10, 0xa0, 0x98, 0x00,
+    0x00, 0x00, 0x00, 0x03, 0x47, 0x45, 0x00, 0xa3, 0x01, 0xe5, 0x00, 0x10, 0x5d, 0x54, 0x5d, 0xfb,
+    0x25, 0x00, 0x81, 0x10, 0xd9, 0x54, 0xd9, 0x72, 0x1d, 0x7a, 0x1d, 0x0b, 0xc7, 0x05, 0x03, 0xfb,
+    0x27, 0x09, 0xf6, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x34, 0x93,
+    0x85, 0x25, 0x4c, 0x6f, 0x50, 0xd7, 0xe2, 0x82, 0x80, 0x00, 0x00, 0xc0, 0x99, 0x37, 0x05, 0x00,
+    0x04, 0xb7, 0x45, 0x10, 0x40, 0xec, 0x55, 0x37, 0x16, 0x03, 0x20, 0x13, 0x04, 0x06, 0xb1, 0x50,
+    0x54, 0x13, 0x09, 0xf5, 0xff, 0x2b, 0xe5, 0x05, 0x74, 0x48, 0xd0, 0xb3, 0x24, 0xc5, 0x00, 0x22,
+    0x85, 0xa9, 0x3f, 0x03, 0x45, 0x64, 0x00, 0x0b, 0x16, 0x05, 0x01, 0x03, 0x45, 0x54, 0x00, 0x13,
+    0x35, 0x15, 0x00, 0x65, 0x8d, 0x93, 0x15, 0x15, 0x00, 0xa9, 0x8c, 0x23, 0x03, 0xb4, 0x00, 0x48,
+    0x50, 0x2a, 0x10, 0x48, 0xd4, 0x37, 0x86, 0x12, 0x40, 0x03, 0x25, 0x06, 0x0b, 0x83, 0x25, 0x46,
+    0x0b, 0x03, 0x26, 0xc6, 0x0b, 0x69, 0x82, 0xb3, 0xe6, 0xa5, 0x00, 0xb3, 0xf6, 0x26, 0x01, 0x23,
+    0x02, 0xc4, 0x00, 0x99, 0xc6, 0xb3, 0xf5, 0x25, 0x01, 0x33, 0x75, 0x25, 0x01, 0x08, 0xdc, 0x4c,
+    0xdc, 0x81, 0xc4, 0x22, 0x85, 0x80, 0x99, 0xb1, 0xb7, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0x40,
+    0x98, 0x22, 0xa0, 0x53, 0x15, 0x05, 0xc2, 0x53, 0x00, 0x05, 0xd2, 0x53, 0x74, 0x05, 0x0a, 0xef,
+    0x30, 0x8e, 0xb0, 0x31, 0xc1, 0xef, 0x30, 0x2e, 0xb0, 0x13, 0x45, 0x45, 0x00, 0x93, 0x05, 0x40,
+    0x06, 0x13, 0x06, 0x80, 0x0c, 0x2b, 0xe6, 0xa5, 0x20, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85,
+    0x5a, 0x53, 0x15, 0x04, 0xc2, 0xd3, 0x00, 0x05, 0xd2, 0xd3, 0x70, 0x14, 0x0a, 0xd3, 0xf0, 0x00,
+    0x12, 0x53, 0x95, 0x00, 0xc2, 0xb3, 0x65, 0xc5, 0x02, 0x0d, 0x8d, 0x53, 0x01, 0x05, 0xd2, 0xd3,
+    0xf0, 0x20, 0x0a, 0x53, 0xf4, 0x00, 0x1a, 0xef, 0xf0, 0x5d, 0xd5, 0x37, 0xb5, 0x09, 0x00, 0x07,
+    0x30, 0x85, 0x55, 0x53, 0x15, 0x85, 0xa2, 0x43, 0x70, 0x05, 0x42, 0x2b, 0x64, 0xa0, 0x3a, 0x53,
+    0x05, 0x84, 0x22, 0x02, 0x24, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xd0, 0x8a, 0xea, 0x00,
+    0x00, 0x00, 0x00, 0xcc, 0x9a, 0x22, 0xb8, 0x26, 0xb4, 0x36, 0x89, 0x32, 0x84, 0x53, 0x84, 0xb5,
+    0x22, 0xae, 0x89, 0xd3, 0x04, 0xa5, 0x22, 0xaa, 0x84, 0xef, 0xe0, 0xea, 0xb0, 0x2a, 0x8a, 0x03,
+    0x55, 0x05, 0x0d, 0x69, 0xc1, 0x13, 0x06, 0x84, 0x07, 0x93, 0x06, 0x94, 0x07, 0xa4, 0x91, 0x0d,
+    0x45, 0xef, 0xd0, 0xeb, 0xe6, 0x02, 0xd2, 0x02, 0xd0, 0x08, 0x10, 0x53, 0x85, 0x94, 0x22, 0xef,
+    0xe0, 0x9e, 0xe5, 0x26, 0x85, 0xef, 0x30, 0xec, 0xf6, 0x02, 0x35, 0x8b, 0x13, 0x05, 0x01, 0x52,
+    0x85, 0xa2, 0x85, 0xef, 0xe0, 0xda, 0xa4, 0x29, 0xa0, 0x52, 0x85, 0xa2, 0x85, 0xef, 0xe0, 0xba,
+    0x9c, 0x07, 0x30, 0x84, 0x01, 0x82, 0x30, 0x53, 0xf0, 0x00, 0x0a, 0x02, 0xb0, 0x53, 0x05, 0x84,
+    0x22, 0x22, 0x85, 0xce, 0x85, 0x4a, 0x86, 0xef, 0x00, 0x0b, 0x94, 0x13, 0x05, 0x84, 0x03, 0x13,
+    0x06, 0xc4, 0x02, 0x93, 0x06, 0x84, 0x02, 0xce, 0x85, 0xef, 0x80, 0xfe, 0xa6, 0x08, 0xa0, 0xef,
+    0xa0, 0x0c, 0xf8, 0x48, 0x74, 0x0c, 0x74, 0x02, 0x36, 0x53, 0x05, 0x05, 0x42, 0xd3, 0x85, 0x05,
+    0x42, 0xce, 0x85, 0xef, 0x80, 0x4e, 0xf6, 0x53, 0x04, 0xa5, 0x22, 0x0a, 0x85, 0x93, 0x05, 0x00,
+    0x02, 0x93, 0x06, 0x00, 0x02, 0x01, 0x46, 0xef, 0x40, 0xd7, 0xa7, 0x8a, 0x85, 0x4e, 0x85, 0xef,
+    0x50, 0x1b, 0xc0, 0x08, 0x74, 0xc2, 0x25, 0x53, 0x05, 0x05, 0x42, 0xef, 0x80, 0x5e, 0x9b, 0xd3,
+    0x05, 0xa5, 0x22, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x36, 0x05, 0x56, 0x22, 0x85, 0x53, 0x05, 0x84,
+    0x22, 0xef, 0x00, 0x2b, 0x8a, 0xa2, 0x34, 0x42, 0x34, 0xac, 0x9a, 0x00, 0x00, 0x00, 0x00, 0xd0,
+    0x99, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0x85, 0x56, 0x13, 0x05, 0x51, 0x02, 0x6d, 0x46, 0x13,
+    0x04, 0x51, 0x02, 0xef, 0x70, 0x56, 0xe7, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x05, 0x35, 0x58, 0x13,
+    0x05, 0xa1, 0x00, 0x6d, 0x46, 0x93, 0x04, 0xa1, 0x00, 0xef, 0x70, 0xf6, 0xe5, 0xef, 0x30, 0xbc,
+    0x97, 0xab, 0x64, 0xa4, 0x20, 0x37, 0xb5, 0x00, 0x20, 0x13, 0x04, 0x05, 0xf2, 0x93, 0x05, 0x40,
+    0x02, 0x93, 0x06, 0x40, 0x02, 0x13, 0x09, 0x40, 0x02, 0x22, 0x85, 0x01, 0x46, 0xef, 0x40, 0x77,
+    0x9f, 0x26, 0x85, 0xef, 0x80, 0x46, 0xb9, 0xaa, 0x86, 0x93, 0x05, 0x40, 0x02, 0x22, 0x85, 0x26,
+    0x86, 0xef, 0x40, 0xa7, 0xbc, 0x19, 0xcd, 0x7b, 0x25, 0x00, 0x81, 0x41, 0xcd, 0x37, 0x05, 0x23,
+    0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01, 0x38, 0x93, 0x85, 0x25, 0x34, 0xef, 0x50, 0xb7,
+    0xa4, 0xb0, 0x99, 0x26, 0x85, 0xef, 0x80, 0x26, 0xb6, 0xaa, 0x84, 0x8b, 0x28, 0x05, 0x1f, 0x7b,
+    0x25, 0x00, 0x81, 0x25, 0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01,
+    0x3d, 0x93, 0x85, 0x25, 0x34, 0x26, 0x86, 0xef, 0x50, 0x57, 0xa7, 0xb0, 0x99, 0xef, 0x80, 0x67,
+    0xa4, 0xaa, 0x86, 0x33, 0x85, 0x84, 0x00, 0xb3, 0x05, 0x99, 0x40, 0x37, 0xb6, 0x09, 0x00, 0x13,
+    0x06, 0xe6, 0x59, 0xef, 0x10, 0x57, 0xb3, 0x0b, 0x22, 0x05, 0x00, 0xaa, 0x94, 0x31, 0xa8, 0x7b,
+    0x25, 0x00, 0x81, 0x19, 0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x01,
+    0x44, 0x93, 0x85, 0x25, 0x34, 0xef, 0x50, 0x37, 0x9e, 0x13, 0x06, 0x40, 0x02, 0x22, 0x85, 0xa6,
+    0x85, 0xef, 0x70, 0x7e, 0x87, 0x93, 0x85, 0x34, 0x00, 0x13, 0x06, 0x40, 0x02, 0x22, 0x85, 0xef,
+    0x70, 0x1e, 0x8f, 0xb0, 0x99, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x20, 0xfe, 0xef, 0x3d, 0xc1, 0x2a,
+    0x84, 0x37, 0xb5, 0x00, 0x20, 0x03, 0x15, 0x85, 0x6a, 0x85, 0x65, 0x95, 0x05, 0x23, 0x10, 0xb4,
+    0x00, 0x93, 0x05, 0x85, 0x00, 0x23, 0x13, 0xb4, 0x00, 0x13, 0x05, 0x84, 0x00, 0xac, 0x91, 0xef,
+    0xf0, 0xdd, 0xae, 0x23, 0x11, 0xa4, 0x00, 0xef, 0xf0, 0x9d, 0x91, 0xfb, 0x25, 0x00, 0x81, 0x23,
+    0x12, 0xa4, 0x00, 0x0b, 0xc8, 0x05, 0x03, 0x03, 0x56, 0x64, 0x00, 0x83, 0x56, 0x24, 0x00, 0x37,
+    0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x00, 0x25, 0x93, 0x85, 0x25, 0x4c, 0xef,
+    0x50, 0x57, 0xa1, 0x03, 0x55, 0x64, 0x00, 0x93, 0x05, 0x85, 0x00, 0x22, 0x85, 0x80, 0x98, 0x6f,
+    0xf0, 0xdd, 0x96, 0x9f, 0x1f
+};
+
+/*
+01 07 f8 a0 98 00 00 40 98 0b 94 15 01 2a 86 13 05 b1 00 85 45 85 46 ef 40 47 aa 03 46 b1 00 8b
+1f 06 01 37 55 00 20 13 05 85 88 0c 51 48 51 fb 26 00 81 37 b7 09 00 23 26 a7 70 23 24 b7 70 0b
+c6 06 03 37 05 23 00 13 05 e5 17 b7 b5 02 30 93 85 25 5c ef 50 97 95 20 98 85 45 39 a8 7b 25 00
+81 19 c9 37 05 23 00 13 05 e5 17 b7 b5 02 2b 93 85 25 54 ef 50 97 93 89 45 7b 6e b5 6c 20 98 00
+00 00 00 c0 98 2a 84 ef 70 4b cd aa 85 05 45 85 c5 0b 54 04 0a 85 45 b3 95 85 00 93 f5 85 23 81
+ed fd 75 fd 15 a2 95 8b d4 05 09 05 46 b3 15 b6 00 93 f5 15 14 91 c1 a0 98 01 45 a0 98 00 00 c0
+98 8b 9f 05 02 2a 86 0a 85 89 45 89 46 09 44 ef 40 c7 9e 03 46 01 00 0b 4c 06 02 7b 25 00 81 09
+cd 83 46 11 00 37 05 23 00 13 05 e5 17 b7 b5 02 4b 93 85 25 54 ef 50 f7 90 7b 6e 85 6c a0 98 85
+45 7b 6e b5 6c a0 98 ef 30 0c c4 2a 84 83 45 01 00 03 25 45 11 2c c8 0b 97 05 01 13 65 05 04 23
+2a a4 10 ef 30 4c f1 13 35 15 00 05 05 23 0a a4 04 29 a0 13 75 f5 fb 23 2a a4 10 7b 25 00 81 0b
+48 05 03 03 46 01 00 83 46 11 00 37 05 23 00 13 05 e5 17 b7 b5 02 5a 93 85 25 5c ef 50 97 8a a0
+98 00 00 4c 98 0b 92 25 1c 2a 86 08 10 f1 45 f1 46 ef 40 a7 94 83 46 01 02 37 b5 09 00 83 05 15
+6d 36 86 2b e6 d5 20 a3 08 c5 6c 03 47 11 02 83 47 21 02 7b 25 00 81 b7 b5 09 00 23 88 e5 70 93
+85 05 71 a3 80 f5 00 0b 41 15 03 03 48 31 02 83 58 41 02 83 52 61 02 03 53 81 02 83 53 a1 02 32
+5e 42 55 d2 55 62 56 32 cc 2e ca 2a c8 72 c6 1e c4 1a c2 37 05 23 00 13 05 e5 17 b7 b5 02 73 93
+85 25 5c 31 46 16 c0 ef 50 d7 93 2c 98 85 45 7b 6e b5 6c 2c 98 00 00 40 98 22 a0 33 c8 b6 00 b3
+38 c5 00 33 b7 d5 00 2b e7 08 21 33 38 a6 00 b3 87 b6 40 b3 87 07 41 33 08 a6 40 95 8d b3 85 15
+41 11 8d ab e5 e7 22 2b 65 e8 22 41 81 2b 26 b5 20 93 d6 05 01 33 35 c0 00 2b 05 b5 60 e8 8d 70
+8d 2b 65 e6 22 ab e5 e6 22 ef d0 a6 bf 37 b5 09 00 07 30 85 5a 53 74 05 12 ef 50 eb e5 ef d0 66
+be 53 75 a4 1a 02 24 20 98 00 00 c0 98 ef 10 6e d4 2a 84 ef 50 5e c4 37 b6 09 00 83 25 c6 70 03
+27 86 70 33 66 b7 00 01 ca 74 49 30 49 3a 85 a5 37 53 15 15 c2 11 a0 01 45 08 c0 ef b0 4e d5 23
+02 a4 00 ef 50 4e bc b7 c5 04 20 93 85 85 f6 07 b0 05 73 53 75 10 40 53 06 05 e0 a3 28 c4 00 07
+b0 05 14 53 75 10 40 53 06 05 e0 a3 26 c4 00 03 a6 85 71 83 a5 05 1d 23 03 a4 00 a3 13 c4 00 a3
+24 b4 00 ef 10 4e cc 2a 84 05 65 2d 05 23 10 a4 00 55 45 23 13 a4 00 ef f0 8d de 83 55 64 00 23
+12 a4 00 13 05 84 00 ef f0 4d fa 2a 87 23 11 a4 00 7b 25 00 81 0b 48 05 03 03 56 04 00 83 56 64
+00 37 05 23 00 13 05 e5 17 b7 b5 03 45 93 85 25 5c ef 50 e7 f2 03 55 64 00 93 05 85 00 22 85 80
+98 6f f0 ad e2 00 00 40 99 03 c6 b5 00 2a 84 0d 45 0b 03 16 01 83 c4 95 00 33 85 b4 00 03 45 25
+00 0b cf 04 03 0b 0e 05 02 0b 0d 05 04 ef 10 e0 08 4c 44 53 80 05 d2 d3 80 14 d2 11 c5 37 b5 09
+00 07 31 85 5b 29 a0 37 b5 09 00 07 31 05 5b d3 f0 20 12 d3 85 00 a2 15 45 91 e1 11 45 20 99 00
+00 00 00 83 45 f5 02 13 f6 05 02 53 05 00 d2 59 ca 54 45 18 45 37 b6 09 00 07 30 06 5c 03 46 15
+02 d3 80 16 d2 53 01 17 d2 43 70 01 0a 0b 53 16 06 85 46 b3 96 c6 00 93 f6 96 02 9d ce ab e6 35
+44 11 ca 03 05 05 02 0b 17 06 03 37 07 04 20 13 07 07 de 21 a8 03 05 05 02 37 57 04 20 13 07 07
+cf 29 a0 df bc
+*/
+const char g_cfg_cmd7[] = {
+    0x01, 0x07, 0xf8, 0xa0, 0x98, 0x00, 0x00, 0x40, 0x98, 0x0b, 0x94, 0x15, 0x01, 0x2a, 0x86, 0x13,
+    0x05, 0xb1, 0x00, 0x85, 0x45, 0x85, 0x46, 0xef, 0x40, 0x47, 0xaa, 0x03, 0x46, 0xb1, 0x00, 0x8b,
+    0x1f, 0x06, 0x01, 0x37, 0x55, 0x00, 0x20, 0x13, 0x05, 0x85, 0x88, 0x0c, 0x51, 0x48, 0x51, 0xfb,
+    0x26, 0x00, 0x81, 0x37, 0xb7, 0x09, 0x00, 0x23, 0x26, 0xa7, 0x70, 0x23, 0x24, 0xb7, 0x70, 0x0b,
+    0xc6, 0x06, 0x03, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x30, 0x93,
+    0x85, 0x25, 0x5c, 0xef, 0x50, 0x97, 0x95, 0x20, 0x98, 0x85, 0x45, 0x39, 0xa8, 0x7b, 0x25, 0x00,
+    0x81, 0x19, 0xc9, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x2b, 0x93,
+    0x85, 0x25, 0x54, 0xef, 0x50, 0x97, 0x93, 0x89, 0x45, 0x7b, 0x6e, 0xb5, 0x6c, 0x20, 0x98, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0x98, 0x2a, 0x84, 0xef, 0x70, 0x4b, 0xcd, 0xaa, 0x85, 0x05, 0x45, 0x85,
+    0xc5, 0x0b, 0x54, 0x04, 0x0a, 0x85, 0x45, 0xb3, 0x95, 0x85, 0x00, 0x93, 0xf5, 0x85, 0x23, 0x81,
+    0xed, 0xfd, 0x75, 0xfd, 0x15, 0xa2, 0x95, 0x8b, 0xd4, 0x05, 0x09, 0x05, 0x46, 0xb3, 0x15, 0xb6,
+    0x00, 0x93, 0xf5, 0x15, 0x14, 0x91, 0xc1, 0xa0, 0x98, 0x01, 0x45, 0xa0, 0x98, 0x00, 0x00, 0xc0,
+    0x98, 0x8b, 0x9f, 0x05, 0x02, 0x2a, 0x86, 0x0a, 0x85, 0x89, 0x45, 0x89, 0x46, 0x09, 0x44, 0xef,
+    0x40, 0xc7, 0x9e, 0x03, 0x46, 0x01, 0x00, 0x0b, 0x4c, 0x06, 0x02, 0x7b, 0x25, 0x00, 0x81, 0x09,
+    0xcd, 0x83, 0x46, 0x11, 0x00, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02,
+    0x4b, 0x93, 0x85, 0x25, 0x54, 0xef, 0x50, 0xf7, 0x90, 0x7b, 0x6e, 0x85, 0x6c, 0xa0, 0x98, 0x85,
+    0x45, 0x7b, 0x6e, 0xb5, 0x6c, 0xa0, 0x98, 0xef, 0x30, 0x0c, 0xc4, 0x2a, 0x84, 0x83, 0x45, 0x01,
+    0x00, 0x03, 0x25, 0x45, 0x11, 0x2c, 0xc8, 0x0b, 0x97, 0x05, 0x01, 0x13, 0x65, 0x05, 0x04, 0x23,
+    0x2a, 0xa4, 0x10, 0xef, 0x30, 0x4c, 0xf1, 0x13, 0x35, 0x15, 0x00, 0x05, 0x05, 0x23, 0x0a, 0xa4,
+    0x04, 0x29, 0xa0, 0x13, 0x75, 0xf5, 0xfb, 0x23, 0x2a, 0xa4, 0x10, 0x7b, 0x25, 0x00, 0x81, 0x0b,
+    0x48, 0x05, 0x03, 0x03, 0x46, 0x01, 0x00, 0x83, 0x46, 0x11, 0x00, 0x37, 0x05, 0x23, 0x00, 0x13,
+    0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x5a, 0x93, 0x85, 0x25, 0x5c, 0xef, 0x50, 0x97, 0x8a, 0xa0,
+    0x98, 0x00, 0x00, 0x4c, 0x98, 0x0b, 0x92, 0x25, 0x1c, 0x2a, 0x86, 0x08, 0x10, 0xf1, 0x45, 0xf1,
+    0x46, 0xef, 0x40, 0xa7, 0x94, 0x83, 0x46, 0x01, 0x02, 0x37, 0xb5, 0x09, 0x00, 0x83, 0x05, 0x15,
+    0x6d, 0x36, 0x86, 0x2b, 0xe6, 0xd5, 0x20, 0xa3, 0x08, 0xc5, 0x6c, 0x03, 0x47, 0x11, 0x02, 0x83,
+    0x47, 0x21, 0x02, 0x7b, 0x25, 0x00, 0x81, 0xb7, 0xb5, 0x09, 0x00, 0x23, 0x88, 0xe5, 0x70, 0x93,
+    0x85, 0x05, 0x71, 0xa3, 0x80, 0xf5, 0x00, 0x0b, 0x41, 0x15, 0x03, 0x03, 0x48, 0x31, 0x02, 0x83,
+    0x58, 0x41, 0x02, 0x83, 0x52, 0x61, 0x02, 0x03, 0x53, 0x81, 0x02, 0x83, 0x53, 0xa1, 0x02, 0x32,
+    0x5e, 0x42, 0x55, 0xd2, 0x55, 0x62, 0x56, 0x32, 0xcc, 0x2e, 0xca, 0x2a, 0xc8, 0x72, 0xc6, 0x1e,
+    0xc4, 0x1a, 0xc2, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x02, 0x73, 0x93,
+    0x85, 0x25, 0x5c, 0x31, 0x46, 0x16, 0xc0, 0xef, 0x50, 0xd7, 0x93, 0x2c, 0x98, 0x85, 0x45, 0x7b,
+    0x6e, 0xb5, 0x6c, 0x2c, 0x98, 0x00, 0x00, 0x40, 0x98, 0x22, 0xa0, 0x33, 0xc8, 0xb6, 0x00, 0xb3,
+    0x38, 0xc5, 0x00, 0x33, 0xb7, 0xd5, 0x00, 0x2b, 0xe7, 0x08, 0x21, 0x33, 0x38, 0xa6, 0x00, 0xb3,
+    0x87, 0xb6, 0x40, 0xb3, 0x87, 0x07, 0x41, 0x33, 0x08, 0xa6, 0x40, 0x95, 0x8d, 0xb3, 0x85, 0x15,
+    0x41, 0x11, 0x8d, 0xab, 0xe5, 0xe7, 0x22, 0x2b, 0x65, 0xe8, 0x22, 0x41, 0x81, 0x2b, 0x26, 0xb5,
+    0x20, 0x93, 0xd6, 0x05, 0x01, 0x33, 0x35, 0xc0, 0x00, 0x2b, 0x05, 0xb5, 0x60, 0xe8, 0x8d, 0x70,
+    0x8d, 0x2b, 0x65, 0xe6, 0x22, 0xab, 0xe5, 0xe6, 0x22, 0xef, 0xd0, 0xa6, 0xbf, 0x37, 0xb5, 0x09,
+    0x00, 0x07, 0x30, 0x85, 0x5a, 0x53, 0x74, 0x05, 0x12, 0xef, 0x50, 0xeb, 0xe5, 0xef, 0xd0, 0x66,
+    0xbe, 0x53, 0x75, 0xa4, 0x1a, 0x02, 0x24, 0x20, 0x98, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x10, 0x6e,
+    0xd4, 0x2a, 0x84, 0xef, 0x50, 0x5e, 0xc4, 0x37, 0xb6, 0x09, 0x00, 0x83, 0x25, 0xc6, 0x70, 0x03,
+    0x27, 0x86, 0x70, 0x33, 0x66, 0xb7, 0x00, 0x01, 0xca, 0x74, 0x49, 0x30, 0x49, 0x3a, 0x85, 0xa5,
+    0x37, 0x53, 0x15, 0x15, 0xc2, 0x11, 0xa0, 0x01, 0x45, 0x08, 0xc0, 0xef, 0xb0, 0x4e, 0xd5, 0x23,
+    0x02, 0xa4, 0x00, 0xef, 0x50, 0x4e, 0xbc, 0xb7, 0xc5, 0x04, 0x20, 0x93, 0x85, 0x85, 0xf6, 0x07,
+    0xb0, 0x05, 0x73, 0x53, 0x75, 0x10, 0x40, 0x53, 0x06, 0x05, 0xe0, 0xa3, 0x28, 0xc4, 0x00, 0x07,
+    0xb0, 0x05, 0x14, 0x53, 0x75, 0x10, 0x40, 0x53, 0x06, 0x05, 0xe0, 0xa3, 0x26, 0xc4, 0x00, 0x03,
+    0xa6, 0x85, 0x71, 0x83, 0xa5, 0x05, 0x1d, 0x23, 0x03, 0xa4, 0x00, 0xa3, 0x13, 0xc4, 0x00, 0xa3,
+    0x24, 0xb4, 0x00, 0xef, 0x10, 0x4e, 0xcc, 0x2a, 0x84, 0x05, 0x65, 0x2d, 0x05, 0x23, 0x10, 0xa4,
+    0x00, 0x55, 0x45, 0x23, 0x13, 0xa4, 0x00, 0xef, 0xf0, 0x8d, 0xde, 0x83, 0x55, 0x64, 0x00, 0x23,
+    0x12, 0xa4, 0x00, 0x13, 0x05, 0x84, 0x00, 0xef, 0xf0, 0x4d, 0xfa, 0x2a, 0x87, 0x23, 0x11, 0xa4,
+    0x00, 0x7b, 0x25, 0x00, 0x81, 0x0b, 0x48, 0x05, 0x03, 0x03, 0x56, 0x04, 0x00, 0x83, 0x56, 0x64,
+    0x00, 0x37, 0x05, 0x23, 0x00, 0x13, 0x05, 0xe5, 0x17, 0xb7, 0xb5, 0x03, 0x45, 0x93, 0x85, 0x25,
+    0x5c, 0xef, 0x50, 0xe7, 0xf2, 0x03, 0x55, 0x64, 0x00, 0x93, 0x05, 0x85, 0x00, 0x22, 0x85, 0x80,
+    0x98, 0x6f, 0xf0, 0xad, 0xe2, 0x00, 0x00, 0x40, 0x99, 0x03, 0xc6, 0xb5, 0x00, 0x2a, 0x84, 0x0d,
+    0x45, 0x0b, 0x03, 0x16, 0x01, 0x83, 0xc4, 0x95, 0x00, 0x33, 0x85, 0xb4, 0x00, 0x03, 0x45, 0x25,
+    0x00, 0x0b, 0xcf, 0x04, 0x03, 0x0b, 0x0e, 0x05, 0x02, 0x0b, 0x0d, 0x05, 0x04, 0xef, 0x10, 0xe0,
+    0x08, 0x4c, 0x44, 0x53, 0x80, 0x05, 0xd2, 0xd3, 0x80, 0x14, 0xd2, 0x11, 0xc5, 0x37, 0xb5, 0x09,
+    0x00, 0x07, 0x31, 0x85, 0x5b, 0x29, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x31, 0x05, 0x5b, 0xd3,
+    0xf0, 0x20, 0x12, 0xd3, 0x85, 0x00, 0xa2, 0x15, 0x45, 0x91, 0xe1, 0x11, 0x45, 0x20, 0x99, 0x00,
+    0x00, 0x00, 0x00, 0x83, 0x45, 0xf5, 0x02, 0x13, 0xf6, 0x05, 0x02, 0x53, 0x05, 0x00, 0xd2, 0x59,
+    0xca, 0x54, 0x45, 0x18, 0x45, 0x37, 0xb6, 0x09, 0x00, 0x07, 0x30, 0x06, 0x5c, 0x03, 0x46, 0x15,
+    0x02, 0xd3, 0x80, 0x16, 0xd2, 0x53, 0x01, 0x17, 0xd2, 0x43, 0x70, 0x01, 0x0a, 0x0b, 0x53, 0x16,
+    0x06, 0x85, 0x46, 0xb3, 0x96, 0xc6, 0x00, 0x93, 0xf6, 0x96, 0x02, 0x9d, 0xce, 0xab, 0xe6, 0x35,
+    0x44, 0x11, 0xca, 0x03, 0x05, 0x05, 0x02, 0x0b, 0x17, 0x06, 0x03, 0x37, 0x07, 0x04, 0x20, 0x13,
+    0x07, 0x07, 0xde, 0x21, 0xa8, 0x03, 0x05, 0x05, 0x02, 0x37, 0x57, 0x04, 0x20, 0x13, 0x07, 0x07,
+    0xcf, 0x29, 0xa0, 0xdf, 0xbc
+};
+
+/*
+01 08 f7 37 57 04 20 13 07 07 cc 3a 95 89 ca 03 45 05 00 11 c5 63 82 a6 02 53 05 00 22 82 80 01
+45 13 36 16 00 8d 89 93 c6 35 00 ab 65 d0 20 2b e5 c5 22 09 c9 0b 19 f5 01 37 b5 09 00 87 30 85
+5c 53 75 10 02 82 80 00 00 00 00 c4 99 2a 84 03 06 05 02 03 45 15 02 ae 84 23 90 c5 02 a3 86 a5
+02 b2 85 ef 90 ce e6 83 d5 04 02 03 c6 d4 02 23 91 a4 02 2e 89 8b 15 06 01 37 15 00 20 13 05 85
+01 2b 05 b5 04 08 41 13 09 75 00 03 05 04 03 23 88 a4 02 ec 91 32 85 ef f0 1e df a3 89 a4 02 03
+c5 d4 02 02 c4 02 c2 02 c0 93 15 09 01 c1 81 0a 86 ef 80 3e a4 02 45 83 05 44 02 03 06 b4 02 23
+83 a4 02 23 86 b4 02 a3 82 c4 02 03 05 e4 01 83 05 34 02 03 06 74 02 83 06 24 02 23 82 a4 02 a3
+83 b4 02 a3 88 c4 02 13 85 d6 ff 88 91 93 b5 a5 00 13 06 10 21 33 55 a6 00 6d 8d 4c 44 10 44 b7
+b6 09 00 07 b0 06 5c 23 8a a4 02 d3 80 05 d2 53 01 16 d2 43 70 01 0a 27 b8 04 00 22 85 59 35 03
+05 f4 02 88 a8 23 87 a4 02 a4 99 40 99 ef 30 ac 81 2a 84 13 05 f0 0f 23 12 a4 00 ef 30 cc af 93
+05 10 24 93 04 10 20 13 06 10 20 2b e6 a5 20 23 2a c4 10 ef 30 4c ae 83 25 44 11 13 35 15 00 05
+05 13 f6 05 04 a3 0a a4 04 09 c6 05 46 30 c8 23 0a a4 04 13 f5 05 20 23 0b 04 04 11 c5 ef 30 ac
+ab 19 e1 23 1c 94 04 23 01 04 14 20 99 00 00 40 98 ef 20 7c fb 89 45 23 05 b5 00 b7 d5 4c 3f 93
+85 d5 cc 23 26 b5 12 20 98 00 00 c0 98 ef 50 2d bb 79 ed 37 b5 04 20 93 05 05 6b c8 49 09 c9 07
+b0 85 00 05 05 d3 00 15 d2 53 15 10 a2 69 e1 ef 50 ce 81 b7 c5 04 20 13 84 85 f6 83 25 04 16 13
+35 15 00 93 b5 15 00 4d 8d 5d e1 ef 20 dc f5 03 45 c5 0e 0b 17 25 01 ef 50 0e 87 07 30 84 12 b7
+b5 09 00 87 b0 05 66 d3 95 00 a2 37 b6 09 00 13 06 86 5d ab 05 b6 06 07 b0 05 00 b7 b5 09 00 87
+b0 05 5d b7 b5 09 00 83 c5 05 71 13 35 15 00 2b e0 a0 3a 07 25 04 1d 13 b5 15 00 d3 80 15 d2 ab
+60 a0 3a 53 00 05 42 53 95 00 a2 05 c9 23 20 04 16 23 20 04 18 13 05 84 1f 93 05 00 29 93 06 00
+29 01 46 ef 40 07 a7 13 05 84 48 93 05 00 29 93 06 00 29 01 46 80 98 6f 40 c7 a5 03 45 14 72 0b
+14 05 02 ef 40 5e fe 79 d1 ef 40 bd a3 61 d1 a0 98 00 00 c0 98 37 24 04 20 83 25 44 e3 37 b5 09
+00 03 45 15 6d b3 35 b0 00 13 06 d5 fd 13 36 16 00 d1 8d 99 e5 ef 20 3c d2 13 05 44 e3 85 45 0c
+c1 ed 35 80 98 6f 00 30 54 00 00 40 99 2a 84 ef 60 1d bc aa 84 ef 40 7e f3 05 c1 37 b5 09 00 03
+45 15 71 93 75 05 08 91 e5 13 75 05 04 11 c5 09 45 11 a0 05 45 23 8c a4 00 03 c5 84 01 93 65 25
+00 8b 93 05 02 22 85 ef 70 0d c5 03 c5 84 01 8b 14 05 01 09 45 23 8c a4 00 22 85 ef 70 cd c3 11
+c1 20 99 05 45 23 8c a4 00 22 85 00 99 6f 70 ad c2 00 00 40 99 2a 84 05 65 b3 05 a4 00 83 a5 85
+b0 13 05 05 b0 0b 98 05 01 b7 d5 4c 3f 93 85 d5 cc 23 26 b4 0e b7 05 40 40 23 28 b4 0e b7 05 00
+40 23 24 b4 0e b3 04 a4 00 ef 20 fc dd 03 45 c5 0e 15 cd ef 20 5c dd 03 45 c5 0e 0d e1 07 30 84
+05 37 b5 09 00 87 30 85 5e 53 15 10 a2 01 c9 37 05 00 40 23 26 a4 0e 37 05 80 3f 31 a0 88 40 0b
+15 05 01 37 05 80 40 23 28 a4 0e 21 a0 03 c5 84 01 69 d1 20 99 00 00 50 9e a2 a0 26 bc 4a b8 4e
+b4 52 b0 56 ac 5a a8 5e a4 32 84 ae 89 2a c2 ef 00 d0 42 64 9d 93 25 14 00 4d 8d 63 19 05 14 81
+44 09 65 13 05 05 86 b3 8a a9 00 05 65 13 0b 85 c6 b3 8b 69 01 13 8c 89 12 b7 b5 09 00 07 a4 05
+5f b7 b5 78 80
+*/
+const char g_cfg_cmd8[] = {
+    0x01, 0x08, 0xf7, 0x37, 0x57, 0x04, 0x20, 0x13, 0x07, 0x07, 0xcc, 0x3a, 0x95, 0x89, 0xca, 0x03,
+    0x45, 0x05, 0x00, 0x11, 0xc5, 0x63, 0x82, 0xa6, 0x02, 0x53, 0x05, 0x00, 0x22, 0x82, 0x80, 0x01,
+    0x45, 0x13, 0x36, 0x16, 0x00, 0x8d, 0x89, 0x93, 0xc6, 0x35, 0x00, 0xab, 0x65, 0xd0, 0x20, 0x2b,
+    0xe5, 0xc5, 0x22, 0x09, 0xc9, 0x0b, 0x19, 0xf5, 0x01, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85,
+    0x5c, 0x53, 0x75, 0x10, 0x02, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x99, 0x2a, 0x84, 0x03,
+    0x06, 0x05, 0x02, 0x03, 0x45, 0x15, 0x02, 0xae, 0x84, 0x23, 0x90, 0xc5, 0x02, 0xa3, 0x86, 0xa5,
+    0x02, 0xb2, 0x85, 0xef, 0x90, 0xce, 0xe6, 0x83, 0xd5, 0x04, 0x02, 0x03, 0xc6, 0xd4, 0x02, 0x23,
+    0x91, 0xa4, 0x02, 0x2e, 0x89, 0x8b, 0x15, 0x06, 0x01, 0x37, 0x15, 0x00, 0x20, 0x13, 0x05, 0x85,
+    0x01, 0x2b, 0x05, 0xb5, 0x04, 0x08, 0x41, 0x13, 0x09, 0x75, 0x00, 0x03, 0x05, 0x04, 0x03, 0x23,
+    0x88, 0xa4, 0x02, 0xec, 0x91, 0x32, 0x85, 0xef, 0xf0, 0x1e, 0xdf, 0xa3, 0x89, 0xa4, 0x02, 0x03,
+    0xc5, 0xd4, 0x02, 0x02, 0xc4, 0x02, 0xc2, 0x02, 0xc0, 0x93, 0x15, 0x09, 0x01, 0xc1, 0x81, 0x0a,
+    0x86, 0xef, 0x80, 0x3e, 0xa4, 0x02, 0x45, 0x83, 0x05, 0x44, 0x02, 0x03, 0x06, 0xb4, 0x02, 0x23,
+    0x83, 0xa4, 0x02, 0x23, 0x86, 0xb4, 0x02, 0xa3, 0x82, 0xc4, 0x02, 0x03, 0x05, 0xe4, 0x01, 0x83,
+    0x05, 0x34, 0x02, 0x03, 0x06, 0x74, 0x02, 0x83, 0x06, 0x24, 0x02, 0x23, 0x82, 0xa4, 0x02, 0xa3,
+    0x83, 0xb4, 0x02, 0xa3, 0x88, 0xc4, 0x02, 0x13, 0x85, 0xd6, 0xff, 0x88, 0x91, 0x93, 0xb5, 0xa5,
+    0x00, 0x13, 0x06, 0x10, 0x21, 0x33, 0x55, 0xa6, 0x00, 0x6d, 0x8d, 0x4c, 0x44, 0x10, 0x44, 0xb7,
+    0xb6, 0x09, 0x00, 0x07, 0xb0, 0x06, 0x5c, 0x23, 0x8a, 0xa4, 0x02, 0xd3, 0x80, 0x05, 0xd2, 0x53,
+    0x01, 0x16, 0xd2, 0x43, 0x70, 0x01, 0x0a, 0x27, 0xb8, 0x04, 0x00, 0x22, 0x85, 0x59, 0x35, 0x03,
+    0x05, 0xf4, 0x02, 0x88, 0xa8, 0x23, 0x87, 0xa4, 0x02, 0xa4, 0x99, 0x40, 0x99, 0xef, 0x30, 0xac,
+    0x81, 0x2a, 0x84, 0x13, 0x05, 0xf0, 0x0f, 0x23, 0x12, 0xa4, 0x00, 0xef, 0x30, 0xcc, 0xaf, 0x93,
+    0x05, 0x10, 0x24, 0x93, 0x04, 0x10, 0x20, 0x13, 0x06, 0x10, 0x20, 0x2b, 0xe6, 0xa5, 0x20, 0x23,
+    0x2a, 0xc4, 0x10, 0xef, 0x30, 0x4c, 0xae, 0x83, 0x25, 0x44, 0x11, 0x13, 0x35, 0x15, 0x00, 0x05,
+    0x05, 0x13, 0xf6, 0x05, 0x04, 0xa3, 0x0a, 0xa4, 0x04, 0x09, 0xc6, 0x05, 0x46, 0x30, 0xc8, 0x23,
+    0x0a, 0xa4, 0x04, 0x13, 0xf5, 0x05, 0x20, 0x23, 0x0b, 0x04, 0x04, 0x11, 0xc5, 0xef, 0x30, 0xac,
+    0xab, 0x19, 0xe1, 0x23, 0x1c, 0x94, 0x04, 0x23, 0x01, 0x04, 0x14, 0x20, 0x99, 0x00, 0x00, 0x40,
+    0x98, 0xef, 0x20, 0x7c, 0xfb, 0x89, 0x45, 0x23, 0x05, 0xb5, 0x00, 0xb7, 0xd5, 0x4c, 0x3f, 0x93,
+    0x85, 0xd5, 0xcc, 0x23, 0x26, 0xb5, 0x12, 0x20, 0x98, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x50, 0x2d,
+    0xbb, 0x79, 0xed, 0x37, 0xb5, 0x04, 0x20, 0x93, 0x05, 0x05, 0x6b, 0xc8, 0x49, 0x09, 0xc9, 0x07,
+    0xb0, 0x85, 0x00, 0x05, 0x05, 0xd3, 0x00, 0x15, 0xd2, 0x53, 0x15, 0x10, 0xa2, 0x69, 0xe1, 0xef,
+    0x50, 0xce, 0x81, 0xb7, 0xc5, 0x04, 0x20, 0x13, 0x84, 0x85, 0xf6, 0x83, 0x25, 0x04, 0x16, 0x13,
+    0x35, 0x15, 0x00, 0x93, 0xb5, 0x15, 0x00, 0x4d, 0x8d, 0x5d, 0xe1, 0xef, 0x20, 0xdc, 0xf5, 0x03,
+    0x45, 0xc5, 0x0e, 0x0b, 0x17, 0x25, 0x01, 0xef, 0x50, 0x0e, 0x87, 0x07, 0x30, 0x84, 0x12, 0xb7,
+    0xb5, 0x09, 0x00, 0x87, 0xb0, 0x05, 0x66, 0xd3, 0x95, 0x00, 0xa2, 0x37, 0xb6, 0x09, 0x00, 0x13,
+    0x06, 0x86, 0x5d, 0xab, 0x05, 0xb6, 0x06, 0x07, 0xb0, 0x05, 0x00, 0xb7, 0xb5, 0x09, 0x00, 0x87,
+    0xb0, 0x05, 0x5d, 0xb7, 0xb5, 0x09, 0x00, 0x83, 0xc5, 0x05, 0x71, 0x13, 0x35, 0x15, 0x00, 0x2b,
+    0xe0, 0xa0, 0x3a, 0x07, 0x25, 0x04, 0x1d, 0x13, 0xb5, 0x15, 0x00, 0xd3, 0x80, 0x15, 0xd2, 0xab,
+    0x60, 0xa0, 0x3a, 0x53, 0x00, 0x05, 0x42, 0x53, 0x95, 0x00, 0xa2, 0x05, 0xc9, 0x23, 0x20, 0x04,
+    0x16, 0x23, 0x20, 0x04, 0x18, 0x13, 0x05, 0x84, 0x1f, 0x93, 0x05, 0x00, 0x29, 0x93, 0x06, 0x00,
+    0x29, 0x01, 0x46, 0xef, 0x40, 0x07, 0xa7, 0x13, 0x05, 0x84, 0x48, 0x93, 0x05, 0x00, 0x29, 0x93,
+    0x06, 0x00, 0x29, 0x01, 0x46, 0x80, 0x98, 0x6f, 0x40, 0xc7, 0xa5, 0x03, 0x45, 0x14, 0x72, 0x0b,
+    0x14, 0x05, 0x02, 0xef, 0x40, 0x5e, 0xfe, 0x79, 0xd1, 0xef, 0x40, 0xbd, 0xa3, 0x61, 0xd1, 0xa0,
+    0x98, 0x00, 0x00, 0xc0, 0x98, 0x37, 0x24, 0x04, 0x20, 0x83, 0x25, 0x44, 0xe3, 0x37, 0xb5, 0x09,
+    0x00, 0x03, 0x45, 0x15, 0x6d, 0xb3, 0x35, 0xb0, 0x00, 0x13, 0x06, 0xd5, 0xfd, 0x13, 0x36, 0x16,
+    0x00, 0xd1, 0x8d, 0x99, 0xe5, 0xef, 0x20, 0x3c, 0xd2, 0x13, 0x05, 0x44, 0xe3, 0x85, 0x45, 0x0c,
+    0xc1, 0xed, 0x35, 0x80, 0x98, 0x6f, 0x00, 0x30, 0x54, 0x00, 0x00, 0x40, 0x99, 0x2a, 0x84, 0xef,
+    0x60, 0x1d, 0xbc, 0xaa, 0x84, 0xef, 0x40, 0x7e, 0xf3, 0x05, 0xc1, 0x37, 0xb5, 0x09, 0x00, 0x03,
+    0x45, 0x15, 0x71, 0x93, 0x75, 0x05, 0x08, 0x91, 0xe5, 0x13, 0x75, 0x05, 0x04, 0x11, 0xc5, 0x09,
+    0x45, 0x11, 0xa0, 0x05, 0x45, 0x23, 0x8c, 0xa4, 0x00, 0x03, 0xc5, 0x84, 0x01, 0x93, 0x65, 0x25,
+    0x00, 0x8b, 0x93, 0x05, 0x02, 0x22, 0x85, 0xef, 0x70, 0x0d, 0xc5, 0x03, 0xc5, 0x84, 0x01, 0x8b,
+    0x14, 0x05, 0x01, 0x09, 0x45, 0x23, 0x8c, 0xa4, 0x00, 0x22, 0x85, 0xef, 0x70, 0xcd, 0xc3, 0x11,
+    0xc1, 0x20, 0x99, 0x05, 0x45, 0x23, 0x8c, 0xa4, 0x00, 0x22, 0x85, 0x00, 0x99, 0x6f, 0x70, 0xad,
+    0xc2, 0x00, 0x00, 0x40, 0x99, 0x2a, 0x84, 0x05, 0x65, 0xb3, 0x05, 0xa4, 0x00, 0x83, 0xa5, 0x85,
+    0xb0, 0x13, 0x05, 0x05, 0xb0, 0x0b, 0x98, 0x05, 0x01, 0xb7, 0xd5, 0x4c, 0x3f, 0x93, 0x85, 0xd5,
+    0xcc, 0x23, 0x26, 0xb4, 0x0e, 0xb7, 0x05, 0x40, 0x40, 0x23, 0x28, 0xb4, 0x0e, 0xb7, 0x05, 0x00,
+    0x40, 0x23, 0x24, 0xb4, 0x0e, 0xb3, 0x04, 0xa4, 0x00, 0xef, 0x20, 0xfc, 0xdd, 0x03, 0x45, 0xc5,
+    0x0e, 0x15, 0xcd, 0xef, 0x20, 0x5c, 0xdd, 0x03, 0x45, 0xc5, 0x0e, 0x0d, 0xe1, 0x07, 0x30, 0x84,
+    0x05, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85, 0x5e, 0x53, 0x15, 0x10, 0xa2, 0x01, 0xc9, 0x37,
+    0x05, 0x00, 0x40, 0x23, 0x26, 0xa4, 0x0e, 0x37, 0x05, 0x80, 0x3f, 0x31, 0xa0, 0x88, 0x40, 0x0b,
+    0x15, 0x05, 0x01, 0x37, 0x05, 0x80, 0x40, 0x23, 0x28, 0xa4, 0x0e, 0x21, 0xa0, 0x03, 0xc5, 0x84,
+    0x01, 0x69, 0xd1, 0x20, 0x99, 0x00, 0x00, 0x50, 0x9e, 0xa2, 0xa0, 0x26, 0xbc, 0x4a, 0xb8, 0x4e,
+    0xb4, 0x52, 0xb0, 0x56, 0xac, 0x5a, 0xa8, 0x5e, 0xa4, 0x32, 0x84, 0xae, 0x89, 0x2a, 0xc2, 0xef,
+    0x00, 0xd0, 0x42, 0x64, 0x9d, 0x93, 0x25, 0x14, 0x00, 0x4d, 0x8d, 0x63, 0x19, 0x05, 0x14, 0x81,
+    0x44, 0x09, 0x65, 0x13, 0x05, 0x05, 0x86, 0xb3, 0x8a, 0xa9, 0x00, 0x05, 0x65, 0x13, 0x0b, 0x85,
+    0xc6, 0xb3, 0x8b, 0x69, 0x01, 0x13, 0x8c, 0x89, 0x12, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa4, 0x05,
+    0x5f, 0xb7, 0xb5, 0x78, 0x80
+};
+
+/*
+01 09 f6 09 00 87 a4 45 5f b7 b5 09 00 07 b9 05 6a b7 b5 09 00 87 b9 85 60 b7 b5 09 00 07 aa 85
+5f b7 b5 09 00 87 aa c5 5f b7 b5 09 00 07 bb 05 60 93 0c 05 c6 13 0d 45 c6 d3 0b 00 f0 ab 8d 99
+04 13 8a 8d 2a 52 85 53 05 84 20 ef 40 5d dd 13 85 8d 36 53 85 94 20 ef 40 9d dc 81 45 01 45 01
+49 2b 86 99 0a 33 08 96 01 b3 08 a6 01 33 07 66 01 e2 87 5e 86 53 05 00 f0 63 87 b4 04 b3 86 ba
+00 83 c6 06 00 a9 c2 87 25 08 00 07 26 86 ff 87 a6 08 00 07 27 c6 ff 1c 63 07 28 06 00 d3 f6 e6
+10 c3 f5 c5 68 c3 f5 07 59 53 80 05 42 d3 06 0b a2 99 c6 90 63 05 05 53 76 b6 18 53 75 c5 00 d3
+86 75 a1 91 c2 05 09 85 05 13 06 06 02 91 07 e3 15 b4 fa 1d c1 87 a5 8d 12 53 76 05 d0 53 75 c5
+18 53 75 45 01 53 15 b5 a0 01 c9 53 f5 b5 10 53 75 55 11 52 85 ef 40 bd d2 8b 3b 09 03 12 45 2b
+75 95 58 48 75 53 00 05 42 53 70 20 13 53 15 30 a3 19 c9 07 a5 8d 12 53 15 aa a0 11 c5 53 75 a5
+10 52 85 ef 40 dd cf 85 04 e3 9a 84 f0 a2 2b 42 2b e2 2a 02 3a a2 39 42 39 e2 34 06 24 30 9e 00
+00 00 00 40 99 2e 84 aa 84 ef 20 fc bf 03 45 c5 0e 25 c1 05 65 26 95 03 05 a5 b4 75 15 08 91 8b
+54 15 02 8b 23 14 01 01 46 b3 25 80 00 09 65 93 06 05 86 a6 96 22 87 83 c7 06 00 81 c7 83 c7 06
+03 3e 96 7d 17 85 06 65 fb 13 26 86 00 e4 9d d1 8d 85 e1 13 05 05 89 26 95 83 45 05 fd 81 c5 83
+45 05 00 81 e5 23 08 05 fc 02 11 7d 14 05 05 6d f4 20 99 00 00 00 00 44 9a 22 a8 26 a4 b2 89 8b
+86 06 02 8b 98 16 01 89 65 93 85 05 89 b3 04 b5 00 13 04 85 1e 21 05 01 a8 89 65 93 85 05 86 b3
+04 b5 00 13 04 85 12 00 21 ef 00 30 21 0b ae 09 01 2a 89 d3 04 00 f0 03 c5 04 00 05 c1 08 60 53
+05 05 42 ef 90 a6 80 53 15 a4 a2 63 06 09 00 11 c5 08 60 53 95 a4 a0 11 c1 82 10 fd 19 11 04 85
+04 e3 9b 09 fc a2 24 42 24 24 9a 00 00 00 00 c8 99 22 ac 26 a8 4a a4 2a 84 05 65 13 05 a5 b2 b3
+04 a4 00 07 b0 64 0b 87 b0 e4 0a 09 65 53 75 10 40 d3 f5 10 40 b7 b5 09 00 07 b0 05 61 b7 b5 09
+00 87 b0 85 61 83 d5 04 00 53 81 05 42 53 71 01 12 d3 01 05 42 53 82 15 d2 53 72 12 12 43 f0 01
+22 b7 b5 09 00 07 a5 85 62 87 31 04 0a 13 05 d5 8c 53 74 10 40 d3 05 85 a0 43 f0 11 12 8d e9 b7
+b5 09 00 07 a5 c5 62 53 06 a4 a0 b7 b5 09 00 0d e6 37 b6 09 00 07 25 46 63 87 a5 05 63 b7 b5 09
+00 07 a6 85 63 53 75 a4 00 43 75 c5 58 01 a8 b7 b5 09 00 07 a5 c5 67 19 a0 07 a5 05 63 83 85 04
+02 d3 74 10 40 f5 15 8c 91 33 09 a4 00 8b c8 05 02 53 79 95 10 ef 00 70 10 0d c1 28 34 ef 80 16
+f1 37 b5 09 00 07 30 05 62 53 15 05 a2 19 c5 ef 30 5d 8b 07 30 05 46 53 79 10 40 37 b5 09 00 07
+25 c5 63 03 45 09 00 d3 15 a9 a0 37 b6 09 00 07 30 86 66 13 35 65 00 6d 8d d3 00 09 42 ab 60 a0
+3a 27 38 14 04 53 00 04 42 27 bb 04 0a 27 b3 14 0a 53 80 04 42 27 b7 04 0a ef 40 ad d2 aa 84 48
+71 0c 61 30 65 53 75 a5 10 43 f5 b5 50 43 75 c6 50 53 05 05 42 ef a0 76 ac 87 a5 84 0d 07 a6 44
+0b 87 a6 c4 0f 08 b4 53 f5 b5 10 43 75 c6 50 43 f5 d6 50 53 05 05 42 ef a0 56 aa 08 b0 22 29 c2
+24 62 24 a8 99 00 00 c0 99 2e 86 2a 84 05 65 07 30 84 05 b7 b5 09 00 87 b0 05 64 b3 05 a4 00 83
+c5 85 b1 13 05 85 b0 d3 96 00 a2 b3 04 a4 00 81 c6 99 c1 81 45 82 14 32 85 ef 40 ad ee cc 44 05
+49 8b 81 05 01 2a 89 07 30 84 05 37 b5 09 00 87 30 85 65 53 15 10 a2 01 cd ef 20 ad 93 8b 14 05
+01 ef 40 3d de
+*/
+const char g_cfg_cmd9[] = {
+    0x01, 0x09, 0xf6, 0x09, 0x00, 0x87, 0xa4, 0x45, 0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb9, 0x05,
+    0x6a, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb9, 0x85, 0x60, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xaa, 0x85,
+    0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xaa, 0xc5, 0x5f, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xbb, 0x05,
+    0x60, 0x93, 0x0c, 0x05, 0xc6, 0x13, 0x0d, 0x45, 0xc6, 0xd3, 0x0b, 0x00, 0xf0, 0xab, 0x8d, 0x99,
+    0x04, 0x13, 0x8a, 0x8d, 0x2a, 0x52, 0x85, 0x53, 0x05, 0x84, 0x20, 0xef, 0x40, 0x5d, 0xdd, 0x13,
+    0x85, 0x8d, 0x36, 0x53, 0x85, 0x94, 0x20, 0xef, 0x40, 0x9d, 0xdc, 0x81, 0x45, 0x01, 0x45, 0x01,
+    0x49, 0x2b, 0x86, 0x99, 0x0a, 0x33, 0x08, 0x96, 0x01, 0xb3, 0x08, 0xa6, 0x01, 0x33, 0x07, 0x66,
+    0x01, 0xe2, 0x87, 0x5e, 0x86, 0x53, 0x05, 0x00, 0xf0, 0x63, 0x87, 0xb4, 0x04, 0xb3, 0x86, 0xba,
+    0x00, 0x83, 0xc6, 0x06, 0x00, 0xa9, 0xc2, 0x87, 0x25, 0x08, 0x00, 0x07, 0x26, 0x86, 0xff, 0x87,
+    0xa6, 0x08, 0x00, 0x07, 0x27, 0xc6, 0xff, 0x1c, 0x63, 0x07, 0x28, 0x06, 0x00, 0xd3, 0xf6, 0xe6,
+    0x10, 0xc3, 0xf5, 0xc5, 0x68, 0xc3, 0xf5, 0x07, 0x59, 0x53, 0x80, 0x05, 0x42, 0xd3, 0x06, 0x0b,
+    0xa2, 0x99, 0xc6, 0x90, 0x63, 0x05, 0x05, 0x53, 0x76, 0xb6, 0x18, 0x53, 0x75, 0xc5, 0x00, 0xd3,
+    0x86, 0x75, 0xa1, 0x91, 0xc2, 0x05, 0x09, 0x85, 0x05, 0x13, 0x06, 0x06, 0x02, 0x91, 0x07, 0xe3,
+    0x15, 0xb4, 0xfa, 0x1d, 0xc1, 0x87, 0xa5, 0x8d, 0x12, 0x53, 0x76, 0x05, 0xd0, 0x53, 0x75, 0xc5,
+    0x18, 0x53, 0x75, 0x45, 0x01, 0x53, 0x15, 0xb5, 0xa0, 0x01, 0xc9, 0x53, 0xf5, 0xb5, 0x10, 0x53,
+    0x75, 0x55, 0x11, 0x52, 0x85, 0xef, 0x40, 0xbd, 0xd2, 0x8b, 0x3b, 0x09, 0x03, 0x12, 0x45, 0x2b,
+    0x75, 0x95, 0x58, 0x48, 0x75, 0x53, 0x00, 0x05, 0x42, 0x53, 0x70, 0x20, 0x13, 0x53, 0x15, 0x30,
+    0xa3, 0x19, 0xc9, 0x07, 0xa5, 0x8d, 0x12, 0x53, 0x15, 0xaa, 0xa0, 0x11, 0xc5, 0x53, 0x75, 0xa5,
+    0x10, 0x52, 0x85, 0xef, 0x40, 0xdd, 0xcf, 0x85, 0x04, 0xe3, 0x9a, 0x84, 0xf0, 0xa2, 0x2b, 0x42,
+    0x2b, 0xe2, 0x2a, 0x02, 0x3a, 0xa2, 0x39, 0x42, 0x39, 0xe2, 0x34, 0x06, 0x24, 0x30, 0x9e, 0x00,
+    0x00, 0x00, 0x00, 0x40, 0x99, 0x2e, 0x84, 0xaa, 0x84, 0xef, 0x20, 0xfc, 0xbf, 0x03, 0x45, 0xc5,
+    0x0e, 0x25, 0xc1, 0x05, 0x65, 0x26, 0x95, 0x03, 0x05, 0xa5, 0xb4, 0x75, 0x15, 0x08, 0x91, 0x8b,
+    0x54, 0x15, 0x02, 0x8b, 0x23, 0x14, 0x01, 0x01, 0x46, 0xb3, 0x25, 0x80, 0x00, 0x09, 0x65, 0x93,
+    0x06, 0x05, 0x86, 0xa6, 0x96, 0x22, 0x87, 0x83, 0xc7, 0x06, 0x00, 0x81, 0xc7, 0x83, 0xc7, 0x06,
+    0x03, 0x3e, 0x96, 0x7d, 0x17, 0x85, 0x06, 0x65, 0xfb, 0x13, 0x26, 0x86, 0x00, 0xe4, 0x9d, 0xd1,
+    0x8d, 0x85, 0xe1, 0x13, 0x05, 0x05, 0x89, 0x26, 0x95, 0x83, 0x45, 0x05, 0xfd, 0x81, 0xc5, 0x83,
+    0x45, 0x05, 0x00, 0x81, 0xe5, 0x23, 0x08, 0x05, 0xfc, 0x02, 0x11, 0x7d, 0x14, 0x05, 0x05, 0x6d,
+    0xf4, 0x20, 0x99, 0x00, 0x00, 0x00, 0x00, 0x44, 0x9a, 0x22, 0xa8, 0x26, 0xa4, 0xb2, 0x89, 0x8b,
+    0x86, 0x06, 0x02, 0x8b, 0x98, 0x16, 0x01, 0x89, 0x65, 0x93, 0x85, 0x05, 0x89, 0xb3, 0x04, 0xb5,
+    0x00, 0x13, 0x04, 0x85, 0x1e, 0x21, 0x05, 0x01, 0xa8, 0x89, 0x65, 0x93, 0x85, 0x05, 0x86, 0xb3,
+    0x04, 0xb5, 0x00, 0x13, 0x04, 0x85, 0x12, 0x00, 0x21, 0xef, 0x00, 0x30, 0x21, 0x0b, 0xae, 0x09,
+    0x01, 0x2a, 0x89, 0xd3, 0x04, 0x00, 0xf0, 0x03, 0xc5, 0x04, 0x00, 0x05, 0xc1, 0x08, 0x60, 0x53,
+    0x05, 0x05, 0x42, 0xef, 0x90, 0xa6, 0x80, 0x53, 0x15, 0xa4, 0xa2, 0x63, 0x06, 0x09, 0x00, 0x11,
+    0xc5, 0x08, 0x60, 0x53, 0x95, 0xa4, 0xa0, 0x11, 0xc1, 0x82, 0x10, 0xfd, 0x19, 0x11, 0x04, 0x85,
+    0x04, 0xe3, 0x9b, 0x09, 0xfc, 0xa2, 0x24, 0x42, 0x24, 0x24, 0x9a, 0x00, 0x00, 0x00, 0x00, 0xc8,
+    0x99, 0x22, 0xac, 0x26, 0xa8, 0x4a, 0xa4, 0x2a, 0x84, 0x05, 0x65, 0x13, 0x05, 0xa5, 0xb2, 0xb3,
+    0x04, 0xa4, 0x00, 0x07, 0xb0, 0x64, 0x0b, 0x87, 0xb0, 0xe4, 0x0a, 0x09, 0x65, 0x53, 0x75, 0x10,
+    0x40, 0xd3, 0xf5, 0x10, 0x40, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb0, 0x05, 0x61, 0xb7, 0xb5, 0x09,
+    0x00, 0x87, 0xb0, 0x85, 0x61, 0x83, 0xd5, 0x04, 0x00, 0x53, 0x81, 0x05, 0x42, 0x53, 0x71, 0x01,
+    0x12, 0xd3, 0x01, 0x05, 0x42, 0x53, 0x82, 0x15, 0xd2, 0x53, 0x72, 0x12, 0x12, 0x43, 0xf0, 0x01,
+    0x22, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xa5, 0x85, 0x62, 0x87, 0x31, 0x04, 0x0a, 0x13, 0x05, 0xd5,
+    0x8c, 0x53, 0x74, 0x10, 0x40, 0xd3, 0x05, 0x85, 0xa0, 0x43, 0xf0, 0x11, 0x12, 0x8d, 0xe9, 0xb7,
+    0xb5, 0x09, 0x00, 0x07, 0xa5, 0xc5, 0x62, 0x53, 0x06, 0xa4, 0xa0, 0xb7, 0xb5, 0x09, 0x00, 0x0d,
+    0xe6, 0x37, 0xb6, 0x09, 0x00, 0x07, 0x25, 0x46, 0x63, 0x87, 0xa5, 0x05, 0x63, 0xb7, 0xb5, 0x09,
+    0x00, 0x07, 0xa6, 0x85, 0x63, 0x53, 0x75, 0xa4, 0x00, 0x43, 0x75, 0xc5, 0x58, 0x01, 0xa8, 0xb7,
+    0xb5, 0x09, 0x00, 0x07, 0xa5, 0xc5, 0x67, 0x19, 0xa0, 0x07, 0xa5, 0x05, 0x63, 0x83, 0x85, 0x04,
+    0x02, 0xd3, 0x74, 0x10, 0x40, 0xf5, 0x15, 0x8c, 0x91, 0x33, 0x09, 0xa4, 0x00, 0x8b, 0xc8, 0x05,
+    0x02, 0x53, 0x79, 0x95, 0x10, 0xef, 0x00, 0x70, 0x10, 0x0d, 0xc1, 0x28, 0x34, 0xef, 0x80, 0x16,
+    0xf1, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x62, 0x53, 0x15, 0x05, 0xa2, 0x19, 0xc5, 0xef,
+    0x30, 0x5d, 0x8b, 0x07, 0x30, 0x05, 0x46, 0x53, 0x79, 0x10, 0x40, 0x37, 0xb5, 0x09, 0x00, 0x07,
+    0x25, 0xc5, 0x63, 0x03, 0x45, 0x09, 0x00, 0xd3, 0x15, 0xa9, 0xa0, 0x37, 0xb6, 0x09, 0x00, 0x07,
+    0x30, 0x86, 0x66, 0x13, 0x35, 0x65, 0x00, 0x6d, 0x8d, 0xd3, 0x00, 0x09, 0x42, 0xab, 0x60, 0xa0,
+    0x3a, 0x27, 0x38, 0x14, 0x04, 0x53, 0x00, 0x04, 0x42, 0x27, 0xbb, 0x04, 0x0a, 0x27, 0xb3, 0x14,
+    0x0a, 0x53, 0x80, 0x04, 0x42, 0x27, 0xb7, 0x04, 0x0a, 0xef, 0x40, 0xad, 0xd2, 0xaa, 0x84, 0x48,
+    0x71, 0x0c, 0x61, 0x30, 0x65, 0x53, 0x75, 0xa5, 0x10, 0x43, 0xf5, 0xb5, 0x50, 0x43, 0x75, 0xc6,
+    0x50, 0x53, 0x05, 0x05, 0x42, 0xef, 0xa0, 0x76, 0xac, 0x87, 0xa5, 0x84, 0x0d, 0x07, 0xa6, 0x44,
+    0x0b, 0x87, 0xa6, 0xc4, 0x0f, 0x08, 0xb4, 0x53, 0xf5, 0xb5, 0x10, 0x43, 0x75, 0xc6, 0x50, 0x43,
+    0xf5, 0xd6, 0x50, 0x53, 0x05, 0x05, 0x42, 0xef, 0xa0, 0x56, 0xaa, 0x08, 0xb0, 0x22, 0x29, 0xc2,
+    0x24, 0x62, 0x24, 0xa8, 0x99, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x86, 0x2a, 0x84, 0x05, 0x65, 0x07,
+    0x30, 0x84, 0x05, 0xb7, 0xb5, 0x09, 0x00, 0x87, 0xb0, 0x05, 0x64, 0xb3, 0x05, 0xa4, 0x00, 0x83,
+    0xc5, 0x85, 0xb1, 0x13, 0x05, 0x85, 0xb0, 0xd3, 0x96, 0x00, 0xa2, 0xb3, 0x04, 0xa4, 0x00, 0x81,
+    0xc6, 0x99, 0xc1, 0x81, 0x45, 0x82, 0x14, 0x32, 0x85, 0xef, 0x40, 0xad, 0xee, 0xcc, 0x44, 0x05,
+    0x49, 0x8b, 0x81, 0x05, 0x01, 0x2a, 0x89, 0x07, 0x30, 0x84, 0x05, 0x37, 0xb5, 0x09, 0x00, 0x87,
+    0x30, 0x85, 0x65, 0x53, 0x15, 0x10, 0xa2, 0x01, 0xcd, 0xef, 0x20, 0xad, 0x93, 0x8b, 0x14, 0x05,
+    0x01, 0xef, 0x40, 0x3d, 0xde
+};
+
+/*
+01 0a f5 7d d7 8b 02 05 02 05 49 23 88 24 01 22 85 ef 40 ad ef aa 85 01 45 8b 81 05 01 4a 85 8c
+40 0b 96 05 01 83 c5 24 04 0b 84 05 02 ef 40 3d 86 8b 12 05 01 01 45 82 14 a0 99 01 45 a0 99 00
+00 00 00 c8 99 22 ac 26 a8 4a a4 32 84 08 22 2e 89 aa 84 ef 80 66 9d 07 30 04 00 53 04 a5 22 53
+05 00 22 ef 80 86 82 07 30 84 00 d3 04 a5 22 53 05 00 22 ef 80 66 9b 07 30 84 00 53 09 a5 22 53
+05 00 22 ef 80 86 80 07 b0 84 00 87 b0 04 00 53 11 84 22 87 b1 04 01 53 70 20 12 d3 70 19 12 c7
+70 05 0a 53 f1 34 12 c3 70 25 0a 27 30 19 00 87 b0 04 00 d3 70 15 12 43 70 09 0a 43 70 29 02 27
+34 09 00 07 b0 84 00 88 4c 53 f0 04 12 43 70 34 02 27 38 09 00 23 2c a9 00 22 29 c2 24 62 24 a8
+99 00 00 dc 99 59 71 a2 ad a6 a9 2a 84 07 30 05 00 87 30 85 00 07 31 05 01 53 84 b5 22 d3 04 a5
+22 ae 84 02 b9 06 bd 8a a1 05 49 ca c5 08 19 8c 18 ef 40 fb d4 07 30 84 02 87 30 04 03 07 31 84
+03 02 a9 06 ad 0a b1 4a d5 28 10 0c 09 13 06 00 02 ef 60 76 fe 28 00 8c 18 13 06 00 02 ef 60 b6
+fd 28 10 2c 00 90 08 b4 00 ef 40 7b ee 46 20 e6 20 53 70 90 12 82 a8 53 f0 90 12 82 ac 88 08 0c
+09 90 18 c5 35 4a 20 ea 20 0a 31 27 34 04 02 27 38 14 02 27 3c 24 02 07 30 04 00 87 b0 04 00 53
+70 10 0a 87 30 84 00 07 b1 84 00 87 31 04 01 07 b2 04 01 02 a9 53 f0 20 0a 02 ad 53 f0 41 0a 02
+b1 4a d5 28 10 0c 09 13 06 00 02 ef 60 d6 f6 28 00 8c 18 13 06 00 02 ef 60 16 f6 28 10 2c 00 90
+08 b4 00 ef 40 db e6 46 20 e6 20 53 70 80 12 82 a8 53 f0 80 12 82 ac 88 08 0c 09 90 18 9d 35 07
+b0 04 00 ca 20 53 70 10 02 27 30 04 00 07 b0 84 00 ea 20 53 70 10 02 27 34 04 00 07 b0 04 01 8a
+30 53 70 10 02 27 38 04 00 ce 24 6e 24 65 61 bc 99 00 00 40 9b 2e 8a aa 84 05 64 13 05 04 b1 b3
+89 a4 00 ef 20 4c f2 83 2a 85 0e ef 30 8d d9 aa 85 26 85 95 3b b3 85 84 00 83 a5 85 b3 25 46 b3
+35 b6 00 33 35 a0 00 6d 8d 15 e1 13 05 84 b7 26 95 b7 b5 09 00 07 b5 05 65 d2 85 ef 40 4d fd 23
+a0 09 00 37 55 04 20 23 2e 05 72 20 9b 13 05 84 b7 33 89 a4 00 63 8a 0a 00 53 05 00 d2 52 85 ca
+85 ef 40 ed fa 05 45 2d a0 37 b5 09 00 07 35 85 5c 37 b5 09 00 87 35 85 64 52 85 ca 85 99 35 37
+b5 09 00 07 35 05 65 4a 85 d2 85 ef 40 4d f8 01 45 23 a0 a9 00 b7 55 04 20 23 ae a5 72 52 85 a6
+85 00 9b 6f f0 1c 92 00 00 00 00 37 b5 09 00 07 30 05 65 53 95 05 a2 11 c5 37 b5 09 00 07 30 85
+65 b9 a8 53 15 05 a2 01 c9 37 b5 09 00 07 30 85 5c 53 70 05 02 a9 a0 37 b5 09 00 07 30 05 66 53
+15 05 a2 01 cd 37 b5 09 00 07 30 85 5c 37 b5 09 00 87 30 85 5e 43 70 15 02 1d a0 37 b5 09 00 07
+30 85 66 53 15 05 a2 01 c9 37 b5 09 00 07 30 85 5c 53 70 05 12 29 a0 37 b5 09 00 07 30 05 67 53
+75 c0 12 82 80 00 00 c0 9b 37 bb 09 00 93 04 4b 6d dc 40 ba 89 36 89 32 8a 2e 84 aa 8a 05 65 93
+05 05 a0 3e 85 01 46 ae 86 ef 30 b7 96 03 25 4b 6d 93 05 80 2d 93 06 80 2d 01 46 ef 30 97 95 22
+85 ef b0 bd e1 83 26 4b 6d d8 40 05 45 d6 85 22 86 ef 90 2d d5 05 c5 03 25 4b 6d 93 95 29 00 13
+06 05 1e 93 06 40 0c 52 85 ef 30 27 b1 d0 40 22 85 d2 85 ca 86 ef 80 bd dd 33 35 a0 00 a0 9b 00
+00 00 00 8b 2f 05 01 81 48 33 28 b0 00 13 13 25 00 93 92 25 00 63 01 08 02 b2 83 36 8e ba 8e ae
+87 5b a5 43 a0 db 25 4e a0 53 75 b5 10 27 a0 ae 00 fd 17 9a 9e f5 f7 85 08 11 07 16 96 e3 9c a8
+fc 82 80 7e 95
+*/
+const char g_cfg_cmd10[] = {
+    0x01, 0x0a, 0xf5, 0x7d, 0xd7, 0x8b, 0x02, 0x05, 0x02, 0x05, 0x49, 0x23, 0x88, 0x24, 0x01, 0x22,
+    0x85, 0xef, 0x40, 0xad, 0xef, 0xaa, 0x85, 0x01, 0x45, 0x8b, 0x81, 0x05, 0x01, 0x4a, 0x85, 0x8c,
+    0x40, 0x0b, 0x96, 0x05, 0x01, 0x83, 0xc5, 0x24, 0x04, 0x0b, 0x84, 0x05, 0x02, 0xef, 0x40, 0x3d,
+    0x86, 0x8b, 0x12, 0x05, 0x01, 0x01, 0x45, 0x82, 0x14, 0xa0, 0x99, 0x01, 0x45, 0xa0, 0x99, 0x00,
+    0x00, 0x00, 0x00, 0xc8, 0x99, 0x22, 0xac, 0x26, 0xa8, 0x4a, 0xa4, 0x32, 0x84, 0x08, 0x22, 0x2e,
+    0x89, 0xaa, 0x84, 0xef, 0x80, 0x66, 0x9d, 0x07, 0x30, 0x04, 0x00, 0x53, 0x04, 0xa5, 0x22, 0x53,
+    0x05, 0x00, 0x22, 0xef, 0x80, 0x86, 0x82, 0x07, 0x30, 0x84, 0x00, 0xd3, 0x04, 0xa5, 0x22, 0x53,
+    0x05, 0x00, 0x22, 0xef, 0x80, 0x66, 0x9b, 0x07, 0x30, 0x84, 0x00, 0x53, 0x09, 0xa5, 0x22, 0x53,
+    0x05, 0x00, 0x22, 0xef, 0x80, 0x86, 0x80, 0x07, 0xb0, 0x84, 0x00, 0x87, 0xb0, 0x04, 0x00, 0x53,
+    0x11, 0x84, 0x22, 0x87, 0xb1, 0x04, 0x01, 0x53, 0x70, 0x20, 0x12, 0xd3, 0x70, 0x19, 0x12, 0xc7,
+    0x70, 0x05, 0x0a, 0x53, 0xf1, 0x34, 0x12, 0xc3, 0x70, 0x25, 0x0a, 0x27, 0x30, 0x19, 0x00, 0x87,
+    0xb0, 0x04, 0x00, 0xd3, 0x70, 0x15, 0x12, 0x43, 0x70, 0x09, 0x0a, 0x43, 0x70, 0x29, 0x02, 0x27,
+    0x34, 0x09, 0x00, 0x07, 0xb0, 0x84, 0x00, 0x88, 0x4c, 0x53, 0xf0, 0x04, 0x12, 0x43, 0x70, 0x34,
+    0x02, 0x27, 0x38, 0x09, 0x00, 0x23, 0x2c, 0xa9, 0x00, 0x22, 0x29, 0xc2, 0x24, 0x62, 0x24, 0xa8,
+    0x99, 0x00, 0x00, 0xdc, 0x99, 0x59, 0x71, 0xa2, 0xad, 0xa6, 0xa9, 0x2a, 0x84, 0x07, 0x30, 0x05,
+    0x00, 0x87, 0x30, 0x85, 0x00, 0x07, 0x31, 0x05, 0x01, 0x53, 0x84, 0xb5, 0x22, 0xd3, 0x04, 0xa5,
+    0x22, 0xae, 0x84, 0x02, 0xb9, 0x06, 0xbd, 0x8a, 0xa1, 0x05, 0x49, 0xca, 0xc5, 0x08, 0x19, 0x8c,
+    0x18, 0xef, 0x40, 0xfb, 0xd4, 0x07, 0x30, 0x84, 0x02, 0x87, 0x30, 0x04, 0x03, 0x07, 0x31, 0x84,
+    0x03, 0x02, 0xa9, 0x06, 0xad, 0x0a, 0xb1, 0x4a, 0xd5, 0x28, 0x10, 0x0c, 0x09, 0x13, 0x06, 0x00,
+    0x02, 0xef, 0x60, 0x76, 0xfe, 0x28, 0x00, 0x8c, 0x18, 0x13, 0x06, 0x00, 0x02, 0xef, 0x60, 0xb6,
+    0xfd, 0x28, 0x10, 0x2c, 0x00, 0x90, 0x08, 0xb4, 0x00, 0xef, 0x40, 0x7b, 0xee, 0x46, 0x20, 0xe6,
+    0x20, 0x53, 0x70, 0x90, 0x12, 0x82, 0xa8, 0x53, 0xf0, 0x90, 0x12, 0x82, 0xac, 0x88, 0x08, 0x0c,
+    0x09, 0x90, 0x18, 0xc5, 0x35, 0x4a, 0x20, 0xea, 0x20, 0x0a, 0x31, 0x27, 0x34, 0x04, 0x02, 0x27,
+    0x38, 0x14, 0x02, 0x27, 0x3c, 0x24, 0x02, 0x07, 0x30, 0x04, 0x00, 0x87, 0xb0, 0x04, 0x00, 0x53,
+    0x70, 0x10, 0x0a, 0x87, 0x30, 0x84, 0x00, 0x07, 0xb1, 0x84, 0x00, 0x87, 0x31, 0x04, 0x01, 0x07,
+    0xb2, 0x04, 0x01, 0x02, 0xa9, 0x53, 0xf0, 0x20, 0x0a, 0x02, 0xad, 0x53, 0xf0, 0x41, 0x0a, 0x02,
+    0xb1, 0x4a, 0xd5, 0x28, 0x10, 0x0c, 0x09, 0x13, 0x06, 0x00, 0x02, 0xef, 0x60, 0xd6, 0xf6, 0x28,
+    0x00, 0x8c, 0x18, 0x13, 0x06, 0x00, 0x02, 0xef, 0x60, 0x16, 0xf6, 0x28, 0x10, 0x2c, 0x00, 0x90,
+    0x08, 0xb4, 0x00, 0xef, 0x40, 0xdb, 0xe6, 0x46, 0x20, 0xe6, 0x20, 0x53, 0x70, 0x80, 0x12, 0x82,
+    0xa8, 0x53, 0xf0, 0x80, 0x12, 0x82, 0xac, 0x88, 0x08, 0x0c, 0x09, 0x90, 0x18, 0x9d, 0x35, 0x07,
+    0xb0, 0x04, 0x00, 0xca, 0x20, 0x53, 0x70, 0x10, 0x02, 0x27, 0x30, 0x04, 0x00, 0x07, 0xb0, 0x84,
+    0x00, 0xea, 0x20, 0x53, 0x70, 0x10, 0x02, 0x27, 0x34, 0x04, 0x00, 0x07, 0xb0, 0x04, 0x01, 0x8a,
+    0x30, 0x53, 0x70, 0x10, 0x02, 0x27, 0x38, 0x04, 0x00, 0xce, 0x24, 0x6e, 0x24, 0x65, 0x61, 0xbc,
+    0x99, 0x00, 0x00, 0x40, 0x9b, 0x2e, 0x8a, 0xaa, 0x84, 0x05, 0x64, 0x13, 0x05, 0x04, 0xb1, 0xb3,
+    0x89, 0xa4, 0x00, 0xef, 0x20, 0x4c, 0xf2, 0x83, 0x2a, 0x85, 0x0e, 0xef, 0x30, 0x8d, 0xd9, 0xaa,
+    0x85, 0x26, 0x85, 0x95, 0x3b, 0xb3, 0x85, 0x84, 0x00, 0x83, 0xa5, 0x85, 0xb3, 0x25, 0x46, 0xb3,
+    0x35, 0xb6, 0x00, 0x33, 0x35, 0xa0, 0x00, 0x6d, 0x8d, 0x15, 0xe1, 0x13, 0x05, 0x84, 0xb7, 0x26,
+    0x95, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb5, 0x05, 0x65, 0xd2, 0x85, 0xef, 0x40, 0x4d, 0xfd, 0x23,
+    0xa0, 0x09, 0x00, 0x37, 0x55, 0x04, 0x20, 0x23, 0x2e, 0x05, 0x72, 0x20, 0x9b, 0x13, 0x05, 0x84,
+    0xb7, 0x33, 0x89, 0xa4, 0x00, 0x63, 0x8a, 0x0a, 0x00, 0x53, 0x05, 0x00, 0xd2, 0x52, 0x85, 0xca,
+    0x85, 0xef, 0x40, 0xed, 0xfa, 0x05, 0x45, 0x2d, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x35, 0x85,
+    0x5c, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x35, 0x85, 0x64, 0x52, 0x85, 0xca, 0x85, 0x99, 0x35, 0x37,
+    0xb5, 0x09, 0x00, 0x07, 0x35, 0x05, 0x65, 0x4a, 0x85, 0xd2, 0x85, 0xef, 0x40, 0x4d, 0xf8, 0x01,
+    0x45, 0x23, 0xa0, 0xa9, 0x00, 0xb7, 0x55, 0x04, 0x20, 0x23, 0xae, 0xa5, 0x72, 0x52, 0x85, 0xa6,
+    0x85, 0x00, 0x9b, 0x6f, 0xf0, 0x1c, 0x92, 0x00, 0x00, 0x00, 0x00, 0x37, 0xb5, 0x09, 0x00, 0x07,
+    0x30, 0x05, 0x65, 0x53, 0x95, 0x05, 0xa2, 0x11, 0xc5, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85,
+    0x65, 0xb9, 0xa8, 0x53, 0x15, 0x05, 0xa2, 0x01, 0xc9, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85,
+    0x5c, 0x53, 0x70, 0x05, 0x02, 0xa9, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x66, 0x53,
+    0x15, 0x05, 0xa2, 0x01, 0xcd, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x5c, 0x37, 0xb5, 0x09,
+    0x00, 0x87, 0x30, 0x85, 0x5e, 0x43, 0x70, 0x15, 0x02, 0x1d, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07,
+    0x30, 0x85, 0x66, 0x53, 0x15, 0x05, 0xa2, 0x01, 0xc9, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x85,
+    0x5c, 0x53, 0x70, 0x05, 0x12, 0x29, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x07, 0x30, 0x05, 0x67, 0x53,
+    0x75, 0xc0, 0x12, 0x82, 0x80, 0x00, 0x00, 0xc0, 0x9b, 0x37, 0xbb, 0x09, 0x00, 0x93, 0x04, 0x4b,
+    0x6d, 0xdc, 0x40, 0xba, 0x89, 0x36, 0x89, 0x32, 0x8a, 0x2e, 0x84, 0xaa, 0x8a, 0x05, 0x65, 0x93,
+    0x05, 0x05, 0xa0, 0x3e, 0x85, 0x01, 0x46, 0xae, 0x86, 0xef, 0x30, 0xb7, 0x96, 0x03, 0x25, 0x4b,
+    0x6d, 0x93, 0x05, 0x80, 0x2d, 0x93, 0x06, 0x80, 0x2d, 0x01, 0x46, 0xef, 0x30, 0x97, 0x95, 0x22,
+    0x85, 0xef, 0xb0, 0xbd, 0xe1, 0x83, 0x26, 0x4b, 0x6d, 0xd8, 0x40, 0x05, 0x45, 0xd6, 0x85, 0x22,
+    0x86, 0xef, 0x90, 0x2d, 0xd5, 0x05, 0xc5, 0x03, 0x25, 0x4b, 0x6d, 0x93, 0x95, 0x29, 0x00, 0x13,
+    0x06, 0x05, 0x1e, 0x93, 0x06, 0x40, 0x0c, 0x52, 0x85, 0xef, 0x30, 0x27, 0xb1, 0xd0, 0x40, 0x22,
+    0x85, 0xd2, 0x85, 0xca, 0x86, 0xef, 0x80, 0xbd, 0xdd, 0x33, 0x35, 0xa0, 0x00, 0xa0, 0x9b, 0x00,
+    0x00, 0x00, 0x00, 0x8b, 0x2f, 0x05, 0x01, 0x81, 0x48, 0x33, 0x28, 0xb0, 0x00, 0x13, 0x13, 0x25,
+    0x00, 0x93, 0x92, 0x25, 0x00, 0x63, 0x01, 0x08, 0x02, 0xb2, 0x83, 0x36, 0x8e, 0xba, 0x8e, 0xae,
+    0x87, 0x5b, 0xa5, 0x43, 0xa0, 0xdb, 0x25, 0x4e, 0xa0, 0x53, 0x75, 0xb5, 0x10, 0x27, 0xa0, 0xae,
+    0x00, 0xfd, 0x17, 0x9a, 0x9e, 0xf5, 0xf7, 0x85, 0x08, 0x11, 0x07, 0x16, 0x96, 0xe3, 0x9c, 0xa8,
+    0xfc, 0x82, 0x80, 0x7e, 0x95
+};
+
+/*
+01 0b f4 00 00 00 00 48 9e 22 b0 26 ac 80 10 83 2a 44 00 83 2d 04 00 2a 89 37 b5 09 00 63 d5 ba
+01 07 24 85 67 a1 aa c6 89 be 84 36 8c 2e 8b 23 24 e4 fa 23 26 04 fb 23 28 c4 fa 23 2a 24 fa 3d
+45 ab 05 55 05 c1 99 33 0a b1 40 52 81 b3 85 ba 03 ab 05 b5 04 c1 99 33 0d b1 40 6a 81 b3 0c b1
+40 66 81 ab 05 b5 05 c1 99 b3 05 b1 40 23 22 b4 fa 2e 81 b3 85 bd 03 2b 05 b5 04 41 99 b3 0b a1
+40 5e 81 93 95 2a 00 52 85 01 46 ae 86 ef 30 77 84 6a 85 e2 85 56 86 ee 86 5a 87 ef e0 cd 95 0b
+a9 0a 01 13 05 f9 ff 13 35 15 00 d6 85 52 86 5b a5 44 a0 d3 75 a5 10 ab 65 a5 38 fd 15 5b 22 b6
+e0 fd f5 6e 85 d6 85 6a 86 d2 86 66 87 dd 3d 37 b5 09 00 87 24 c5 67 d3 05 00 f0 53 04 00 f0 01
+45 ee 85 6e 86 d6 86 53 85 94 20 66 87 ea 87 5e 88 ef e0 ed 8a 5e 85 ee 85 ef e0 ad ca 11 c5 37
+b5 09 00 07 24 85 67 b1 a8 8b a7 0d 01 11 45 2b 05 b5 05 53 04 00 f0 de 85 6e 86 88 61 53 74 a4
+00 7d 16 aa 95 7d fa 05 46 d3 05 00 f0 01 45 ee 85 d6 86 53 85 94 20 66 87 83 27 84 fa 83 24 44
+fa 26 88 ef e0 cd 85 05 46 d3 05 00 f0 01 45 ee 85 ee 86 53 85 94 20 5e 87 a6 87 03 28 c4 fa ef
+e0 0d 84 83 24 44 fb 63 8a 09 00 5e 85 ce 85 6e 86 ee 86 03 27 04 fb ef e0 8d 8b 26 81 53 05 84
+20 13 01 04 fa e2 24 02 34 28 9e c0 98 2a 84 ef 20 8c bb 81 45 37 b6 09 00 13 06 c6 6d b3 86 c5
+00 83 c6 06 00 63 86 86 00 a1 05 8b 9c f5 28 01 a8 08 41 b2 95 cc 41 e9 8d 05 45 91 c1 a0 98 01
+45 a0 98 00 00 00 00 c0 99 2e 84 aa 84 ef c0 2b 87 15 c5 ef 40 0e ae 37 b5 09 00 87 25 05 68 53
+85 a5 a0 05 49 09 ed e0 91 26 85 ef 70 9e 9e 37 b5 09 00 07 30 85 68 53 15 05 a2 11 c1 01 49 4a
+85 a0 99 00 00 00 00 c0 9b 0b c9 15 e4 ae 89 2a 89 01 45 a5 3f 21 cd 31 4a 05 44 13 0b 40 0e a0
+90 26 85 ef 90 dc b2 aa 8a 01 45 a6 85 69 3f 0b 16 05 01 33 05 49 01 b3 85 49 41 93 06 80 0d 56
+86 ef 30 a7 87 5a 8a 13 35 04 02 05 04 13 0b 8a 0d b3 b5 69 01 e4 9d 6d 8d 79 f1 93 05 4a ff 0d
+45 05 46 ca 86 4e 87 ef 00 9e 95 11 a0 01 4a 52 85 a0 9b 00 00 00 00 40 9b 8b c8 15 e4 ae 89 2a
+89 0d 45 21 37 39 c9 31 4a 85 44 13 04 40 0e 64 91 ef c0 7a e3 aa 8a a4 91 0d 45 35 37 0b 16 05
+01 33 05 49 01 b3 85 49 41 93 06 80 0d 56 86 ef 30 c7 80 22 8a 13 b5 24 03 85 04 13 04 8a 0d b3
+b5 89 00 e4 9d 6d 8d 61 f5 93 05 4a ff 1d 45 05 46 ca 86 4e 87 ef 00 be 8e 11 a0 01 4a 52 85 20
+9b 00 00 c0 9b 0b c9 15 d4 ae 89 2a 89 19 45 71 3d 21 cd 31 4a 05 44 13 0b 40 0d a0 90 26 85 ef
+d0 9b a5 aa 8a 19 45 a6 85 7d 3d 0b 16 05 01 33 05 49 01 b3 85 49 41 93 06 80 0c 56 86 ef 20 f7
+f9 5a 8a 13 35 44 02 05 04 13 0b 8a 0c b3 b5 69 01 e4 9d 6d 8d 79 f1 93 05 4a ff 39 45 05 46 ca
+86 4e 87 ef 00 de 87 11 a0 01 4a 52 85 a0 9b 00 00 00 00 c0 9b 0b ca 15 bc ae 89 2a 89 05 45 05
+44 2d 35 29 cd 31 4a 13 0b c0 0b a0 90 26 85 ef f0 0b db aa 8a 05 45 a6 85 b9 35 0b 17 05 01 23
+96 8a 0a 33 05 49 01 b3 85 49 41 93 06 00 0b 56 86 ef 20 b7 f2 5a 8a 13 35 84 01 05 04 13 0b 0a
+0b b3 b5 69 01 e4 9d 6d 8d 69 f1 93 05 4a ff 55 45 05 46 ca 86 4e 87 ef 00 9e 80 11 a0 01 4a 52
+85 a0 9b 00 00 00 00 37 c5 04 20 13 05 85 f6 83 25 05 16 07 30 85 12 37 b5 09 00 87 30 85 5c 37
+b5 09 00 07 31 05 69 33 35 b0 00 d3 85 00 a2 6d 8d d3 05 20 a2 6d 8d 82 80 00 00 37 b5 09 00 03
+45 25 71 3a 36
+*/
+const char g_cfg_cmd11[] = {
+    0x01, 0x0b, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x48, 0x9e, 0x22, 0xb0, 0x26, 0xac, 0x80, 0x10, 0x83,
+    0x2a, 0x44, 0x00, 0x83, 0x2d, 0x04, 0x00, 0x2a, 0x89, 0x37, 0xb5, 0x09, 0x00, 0x63, 0xd5, 0xba,
+    0x01, 0x07, 0x24, 0x85, 0x67, 0xa1, 0xaa, 0xc6, 0x89, 0xbe, 0x84, 0x36, 0x8c, 0x2e, 0x8b, 0x23,
+    0x24, 0xe4, 0xfa, 0x23, 0x26, 0x04, 0xfb, 0x23, 0x28, 0xc4, 0xfa, 0x23, 0x2a, 0x24, 0xfa, 0x3d,
+    0x45, 0xab, 0x05, 0x55, 0x05, 0xc1, 0x99, 0x33, 0x0a, 0xb1, 0x40, 0x52, 0x81, 0xb3, 0x85, 0xba,
+    0x03, 0xab, 0x05, 0xb5, 0x04, 0xc1, 0x99, 0x33, 0x0d, 0xb1, 0x40, 0x6a, 0x81, 0xb3, 0x0c, 0xb1,
+    0x40, 0x66, 0x81, 0xab, 0x05, 0xb5, 0x05, 0xc1, 0x99, 0xb3, 0x05, 0xb1, 0x40, 0x23, 0x22, 0xb4,
+    0xfa, 0x2e, 0x81, 0xb3, 0x85, 0xbd, 0x03, 0x2b, 0x05, 0xb5, 0x04, 0x41, 0x99, 0xb3, 0x0b, 0xa1,
+    0x40, 0x5e, 0x81, 0x93, 0x95, 0x2a, 0x00, 0x52, 0x85, 0x01, 0x46, 0xae, 0x86, 0xef, 0x30, 0x77,
+    0x84, 0x6a, 0x85, 0xe2, 0x85, 0x56, 0x86, 0xee, 0x86, 0x5a, 0x87, 0xef, 0xe0, 0xcd, 0x95, 0x0b,
+    0xa9, 0x0a, 0x01, 0x13, 0x05, 0xf9, 0xff, 0x13, 0x35, 0x15, 0x00, 0xd6, 0x85, 0x52, 0x86, 0x5b,
+    0xa5, 0x44, 0xa0, 0xd3, 0x75, 0xa5, 0x10, 0xab, 0x65, 0xa5, 0x38, 0xfd, 0x15, 0x5b, 0x22, 0xb6,
+    0xe0, 0xfd, 0xf5, 0x6e, 0x85, 0xd6, 0x85, 0x6a, 0x86, 0xd2, 0x86, 0x66, 0x87, 0xdd, 0x3d, 0x37,
+    0xb5, 0x09, 0x00, 0x87, 0x24, 0xc5, 0x67, 0xd3, 0x05, 0x00, 0xf0, 0x53, 0x04, 0x00, 0xf0, 0x01,
+    0x45, 0xee, 0x85, 0x6e, 0x86, 0xd6, 0x86, 0x53, 0x85, 0x94, 0x20, 0x66, 0x87, 0xea, 0x87, 0x5e,
+    0x88, 0xef, 0xe0, 0xed, 0x8a, 0x5e, 0x85, 0xee, 0x85, 0xef, 0xe0, 0xad, 0xca, 0x11, 0xc5, 0x37,
+    0xb5, 0x09, 0x00, 0x07, 0x24, 0x85, 0x67, 0xb1, 0xa8, 0x8b, 0xa7, 0x0d, 0x01, 0x11, 0x45, 0x2b,
+    0x05, 0xb5, 0x05, 0x53, 0x04, 0x00, 0xf0, 0xde, 0x85, 0x6e, 0x86, 0x88, 0x61, 0x53, 0x74, 0xa4,
+    0x00, 0x7d, 0x16, 0xaa, 0x95, 0x7d, 0xfa, 0x05, 0x46, 0xd3, 0x05, 0x00, 0xf0, 0x01, 0x45, 0xee,
+    0x85, 0xd6, 0x86, 0x53, 0x85, 0x94, 0x20, 0x66, 0x87, 0x83, 0x27, 0x84, 0xfa, 0x83, 0x24, 0x44,
+    0xfa, 0x26, 0x88, 0xef, 0xe0, 0xcd, 0x85, 0x05, 0x46, 0xd3, 0x05, 0x00, 0xf0, 0x01, 0x45, 0xee,
+    0x85, 0xee, 0x86, 0x53, 0x85, 0x94, 0x20, 0x5e, 0x87, 0xa6, 0x87, 0x03, 0x28, 0xc4, 0xfa, 0xef,
+    0xe0, 0x0d, 0x84, 0x83, 0x24, 0x44, 0xfb, 0x63, 0x8a, 0x09, 0x00, 0x5e, 0x85, 0xce, 0x85, 0x6e,
+    0x86, 0xee, 0x86, 0x03, 0x27, 0x04, 0xfb, 0xef, 0xe0, 0x8d, 0x8b, 0x26, 0x81, 0x53, 0x05, 0x84,
+    0x20, 0x13, 0x01, 0x04, 0xfa, 0xe2, 0x24, 0x02, 0x34, 0x28, 0x9e, 0xc0, 0x98, 0x2a, 0x84, 0xef,
+    0x20, 0x8c, 0xbb, 0x81, 0x45, 0x37, 0xb6, 0x09, 0x00, 0x13, 0x06, 0xc6, 0x6d, 0xb3, 0x86, 0xc5,
+    0x00, 0x83, 0xc6, 0x06, 0x00, 0x63, 0x86, 0x86, 0x00, 0xa1, 0x05, 0x8b, 0x9c, 0xf5, 0x28, 0x01,
+    0xa8, 0x08, 0x41, 0xb2, 0x95, 0xcc, 0x41, 0xe9, 0x8d, 0x05, 0x45, 0x91, 0xc1, 0xa0, 0x98, 0x01,
+    0x45, 0xa0, 0x98, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x99, 0x2e, 0x84, 0xaa, 0x84, 0xef, 0xc0, 0x2b,
+    0x87, 0x15, 0xc5, 0xef, 0x40, 0x0e, 0xae, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x25, 0x05, 0x68, 0x53,
+    0x85, 0xa5, 0xa0, 0x05, 0x49, 0x09, 0xed, 0xe0, 0x91, 0x26, 0x85, 0xef, 0x70, 0x9e, 0x9e, 0x37,
+    0xb5, 0x09, 0x00, 0x07, 0x30, 0x85, 0x68, 0x53, 0x15, 0x05, 0xa2, 0x11, 0xc1, 0x01, 0x49, 0x4a,
+    0x85, 0xa0, 0x99, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xc9, 0x15, 0xe4, 0xae, 0x89, 0x2a,
+    0x89, 0x01, 0x45, 0xa5, 0x3f, 0x21, 0xcd, 0x31, 0x4a, 0x05, 0x44, 0x13, 0x0b, 0x40, 0x0e, 0xa0,
+    0x90, 0x26, 0x85, 0xef, 0x90, 0xdc, 0xb2, 0xaa, 0x8a, 0x01, 0x45, 0xa6, 0x85, 0x69, 0x3f, 0x0b,
+    0x16, 0x05, 0x01, 0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0d, 0x56,
+    0x86, 0xef, 0x30, 0xa7, 0x87, 0x5a, 0x8a, 0x13, 0x35, 0x04, 0x02, 0x05, 0x04, 0x13, 0x0b, 0x8a,
+    0x0d, 0xb3, 0xb5, 0x69, 0x01, 0xe4, 0x9d, 0x6d, 0x8d, 0x79, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x0d,
+    0x45, 0x05, 0x46, 0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0x9e, 0x95, 0x11, 0xa0, 0x01, 0x4a, 0x52,
+    0x85, 0xa0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9b, 0x8b, 0xc8, 0x15, 0xe4, 0xae, 0x89, 0x2a,
+    0x89, 0x0d, 0x45, 0x21, 0x37, 0x39, 0xc9, 0x31, 0x4a, 0x85, 0x44, 0x13, 0x04, 0x40, 0x0e, 0x64,
+    0x91, 0xef, 0xc0, 0x7a, 0xe3, 0xaa, 0x8a, 0xa4, 0x91, 0x0d, 0x45, 0x35, 0x37, 0x0b, 0x16, 0x05,
+    0x01, 0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0d, 0x56, 0x86, 0xef,
+    0x30, 0xc7, 0x80, 0x22, 0x8a, 0x13, 0xb5, 0x24, 0x03, 0x85, 0x04, 0x13, 0x04, 0x8a, 0x0d, 0xb3,
+    0xb5, 0x89, 0x00, 0xe4, 0x9d, 0x6d, 0x8d, 0x61, 0xf5, 0x93, 0x05, 0x4a, 0xff, 0x1d, 0x45, 0x05,
+    0x46, 0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0xbe, 0x8e, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85, 0x20,
+    0x9b, 0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xc9, 0x15, 0xd4, 0xae, 0x89, 0x2a, 0x89, 0x19, 0x45, 0x71,
+    0x3d, 0x21, 0xcd, 0x31, 0x4a, 0x05, 0x44, 0x13, 0x0b, 0x40, 0x0d, 0xa0, 0x90, 0x26, 0x85, 0xef,
+    0xd0, 0x9b, 0xa5, 0xaa, 0x8a, 0x19, 0x45, 0xa6, 0x85, 0x7d, 0x3d, 0x0b, 0x16, 0x05, 0x01, 0x33,
+    0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x80, 0x0c, 0x56, 0x86, 0xef, 0x20, 0xf7,
+    0xf9, 0x5a, 0x8a, 0x13, 0x35, 0x44, 0x02, 0x05, 0x04, 0x13, 0x0b, 0x8a, 0x0c, 0xb3, 0xb5, 0x69,
+    0x01, 0xe4, 0x9d, 0x6d, 0x8d, 0x79, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x39, 0x45, 0x05, 0x46, 0xca,
+    0x86, 0x4e, 0x87, 0xef, 0x00, 0xde, 0x87, 0x11, 0xa0, 0x01, 0x4a, 0x52, 0x85, 0xa0, 0x9b, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0x9b, 0x0b, 0xca, 0x15, 0xbc, 0xae, 0x89, 0x2a, 0x89, 0x05, 0x45, 0x05,
+    0x44, 0x2d, 0x35, 0x29, 0xcd, 0x31, 0x4a, 0x13, 0x0b, 0xc0, 0x0b, 0xa0, 0x90, 0x26, 0x85, 0xef,
+    0xf0, 0x0b, 0xdb, 0xaa, 0x8a, 0x05, 0x45, 0xa6, 0x85, 0xb9, 0x35, 0x0b, 0x17, 0x05, 0x01, 0x23,
+    0x96, 0x8a, 0x0a, 0x33, 0x05, 0x49, 0x01, 0xb3, 0x85, 0x49, 0x41, 0x93, 0x06, 0x00, 0x0b, 0x56,
+    0x86, 0xef, 0x20, 0xb7, 0xf2, 0x5a, 0x8a, 0x13, 0x35, 0x84, 0x01, 0x05, 0x04, 0x13, 0x0b, 0x0a,
+    0x0b, 0xb3, 0xb5, 0x69, 0x01, 0xe4, 0x9d, 0x6d, 0x8d, 0x69, 0xf1, 0x93, 0x05, 0x4a, 0xff, 0x55,
+    0x45, 0x05, 0x46, 0xca, 0x86, 0x4e, 0x87, 0xef, 0x00, 0x9e, 0x80, 0x11, 0xa0, 0x01, 0x4a, 0x52,
+    0x85, 0xa0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x37, 0xc5, 0x04, 0x20, 0x13, 0x05, 0x85, 0xf6, 0x83,
+    0x25, 0x05, 0x16, 0x07, 0x30, 0x85, 0x12, 0x37, 0xb5, 0x09, 0x00, 0x87, 0x30, 0x85, 0x5c, 0x37,
+    0xb5, 0x09, 0x00, 0x07, 0x31, 0x05, 0x69, 0x33, 0x35, 0xb0, 0x00, 0xd3, 0x85, 0x00, 0xa2, 0x6d,
+    0x8d, 0xd3, 0x05, 0x20, 0xa2, 0x6d, 0x8d, 0x82, 0x80, 0x00, 0x00, 0x37, 0xb5, 0x09, 0x00, 0x03,
+    0x45, 0x25, 0x71, 0x3a, 0x36
+};
+
+/*
+01 0c f3 82 80 00 00 c0 98 ef 20 ec c2 01 e5 05 44 5d 3f 11 e1 01 44 37 b5 09 00 23 09 85 70 a0
+98 00 00 40 98 37 b5 09 00 03 45 25 71 0d c1 ef e0 1e f9 85 45 a3 00 b5 00 ef 20 ae 90 aa 85 35
+45 0b 84 05 01 ef e0 be f7 8d 45 23 11 b5 00 05 45 20 98 00 00 00 00 dc 9d 13 01 01 dd 27 3c 81
+28 36 84 b2 89 2e 89 28 00 93 05 00 29 7d 56 93 06 00 29 13 0a 81 00 ef 30 c7 c5 28 00 93 05 40
+0a ef 50 7e d5 37 15 09 00 13 05 05 98 ab 05 84 04 33 86 a5 00 83 0a 06 00 13 a6 1a 00 93 b6 19
+00 01 4b 55 8e 51 ea 2e 95 93 0b 15 00 37 b5 09 00 07 34 85 69 05 4c 37 15 09 00 93 0c 45 9a 81
+44 33 85 9b 00 03 44 05 00 13 1d 0c 01 13 5d 0d 41 0b 5f 04 1b 22 85 ea 85 ef 80 6e df 0d c5 ab
+85 8c 04 03 94 25 00 63 40 04 02 ab 05 aa 04 8c 41 8b 85 05 ff ef 70 2e e7 19 c5 28 69 53 00 05
+42 53 05 80 a2 19 cd 85 04 0b 9e e4 04 33 25 5d 01 93 15 0b 01 c1 81 b3 b5 35 01 6d 8d 05 0c 45
+f1 21 a8 33 05 84 01 93 15 0b 01 c1 81 05 0b ab 05 b9 02 23 90 a5 00 d9 bf 13 15 0b 01 41 81 07
+34 81 29 13 01 01 23 bc 9d 00 00 5c 9e 13 01 01 dc 27 38 81 2a 27 34 91 2a 27 30 21 2b 2a c6 63
+0d 05 14 2e 84 01 45 93 09 01 01 fd 55 13 06 00 29 b3 86 a9 00 11 05 8c c2 e3 1c c5 fe 08 08 93
+05 40 0a ef 50 5e c5 13 7a f4 0f 63 07 0a 12 01 45 81 4a b7 b5 09 00 07 b4 85 69 b7 b5 09 00 87
+b4 05 6a b7 15 09 00 13 8b 45 9a 53 09 00 d2 ab 05 ab 04 83 9b 05 00 0b ae 3b 01 32 46 2b 0c a6
+10 93 8c 25 00 85 44 13 f5 fa 0f e4 91 ef 80 2e d0 2a 84 7d 15 28 91 8b 53 35 a3 22 85 ef 70 ae
+d8 83 4d 0c 00 0b d0 3d 24 83 95 0c 00 63 cc 05 0a 2a 8d 1d c1 07 25 0d 05 53 00 05 42 53 05 80
+a2 55 e1 2b 85 89 04 08 41 a6 95 2b 06 bc 03 23 12 b6 00 8b 16 05 ff 15 a8 2b 85 89 04 08 41 8b
+01 25 ff a6 95 2b 06 bc 03 23 12 b6 00 13 34 1d 00 33 09 bc 01 23 0e 09 0c ef 50 3e c5 93 05 15
+00 ab 65 a0 20 23 0e b9 0c 0d ec 07 25 0d 05 53 00 05 42 53 15 04 a2 53 70 90 12 d3 00 29 23 ab
+60 a0 3a d3 95 00 c2 2b 06 bc 03 23 16 b6 04 53 00 29 23 11 cd 07 25 4d 05 53 00 05 42 53 70 90
+12 39 a0 2b 05 bc 03 23 16 05 04 53 00 29 23 53 15 00 c2 ab 05 bc 03 23 9a a5 08 03 05 0c 00 05
+05 23 00 ac 00 13 85 14 00 e8 90 e3 de 9b f0 85 0a 13 f5 fa 0f e3 6d 45 ef 07 39 01 2a 87 34 81
+2a 07 34 01 2b 13 01 01 24 3c 9e 00 00 00 00 c0 99 2e 89 aa 84 93 06 c5 10 37 b5 09 00 13 06 85
+6a 93 05 00 08 4a 85 ef 00 07 ba 63 45 05 06 13 84 04 0d 22 85 ef 60 36 b8 aa 86 93 05 00 08 4a
+85 22 86 ef 70 97 9e 39 e5 93 84 04 0f 26 85 ef 60 96 b6 aa 86 93 05 00 08 4a 85 26 86 ef 70 f7
+9c 15 e9 26 85 ef 60 36 b5 8b 13 05 01 37 b5 09 00 13 04 f5 6a 29 a0 37 b5 09 00 13 04 15 6b 22
+85 ef 60 76 b3 aa 86 93 05 00 08 4a 85 22 86 ef 70 d7 99 11 c1 a0 99 4a 85 ef 60 f6 b1 aa 85 13
+06 00 08 4a 85 ef 60 2e 89 4a 85 ef 60 d6 b0 13 06 00 08 aa 85 4a 85 80 99 6f 60 6e 90 00 00 40
+9a 32 89 ae 89 01 45 01 44 93 85 a5 1b 33 86 a5 00 03 16 06 00 63 43 c0 00 01 46 30 92 09 05 32
+94 0b 1b f5 0c 93 86 c9 10 37 b5 09 00 13 06 85 6b 93 05 00 08 4a 85 ef 00 07 ad 63 47 05 0a 93
+84 09 0d 26 85 ef 60 36 ab aa 86 93 05 00 08 4a 85 26 86 ef 70 97 91 49 e9 93 84 09 03 26 85 ef
+60 96 a9 aa 86 93 05 00 08 4a 85 26 86 ef 70 f7 8f 25 ed 93 84 09 10 26 85 ef 60 f6 a7 aa 86 93
+05 00 08 85 27
+*/
+const char g_cfg_cmd12[] = {
+    0x01, 0x0c, 0xf3, 0x82, 0x80, 0x00, 0x00, 0xc0, 0x98, 0xef, 0x20, 0xec, 0xc2, 0x01, 0xe5, 0x05,
+    0x44, 0x5d, 0x3f, 0x11, 0xe1, 0x01, 0x44, 0x37, 0xb5, 0x09, 0x00, 0x23, 0x09, 0x85, 0x70, 0xa0,
+    0x98, 0x00, 0x00, 0x40, 0x98, 0x37, 0xb5, 0x09, 0x00, 0x03, 0x45, 0x25, 0x71, 0x0d, 0xc1, 0xef,
+    0xe0, 0x1e, 0xf9, 0x85, 0x45, 0xa3, 0x00, 0xb5, 0x00, 0xef, 0x20, 0xae, 0x90, 0xaa, 0x85, 0x35,
+    0x45, 0x0b, 0x84, 0x05, 0x01, 0xef, 0xe0, 0xbe, 0xf7, 0x8d, 0x45, 0x23, 0x11, 0xb5, 0x00, 0x05,
+    0x45, 0x20, 0x98, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x9d, 0x13, 0x01, 0x01, 0xdd, 0x27, 0x3c, 0x81,
+    0x28, 0x36, 0x84, 0xb2, 0x89, 0x2e, 0x89, 0x28, 0x00, 0x93, 0x05, 0x00, 0x29, 0x7d, 0x56, 0x93,
+    0x06, 0x00, 0x29, 0x13, 0x0a, 0x81, 0x00, 0xef, 0x30, 0xc7, 0xc5, 0x28, 0x00, 0x93, 0x05, 0x40,
+    0x0a, 0xef, 0x50, 0x7e, 0xd5, 0x37, 0x15, 0x09, 0x00, 0x13, 0x05, 0x05, 0x98, 0xab, 0x05, 0x84,
+    0x04, 0x33, 0x86, 0xa5, 0x00, 0x83, 0x0a, 0x06, 0x00, 0x13, 0xa6, 0x1a, 0x00, 0x93, 0xb6, 0x19,
+    0x00, 0x01, 0x4b, 0x55, 0x8e, 0x51, 0xea, 0x2e, 0x95, 0x93, 0x0b, 0x15, 0x00, 0x37, 0xb5, 0x09,
+    0x00, 0x07, 0x34, 0x85, 0x69, 0x05, 0x4c, 0x37, 0x15, 0x09, 0x00, 0x93, 0x0c, 0x45, 0x9a, 0x81,
+    0x44, 0x33, 0x85, 0x9b, 0x00, 0x03, 0x44, 0x05, 0x00, 0x13, 0x1d, 0x0c, 0x01, 0x13, 0x5d, 0x0d,
+    0x41, 0x0b, 0x5f, 0x04, 0x1b, 0x22, 0x85, 0xea, 0x85, 0xef, 0x80, 0x6e, 0xdf, 0x0d, 0xc5, 0xab,
+    0x85, 0x8c, 0x04, 0x03, 0x94, 0x25, 0x00, 0x63, 0x40, 0x04, 0x02, 0xab, 0x05, 0xaa, 0x04, 0x8c,
+    0x41, 0x8b, 0x85, 0x05, 0xff, 0xef, 0x70, 0x2e, 0xe7, 0x19, 0xc5, 0x28, 0x69, 0x53, 0x00, 0x05,
+    0x42, 0x53, 0x05, 0x80, 0xa2, 0x19, 0xcd, 0x85, 0x04, 0x0b, 0x9e, 0xe4, 0x04, 0x33, 0x25, 0x5d,
+    0x01, 0x93, 0x15, 0x0b, 0x01, 0xc1, 0x81, 0xb3, 0xb5, 0x35, 0x01, 0x6d, 0x8d, 0x05, 0x0c, 0x45,
+    0xf1, 0x21, 0xa8, 0x33, 0x05, 0x84, 0x01, 0x93, 0x15, 0x0b, 0x01, 0xc1, 0x81, 0x05, 0x0b, 0xab,
+    0x05, 0xb9, 0x02, 0x23, 0x90, 0xa5, 0x00, 0xd9, 0xbf, 0x13, 0x15, 0x0b, 0x01, 0x41, 0x81, 0x07,
+    0x34, 0x81, 0x29, 0x13, 0x01, 0x01, 0x23, 0xbc, 0x9d, 0x00, 0x00, 0x5c, 0x9e, 0x13, 0x01, 0x01,
+    0xdc, 0x27, 0x38, 0x81, 0x2a, 0x27, 0x34, 0x91, 0x2a, 0x27, 0x30, 0x21, 0x2b, 0x2a, 0xc6, 0x63,
+    0x0d, 0x05, 0x14, 0x2e, 0x84, 0x01, 0x45, 0x93, 0x09, 0x01, 0x01, 0xfd, 0x55, 0x13, 0x06, 0x00,
+    0x29, 0xb3, 0x86, 0xa9, 0x00, 0x11, 0x05, 0x8c, 0xc2, 0xe3, 0x1c, 0xc5, 0xfe, 0x08, 0x08, 0x93,
+    0x05, 0x40, 0x0a, 0xef, 0x50, 0x5e, 0xc5, 0x13, 0x7a, 0xf4, 0x0f, 0x63, 0x07, 0x0a, 0x12, 0x01,
+    0x45, 0x81, 0x4a, 0xb7, 0xb5, 0x09, 0x00, 0x07, 0xb4, 0x85, 0x69, 0xb7, 0xb5, 0x09, 0x00, 0x87,
+    0xb4, 0x05, 0x6a, 0xb7, 0x15, 0x09, 0x00, 0x13, 0x8b, 0x45, 0x9a, 0x53, 0x09, 0x00, 0xd2, 0xab,
+    0x05, 0xab, 0x04, 0x83, 0x9b, 0x05, 0x00, 0x0b, 0xae, 0x3b, 0x01, 0x32, 0x46, 0x2b, 0x0c, 0xa6,
+    0x10, 0x93, 0x8c, 0x25, 0x00, 0x85, 0x44, 0x13, 0xf5, 0xfa, 0x0f, 0xe4, 0x91, 0xef, 0x80, 0x2e,
+    0xd0, 0x2a, 0x84, 0x7d, 0x15, 0x28, 0x91, 0x8b, 0x53, 0x35, 0xa3, 0x22, 0x85, 0xef, 0x70, 0xae,
+    0xd8, 0x83, 0x4d, 0x0c, 0x00, 0x0b, 0xd0, 0x3d, 0x24, 0x83, 0x95, 0x0c, 0x00, 0x63, 0xcc, 0x05,
+    0x0a, 0x2a, 0x8d, 0x1d, 0xc1, 0x07, 0x25, 0x0d, 0x05, 0x53, 0x00, 0x05, 0x42, 0x53, 0x05, 0x80,
+    0xa2, 0x55, 0xe1, 0x2b, 0x85, 0x89, 0x04, 0x08, 0x41, 0xa6, 0x95, 0x2b, 0x06, 0xbc, 0x03, 0x23,
+    0x12, 0xb6, 0x00, 0x8b, 0x16, 0x05, 0xff, 0x15, 0xa8, 0x2b, 0x85, 0x89, 0x04, 0x08, 0x41, 0x8b,
+    0x01, 0x25, 0xff, 0xa6, 0x95, 0x2b, 0x06, 0xbc, 0x03, 0x23, 0x12, 0xb6, 0x00, 0x13, 0x34, 0x1d,
+    0x00, 0x33, 0x09, 0xbc, 0x01, 0x23, 0x0e, 0x09, 0x0c, 0xef, 0x50, 0x3e, 0xc5, 0x93, 0x05, 0x15,
+    0x00, 0xab, 0x65, 0xa0, 0x20, 0x23, 0x0e, 0xb9, 0x0c, 0x0d, 0xec, 0x07, 0x25, 0x0d, 0x05, 0x53,
+    0x00, 0x05, 0x42, 0x53, 0x15, 0x04, 0xa2, 0x53, 0x70, 0x90, 0x12, 0xd3, 0x00, 0x29, 0x23, 0xab,
+    0x60, 0xa0, 0x3a, 0xd3, 0x95, 0x00, 0xc2, 0x2b, 0x06, 0xbc, 0x03, 0x23, 0x16, 0xb6, 0x04, 0x53,
+    0x00, 0x29, 0x23, 0x11, 0xcd, 0x07, 0x25, 0x4d, 0x05, 0x53, 0x00, 0x05, 0x42, 0x53, 0x70, 0x90,
+    0x12, 0x39, 0xa0, 0x2b, 0x05, 0xbc, 0x03, 0x23, 0x16, 0x05, 0x04, 0x53, 0x00, 0x29, 0x23, 0x53,
+    0x15, 0x00, 0xc2, 0xab, 0x05, 0xbc, 0x03, 0x23, 0x9a, 0xa5, 0x08, 0x03, 0x05, 0x0c, 0x00, 0x05,
+    0x05, 0x23, 0x00, 0xac, 0x00, 0x13, 0x85, 0x14, 0x00, 0xe8, 0x90, 0xe3, 0xde, 0x9b, 0xf0, 0x85,
+    0x0a, 0x13, 0xf5, 0xfa, 0x0f, 0xe3, 0x6d, 0x45, 0xef, 0x07, 0x39, 0x01, 0x2a, 0x87, 0x34, 0x81,
+    0x2a, 0x07, 0x34, 0x01, 0x2b, 0x13, 0x01, 0x01, 0x24, 0x3c, 0x9e, 0x00, 0x00, 0x00, 0x00, 0xc0,
+    0x99, 0x2e, 0x89, 0xaa, 0x84, 0x93, 0x06, 0xc5, 0x10, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x06, 0x85,
+    0x6a, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x00, 0x07, 0xba, 0x63, 0x45, 0x05, 0x06, 0x13,
+    0x84, 0x04, 0x0d, 0x22, 0x85, 0xef, 0x60, 0x36, 0xb8, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a,
+    0x85, 0x22, 0x86, 0xef, 0x70, 0x97, 0x9e, 0x39, 0xe5, 0x93, 0x84, 0x04, 0x0f, 0x26, 0x85, 0xef,
+    0x60, 0x96, 0xb6, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x26, 0x86, 0xef, 0x70, 0xf7,
+    0x9c, 0x15, 0xe9, 0x26, 0x85, 0xef, 0x60, 0x36, 0xb5, 0x8b, 0x13, 0x05, 0x01, 0x37, 0xb5, 0x09,
+    0x00, 0x13, 0x04, 0xf5, 0x6a, 0x29, 0xa0, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x04, 0x15, 0x6b, 0x22,
+    0x85, 0xef, 0x60, 0x76, 0xb3, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x22, 0x86, 0xef,
+    0x70, 0xd7, 0x99, 0x11, 0xc1, 0xa0, 0x99, 0x4a, 0x85, 0xef, 0x60, 0xf6, 0xb1, 0xaa, 0x85, 0x13,
+    0x06, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x60, 0x2e, 0x89, 0x4a, 0x85, 0xef, 0x60, 0xd6, 0xb0, 0x13,
+    0x06, 0x00, 0x08, 0xaa, 0x85, 0x4a, 0x85, 0x80, 0x99, 0x6f, 0x60, 0x6e, 0x90, 0x00, 0x00, 0x40,
+    0x9a, 0x32, 0x89, 0xae, 0x89, 0x01, 0x45, 0x01, 0x44, 0x93, 0x85, 0xa5, 0x1b, 0x33, 0x86, 0xa5,
+    0x00, 0x03, 0x16, 0x06, 0x00, 0x63, 0x43, 0xc0, 0x00, 0x01, 0x46, 0x30, 0x92, 0x09, 0x05, 0x32,
+    0x94, 0x0b, 0x1b, 0xf5, 0x0c, 0x93, 0x86, 0xc9, 0x10, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x06, 0x85,
+    0x6b, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x00, 0x07, 0xad, 0x63, 0x47, 0x05, 0x0a, 0x93,
+    0x84, 0x09, 0x0d, 0x26, 0x85, 0xef, 0x60, 0x36, 0xab, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a,
+    0x85, 0x26, 0x86, 0xef, 0x70, 0x97, 0x91, 0x49, 0xe9, 0x93, 0x84, 0x09, 0x03, 0x26, 0x85, 0xef,
+    0x60, 0x96, 0xa9, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x26, 0x86, 0xef, 0x70, 0xf7,
+    0x8f, 0x25, 0xed, 0x93, 0x84, 0x09, 0x10, 0x26, 0x85, 0xef, 0x60, 0xf6, 0xa7, 0xaa, 0x86, 0x93,
+    0x05, 0x00, 0x08, 0x85, 0x27
+};
+
+/*
+01 0d f2 4a 85 26 86 ef 70 57 8e 39 ed 93 06 00 08 22 85 81 45 4a 86 ef 50 de f1 4e 85 ef 60 b6
+a5 aa 86 93 05 00 08 4a 85 4e 86 ef 70 17 8c 0d ed 13 84 09 05 22 85 ef 60 16 a4 aa 86 93 05 00
+08 4a 85 22 86 ef 70 77 8a 05 e1 37 b5 09 00 13 04 f5 6b 22 85 ef 60 36 a2 aa 86 93 05 00 08 4a
+85 22 86 ef 70 97 88 11 c1 20 9a 4a 85 ef 60 b6 a0 aa 85 13 06 00 08 4a 85 ef 50 fe f7 4a 85 ef
+60 96 9f 13 06 00 08 aa 85 4a 85 00 9a 6f 50 3e ff 00 00 40 98 ef 10 ae ec b7 c5 04 20 03 a6 85
+0c 81 45 01 e6 85 45 0b 52 05 05 2e 85 20 98 ef b0 5b b0 13 25 55 00 8d 45 33 85 a5 40 20 98 00
+00 00 00 c0 99 2a 84 f1 37 aa 84 ef b0 9b ae 2a 89 84 92 37 b5 09 00 93 04 e5 59 91 45 22 85 26
+86 ef 00 67 9a 63 4a 05 00 13 05 44 00 c1 45 26 86 ca 86 80 99 6f 00 27 99 a0 99 dc 99 7d 71 2e
+89 aa 84 08 10 93 05 00 06 93 06 00 06 01 46 ef 20 57 fc 28 00 d1 45 d1 46 01 46 ef 20 97 fb 37
+05 05 20 13 04 85 c3 22 85 ef 60 2e af 08 10 a2 85 ef 60 2e ab 28 00 71 37 37 b5 09 00 13 06 25
+6c 26 85 ca 85 ef 70 a7 bc 3d e9 10 10 26 85 ca 85 ef 70 e7 bb 2d e5 10 18 26 85 ca 85 ef 70 27
+bb 39 ed 90 00 26 85 ca 85 ef 70 67 ba 29 e9 90 08 26 85 ca 85 ef 70 a7 b9 39 e1 30 00 26 85 ca
+85 ef 70 e7 b8 0d ed 90 10 26 85 ca 85 ef 70 27 b8 1d e5 70 00 26 85 ca 85 ef 70 67 b7 0d e1 26
+85 ef 60 76 8d aa 85 26 85 4a 86 ef 50 de e4 26 85 ef 60 76 8c aa 85 26 85 4a 86 ef 50 5e ec 41
+61 bc 99 7d 71 37 c6 04 20 07 25 86 13 c8 e5 13 05 05 03 53 00 05 42 02 a4 22 47 b2 47 b7 b5 09
+00 13 86 b5 6c c1 45 41 61 6f 00 e7 89 00 00 82 80 00 00 37 45 05 20 23 2a 05 8c 23 28 05 8c 37
+b5 09 00 23 26 05 70 23 24 05 70 82 80 00 00 49 1f 00 00 00 00 00 00 49 1f 00 00 00 00 00 00 00
+00 00 00 49 1f 00 00 c7 31 00 00 63 65 ce 00 05 00 e9 51 47 03 08 00 87 40 04 01 04 00 73 4c 6b
+0b 06 00 87 40 08 02 03 00 88 41 64 08 06 00 88 41 32 04 07 00 43 44 8d 04 07 00 43 44 1a 09 06
+00 63 65 ce 00 05 00 e9 51 47 03 08 00 fd 78 c9 01 05 00 73 4c 6b 0b 06 00 47 6e cd 03 05 00 88
+41 64 08 06 00 00 00 00 00 00 00 43 44 8d 04 07 00 43 44 1a 09 06 00 63 65 ce 00 05 00 e9 51 47
+03 08 00 63 65 ce 00 05 00 e9 51 1c 0d 06 00 aa 79 28 01 05 00 de 7a bf 0e 07 00 00 00 00 00 00
+00 43 44 8d 04 07 00 43 44 1a 09 06 00 63 65 ce 00 05 00 e9 51 47 03 08 00 d3 64 ed 09 02 00 43
+44 35 12 05 00 87 40 08 02 03 00 de 7a 7f 1d 06 00 88 41 32 04 07 00 43 44 8d 04 07 00 43 44 1a
+09 06 00 63 65 ce 00 05 00 e9 51 47 03 08 00 fd 78 c9 01 05 00 43 44 35 12 05 00 47 6e cd 03 05
+00 88 41 64 08 06 00 00 00 00 00 00 00 43 44 8d 04 07 00 43 44 1a 09 06 00 63 65 ce 00 05 00 e9
+51 47 03 08 00 63 65 ce 00 05 00 e9 51 1c 0d 06 00 aa 79 28 01 05 00 de 7a bf 0e 07 00 00 00 00
+00 00 00 43 44 8d 04 07 00 43 44 1a 09 06 00 63 65 ce 00 05 00 e9 51 1c 0d 06 00 87 40 04 01 04
+00 73 4c 6b 0b 06 00 87 40 08 02 03 00 88 41 64 08 06 00 88 41 32 04 07 00 00 00 00 00 00 00 00
+00 00 00 00 00 63 65 ce 00 05 00 e9 51 1c 0d 06 00 fd 78 c9 01 05 00 73 4c 6b 0b 06 00 47 6e cd
+03 05 00 88 41 64 08 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 65 ce 00 05
+00 e9 51 1c 0d 06 00 63 65 ce 00 05 00 e9 51 1c 0d 06 00 aa 79 28 01 05 00 de 7a bf 0e 07 00 00
+00 00 00 93 71
+*/
+const char g_cfg_cmd13[] = {
+    0x01, 0x0d, 0xf2, 0x4a, 0x85, 0x26, 0x86, 0xef, 0x70, 0x57, 0x8e, 0x39, 0xed, 0x93, 0x06, 0x00,
+    0x08, 0x22, 0x85, 0x81, 0x45, 0x4a, 0x86, 0xef, 0x50, 0xde, 0xf1, 0x4e, 0x85, 0xef, 0x60, 0xb6,
+    0xa5, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a, 0x85, 0x4e, 0x86, 0xef, 0x70, 0x17, 0x8c, 0x0d,
+    0xed, 0x13, 0x84, 0x09, 0x05, 0x22, 0x85, 0xef, 0x60, 0x16, 0xa4, 0xaa, 0x86, 0x93, 0x05, 0x00,
+    0x08, 0x4a, 0x85, 0x22, 0x86, 0xef, 0x70, 0x77, 0x8a, 0x05, 0xe1, 0x37, 0xb5, 0x09, 0x00, 0x13,
+    0x04, 0xf5, 0x6b, 0x22, 0x85, 0xef, 0x60, 0x36, 0xa2, 0xaa, 0x86, 0x93, 0x05, 0x00, 0x08, 0x4a,
+    0x85, 0x22, 0x86, 0xef, 0x70, 0x97, 0x88, 0x11, 0xc1, 0x20, 0x9a, 0x4a, 0x85, 0xef, 0x60, 0xb6,
+    0xa0, 0xaa, 0x85, 0x13, 0x06, 0x00, 0x08, 0x4a, 0x85, 0xef, 0x50, 0xfe, 0xf7, 0x4a, 0x85, 0xef,
+    0x60, 0x96, 0x9f, 0x13, 0x06, 0x00, 0x08, 0xaa, 0x85, 0x4a, 0x85, 0x00, 0x9a, 0x6f, 0x50, 0x3e,
+    0xff, 0x00, 0x00, 0x40, 0x98, 0xef, 0x10, 0xae, 0xec, 0xb7, 0xc5, 0x04, 0x20, 0x03, 0xa6, 0x85,
+    0x0c, 0x81, 0x45, 0x01, 0xe6, 0x85, 0x45, 0x0b, 0x52, 0x05, 0x05, 0x2e, 0x85, 0x20, 0x98, 0xef,
+    0xb0, 0x5b, 0xb0, 0x13, 0x25, 0x55, 0x00, 0x8d, 0x45, 0x33, 0x85, 0xa5, 0x40, 0x20, 0x98, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0x99, 0x2a, 0x84, 0xf1, 0x37, 0xaa, 0x84, 0xef, 0xb0, 0x9b, 0xae, 0x2a,
+    0x89, 0x84, 0x92, 0x37, 0xb5, 0x09, 0x00, 0x93, 0x04, 0xe5, 0x59, 0x91, 0x45, 0x22, 0x85, 0x26,
+    0x86, 0xef, 0x00, 0x67, 0x9a, 0x63, 0x4a, 0x05, 0x00, 0x13, 0x05, 0x44, 0x00, 0xc1, 0x45, 0x26,
+    0x86, 0xca, 0x86, 0x80, 0x99, 0x6f, 0x00, 0x27, 0x99, 0xa0, 0x99, 0xdc, 0x99, 0x7d, 0x71, 0x2e,
+    0x89, 0xaa, 0x84, 0x08, 0x10, 0x93, 0x05, 0x00, 0x06, 0x93, 0x06, 0x00, 0x06, 0x01, 0x46, 0xef,
+    0x20, 0x57, 0xfc, 0x28, 0x00, 0xd1, 0x45, 0xd1, 0x46, 0x01, 0x46, 0xef, 0x20, 0x97, 0xfb, 0x37,
+    0x05, 0x05, 0x20, 0x13, 0x04, 0x85, 0xc3, 0x22, 0x85, 0xef, 0x60, 0x2e, 0xaf, 0x08, 0x10, 0xa2,
+    0x85, 0xef, 0x60, 0x2e, 0xab, 0x28, 0x00, 0x71, 0x37, 0x37, 0xb5, 0x09, 0x00, 0x13, 0x06, 0x25,
+    0x6c, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0xa7, 0xbc, 0x3d, 0xe9, 0x10, 0x10, 0x26, 0x85, 0xca,
+    0x85, 0xef, 0x70, 0xe7, 0xbb, 0x2d, 0xe5, 0x10, 0x18, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x27,
+    0xbb, 0x39, 0xed, 0x90, 0x00, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x67, 0xba, 0x29, 0xe9, 0x90,
+    0x08, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0xa7, 0xb9, 0x39, 0xe1, 0x30, 0x00, 0x26, 0x85, 0xca,
+    0x85, 0xef, 0x70, 0xe7, 0xb8, 0x0d, 0xed, 0x90, 0x10, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x27,
+    0xb8, 0x1d, 0xe5, 0x70, 0x00, 0x26, 0x85, 0xca, 0x85, 0xef, 0x70, 0x67, 0xb7, 0x0d, 0xe1, 0x26,
+    0x85, 0xef, 0x60, 0x76, 0x8d, 0xaa, 0x85, 0x26, 0x85, 0x4a, 0x86, 0xef, 0x50, 0xde, 0xe4, 0x26,
+    0x85, 0xef, 0x60, 0x76, 0x8c, 0xaa, 0x85, 0x26, 0x85, 0x4a, 0x86, 0xef, 0x50, 0x5e, 0xec, 0x41,
+    0x61, 0xbc, 0x99, 0x7d, 0x71, 0x37, 0xc6, 0x04, 0x20, 0x07, 0x25, 0x86, 0x13, 0xc8, 0xe5, 0x13,
+    0x05, 0x05, 0x03, 0x53, 0x00, 0x05, 0x42, 0x02, 0xa4, 0x22, 0x47, 0xb2, 0x47, 0xb7, 0xb5, 0x09,
+    0x00, 0x13, 0x86, 0xb5, 0x6c, 0xc1, 0x45, 0x41, 0x61, 0x6f, 0x00, 0xe7, 0x89, 0x00, 0x00, 0x82,
+    0x80, 0x00, 0x00, 0x37, 0x45, 0x05, 0x20, 0x23, 0x2a, 0x05, 0x8c, 0x23, 0x28, 0x05, 0x8c, 0x37,
+    0xb5, 0x09, 0x00, 0x23, 0x26, 0x05, 0x70, 0x23, 0x24, 0x05, 0x70, 0x82, 0x80, 0x00, 0x00, 0x49,
+    0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x49, 0x1f, 0x00, 0x00, 0xc7, 0x31, 0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05,
+    0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0x87, 0x40, 0x04, 0x01, 0x04, 0x00, 0x73, 0x4c, 0x6b,
+    0x0b, 0x06, 0x00, 0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0x88, 0x41, 0x64, 0x08, 0x06, 0x00, 0x88,
+    0x41, 0x32, 0x04, 0x07, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06,
+    0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xfd, 0x78, 0xc9,
+    0x01, 0x05, 0x00, 0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00, 0x47, 0x6e, 0xcd, 0x03, 0x05, 0x00, 0x88,
+    0x41, 0x64, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07,
+    0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47,
+    0x03, 0x08, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0xaa,
+    0x79, 0x28, 0x01, 0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce,
+    0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xd3, 0x64, 0xed, 0x09, 0x02, 0x00, 0x43,
+    0x44, 0x35, 0x12, 0x05, 0x00, 0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0xde, 0x7a, 0x7f, 0x1d, 0x06,
+    0x00, 0x88, 0x41, 0x32, 0x04, 0x07, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a,
+    0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x47, 0x03, 0x08, 0x00, 0xfd,
+    0x78, 0xc9, 0x01, 0x05, 0x00, 0x43, 0x44, 0x35, 0x12, 0x05, 0x00, 0x47, 0x6e, 0xcd, 0x03, 0x05,
+    0x00, 0x88, 0x41, 0x64, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44, 0x8d,
+    0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9,
+    0x51, 0x47, 0x03, 0x08, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06,
+    0x00, 0xaa, 0x79, 0x28, 0x01, 0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x07, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x06, 0x00, 0x63,
+    0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0x87, 0x40, 0x04, 0x01, 0x04,
+    0x00, 0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00, 0x87, 0x40, 0x08, 0x02, 0x03, 0x00, 0x88, 0x41, 0x64,
+    0x08, 0x06, 0x00, 0x88, 0x41, 0x32, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06,
+    0x00, 0xfd, 0x78, 0xc9, 0x01, 0x05, 0x00, 0x73, 0x4c, 0x6b, 0x0b, 0x06, 0x00, 0x47, 0x6e, 0xcd,
+    0x03, 0x05, 0x00, 0x88, 0x41, 0x64, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05,
+    0x00, 0xe9, 0x51, 0x1c, 0x0d, 0x06, 0x00, 0x63, 0x65, 0xce, 0x00, 0x05, 0x00, 0xe9, 0x51, 0x1c,
+    0x0d, 0x06, 0x00, 0xaa, 0x79, 0x28, 0x01, 0x05, 0x00, 0xde, 0x7a, 0xbf, 0x0e, 0x07, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x93, 0x71
+};
+
+/*
+01 0e f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 57 61 00 0e 00 53 55 23 01 12 00 cd 4f 29
+00 10 00 43 44 ea 02 14 00 60 52 ae 00 11 00 43 44 ea 02 14 00 43 44 2f 02 15 00 43 44 47 02 14
+00 43 44 8d 04 14 00 21 57 61 00 0e 00 53 55 23 01 12 00 cd 4f 29 00 10 00 43 44 ea 02 14 00 60
+52 ae 00 11 00 43 44 ea 02 14 00 43 44 2f 02 15 00 43 44 47 02 14 00 43 44 8d 04 14 00 21 57 61
+00 0e 00 53 55 23 01 12 00 25 66 2a 00 11 00 43 44 76 05 13 00 60 52 a3 00 11 00 43 44 bb 02 14
+00 43 44 2f 02 15 00 43 44 02 06 13 00 43 44 35 12 13 00 0d 5f 3a 00 0f 00 43 44 5d 00 13 00 cd
+4f 7f 00 10 00 43 44 1a 09 14 00 60 52 1f 02 11 00 43 44 1a 09 14 00 43 44 8d 04 15 00 43 44 47
+02 14 00 43 44 8d 04 14 00 0d 5f 3a 00 0f 00 43 44 5d 00 13 00 cd 4f 7f 00 10 00 43 44 1a 09 14
+00 60 52 1f 02 11 00 43 44 1a 09 14 00 43 44 8d 04 15 00 43 44 47 02 14 00 43 44 8d 04 14 00 21
+57 61 00 0e 00 53 55 23 01 12 00 25 66 d1 00 11 00 43 44 35 12 13 00 60 52 1f 02 11 00 43 44 1a
+09 14 00 43 44 8d 04 15 00 43 44 e9 00 14 00 43 44 d2 01 14 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 c0 00 00 00 c4 1d 43 d7 41 24 41 63 68 69 6c 6c 65 73 2c 48 37 53 31 2c 51 33 35 2c 46 31
+50 32 36 2e 30 00 24 41 63 68 69 6c 6c 65 73 2c 48 37 53 31 2c 51 35 30 2c 46 31 50 32 36 2e 30
+00 2c 25 64 00 00 00 00 00 00 00 00 00 00 00 00 40 8f 40 33 33 33 33 33 33 e3 3f 9a 99 99 99 99
+99 d9 3f 00 00 00 00 00 00 10 3e 00 00 00 00 00 00 e0 3f 00 00 00 00 00 00 34 40 00 00 00 00 00
+00 34 40 00 00 00 00 00 00 3e 40 00 00 00 00 00 00 00 40 00 00 a0 41 0a d7 23 3d 00 00 a0 40 00
+00 40 40 33 33 33 33 33 33 eb 3f 00 00 00 00 00 00 4e 40 e8 6a 2b f6 97 dd ed 3f c0 a8 a4 4e 40
+13 b1 3f 00 00 00 00 00 00 24 40 00 00 f0 41 00 00 c8 41 00 00 20 40 00 00 c8 c1 9a 99 99 be 00
+00 a0 42 00 00 00 00 00 00 1c 40 9a 99 99 99 99 99 b9 3f 00 00 00 00 00 00 f0 3f 33 33 33 33 33
+33 d3 3f 00 00 00 00 00 00 14 40 00 00 00 00 00 00 54 40 00 00 00 00 00 00 44 40 00 00 80 bf 00
+00 80 3f 00 50 c3 47 00 00 00 00 87 44 e7 4a 18 57 c6 3f 00 00 00 00 00 00 20 40 55 94 e7 4a 18
+57 b6 3f f8 c1 63 1a dc a5 4c 40 24 25 73 5a 44 41 00 2c 2c 2c 30 30 2c 30 30 00 24 25 73 47 47
+41 00 2c 2c 00 24 50 4e 54 48 30 30 31 00 2c 25 2e 32 66 00 23 00 00 00 70 05 20 d8 72 05 20 00
+00 00 00 01 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00 08 00 00 00 05
+00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 6e 1b
+*/
+const char g_cfg_cmd14[] = {
+    0x01, 0x0e, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x21, 0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0xcd, 0x4f, 0x29,
+    0x00, 0x10, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x60, 0x52, 0xae, 0x00, 0x11, 0x00, 0x43,
+    0x44, 0xea, 0x02, 0x14, 0x00, 0x43, 0x44, 0x2f, 0x02, 0x15, 0x00, 0x43, 0x44, 0x47, 0x02, 0x14,
+    0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x21, 0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23,
+    0x01, 0x12, 0x00, 0xcd, 0x4f, 0x29, 0x00, 0x10, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x60,
+    0x52, 0xae, 0x00, 0x11, 0x00, 0x43, 0x44, 0xea, 0x02, 0x14, 0x00, 0x43, 0x44, 0x2f, 0x02, 0x15,
+    0x00, 0x43, 0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x21, 0x57, 0x61,
+    0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0x25, 0x66, 0x2a, 0x00, 0x11, 0x00, 0x43,
+    0x44, 0x76, 0x05, 0x13, 0x00, 0x60, 0x52, 0xa3, 0x00, 0x11, 0x00, 0x43, 0x44, 0xbb, 0x02, 0x14,
+    0x00, 0x43, 0x44, 0x2f, 0x02, 0x15, 0x00, 0x43, 0x44, 0x02, 0x06, 0x13, 0x00, 0x43, 0x44, 0x35,
+    0x12, 0x13, 0x00, 0x0d, 0x5f, 0x3a, 0x00, 0x0f, 0x00, 0x43, 0x44, 0x5d, 0x00, 0x13, 0x00, 0xcd,
+    0x4f, 0x7f, 0x00, 0x10, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x60, 0x52, 0x1f, 0x02, 0x11,
+    0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x15, 0x00, 0x43, 0x44, 0x47,
+    0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x0d, 0x5f, 0x3a, 0x00, 0x0f, 0x00, 0x43,
+    0x44, 0x5d, 0x00, 0x13, 0x00, 0xcd, 0x4f, 0x7f, 0x00, 0x10, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14,
+    0x00, 0x60, 0x52, 0x1f, 0x02, 0x11, 0x00, 0x43, 0x44, 0x1a, 0x09, 0x14, 0x00, 0x43, 0x44, 0x8d,
+    0x04, 0x15, 0x00, 0x43, 0x44, 0x47, 0x02, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x14, 0x00, 0x21,
+    0x57, 0x61, 0x00, 0x0e, 0x00, 0x53, 0x55, 0x23, 0x01, 0x12, 0x00, 0x25, 0x66, 0xd1, 0x00, 0x11,
+    0x00, 0x43, 0x44, 0x35, 0x12, 0x13, 0x00, 0x60, 0x52, 0x1f, 0x02, 0x11, 0x00, 0x43, 0x44, 0x1a,
+    0x09, 0x14, 0x00, 0x43, 0x44, 0x8d, 0x04, 0x15, 0x00, 0x43, 0x44, 0xe9, 0x00, 0x14, 0x00, 0x43,
+    0x44, 0xd2, 0x01, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc4, 0x1d, 0x43, 0xd7, 0x41, 0x24, 0x41, 0x63, 0x68, 0x69,
+    0x6c, 0x6c, 0x65, 0x73, 0x2c, 0x48, 0x37, 0x53, 0x31, 0x2c, 0x51, 0x33, 0x35, 0x2c, 0x46, 0x31,
+    0x50, 0x32, 0x36, 0x2e, 0x30, 0x00, 0x24, 0x41, 0x63, 0x68, 0x69, 0x6c, 0x6c, 0x65, 0x73, 0x2c,
+    0x48, 0x37, 0x53, 0x31, 0x2c, 0x51, 0x35, 0x30, 0x2c, 0x46, 0x31, 0x50, 0x32, 0x36, 0x2e, 0x30,
+    0x00, 0x2c, 0x25, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x40, 0x8f, 0x40, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xe3, 0x3f, 0x9a, 0x99, 0x99, 0x99, 0x99,
+    0x99, 0xd9, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x40, 0x00, 0x00, 0xa0, 0x41, 0x0a, 0xd7, 0x23, 0x3d, 0x00, 0x00, 0xa0, 0x40, 0x00,
+    0x00, 0x40, 0x40, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xeb, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x4e, 0x40, 0xe8, 0x6a, 0x2b, 0xf6, 0x97, 0xdd, 0xed, 0x3f, 0xc0, 0xa8, 0xa4, 0x4e, 0x40,
+    0x13, 0xb1, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0xf0, 0x41, 0x00,
+    0x00, 0xc8, 0x41, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0xc8, 0xc1, 0x9a, 0x99, 0x99, 0xbe, 0x00,
+    0x00, 0xa0, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x9a, 0x99, 0x99, 0x99, 0x99,
+    0x99, 0xb9, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33,
+    0x33, 0xd3, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x80, 0xbf, 0x00,
+    0x00, 0x80, 0x3f, 0x00, 0x50, 0xc3, 0x47, 0x00, 0x00, 0x00, 0x00, 0x87, 0x44, 0xe7, 0x4a, 0x18,
+    0x57, 0xc6, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x55, 0x94, 0xe7, 0x4a, 0x18,
+    0x57, 0xb6, 0x3f, 0xf8, 0xc1, 0x63, 0x1a, 0xdc, 0xa5, 0x4c, 0x40, 0x24, 0x25, 0x73, 0x5a, 0x44,
+    0x41, 0x00, 0x2c, 0x2c, 0x2c, 0x30, 0x30, 0x2c, 0x30, 0x30, 0x00, 0x24, 0x25, 0x73, 0x47, 0x47,
+    0x41, 0x00, 0x2c, 0x2c, 0x00, 0x24, 0x50, 0x4e, 0x54, 0x48, 0x30, 0x30, 0x31, 0x00, 0x2c, 0x25,
+    0x2e, 0x32, 0x66, 0x00, 0x23, 0x00, 0x00, 0x00, 0x70, 0x05, 0x20, 0xd8, 0x72, 0x05, 0x20, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x6e, 0x1b
+};
+
+/*
+04
+*/
+const char g_cfg_cmd15[] = {
+    0x04
+};
+
+/*
+51 55 49 54 20
+*/
+const char g_cfg_cmd16[] = {
+    0x51, 0x55, 0x49, 0x54, 0x20
+};
+
+const struct cfg_cmd g_cfg_cmds[] = {
+    { g_cfg_cmd0, sizeof(g_cfg_cmd0) },
+    { g_cfg_cmd1, sizeof(g_cfg_cmd1) },
+    { g_cfg_cmd2, sizeof(g_cfg_cmd2) },
+    { g_cfg_cmd3, sizeof(g_cfg_cmd3) },
+    { g_cfg_cmd4, sizeof(g_cfg_cmd4) },
+    { g_cfg_cmd5, sizeof(g_cfg_cmd5) },
+    { g_cfg_cmd6, sizeof(g_cfg_cmd6) },
+    { g_cfg_cmd7, sizeof(g_cfg_cmd7) },
+    { g_cfg_cmd8, sizeof(g_cfg_cmd8) },
+    { g_cfg_cmd9, sizeof(g_cfg_cmd9) },
+    { g_cfg_cmd10, sizeof(g_cfg_cmd10) },
+    { g_cfg_cmd11, sizeof(g_cfg_cmd11) },
+    { g_cfg_cmd12, sizeof(g_cfg_cmd12) },
+    { g_cfg_cmd13, sizeof(g_cfg_cmd13) },
+    { g_cfg_cmd14, sizeof(g_cfg_cmd14) },
+    { g_cfg_cmd15, sizeof(g_cfg_cmd15) },
+    { g_cfg_cmd16, sizeof(g_cfg_cmd16) },
+};
diff --git a/code/sdk/zhihui/GS21_1.10.100/pdr/include/pdr_interface.h b/code/sdk/zhihui/GS21_1.10.100/pdr/include/pdr_interface.h
new file mode 100644 (file)
index 0000000..9c26cc6
--- /dev/null
@@ -0,0 +1,156 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.\r
+ * Description: pdr Interface\r
+ * Version: v0.0\r
+ * Create: 2023-2-25\r
+ */\r
+#ifndef PDR_INTERFACE_H\r
+#define PDR_INTERFACE_H\r
+\r
+#include <stdint.h>\r
+#include <stdarg.h>\r
+#include <stdbool.h>\r
+\r
+// 放大倍数\r
+#define PVT_REPORT_SCALE            (1 << 24) // PVT上报位置的放大系数\r
+#define COMMON_SCALE                (1 << 20) // PVT上报速度的放大系数\r
+\r
+// PDR返回状态列表\r
+#define RET_OK                      0\r
+#define RET_NULL_POINTER            (-1001)\r
+#define RET_CALLBACK_INVALID        (-2001)\r
+#define RET_VERSION_INVALID         (-3001)\r
+\r
+// PDR输出数据的来源\r
+#define GNSS_ONLY               0\r
+#define PDR_ONLY                1\r
+#define PDR_FUSION              2\r
+\r
+// 1.传感器相关\r
+#define ACCL_GYRO_DATA_TS       0.01    // 加计,陀螺数据采样周期 10 ms\r
+#define SENSOR_BUFFER_SIZE      100     // 存放传感器一次数据的buffer长度\r
+#define AXIS_NUM                3       // 传感器3轴\r
+\r
+typedef struct {\r
+    int64_t timestamp;  // 时间戳,单位:ms\r
+    float   x;          // 传感器X轴数据\r
+    float   y;          // 传感器Y轴数据\r
+    float   z;          // 传感器Z轴数据\r
+    int8_t  status;     // 传感器状态标志位\r
+} SensorDataPara;\r
+\r
+typedef struct {\r
+    SensorDataPara sensors[SENSOR_BUFFER_SIZE]; // 传感器值\r
+    uint32_t cnt;                               // 每次上报的个数\r
+} SensorData;\r
+\r
+typedef struct {\r
+    SensorData accl;    // 加计\r
+    SensorData gyro;    // 陀螺仪\r
+    SensorData mag;     // 磁力计\r
+} SensorDataSet;\r
+\r
+typedef enum {\r
+    SENSOR_INVALID = 0, // sensor 数据更新失败\r
+    SENSOR_SYNC_SUCC,   // sensor 数据更新、时间同步成功\r
+    SENSOR_SYNC_FAIL    // sensor 数据更新、时间同步失败\r
+} SensorSts;\r
+\r
+typedef struct {\r
+    SensorSts sensorSts;            // sensor数据更新状态\r
+    int64_t utcMs;                  // GNSS UTC 时间戳, 单位:毫秒, 从 January 1, 1970起\r
+    SensorDataSet sensorDataSet;    // 传感器数据集\r
+} EpochSensorData;\r
+\r
+#pragma pack(1)\r
+// 2.GNSS结果相关\r
+typedef struct {\r
+    uint16_t flags;          // bit0:validity of timestamp(1:valid, 0:invalid),...,bit11:validity of speedAcc.\r
+    uint64_t timestamp;      // 时间戳utc,unix时间,单位ms,从 January 1, 1970起\r
+    int64_t latitude;        // 单位:度;放大2^24倍\r
+    int64_t longitude;       // 单位:度;放大2^24倍\r
+    int64_t clkBias;         // 单位:m;放大2^20倍\r
+    int64_t clkDrift;        // 单位:hz;放大2^20倍\r
+    int64_t speede;          // 单位:m/s;放大2^20倍\r
+    int64_t speedn;          // 单位:m/s;放大2^20倍\r
+    int64_t speedu;          // 单位:m/s;放大2^20倍\r
+    float altitude;          // 单位:m\r
+    float heading;           // 单位:弧度\r
+    float posAcc;            // 位置精度,单位:m\r
+    float speedAcc;          // 速度精度,单位:m/s\r
+} GnssLocInfo;               // PVT上报的定位定速结果\r
+\r
+typedef struct {\r
+    uint32_t deltaTime;     // 收到观测量到pvt结束的时间差,单位: s, 放大2^24倍\r
+    uint8_t context;        // 场景识别结果(0:默认,1:隧道,2:遮挡,3:CBD,4:OPEN,5:室内,6:半面天空,7:室内窗边)\r
+    uint8_t isStatic;       // 是否静态\r
+    uint8_t pvtState;       // PVT的状态(0:LSQ,1:KF)\r
+    uint16_t inuseNum;      // 使用的PSR观测量的个数\r
+    float qop;              // 定位性能质量,单位:米。数值越小定位越准确。\r
+    float hdop;             // 水平位置精度因子\r
+    float ems;              // 伪距残差ems\r
+} GnssPdrCommInfo;          // PVT上报的定位定速过程状态\r
+#pragma pack()\r
+\r
+typedef struct {\r
+    GnssLocInfo locInfo;\r
+    GnssPdrCommInfo gnssState;\r
+} GnssRptRslt;              // PVT上报信息\r
+\r
+// 3.PDR输出相关\r
+typedef struct {\r
+    double lat;     // 纬度,单位: 度\r
+    double lon;     // 经度,单位: 度\r
+    float alt;      // 高度,单位: 米\r
+    bool valid;     // 是否有效\r
+} LlaCoord;         // 大地坐标系\r
+\r
+typedef struct {\r
+    uint8_t src;            // PDR输出的数据来源。0: GNSS_ONLY, 1: PDR_ONLY, 2: PDR_FUSION\r
+    uint64_t timeStampMs;   // 时间戳utc,unix时间,单位ms,从 January 1, 1970起\r
+    float speed;            // 速度,单位:米/秒\r
+    float heading;          // 航向,单位:度\r
+    LlaCoord posLla;        // 位置 lla\r
+} PdrResult;                // PDR输出\r
+\r
+#ifdef _WIN32\r
+#define PDR_INTERFACE_EXPORT __declspec(dllexport)\r
+#elif __linux__\r
+#define PDR_INTERFACE_EXPORT __attribute__ ((visibility("default")))\r
+#else\r
+#define PDR_INTERFACE_EXPORT\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* 对外提供的接口 */\r
+// 获取PDR版本号。\r
+PDR_INTERFACE_EXPORT const char* GetPdrVersion(void);\r
+\r
+// 初始化PDR,正常返回0,异常返回错误码。\r
+PDR_INTERFACE_EXPORT int32_t InitPdrFusion(void);\r
+\r
+/* 函数功能:PDR主流程,正常返回0,异常返回错误码。\r
+ * 函数参数:\r
+ * sensorData  入参  传感器数据,接口内部可能改写数据\r
+ * gnssRslt    入参  GNSS结果\r
+ * arState     入参  运动状态识别结果\r
+ * pdrRslt     出参  保存pdr结果\r
+ * 返回值  :正常返回0,异常返回错误码。\r
+ */\r
+PDR_INTERFACE_EXPORT int32_t ExecutePdrFusion(EpochSensorData *sensorData, const GnssRptRslt *gnssRptRslt,\r
+    PdrResult *pdrRslt);\r
+\r
+// 停止PDR,正常返回0,异常返回错误码。\r
+PDR_INTERFACE_EXPORT int32_t QuitPdrFusion(void);\r
+\r
+// (可选)日志回调函数声明,调用方按此声明实现回调函数,并注册\r
+typedef int (*HipdrLogFunc)(const char *logLevel, const char* fmt, ...);\r
+PDR_INTERFACE_EXPORT int32_t RegPdrLogHandle(HipdrLogFunc cbFunc);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/pdr/libpdr_fusion.a b/code/sdk/zhihui/GS21_1.10.100/pdr/libpdr_fusion.a
new file mode 100644 (file)
index 0000000..cdd9289
Binary files /dev/null and b/code/sdk/zhihui/GS21_1.10.100/pdr/libpdr_fusion.a differ
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/libpgnss_decoder.so b/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/libpgnss_decoder.so
new file mode 100644 (file)
index 0000000..b65696a
Binary files /dev/null and b/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/libpgnss_decoder.so differ
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/pgnss_decoder_interface.h b/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/pgnss_decoder_interface.h
new file mode 100644 (file)
index 0000000..9c2f7fc
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+ * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
+ * Description: pgnss include with pgnss data decode module\r
+ */\r
+\r
+#ifndef PGNSS_DECODER_INTERFACE_H\r
+#define PGNSS_DECODER_INTERFACE_H\r
+\r
+#include <stdint.h>\r
+\r
+#ifndef WIN32\r
+#define EXPORT_API __attribute__((visibility("default")))\r
+#else\r
+#define EXPORT_API __declspec(dllexport)\r
+#endif\r
+\r
+/*\r
+ * 函数功能:获取种子文件可预测的起止时间\r
+ * 入参:filePath:种子文件的完整路径,包括路径和文件名\r
+ * 出参:startTimestamp:种子文件可预测的开始UTC时间对应的unix时间戳\r
+ *      endTimestamp:种子文件可预测的结束UTC时间对应的unix时间戳\r
+ */\r
+EXPORT_API int32_t GetPgnssDataValidTime(const char *filePath, uint32_t *startTimestamp, uint32_t *endTimestamp);\r
+\r
+/*\r
+ * 函数功能:获取跳秒时间\r
+ * 入参:filePath:种子文件的完整路径,包括路径和文件名\r
+ * 返回值:LeapSecond跳秒\r
+ */\r
+EXPORT_API int32_t GetLeapSecond(const char *filePath);\r
+\r
+/*\r
+ * 函数功能:读取PGNSS种子文件,解析PGNSS辅助数据,扩展星历,保存星历文件;\r
+ *         每一份星历文件可使用前后两小时,两份星历文件间隔两小时,支持一次扩展多份星历文件\r
+ * 入参:filePath:种子文件的完整路径,包括路径和文件名\r
+ *      outputDir:扩展的辅助数据存放路径\r
+ *      timestamp:开始预测时间对应的unix时间戳,可取用当前时间,也可自行设置时间,单位:秒\r
+ *      hours:解析X小时星历,调用者需保证种子文件中从timestamp开始有X小时的有效星历\r
+ */\r
+EXPORT_API int32_t ParsePgnssData(const char *filePath, const char *outputDir, uint32_t timestamp, uint32_t hours);\r
+\r
+/*\r
+ * 函数功能:读取PGNSS种子文件,解析PGNSS辅助数据,扩展星历,保存星历文件;\r
+ *          与ParsePgnssData不同,每次解析生成三份文件,分别为GLONASS星历、除GLONASS外其余星历以及其余辅助信息\r
+ *          每一份星历文件可使用前后两小时,两份星历文件间隔两小时,支持一次扩展多份星历文件\r
+ * 入参:与ParsePgnssData一致\r
+ *      filePath:种子文件的完整路径,包括路径和文件名\r
+ *      outputDir:扩展的辅助数据存放路径\r
+ *      timestamp:开始预测时间对应的unix时间戳,可取用当前时间,也可自行设置时间,单位:秒\r
+ *      hours:解析X小时星历,调用者需保证种子文件中从timestamp开始有X小时的有效星历\r
+ */\r
+EXPORT_API int32_t ParsePgnssDataByLessFiles(const char *filePath, const char *outputDir, uint32_t timestamp, uint32_t hours);\r
+\r
+/*\r
+ * 函数功能:返回pgnss解码库的版本号\r
+ * 入参:无\r
+ * 返回值:版本号对应字符串\r
+ */\r
+EXPORT_API const char *GetPgnssVersion(void);\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/build_and_run.sh b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/build_and_run.sh
new file mode 100644 (file)
index 0000000..0311a26
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+
+rm -rf demo_data/output1
+rm -rf demo_data/output2
+
+mkdir -p demo_data/output1
+mkdir -p demo_data/output2
+
+exe_name=decode_demo
+
+gcc -o ${exe_name} server_pgnss_decode_demo.c -ldl
+
+chmod +x ${exe_name}
+
+./${exe_name}
+
+ret=$?
+
+if [ $ret -eq 0 ]; then
+    echo "run ${exe_name} succeed"
+else
+    echo "run ${exe_name} failed"
+    exit 1
+fi
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/clean.sh b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/clean.sh
new file mode 100644 (file)
index 0000000..d773ad2
--- /dev/null
@@ -0,0 +1,5 @@
+rm -f decode_demo
+rm -rf demo_data/output1/*
+rm -rf demo_data/output2/*
+
+rm -f libpgnss_decoder.so
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/demo_data/EE_7days.dat b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/demo_data/EE_7days.dat
new file mode 100644 (file)
index 0000000..dfeec2f
--- /dev/null
@@ -0,0 +1 @@
+{"EE":[{"seedInfo":"U0xMUFNVhtASAAAAAAA="},{"gpsNav":"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"},{"bdsNav":"JwE4AP/rAAAAAAAAAAAAAEgwAzariwgOn7VwADuO+gY0Z4AAEYnLAAP2xmQABz7un/+hFxH/+poNAAEAbQAALzW//9Ev///H4AABWQAAEn//9gAAI//+QAAAACP/2ABgAYupkZN8AAziumAAJJXGP/752Kv/+4++YAB4jcAADQ7j//xjd//9hPAABAEAABNP//4///9wAAN//9QAAQACv/yACwAX/TGsdgAkfOlrAF/hrff+4dJD//1NTHYAJWp2AAHVer//t4f//+tfAAAW0AAAGf//44AAOf//t//5QAFv/4//zAJP66QYAcWF77QHUAH4AB3DfRBH8a//1D7AgAAXMYIABUVSL//dYDD//R9lQAB8aoAAFyqf/+bD///meAAAzAAABP//+wAAGf/+4AAAABX/7AAwAMXU/a9P//udYDwACK12///RtRT//g8AYAAypNAABj2J//4nX//+0VgAAk5AAAhP//7b///wAAH//+QAAIABn/4gBQAIAWMEBL/totWLP9CQvCQAkBlWUAFXFfX/7R/cP/8SyOAAJNqAAAslf//0M///8YAADL//4oAAMgADH/9IAEAAFf74ClIMAPfbDPIDqBSYAA7dvoCzOigABTQxoAD5WXYAAcRKV//oK3R//q3+4ABA01AAC3NP//Qe///ymAAAWIAABB///cAAB///gAAEAAf/9gAgAALqUKmsAAMpnu4ACK3En/++5GJ//uutuAAeOZYAAyuw//8XE///Z5gAAQTgAASP//+H///oAADP//QAAIAAj/8gA3///1CTlnAJPaT0oBdrLCX/t4PG9/9XQ76ACXougABywk//7aLf//rywAAF1gAAA///+aAADv//5P/+0ABZ/9v//gBz+qkGAIZ5kQUB1BQaAAdt30OHpZ//9PmPoAAJd9WAAVBNm//3Jb6//0j9gAAfoFAABdDv//mF///5YAAANsAAAW///qAABf//sAABAAR/+oAQAAF1NEb7P/71k68AAlEPz//0FQz//4Q8MAAMwBgAAY2O//+IuH//sxQAAJgAAAI9//+tAAAAAAB3//iAAFAAT/+IAb//AFagGMv7WYZ0f/RsTUiAJH9ORABTvDl/+zejf//GHxgACVtAAAK2f//89f///cAAAr//+IAAEQAAf//UABQAAH/QAqSDAEiCg/SA6g7zAAO2b6AJhvgAAYwYAAA81RXAAGytBf/6Dacf/64v2AAQU+gAAsCr//z8L//80IAAFrAAAO///5AAAb//4AABgAF//YAJ//i6kORcwADFzAOAAgS1n//v6COf/727/gAHjQ+AAMK5///FVH//270AAEKYAAET///gf//9AAAr//0AADgAF//IAO/9/9U5ZM4CVv44GAW2PLP/7aUWR//W1ZqAAmZcoAAcBEP/+1k///7DYAABfQAAAG///qgAA7//9z//2AAU//UAAgAS/rpBwAH6RJ1AdQnsAAHa99DHGBT//TUg4AADMSxAAFMke//9wsCf/9L6wAAH7uwAAXMJ//5gV//+RIAADfAAAHf//6gAAT//7AAAwADf/qAE//hdSulm///Ao07AAJvwif/8+OdP/+GfFQADLYuAAGGPv//iYj//7KEAACXIAACdf//qQAAAAAAZ//4AABwADf/iAHf+wBUa0kz+0pNsm/0tqwJACT4TNAAUaVf//snT///x47AAAmASAACpV///Nz///8AAAI///igABSAADf/2AAW//p/5gJ0g4AJOo6AgOoYvQADtW+f9WJWAAHZyHAAOxkZwABmXJn/+hZM//+xyDgAEGrIAAKfZ//88D///PwAABdAAADf//+gAAF//9wAAoAA//2ACv/guo7x9CAAwRzZAAHVJ5f/8B06n//BdxoAB4noAAC4d3//xNK//93FAABEIAABA///33///wAAI//9AABIAAf/0ADv/H/WVoO0Al6g3nAFkJ/P/+1pBKX/1+G24AJuLfgAG1Mn//tKA//+ygAAAYN////v//7wAAOf//VAAAAAEn/0AATABv7aQcAHQEnjQHUO0AAB2nfQswFk//0oKpwAA+oFwABRUDr//cBnf//UYNAAB+DYAAFrHf/+aGf//jqAAA1QAACb///AAAD//+oAAUAAf/7ABX/sXUk+zK//w1TPgACg2r3//PKgD//ivHoAAyZrAABdvZ//4vFf/+z+gAAkOAAApv//68AAAAAAFf/+IAAoAAX/5gB//cAUiccg/s67Etf9QLRbIAlcfooAE+EBj/7FwJv/8j+WAAJpGgAApbf//zGAAAAAAABr//44AAX///v/94AGP/0//4CFIOAE8aZDIDqIoMAA7Pvn+wFUAACNooYADlbeEAAXfPD//og1r//tlDYABB/tAACeYP//OP///0ogAAXwAAAx///wAAA///gAAMAAD/+AAr/0LqN82tgAL0R4IABnhrX//BKq3//xhE4AAeJzAAArFw//8Qyf//f8AAARcAAAPT//96AAAEAABf//UAAV////9gA7/r/13nCAgJmXUQgBWo72X/tLGQl/9jzgOACdgxgABqeK//7OvP//tDAAAGH////b///QAADb//0AAAkAA7/84AHv/v/GkHADIZPKUB1E7KAAdm30KSfJ//9GWPAAASKP+AATmt3//2/9U//1ph0AAfJRAABWS///nXn//5IAAAL+AAAo///8AAAn//qAAHAAB/+4AV/5F1H9Gef/8VhCwAAogun//ztAy//5HSsAAMfsQAAV5Hf/+OXP//uIgAAIfAAAKH//+7AAAAAAA3//iAAM////+oAd/0AE/Zm7v7K1RSr/VQINMAJeyHyABNW4G/+wbPr//KbdgACcXoAAKKX//8uQAAAKAAAQ//+YAAGn//l//mABj/74AUAYSDgB5So5iA6ixHAAOy75/plmoAAp7wAAA31NVAAFOECf/6KRyf/7vBOAAQmIQAAk93//zXf//9VYAAGEAAAL///9AAAL//4AAD/////oAJ/8C6jY60AAC6LmYAAWIE4//wZBn//8tpQAAHkS2AAJ61///Daf//4jUAAEdYAADj///eAAADAAAL//2AAF//7//oAL/6f9igEsYCbjXX2AVDaYg/7O8i8f/aCKxAAn37SAAZ5pf/+ywX//7XsAABin///u///5gAAw//8wAAUAAKf/PACf/v/2pBwBHMVG9AdRiTgAHZN9CbDUb//QwksAAFGrWAAEpmmv/9vkuf/9moCAAHt9QAATw7//6B///+dAAACqgAAIQAABAAAF//6gACf//f/0AE/9xdRvbKP//G4ZtAAJ7yXf/84T5P/+a+BgADHzPAAE8pn//j+N//8BaAACAcAACK///xgAACgAAF//5AADv/9//yAGf8gBNialf+xuMbE/1ner5ACZnpXwASy8O//r20T//y+AwAAnjmAACfb///LgAAAFAAABf//pgABv//0f/8AAXf+wALADUg4Ao3q4kgOo2BwADse+f65gKAAMMpFAANrNLAABHYOH/+ispH//B/tgAELrAAAIht//8yu///YOAABigAACv///gAAA//+gABH//P/8AB//Auo2DL6AAuKZwAAEkBYv/8GAY3//RSiwAB6PHgACP5b//wnG//+SPAABI8AAA0///3gAABAAAA//+AABf/+P/9ACP+n/ZxjIYAnYh46AFHIg8f+yxgXv/2x6twAKF8zAAGS3f//sde//+3vAAAYt///5////4AAKf//KAAHgABX/0wAt/5P/SQcAXElm1QHUdcwAB2LfQlbA4//0EMYgABavYYABFW+v//bgbv//davgAB7yaAAEWd//+hV///reAAAoYAABEAAAwAAA//+wAAr//f/+ABH/YXUZADm//yCD2AACXv0f//Mg77//pcxUAAypIwABFNR//48Df//KZgAAf6AAAZv//8oAABf/////+gAA//+//+gBP/IASz4Mx/sLsRN/9euD2IAm4obAAEkBnH/65xtP/81ZuAAJ/cgAAm3///zCAAAB////r//7YAAb//7///oAFP/pgD4AACOAAABQAAAAAAAAAAAABIMAM2q4sIChAqQASY8CGi29z//YEmu3/2CO5AACfadYAAg4Kj/+9fiH/+9anAAH01AAAt3///cO///qoAAEUAABP//5//+4AAcABD/+f+gAAT+21AJ//uGMb4AImWwsABGD/v//OcVr//jWwoACFT0AADZYf/+dRP//wLAAAtcAABd//+4AAAAAAMAAB//4AAAAIAD/nqMcqf8MUgagDQwtzwAHiT6t/6GdsR/++i8wAEFjFAACSj///OaP//7+AAAKsAAAp//87//6AACAAA//+7/5gAYBGkGAHFhe+0BQsc+AJMeBCRrnZwAOiz48ADM1AeAAM8IPAABhJH//m9mP//pnDgADyOQAAUWH//tPP//12AABqAAAAAABoAAZ//2//qAAwAn//J/9bBFwAHAMWr//23m6AADSKC//u9GG//2KcEAA+pXgABgWP//NZX//4mgAAY+AAAz///Z///oAAAAACAAB//3/+ACAMRryxQB1gZb7+XeTeX/8bZyxAC8M+RAAc1sP/+ACr///QjgAAWfoAAAQ///7l///6AAB0AAC3/+r//dAA2AD//l/RSDAD32wzyAocSZAEmOghmYPh3/16uan/9h3LJAAoWCygAIADwf/vJ/L//wIOQAB+/IAAKwP//26///7HAABGAAAP//+X//xAAIgAO//b/qACE/t7h9//7jtSyACLNgtAAQ9Us//zceGf/5NdOAAhz+AAAy1b//m7z//8VgAALiAAAVf//vAAAAAADAAAf/+AAAACAAf54yAEv/HMdxkA0b19XABwgBi/+hKH+f/wsTwABBuhgAAipH//zhz///CAAACrAAAG///M//+4AAkAANf/p/+kAOARJBgCGeZEFAURLJgCTHAQjVXI4ADsMMQAAzvFnAADPD9QAASjlP/5syM//6pH4AA8v+AAFBP//7W7//9RgAAYQAACgAAeAAFf/8//7gAQAJf+yf/imJcABwdWJ//9u7iAAAlJ1v/7scbP/9sK5AAPyxwAAXF///zUj//+J0AAGHAAAOf//3f//4AAAgAAgAAf/8AAAAgDFRJOsAbS/3Q/lwDNdf/K7C3gAvQ13AAGrn5//f4JH//1GQAAFoYAAADX//+6AAAAAAAdgAAf//o//5AAQAA3/0f00gwBIgoP0gKKGjQBJjgIZF+7Z/9deaC//Y0lcgAKKnY4AB8KB3/7wMs//8PVAAAgGAAACgK//9sv//+5AAARwAACv//k//9QACgAC//z/7ABJP7h7mT/+5dGigAjF/mgAEF1MP/81N2v/+Zo1AAIjIMAALzJ//5pd///KOAAC7QAAE3//7wAABAAA//////gAAAAwAH+dx7Bh/y2ZT+ANKpKSAAaEHPv/oLpK//8cV7AAQgrAAAIJL//83f///xKAAAqwAAAv//y///1AAKAACv/5v/tAFQD6QcAB+kSdQFFzwwAkxsEImO6PAA7xkVAANGL7IAAyy/UAAC1on/+bXXP/+vtAAAPFqgABMx//+3w///VIAAFQAAA4AAIAAA///H//IAFAB//cn/7DncAAcQUCP//aJpgAAE3xD/+619n//d38wAD9FWAAFbO//82y///jxAABdYAADj//+P//+gAAIAAIAAH//AAAAIAxhHGqAGSxRbf5aOoSf/zxGdwAL3a60ABiVjv/38Gx//9hBgABaBgAAAm///vIAAAgAAHgAAD//5v/+sAEgAK/7/9hIOACTqOgICjSH8ASY2CGKWVbf/XJzN3/2Ue0gACjUf+AAd6gJ/+7vmf//Hd+AAIFiAAAk9v//au///wIAAEeAAAX//4///kAAsAAj/8f+8AcT+5Jlt//uhswgAI0dLwAA+y8R//NAK5//oGqwACJ7JAACtqP/+ZKP//zyAAAvcAABD//+8AAAQAAL/////4AAAAMAB/nWFrr/8+wvZoDTiuskAF/bAF/6BQxf//LfnwAEJXOAAB5s///Nrf//8egAAKn//////8v///AACsAAd/+P/8QBsA2kHAB0BJ40BR1LuAJMaBCGOElQAPGDHoADUipGAAMQ6EAAAIra//nB37//t09AADuk4AARhH//uf///2iAABKAAAOAACIAAJ//w//2ABgAb/0J//QGdgAHGTvf//1xeF///7kE//uupC//4VNEAA/FkgABPEf//OT///5qAAAWUAAAu///n///wAACAAC/////4AAACAMbY/YQBcCjAX+WIIV//9NIaMAC+nuGAAWaTL/9+mF///cOwAAWcYAAAEv//8AAAAQAAB3/////+X//0ABMAB/+x/fSDgBPGmQyApApvAEmMghg55lv/1vzyV/9nntBAAo4gOgAHJBWf/u6m9//y4bAACCBEAAIcX//2lX//8gAABIAAAA//+P//9AALgAF//D/zAIk/ub7mv/7sCBQACNhc9AAO7c9f/zNjrf/6ff2AAirHQAAnd3//mCL//9QIAAMCAAAO///vAAAIAAC///f//AAEACAAf5z80/v/UDYekA1GcNkABXUjDf+f6fr//z/uEABCoaAAAcMT//zYL///LIAACl///8f//LAAAIAAsAAEf/h//cAgALJBwAyGTylAUjWzgCTGQQgy6SoADzrCUAA19ovgAC7RpP//2th//50ht//8FNAAA68YAADxt//7tv//+GgAARwAADAAAiAAA//7///AAaAE/8Sf/6mpsAByALD//9Lxr///m9NP/7sv4P/+V7zAAPs+oAARR9//zsn//+qwAAFdgAAIP//5///+AABAAAf////+AAgAgDHntoEAU0P1X/lbTFM//XjRiAAv1umQAFDUM//fjSv//4GOAAFlt////b///EgAAGQAAc///v//l///AAUAAR/pf6Eg4AeUqOYgKTMXgBJjAIXztf//9bS7i//avRKAAKOC8QABrwV3/7u9sf/9AcoAAgkrAAB5z//9oD///PQAASH///f//kAAAAADAAAf/v/9wCpP7pIVv/+8PwWgAjb+IwADgeV//8zLin/+wLFgAIshUAAI0+//5dW///Y2AADDAAADP//8AAACAAAv//3//wABAAv//+cmEDj/2HbjJANVAdIAATrIfv/n4SgX/9SHJgAQuvAAAGeG//81Z///zwAAAof//+P//zQAAJAALAAAH/4P/8AJAB6QcARzFRvQFKWqoAkxgEIBRenAA9eXxwANt014AAsbOr//6Pcz/+eDpv//Na2AAOoegAAw5//+7m///pwAAEwAAAwAAIf////+8AAAAGgAv+8oAALMhAAcjtHv//OLjf//y5cL/+7fqv//qUpQAD6hMAADl2//87j///vRAABYQAABP//+QAAAAAAQAAH/////gAIAIAyGY7jAEprv4f5VKZV3/29qXMAMAS90ABH6Qv/33XL//+TBgABZHf///T///yAAACIAAG3//3//5YAAQAFAAAf5//JIOAKN6uJICljksASYuCF2Dmuf/WnB8X/28ngQACjh5qAAZBBX/+74uP//VUvAAII+wAAa8///Zzf//1gAAEj///j//5QAAUAAx////7v/wAuT+6w8T//vdeeAAI34uUAAz9mT//Myah//uXDAACLTDAAB7hP/+W0///3ZAAAxYAAAr///AAAAgAAH//9//8AAQAL/9/nDMMff9zlUB4DWGAvoAEYInV/58gZH//ZGUwAEM2rAABeCv//NKv//9OAAAJz///T//9AAAEAACv//1/+AAAQCYAOkHAFxJZtUBS96CAJMWBB9iiKAAPh6rQADfX6SAAKkSP//9k////npNj//2wQAADqQgAAJOX//upf//8EAABUAAAQAAB///5//vAAEABoAD/tKAAcC7AAHJHWb//yWlT//60bm//u6zA//77NkAA+rmgAAs7f//Oj///85wAAWuAAAL///gAAAAAAEAAB/////4AEACAMkvjXwBBkTov+U4VxX/+Aql2ADAxaZAAPu07/99esf//pSAAAWPP///rP//8uAAAqAABl//8//+cAANABN//X+b/9AzgAAAkAAAAAAAAAAAAASDADNquLCALehbAF7w+PXdNBH/3xmFt/+ymCrAAbj23f//+UVf/2QIYAAGVqQABE3T//6Qv//7RAAACPAAAWAAAX///v//uAAIAAK/+8AEAKEtJGbnf/6k/hkABFyJEAAFjr/f/5ghYgACH2kAARoR///k/D//y9cAACG4AAFv///ygAAD///7//6AADAAC//oACADf7zkT3gBIibuUAj9LGi/9x2bD/++1GHgASj5+AAtlif//cPT//3IAAAAgAAAA1AAAd///9//9IAAbAAMf/h//gAo/3JBgBxYXvtAFzLCAC+VfHhZt28ADrI0KAA4Yi9f/+pvTv/9ROnf/9DU8AAFS74AAfqB//8Q5//9dwAACJgAAS///zAAAEAAGf/9P/9AAb/9/8SWo9wvAADG5thAAAYH2//3WUOf/9tTlgACnxiAAIS43//uSD//5ScAABUoAADZ///2///3AAACAADf//f/+gAIAAf+gCGWyi//bCRZC/uH20mgBIgdngAgHMtv/2fvf//qYhYAASoKAADlp///tf///6f//wQAAFgABn//uf/6AATgAL/pAHEgwA99sM8gC7isABfZXj2tsTv/97jZUf/ssIbwAG7DzX//+tgH/9knLAABplAAARCJ//+fV//+1aAAAmwAAF4AAF///3//8AACQAB//uACACJLSldsx/+pJTUAARiWMQABXec3/+Y7wIAAjyfAAEWJ3//45Y//8zFAAAkAAABZ///8gAAA///8//+wAA4AAf/6ABAAv+9ZbdeAS0/6nAI7EXSf/bGBzP/v0vYQAE0ilgALUlP//2s8//9ybAAAISAAAPQAAHn//9v//UAAIAACX/3v//AJf86QYAhnmRBQBewOQAvz7x40T2+AA78jVgAOHJpn//oQcH//UPMz//RXxQABURYAAH6x///Ga///WaAAAegAAFL//9IAACAABX//L//gAHf+//Qlqb1CaAAyHHt///8IZv/90fHD//cHmEAAqTiQACDEb//7me//+UsAAAT0AAA43//+P//9gAAAgAA3//z//oAC//3/sAhUz7r/2aOH2v7kJQ9QAS0A24AH977b/9iOc//6opyAAE0mAAA5M///7S///9X//8EAACgAAX//63/+8AFP///64CNIMASIKD9IAv3jcAX9l498DOaf/ewytH/7KuUoABuqFT///hF1//ZkdQAAbXuAAEMN///mnP//tqgAAKYAABiAABb//9P//MAAoAAT/7gA0AcS0vc45//qP+WIAEYDaEAAVhId//moCKAAJakYABEKm//+Ig///N1AAAJlAAAWD///IAAAL//+///wAAOAAD/+gAYAJ/ve8gMgE4g2ZYCNpbOL/2bVsx/7/Kt6ABQDnQACz2S//9lhf//cvwAACIAAAEUAAB5//+7//2AACUAAX/9wABACH/CkHAAfpEnUAYLkmAMAn8eV7UcwAPPxIQADiEaJ//5QP7//1Drw//0tEUAAU2fgAB75n//yXn//1zgAAGOAABO///aAAAwAAR//y//+AB3/p/3JaqfLVAAMnXZz//8E27//c1iA//3WSPAAKq+kAAf2M//+6Sf//l6QAAEiAAAN1///u///YAAAIAAL//7//8AAv/7/8AIQwnDP9g4I2j+5m4oeAE4HNzAB+eeF//XH3//+q0FgABPq4AAOP///+0///+////BAAA4AAFX/+l//4ABX/+/+6ApSDgAk6joCAMNrxAGBN+Pj0zGH/3rqYP/+ypjfAAbeSGf//1bo//2kK+AAHGMQABBor//5V7//7gIAACyAAAaAAAU///H//2AAKAAA/+4AQAFEtNoGkH/6jz1iABFbbAAAFQMk//5zJJAACfIwAAQm7f//glb//zwIAACioAAFZ///xgAAC///r//+AADgAA//oAHABf7592yoBQ/koOAjHum5/9hNZof/ATvMAAUwTcAAsnl///X8T//3OwAAAjAAABNAAAef//n//90AAoAACf/bAAsAb/upBwAdASeNAGKzzADBD/HoAqRcAD3nm+AA4lZj//+Czxv/9Qanf/9UrlAAFMhYAAdjJ//8uX//9nwAABSgAAQf//4gAASAAC//8QAAgAb/4/+yWrmWbcADK8cC//+JZlf/3Hpbv/98fwAACtcYAAHnLf//ufX//51eAABEcAADH///9f//3gAAEAACf/+///gAL/+f/QCDDArv/WxpPv/ujIoWgBQ1y9QAfW/A//1a9H//q37YAAUhAAADix///tr///rf//wgAARgABH//ngAAAAVf/f/zALUg4ATxpkMgDHY3gBgwnj6S9tR/97GCWf/svZpgAGyEp3//8Rgv/9s2XAAB2NEAAP+O//+Qb//+5iAAAvwAAG4AAEv//u//+QACv//v/wAEwApLT5b03/+pIw4AARICEQABQy3X/+frQ4AAqWrgAEBiT//3u7//9BLAAArAAABUv//8QAAAf//6///wAA///v/7ACAAH+/Dw88AU+fCRAItLaJf/W4ED//wNZQoAFYGDgALEMD//1nw//90iAAAI+AAAVgAAHX//4P//jAAK///3/3AARAE/7SQcAMhk8pQBksNoAwfjx6tNzjAA+vxPgAOKYuv//baA7//TrPv//YScAABUY8AAG5If//LK///d6AAAUQAAC7//+YAAGAAAX//EAAgAGf9//8lrKmSeAAy6+nf//SMSH/9v763//hOOcAAsk7AABy0L//7em//+k1AAARoAAAqv///P//+YAABgAAf//sAAAAC//X/4AgeV0V/1U/J9P7rKwmIAU66GcAHxgIn/9Q99v/6w4GAAFRggAA4Kf//7j///53//8QAAFQAAOf/5oAAcAFP/0f+AC5IOAHlKjmIAy1/4AYTZ4+7/6E//e3O4X/7Pg4IABqqd5//+oYZ//cY8YAAe+WAAD3Tf//i0f//uygAAMsAAB0AAA///7P//0AAp//r/8QBYAAS1G2Nr//qaLpwAENlv8AAS9DF//owDQAALYtIAA+Es//90mv//RrgAALUgAAUv///EAAAD//+QAAAAAP//3//AAj///v6AIjAFbaBI4CKGdy3/1W96z/8FetGABZD2QACvlv//9UA///dYgAACTgAAF4AABv//9n//6gACz//t/94AFwAv+ykHAEcxUb0AZrBMAMLh8e3nCagAP5TwoADi7qN//1Vkv//0sqM//2+HAAAV9QAABlcv//x3X//4egAAGCAAAe///kAABwAAB//yAAMABX/cACJa3OtPQAMwcGr//wAyj//bTU7//44g7AALn5oAAa08f/+y5v//rF4AAE9gAAJH///p///sAAAgAAD//7AACAAn/0AAAIDCWQP9PWAK/+7Y0e0AFaJubAB7TW///Sy7L/+s/OAABWuIAAN2P//+5///+T///HAABgAACn/+aAAQABN/8X/0AtSDgCjeriSAM9hQAGGq+P1NUw//3vPwF/+1jvPAAaIg7f//ffCf/3bvoAAIMUQAA7dv//4X7//7zwAADXAAAegAAM//+oAAAAAJ//3//QAX/+EtT9ww//6p4p2ABCTpbAAETTn//6aKiAADF9OAAO5L///bNf//0y8AAC+AAAFE///wgAAA///kAABAADf/8//0AI/+/8Aul8YBZz0SEAiOren/9P9xff/B5ndgAXBtoAArh/f//Tf7//3asAAAmIAABlAAAZ///U///EAAt//3//hABwAB/tJBwBcSWbVAGiyIgDDyfHxOK/oAEB8sCAA44NK//87kh//9FcQ//9+P1AAF2WQAAXTH//8Dj//+TYAAB6gAAF///4AAAf///f/8wAEgAR/3ABiWvCVVwADMXQ9//6yVg//2mbnv/+XZrAADEh6AAGRDX//q/v//7JeAABcwAACE///2///7gAAMAAA//+wABAAJ/8gAQB/ppzn/SXJBZ/u/pAzABZY5fQAejnM//0VkA//rcqAAAWTKAADZ1///uP///i///zQAAagAAX//nAAFwAQ/+6ACAKQQ4AAAXAAAAAAAAAAAAAEgwAzariw/9vG3/+5P20a9imN//6UIdgASfOtwAAxq+f/+Uz8X//ipUAAEfgoAAD9G//8tv///tCAABaQAACv//9AAAAAABf//AACP/7AAgAAbdK7yqABGjeYgAJ5bEv/7AQk3//boXQACL9yAABRYT//vbI///ExAABKMAAAUP//83//7gAAFAACf/9gAF//uACgAH/tEz36ApYcGdgCh5Mxf+u4XkP/7ddfAAKl3WAADCDv//rm////jFAAAUMAAAEgAAB///1gAAy//1gACYAA//nAHP8SQYAcWF77f+20y//crTaOjeok///7wM///30koAATUyD//a6jX//zMcgACHP8AABlHf/+T3f//6UAAAxIAAAb///P///gAAf//wAAn/+gAIAANvbMEp//ml4Xv/9Zj9X//XgM///7w0cAA3N1wAAbSR//33Kf//rjAAAnkAAAD///9f///IAAAAAA3//YABn/7AA//8AJNIZj/rQVdIP+xWMaAAotNK8ACOwsr/6qbaf/+b8sAAKdFAAASmf//1A///6X///MAAGP//jAAGP/+gAAAAN/8ICZIMAPfbDPP/bDFD/uXVtGuWcYf/+zJP4AEjjX0AALcnf//lVQx//5NCYABHmpAAA5Nf//LvP//78gAAWoAAAn///IAAAgAAP//yAAj/+QAT/+G3PUUGAARUvTwACWTBX/+xBNP//3Vx+AAiqVwAATD7//75nf//ywQAASVAAAD////N//+oAACwAAP//gABb/6wA7/1/7kAn/AKZXskwAl98Oz/rngvf/+72cYACqWGoAAtf///638f//5TQAAFDAAAB4AAAD//98AAMP/9EAA9//b/8wBP/IkGAIZ5kQX/tV6d/3Mg2jn2ggf//5oiwAAACLiAAExTD//2qqF//87KUAAiDEAAAYeH//kZv//+nQAANKAAAE///uAAAAAAF//9AAJ//oAEAADb0YT0v/50lZ///ZtD7//1ypw//+6UuAANw0cAAGwZf/99HX//6zwAAKNQAABF///O///wAAAYAAF//5AAT/+wAR/8ACJsYDP6yfAu7/tnJD4AKOjYEAAhYFe/+qKMf//oo7AACoSYAAER3//9QP//+MAAACAABL//5QABv//aAAkABP/aAhSDAEiCg/T/2lJO/7mrbRrYyeX//w27uABHZsbAACjPwf/5aDq//+emeAARweAAAMbL//zAT///K4AAFtAAAI///wAAAQAAA//9gAH//kAF/+htzIPNIAEO8wAAAjEh+//snSj//9/bXAAIiGkAAETjf/+/Pf//9KoAAEjAAAAw///yf//nAABH//9//7AAS/+sAR/6f+92rVACnIUcCAI2R5J/64Sz6//wHOtAAqzAUAAKmp//+tjD//+dEAABRAAAAq///5///rAACr//PAAT//pAAAAI/1pBwAH6RJ1/7PrK/9zjdo5t8iv//85NHAAAaHSgABJvH//9rR2P//RnPAAIePoAAF9V//5ED///ngAADdAAAB///5gAACAAA///QACf/4AB//w28gr7v/+fkpI//3Mt7f/9fABf//vTfQADYxxAABoh3//fnN//+pyAACk8AAAa///x///7AAAMAAAf//AAEf/sAEf+gAf86QP+sOq0D/7utZhgCkb1cQAHwMqP/qbbh//6k+AAAqWKAAA+x///Tr///dAAAFQAAKf/+mAAb//zwASf/t/+gFkg4AJOo6A/9mY3P+54e0azTVX//9bAtgARaPNQAAiUhP/+YLPP//rRUgAEZGkAACjo//8w+///1sAABcgAAB3//7wAAH///v//wABf/5ABv/Ybcn0xIABCFQ3gAIAapP/7QqrP//jPkoACF9SgAA7S///wBV///bSAABIeAAAJf//8P//5QAAW//9v//wADP/tAEP+P/wtb4uAp+lhbgCDBCxP+trt8X/8UpRYAKwDlgACdEH//rR2///pPAAAUYAAANP//8n//+gAAg//0gAFn/3gAP//f+qQcAHQEnjf+yeNX/c/naOXm05//+zkPwAAKzfYAARH03//bUy7//1icgACFY+AABaPf/+Spf//5BAAA3gAABD//+AAABAAAH//8AAf/+AAn/0Nu+fMP//oVlCv/99Wbn//ZHw7//8eDgAA0xOQAAX3d//4HUf//qQgAAoTAAAKP//8b//+QAAF///n//8AAv/7ABP/cAHWsva/q9Xi/f/BBG7IApTreAABycDr/6lFEP/+v7EAAKqJAAAOb///0s///2IAACgAAAP//xAAGH/8wAF//xgBoAVIOAE8aZDP/Y3/n/uhftGsAu0///tO4gAEPIvYAAGhDF//mhY///77p4ABFc4AAAfCP//Ma///+KgAAXcAAAX//+4AACP//wAAAAAL/+wAX/2G3HOA7AAQIjmoABx5YL/+17C9//545+AAg02AAAL5v//8DXP//5JAAASFAAABv//+5//+YAAGv/+8AAKAAT/8wA3/j/8ftbmAKi0WiwAeEQED/rUpuL//J9UCACs1xoAAkEE//6ywf//6xQAAFJgAAD3//+sAAAgAAE//9oABZ/9cAHP/EAAkHADIZPKX/sQed/3Rl2jk6ctP//mDu8AADRaYAADui4//3BIn//90+oAAggyAAATs3//lnP//+KQAANKAAAY///eAAAf//8AAAAAD//gAJ/8Dbs+b/f/6JS5T//g+8z//2vzj///bTCAAMwX0AAE4q//+Guv//7BAAAJfAAADP///M///YAAB///sAAEAAB//AAT/1ABrYPWP6tu/l//xm6QKAKYH/3AAaLqh/+o1BX//tongACrp4AADWn//9Gf//9UAAA3///h//+YABJ//QABl/7AAz/3SDgB5So5j/2Cek/7pN7RqvWUoAABjzYABCBX0AABABU//5wBV///UCKAARKcAAAFEP//zI3///uQAAF9AAAEf//vAAAn//5AABgAA//4AD/9htw+X44AD9BBIAAYhz+//t3+k//+y8nAAIDooAACIXf//Bc3//+5EAAEhAAAAU///rf//pAABv//qAAG//8//sAH/5//NEtEgCphJPQAG1l4F/6zkbB//zs9DAArazoAAINSP/+sRT//+zIAABTgAABD///kgAAZAAAP//nAATf/XACT/oAGpBwBHMVG9/6+Xg/900to4+EcP//380SAAA33ygAAukXv/9zjOP//naNAAH5GwAADnt//5t3///mkAAC9AAAG///5AAAJ//+AAAgAAf/8ABf/Q26gIhj/+ikXA//4XWNf/9zmef//+XUgADFRpAAAzC///jAL///EGAACLAAAAyf//1v//2AAAh//5AACv/9//+ACf9wAYQX//+rBXhm/8vgwoACm1tLwAF77WP/qGW5//70ToAArJ6AAAyb///Qj///SgAAQv//xAAAEAAK//2AAX/+mAQf7Eg4Ao3q4k/9dv3v+6hG0amTT2AACCNgAAQIO8QAAEUu//+dsPn//7BwAAEP28AAAjF//8yo///+cAABggAAAn//8AAAJ//+AAAv//QAAAAf/obb+xPUAA+UjdgAFFsKv/7izzn//yoUAAB/FiAAATHr//wd7///4PAABIMAAADf//53//7gAAZ//6AACf/8wAEAAP/P/0jmnkAqlno8gBigmoP+sfOv3/9OszQAK6E1AAB2Xf//q93///uZAAAVQAAARf//4AAAKP//y//+AADX/3gAl/4wCyQcAXElm1f+uKIX/dT7aOLHQY//9rf3gAAOhAQAAHUXL//dkOr//9JwAAB7EYAAAa1//+f////8eAAApwAABL//+4AACf//YAAT//wAAAAH/4Nuavun//omJUP/+CttH//eTqoAACEWQAAwE0wAADqr//5AZ///5ZAAAgBAAAHn//97//+QAAGf/+QAA3/+wACf///0AFa5H4/qpocYP/RTxXgAp6VucABVQN7/6f8DP//DlMAAK1UAAAL6f//z+///0IAAEr//6YAAKAAAX/+cAEv/pgEf+IFOAAAAAAAAAAAAAAAAABIMAM2q4sP8f+TsASrQKbV43ff/VCzEn/+CR9oACE30uAAPRiv//ShvX//TftAAE9GwAAhjP//p+f//usAABoAABcAAE///7//d//kADABMACRLLMpeAANv+xoAIMahMAABgAh//b74f//wwgwABWwDAACX9v//By///0eAAAdMAABb//+7//8gAAAAAWAAX/+v/T///ucolF/6DawGQCWpLt4ALtHjj/7vWkZ/+ckRwAC9e4AADNHP//b1f//67AAAEIAABwAACP//7v/9n//uABwAFP/n/EkGAHFhe+3+QLdwAJVVFNiywkgARXRJD//h2Fp//2qunAAGyy3//zAmH//ppfgACNdoAASKH//1Mf//3AAABH///1//9wAACAARAAN/+n/aAAImSMK3//4ITS//+iFSkAAdoSj//31We//0fzoAAlPFgABW8H//hXX//5SgAANwAAAvAAAGAABH//7//1//8ABAAX//AI4qoxAC7NlOz+0Z5Ib/6R2drACH+RlAAvTH3/+kAlf/+o2oAAPq4AABhv///D///E//+yAADQABeAAI/+3/9IAcAqSDAD32wzz/IL41AEqhCmxOgzv/1TvBr//h75rAAhJibAADr+Df/0lDH//1SiQABQPQAAH/X//6Yf//76AAAcAAAZAABH//7//2//9AA4AR//ES1ajBgADdhwgACCmWqAAAJFuf/27oqf/8WrOAAV+3wAAkQX//wJT//9SoAAHdAAAU///s///MAABAAFgAD//n/1AAf7kZ5hf+j0KEgAmCUAHAC1eIV/+7JwHf/n6PIAAv1xwAAxtz//24X//+w4AABJAAAdgAAe//+j//a//+gAeAA//y/xJBgCGeZEF/kJBMACVLhTWl+1YAETK6O//4a91//9tsfwABpp5f/8xLO//6mYwAAi0cAAEWr//9bL//98gAAO///7f//gAACAAEgAB//l/3gAyJlyWOb/+Cmjk//pGCsAAHTOn//97w5//9MnVAAJTQ4AAVFX//4ed//+Y8AADMgAAKwAADAAAP//9//9QAAAASAE//ACPhrVUAtTKQB/s6jEM/+nYwiwAiVPLQALcyq//oxzP//q48AAD8aAAAXv///tf//wf//vgABCAAXAAAP/s//gALgKUgwBIgoP0/yGC+wBKjYprL0tF/9WB6bf/45a+AAIPTl4AA4RQf/9JRwf/9chEAAUOHAAB5M//+kb///CwAAHoAAGgAAP//+P/9oAAAAPAD//JEuDAZEAA3t2FgAgagZ///9yFn/9uywv//ItMAAFixUAAInN//7+G///XaAAB6AAAEn//6///1AABAABgAAf/3/9gAf+4arBN/pt9C6AJmhxTwAr3vE//unkNP/6LQPgAME5UAAMBE//9s4///s4AAAUAAAHoAAGP//i//3AAAYAHwAK/6/8aQcAB+kSdf5DyooAlQcU1Fo42ABD+8ov/+I91H//byzQAAZH0T//M15P/+utuAAIjkgABAC///YO///kwAADX//+P//5AABAABIAAH/4/+IAgiZxeJh//g5anP/6Zo+gAByMDX//e2Ij//U9xwACT36AAE+h//+Jy///okAAAwwAACIAAA4AADf//X//YAAIAEgA//oAkOKmVAK8Aj0f7Lq4kX/qmQqkAIqrAEACxCmP/6I9D//65ogAA/egAAFq///6n//8D//8wAATgAFf//n/7P/7gD4CVIOACTqOgP8iR44ASnoKafpmAf/V1puH/+W+cMACCth0AANLaH//SfiX//ZgmAAFE1AAAcj///ou///xsAACGAABsAADP//X//aAAIAEAAz/sRLsrbqAAOCrR4AIBP+D//9+OV//b07///zGGAABZCpAACCGf/++rv//2ggAAfMAAA9//+r//9gAAYAAWAAD/9//gAL/t7pExf6oDNZoCbHyAcAKlXtX/7nK2X/+mEqwADDGnAAC5W///a6f//7agAAFcAAB8AABL//3f/98AASAB8ABP+b/MkHAB0BJ43+RVN8AJTgFNHyDIgAQw6e7//jXDN//3BKJAAF0i9//zWQL//tdYgACHSQAAOIX//2J///6uAAA1///d//+gAAWAAR//7/+P/qAMImh80lP/4TPiH/+oYWSAAbpkY//3uaR//13swAAks/gABJBP//iwX//66AAAMMAAAaAAAMAAAv//x//2AAGABIAL/4AJJCm9wCoqNf7+yLElB/612zEACMAUxAAqrpL/+hX6f/+xboAAP+YAABU///+Z///A///cAAFgABP//x/+1//wBMAgSDgBPGmQz/IwvuAEpmimippVf/1i6el//ojynAAgXWxAADAoK//0sTD//3GhwABROYAAGrP//6G///8pAAAkgAAcAAAn//y//3gAGABAAI/5ES+aJzwADjlIkAB+rJj///ABR//3BKz//9DwgAAWQDwAAeY///viD//9xoAAH+AAAM///p///gAAHAAF//+//b/6AD/7cHKj3+tNzp8AnJ+cQACjFgd/+5G1Of/qWUSAAxQXgAAsjT//2pL//+6IAABeAAAfAAAL//9n//iAAIAAe////h/1pBwAyGTyl/kbcCACUuRTPVweUAEISow//5OLrf/9yOEgABTykv/82qp//76KAAAhxeAADAt//9f3///AgAAOP//2f//sAAGgAEP/9f/j/8gDyJqAH1f/+GCI///qnUSgAGoRiP/97x+f/9qpVAAJI/IAAQQd//4rT//+7MAADKgAAFQAACgAAH//7//+AACgASABf9gCTqPVIAojcj4/sWwff/+wlnPAAjVhlgAKRIB//oICf//tJuAAEBwAAATn///h///wf//7gABgAAQ//6v/uAAKAVAGUg4AeUqOY/yPQGgBKUwpnN/AR/9Z81s//7BbEAAIBTAAAAqh7//9MOLf/9/twAAUPrAABih//+hF///NQAAJ4AAGwAAG//7//+AACQAPABP+BEwfGLyAA6A1SgAfOr9P//lut3/9xfsn//WmigAFiosAAG+m//73z///emAACBwAACv//6P//6AACQABX//P/3//QBP+2UPEd/sHS4HAJ4jvYQAnMKwf/uGpv3/6y/7AAMb9kAAKrq//9ot///vkAAAZQAAHoAAA///W//5wACwAG//5/3v+KQcARzFRvf5IZC4AlJIUzIEqVABBGhG//+av/n//dhaQAASOTz//NdJ///ILsAAIiEgAAoA///Wm///zoAADv//9n//8gAB4AA7/+//5f/oBEia6mhc//hxFxP/6zGMgABkun7//e07T//eX+wACSmoAADhZ//+JQ///xoAAA1gAABQAAAYAAA//+3//kAAwAEAAH/UAlRW2tAJu5PMP7CqiL3/s72QkAI6wsoACdvjP/5+dF//7fdgABBIAAAEf///3P//8MAAAAAAZgADf/+P/8AAGAFoBBIOAKN6uJP8klBMASj+KZaJJ6f/WtcgH//BA0QAB/kJkAAI+a7//TPUX//kI+AAFCYQAAWLf//oT///z8AACqAABsAAAv/+3//mAAwADgAD/cRMXMDDgAO4ysoAHtDFT//2PxL//cpfJ//3YF4ABYKcAABjqP/++Nv//4MgAAgsAAAn//+f///AAAsAAT//r/9//8AV/tZhhC/7O0fqwCfqbhcAJZqU7/7e5SH/+wG2AADI/fAACjp///Zt///8KAAAG0AAB1///3//0//+0AA2ABj/9P93/wkHAFxJZtX+SevuAJRrFMlqbegAQDQV3//ops1//3zbbAAD0ai//zKK///0g5gACLYYAAIK3//1Pv//9cAAA8///b///gAAiAAM//r/+YACATIm19m4P/4fRbX/+vb/gAAXsti//3mwc//4mxwAAlBJAAAvoP//hr///8/wAAOCAAAVAAAEAAAH//r//7AAQAA//9/1AJaGM+gCVPUE3+v6MCn/7bmGPACQCOFAAlysv/+etHf/+7HgAAQfAAABB///9h///GAAAOAAGoAAn//d//KACYBaAGCTgAAB0AAAAAAAAAAAAASDADNquLD/M0A+/4rzfr6UE/gH6hmb+BufWzC9SN7ovfrZB8Bhvk9AQBHvb4vw+9V/+7xCEBJVYgAulS/4ll/+URABCAADT//r//D/+gAYA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Q0ACv/0//wAA7OAAAswAAAAAAAAAAAABIMAM2q4sIAALp0AAFhwloSe///9IPf//7xfM4AA+mBCAAT3fD//YARf//NlrAAFTHAAAmKP//nWf//sQAABaAACIAAE//+D//uABoAAf+MAYM5uBBvf/zWaNwAA+78wAA2pOb//mKOz//n4hYABYTrAAC+k//+64v//x9gAAeMAAAWAABgAAF//9r//sACAAAv94Af/q3dpvACTaaRwC0vl5L/7gDBR/65gZ+AAlLQwADg+9//+7Nv//WkgAABBgAAEQAAAAAAAwAAAf//f//+AAUAAAAIAAkGAHFhe+0AAF4kAACx4SfX2Av/+I4lwAAtZKSAAg6gwAAEiHu//rk3v//sKfAACqs4AAPdn//zu///68AABT//+5//+AABEAAL//R//QAoAAGcpAzBwAE0UdwACd8jcAAFM4E//vSQR//3WKwAAvOVAABP43//cpf//6ZgAAREAAAw//+X//9oABQAAM//J//IAuAAAKkDQl/+yrBMn+ly1YaACYDmIACinoK//r0zX/+Q5VAAAp7wAATxP//+6///96AAAd///5//84AASAAV//v/+QAUAJSDAD32wzyAAC+GAABY8Jaf9T///NgdP/+8FfFAAQT9UAAE1Rsf/1rYR//z6fAABW9IAAJGP//5t///7UAAAYgAAhAABD//h//9AAZAAD/lAHjOb7D/P/8wEtQAARGn/AANnZef/5VFf//6IogAAWpBwAAt3v//uZb//8p4AAHpAAAFgAAYAABT//b//8gAfAAD/gAJf6u4qQYAobUYAAtDhmH/+w9j5/+umVOgAKOCAAA4ITf//s/7//1oEAAASgAABHAAAAAAAKAAAH//5///AAEAAEAD//JBgCGeZEFAABf9gAAseEn+5Pr//j8wOAAMiGXgAIcv6AABCIdv/6t0M//7UyQAAsiqAADmR//8uv///AAAAWv//s///kAAQgACP/0//4AI//hnKjxyAABShH7AAoSfVAABDC8//7tCfv/98KUAAMNyoAATG///2uf//+ssAAEpgAAJf//kf//kAATgACf/y//4AKf/QCocuyL/q367B/phYwvgApjx2gAohcN//6fMl//kUXgAALbcAAE7Z///tT///eAAAH///9///MAAFAAFf/7f/kAGACUgwBIgoP0gAAwcAAAWXCW1FM7//yafD//u3sCAAEN6TQABLgz//9WjZf/9GqkAAWMTAACJ7//+Zx//+5gAAGoAAIQAAN//4v//oAGP/+/6ACIznM2KP//Kew0gAEev9gADZqOv/+Sy+3/+kvFAAFxG0AAK++//7iJ///NcAAB8AAABYAAFwAAR//3P//gAHf/+/5ACn+sB4WcALAhBygLOXkGv/qdypH/rt4b4ACyX3AAN/rr//6zY//9Z3AAAFGAAASv///4AACAAAC//+///oAAwACABf/iQcAB+kSdQAAYcoAALLhKElsi//5WlVAADaufoACJ8/8AAPLoz/+pInP/+4bYAALiZgAA3i///Ib///xQAAGT//7H//6AAEAAAX/9X//AB3/wZywvfOAAV6nzwAKPfEwAANBDX/+52hv//gYyQADIbyAAEqAf/9lw///rdAABQwAACD//4v//7AAEwAAb/83//ACH/sAp8h2r/6Q8Awv6ZtWYYALSONwAKF8Fv/+gPWv/5GuKAADF+gABOsf//6+///3YAACD///f//zAABYABX/+v/5ABwAhIOACTqOgIAAMVsAAFlwlxzb1f/8bGCP/7rC1kABFMiUAASdSt//Uzen//TtyAAFo/gAAgcf//mCf//vkAAByAACAAAC//+T//+ABf//f+sAkM54PKk//yPt+IABI0i0AA2TKV//kTmb//p4xgABdfCAACnIP/+3qv//0LAAAfcAAAYAABYAADv/97//8ABv//P+cAt/rGHx+AC+wAhYCy308z/6KtkZ/68tf4AAwWI4ADfMg//+ltf//WdQAABYgAAE3///+AAAcAAA///z//2AAIABAAX/ykHAB0BJ40AAGOgAACz4Si8LSP/+aZMkAA6+PGAAi8KYAADfok//p40v//usnAAC9BwAAN2///xhP//7wAABt//+1//+wAA+AAD//YAAAAX/7GcuuNmAAFxF0cACl3RSAACVt1//uQI9//4af0AAy0+AABJcP//Ykv//6pwAAVSAAAk//+F///AABIAAD//QAAAAZ/6AKcIzsf+c3N3D+mzrvqADDDM9ACg0Lb//mKGf/+SHLgAA1L4AATpv//+rf//9yAAAh///1//8oAAaAAV//p/+YAgAGSDgBPGmQyAADJGAABZ8Jd0YXn//E4Ml/+6KfXAARl1tgAEgID//1Dcx//1eMQABba8AAHkb//5aX//8MAAAfAAAeAAAj//mAAAAAV//v/vAJjOfmLj3/8ezq0AASDWCAANeqE//5B+Df/6rcIAAXj7wAAnX///tu///9QgAAH/AAAGAAAUAAAv//hAAAAAZ//v/sALf6zFK24AzZyGMAshR+7/+bY/1f+vhYrAANCYiAA3lv///non//1n0AAAXwAABP////AAAFAAAT//9//9AABAAUAF/7JBwAyGTylAABlegAAs+EpTsND//nouzAAPv8/gAIx2dAAAzEiv/6bUj//70MoAAvsEAADgJ//8Vv//+rAAAbf//vf//yAAOgAAf/3AAAAD/+xnMbrOkABgPeRAApuknAAAV5zf/7jDBf/+MnTAAMvWoAASBz//2IL//+l0AAFVgAALP//h///2AARAAAP/1gACAD/+gCmOk9D/lV7oQ/pzfGogA0bmBwAoBgrP/5D+Q//kpLwAAOLYAAE6H///qX///bgAAIf//8///KAAHAAFP/5f/oAIgBEg4AeUqOYgAAzMwAAWnCX1lxV//w7idf/ueq8AAEcCroABF3e3/9PdIf/9hCgAAXE7AABwA//+VJ///IAAAIQAAHAAAG//6AAAQAE//6/8gCYzoVNat//GwssgAEaCeQADUX3n/+QddX/+u5qAAF6hUAAJLI//7ZS///XwAACBwAABgAAEgAAI//4wAAQAFv/6/8AC3+tLfnCANy2X1ALE87Zv/k//Y//r+PKYADgBhAAN1vb//5dL//9aQAAAGSAAAUv///wAABAAAF///v//AAAAAHABf+iQcARzFRvQAAZ1QAALThKfzY9//6MJzAAELc9oACMBPcAALXfv/+m9p///AL6AAL25gAA3lf//Gq///noAAGP//8X//+AADQAAD/+AAAgAf/sZzUhyqAAY6rSAAKbjHoAAA/nT/+5Dkf//lNqAADKQqAAEUnf/9k3f//pKAABRYAADH//4///+gAD/////9wABAAX/oApWQJz/43FR3P6elsqAAOCNJYAJ9Vjn/+JWLf/5MUcAADwLgABOSf//6m///2wAACD///H//ygAB4ABP/+P/6gCQAJIOAKN6uJIAANCAAAFpwmD/qdf/8Lc/P/7oyJsABHOKcAAQxuT//TuZH//a6FAAFztgAAZof//k7f//zgAACMAABcAABf/+0AAAAA///f/UAcM6Muxnf/xjMWgABEg8EAAztdz//kOzx//s9qIABeuLAACG8v/+1zP//22AAAhMAAAcAAAwAAB//+oAAAABL//P/MAh/rZkQhADsAZCICwXp4L/4yGoz/7BFoKAA76H4ADcc0//+P9///WrwAABqAAAFT///6AAAIAAB//////qAAAACQAT/ikHAFxJZtUAAGkuAAC14SrDklv/+o8hoABGzikAAiouyAACZXi//p8c///xR6AAC6sAAANGf//yR///6CAABT///J///4AAv/////mAAQAB/9Gc457ggAGbWfIACl2Vl//+4iL//ubxF//6B2EAAx1sAAA/b///aWn//6rgAASyAAAr//+aAAAAAA3//+//iAAX/9/8AKSMwg/+GGNh3+oFd8iADveJpACei7H//gbR3/+TpQgAA/QgAATbv//+rP//9yAAAf///t//8wAAiAAS//j/+wAkAAPDgAAMsAAAAAAAAAAAAASDADNquLD//+BP///SA3p1/BX/+oSS+AAyg7CAAGb39//3FQ3//9OQuAAcIQgAAUY7//qNb//+qQAAKRAAAKf//0///f//x//6//+AAUAGACk8tyLvgAA8DTIAAVH67//r93l//9/ExAAMupyAAFYw//+UML//8K4AAH8IAABp///Qf//+AAAMAADAABAAA/////AAf7OZ694CEO9LaAo0QHg/78psAf+2TVWAAh77UAAyv2v/++H7//2p8AABOQAABi///7f//n///D///AAB//6//f/6AFJBgBxYXvt///AJf//ogb0V/TsAAjcDeAAg1OvAAAw6qv/7XtUf/+7snAAN/1wAAKdz//1Yn///EwAAEtAAAG///4gAAaAASAAIQADf/Z/0f9SeX/4MwAAltEIAAAfXHf/1zNu///TU8wAGWMpAACiif//Kzp//9z8AAD1IAABT///rf//9//////9//+///gAGACAAgCX+Htr+9GlMI/ruQAwgCDMnLQAkkEJ//u1nP//m9tIAAhQwAAEhF///Y////SgAADAAAMgAAd/////+gADAAWAE/90gwA99sM8///f1f//z4N65M03//ri22AAME+nAABZcun/9zb1H//bRJAAG+xUAAEIs//6jx///u2AACkwAACP//9P//3//8v/+v//gAFABgAhPLXOYGAAN4F0gAEu0dP/7DlJP//lCwYADKe3AABGWL//lFH///OnAAB/gAAAU///z////wAADAAAgAAQAAP////wAH+0jLrmAh1uPzAKFC5P/+9ohw3/tzMkIAIrp2gAMiNT//vLO//9sFAAATuAAAYv//+3//5///w///gAAf/+v/3/+gBSQYAhnmRBf//vyv//50G9RWV/AAI/xLAAISWJAAAGA9X/+2oaT//zUogADcd0AAB9Pf/9aif//1iAABGwAAAz//+YAAHAAEgACEAA3/2f8//Unl88xTAAJx5Dv//2iN3/9dc1z//3uRQABkmYgAAfGH//y5g///lzAAA7ZAAAOH//7X///////f//f//v//4ABgAgAIAlgit4/u4iFcf6/m9JoAhkXz8AJBz+f/7m/Lf/50NwAAIf3AABHj///2O///0gAAAsAADIAAHf/////oAAwAFgBP/dIMASIKD9P//31X//80De2LXlf/7V6SgAC4cLMAASXzr//dXIL//4/6YABu4SAAAxhv/+pHf//80AAApYAAAf///P//9///P//r//0ABQAYAGTy0TPLAADKu0IABBTNb/+x8Rt//6voSAAyTtoAANSg//5SLP//2ugAAf9AAAD3//89///8AAAwAAIAAEAAD////8AB/tYQVCAIqCghACfN8Mv/vBfUD/7gdlIACOGfgADGCr//7tGf//beAAAE+AAAGH///t//+j//8P//4AAH//r/9//sAWkHAQfpEnX//74j//+XBvXraDwACQLcEACGQpV///u/V//tw0m//+G5EAA2lWgAASy///XH///+swAARh///8///kAABwABKAAhAAL/9v/P/0J5eVuMwACi11b//44TZ//XcHw//+wD/AAY/FsAAFBCf/8wLH//8FIAAOsQAABZ//+1AAAF//////1//7//+AAYAIACAJQR9a/7nzXmn+w7ciCAIldYpACOnqo/+4JLX/+eTKgACK0wAARpH//9kv//9SAAAEAAA4AACX//z//7AAWAA4AT/+SDgAk6joD//97O///Kg3vp2wn/+99U0AAsL8hAADdvPf/3cMy//+2h2AAbjJgAAH6T//qVf///fAAAKYAAAF///z///f//y//6//+AAUAGACE8sq4oAAAuGjkAANWbS//stn8f//GDCgAMghUAACKqP/+U0v//+ekAAH/wAAAo///PAAAAAAAMAACAABAAA/////AAf7Z9XfQCNr4r0AnSd75/7qLUU/+5Co1gAkU7kAAw3wP/+51T//2/gAABQIAABg///7f//o///D//+AAB//6//f/7AFJBwEdASeN//+9D///kgb20go4AAjq4BAAiE3K///c+QP/7cN9v//360AANodYAABYR//1uF////sAAElf//7///3gAAeAASgAIQADf/Z/z/9CeXVS9EAAqWpS//89Hz//12G1///6P8QAGPD8AAAgw///MBx///s2AADuP///4///rQAACf/////9f/+///gAGACAAQCSGcff+4W/Vy/sfZY5gCMdz1gAjMPi//tonW//n5d4AAjbgAAEVj///Y////WAAAAwAAOAAAj//8f//AAFgAKAF//Eg4ATxpkM///eQP//yAN8c0Yv//xxP8AAKsoZQAAj83//93+Hn//3+pgAG3F0AAAyT//6ma///8YAACmAAABH//8///4//8//+v//gAEABQAhPLEAfOAAKkYuAAChf2f/7N5pH//4hoAADHZtAAAO+T//lRv///06AAB/2AAAE///zoAAAAAADAAAgAAQAAAAA//wAH+3dlcIAkN9SlgJsWJX/+4/hcH/ufhQQAJSF/AAMDnD//uF2//9yCAAAUMAAAXv//+3//6P//w///gAAf/+v/4/+wBSQcBMhk8pf//u+3//40G98FZoAAIwz1AAIqsC3//vQfD/+2kTwAADoFQADb79///jD//9YGgAAECAABOX//+n//9oAAHgAEgACIAA3/1/8//UnlxCumAAK+2t//+6Xvv/9coQAAACPlwABkKGv//8Qt//y46AAAFKgAA9S///5X//6QAAAgAAAf//f//r//4ABgAgAEAkCSYy/tsRxIP7L+9woAj5BSgAIrmIb/7Tugf/6DrgAAJC8gABEEf//2E///2AAAAQAADoAAIf//P//0ABIACgBv/tIOAHlKjmP//3av//8WDfPljdf/9ARo4ACoV9AAAD/8Z//d/3UAAArk4ABtvQ///4cv/+p2wAAATAAApcAAAL///P//+P//L//t//4ABAAUAITyvT9EAACeT/IAAa0rT/+zscP///9GWAAx0L///+kv//5VUAAAAtgAAf3///////86AAAAAAAwAAIAAEAAAAAP/8AB/uG1pOgJQMcXoCZBn3L/t3KZz/7rlwOACXul4AC+UI//7bff//dFAAAFHAAAFv///v//+j//8P//8AAF//r/+P/sAUkHAEcxUb3//7q9//+IBvixhtwACJz1EACNVmD//517X//tZf/AACQG0AA33rf//tkv//U2YAABsQAAUx///q///WAAB4ABKAAiAAN/9f/P/0J5bL3XAAC1bBP//pW9D//WweDAABd5GAAZRhH//8QZf/8rDwAADWIAAP0f//9v//+dAAAGAAAH//1//7//+AAYAIACAI41HpP7Uv3+j+0BqfqAJKj3wACJB0+/+zU8f/+iQ9AACT6QAAQsX//9bP//9mAAAKAAAwAAB3//9//6AAKABYAT/3SDgCjeriT//90Q///Cg314hZf//YIAWAAqHXY///y6lf/3cCJAAA1wOAAbjav//44P//qgUAAAZgAAKSAAAB///y///j//z//6//+AAUAFACE8raSkAAAmJ/IAADYVn//s3LuAAAceNAAMfiL//+UGv/+VYcAABGwAAH7P///q///OgAAAAAAMAACAABAAA/////AAf7lh6ugCXL/W+Alvlo8/7Xr+z/+70qHAAmuVcAAu7tP/+1XD//3akAABTQAABY///7///o///D//+AABf/6//j/7AFJBwFcSWbV//+5f///gwb5nI3sAAiH5VAAkEiU//+ACsP/7Q5agAA3NFAAOQQX//5Hr//07AAAAhcAAFXf//7///1AAAcAATAAIQAC//b/y/9CeWiiy8AAunmS//5E6ef/1jO/wAAlB/QAGZvv//+cIX//J2uAABPCAAEDT///Y///mgAABAAAB//9f/+///gAGACAAgCMS7In+zoeMK/tQ1XNACVq/dwAhyhZ//sbv9//o5vQAAlzOAAEF7///Vv///bAAABQAAOgAAd//8///gAEAAKAH/+AA=="},{"gloNav":"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"},{"galNav":"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"},{"qzsNav":"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"},{"gloAcc":"EkgzNqnpB2bVAfe973v/AAAAhCIQhCCEIAAB////////gAAAAhCIQhCEIIQgAAH/+973vf/8AAACEIQiCEIQAAAH//973ve//4AAAEIRCEIQghAAAAf//3ve//4AAAAIQiEIQhBCEAAA///ve9//wAAAAQhEIQhBCEIAAB///e973v/+AAAACEIQhCEIAAB///e973v/+AAAACEQhCEIQghAAAAf/////+AAAACEIhCEIQQhAAAP/973ve973//AAAABCEIQgAAAAf///ve///wAAAIRCEIYxiEIQQgAAAP/////gAAAABCEIQhCEAAA///ve73ve+97/wAAAIQhCEIQgAAAAA////gAAAABCIQhjGMYhCCEAAA///ve973//AAAAAAAAAAAAH//973ve973v/AAAAhEIQhiEIQghAAAAAAAAAAAAAQhEIQhCEEIAAB//vd73ve9773//AAAAAAAAAAAAAP//////AAAABCIQxjIQgxjEIIQAAAH/////wAAAAAAAAAAAAAH/+93vec5zve+98AAACEIQiEEIQhAAAAAAAAAAAEIhDGMYwAAAIQhEIQQhAAAP//73ve97//gAAAQhCIQghCEAAAB///+97//gAAAAhEIQhCCEIAAAD//+973v/+AAAACEIhCEIIQgAAH//973v//8AAACEIRCEIIQhAAAP//73ve9//wAAAIQiEIQQhAAAAf///ve///wAAAAQiEIQhCCEAAAB//ve973//AAAABCEIQhCEAAAB///e973v/+AAABCIQhCEIIQgAAAP//////+AAAACEIhCEIIQgAAH/+973ve97//gAAAAhCEIQhAAAAA///////4AAAEIhCEMYxCEEIQAAD////////AAAAAAEIQhAAAAf/73u973vve/8AAACEIhCEIQQhCAAAAAAAAAAAAQhEIQxjGIQghCAAP//73ve973v/+AAAAAAAAAAD//+973ve97/wAAAIRCEMYxjGIQghCAAAAAAAAAAAIQhEIQhBCEAAA//3u973ve9773v/AAAAAAAAAAAAH//////gAAAAhEIYxjGMYxjEIIQAAAH/////wAAAAAAAAAAAAD//e93ve973vfe/8AAACEIhCEIQQhCEQhCEIIQhCAAAAB///e973ve9///gAAAAACEIRCEIQhBCEIAAAAH//973ve973v//8AAAAAIQhEIQhCEIIQhAAAAf///ve973ve9//wAAAAAhCEQhCEIQhBCEIAAAD//+973ve973v/+AAAAAEIRCEIQhCEIIQhAAAAf//3ve973ve9//wAAAAQhCIQhCEIQhCCEIAAAD//e973e9973vf+AAAACEIhCEIQhCEIQQhAAAAf/73vd73vfe97/wAAAAQhEIQhCGIQhCCEIAAAD//e97ve9733vf/8AAACEIhCEMYxiEIQghAAAAf//3vd73ve+973/gAAAAhEIQhjGMYhCEEIQAAD//+97ve973vve//4AAAEIhCEMYxjGIQhBCAAAA//3ve73ve9773v/AAAAhCIQhjGMYxiEIIQgAAAP/973e973vfe9//wAAAIRCEIYxjGMQhCCEIAAB///e93ve9733vf+AAAACEQhDGMYxjEIQghAAAAf/73vd73ve9973/gAAAQiEIQxjGMYxCEEIQAAAH/+97ve973vfe9/4AL//e973vf/8AAACEIhCEEIQAAAH///73//+AAAACEQhCEIQghAAAP//73ve9/4AAAAIQhEEIQhAAAAf//3ve97//gAAAQiEIQhCCEAAA////e9///gAAAAhCIQhCCEIAAB///e973v/AAAABCEQhCEEIQAAAH//973vf/8AAAAEIRCEEIQAAAH/+973ve9/4AAAAIQiEIQghCAAAA//////8AAAAEIRCEIQhBCEAAA///ve973v/+AAAAAEIQhAAAAA///ve973v/AAAAhCIQhCEIQghCAAAAB//wAAAAABCEIhCEEIQAAAH/+97ve9973v/AAAAACEIQAAAAAf//////8AAAAEIhCGMYxjEIQQgAAAP/////gAAAAACEIQgAAAAf/73u973vfe9/4AAAEIQiEIIQhAAAAAAAAAAAAAQhEIQhjGIQhBCAAAf/73ve973v/+AAAAAAAAAAAH//973ve97/wAAAIRCEMYxjGMQghCAAAAAAAAAAAAAhCEIQhCAAAA//3u97znO9773/gAAAAAAEAAAAAAAAAAAAAAAAQiEP/wAAAAQhCIQhBCEAAA//3ve973v/+AAABCEIhBCEIAAAAH//973v/+AAABCIQhCEIIQgAAH///73vf//4AAAEIRCEIQQhAAAP//73ve//4AAAAIQiEIQghCAAAA///ve973/gAAAAhCIQghCEAAAB///e97///AAAAhCIQhCEIIQAAAH///7///+AAAACEIQhCEIQAAD//+973ve9/4AAAEIQiEIQQhAAAAA//////8AAAAEIRCEIQhBCEAAA//3ve973//AAAAACEIQhAAAAA///ve973//AAAAhEIQhCEIQQhAAAAf/////AAAAACEIQhCEIAAB///e93ve+97//gAAAAhCEIQhAAAAAB////AAAABCEQhjGMYxiEEIAAAD//+97///+AAAAAAAAAAAH//973e973vvf+AAABCEQhCEIQghCEAAAAAAAAAAIQiEIQxiEIQQgAAH/+97ve9773vf/8AAAAAAAAAD//+973ve//4AAAEIhDGMYxjGMQhBCAAAAAAAAAAAAQhCEIQgAAAP/973e973ve9773/gAAAAACEAAAAEIQhEIQhCCEIQAAAAP///3ve973vf//4AAAAAQhCIQhCEIQQhCAAAA////e973ve97//gAAAABCEIhCEIQhCCEIAAAAH//973ve973vf/8AAAAAIQiEIQhCEIQQhAAAAf//3ve973ve97//gAAAAhCEQhCEIQhCCEIAAAD//+973u9973vf/8AAAAEIRCEIQhCEIQQhAAAAf//3ve73vfe97//gAAAAhCIQhCEIQhCCEIAAAD//+97ve9733vf/8AAAAEIhCEIQxiEIQghCAAAf//3vd73ve+973/gAAAAhEIQhDGMYhCEEIQAAD//+97ve973vve//4AAAEIRCEMYxjGIQhBCAAAA//3ve73ve9973v/AAAAhCIQhDGMYxCEIIQgAAH//973e973vfe9//wAAAIRCEIYxjGMQhCCEAAAB//ve93ve9733vf+AAABCEQhDGMYxjEIQQhAAAAf/73u973ve9973/gAAAQiEIQxjGMYxCEEIQAAD//+97ve973vve//4AAAEIhCGMYxjGIQhBCAAAA///ve73ve974DAAH//973ve9//wAAAIQhEIIQhAAAP//73ve//4AAAAIQiEIQhBCEAAAB//ve97//gAAAQhCIQghCEAAAB///e973v/+AAABCIQhCEEIQAAD///973//+AAAACEIhCEIIQgAAH//973ve//4AAAEIRCEIQQhAAAAf///ve///wAAAIQiEIQghCAAAf//3ve973/gAAAAhCEQhBCEIAAAD///////gAAAQhEIQhCEIIQAAAH//973vf/8AAAAAIQhCEAAAB///e973ve9/4AAAEIRCEIQhBCEAAAAAH/gAAAAACEIhCEIQhBCAAAf/73ve773vf/8AAAAAAAAAAAAf///ve97//gAAAQiEIYxjGMQhBCAAAAAAAAAAAAAACEIQhCEAAAB//ve73ve9773v/AAAABCEIQhAAAAAAD//gAAAABCIQhjGMYxjEIIQAAAH//973//+AAAAAAAAAAAAP/973u973vve/8AAACEQhCEIQhBCEAAAAAAAAAAAQhEIQhCEIQQgAAH/+93ve973vve/8AAAAAAAAAAAP///////8AAA////gAAAABCEQhCEIIQgAD//+973ve//4AAAEIQhCEIQgAAAP//73ve//4AAAEIhCEIQhBCAAAf///ve///wAAAAQhEIQhBCEAAA///ve97//gAAAAhCIQhCCEIAAAD//e973vf+AAAACEIhCCEIAAAD///973v//8AAACEIhCEIQghCAAAf//////8AAAAEIQhEIIQhAAAP//73ve973//AAAAhCEIQhCAAAAB///////wAAAAQiEIQhCEIIQAAD///973v/+AAAAAEIQhCEAAAB///e973ve//4AAAEIhCEIQghCAAAAB////AAAAACEIRCEIQghAAAP//73u9773v/+AAAAAEIQgAAAAA////////wAAAIRCEMYxjGIQghAAAAf/////AAAAAAAIQhAAAAA//3u973ve9973/gAAAQhCEIQhCEAAAAAAAAAAAAhEIQxjGMYxCEEIAA///ve973vf//4AAAAAAAAD//+97ve9773v/AAAAhEIQxjGMQhCCEIAAAAAAAAAIQhEIQhCEEIQAAD/ve73ve973vve/8AAA///wAAAAAhCEIhCEIQghCEAAAAD//+973ve97///AAAAACEIQiEIQhCCEIQAAAAP//73ve973vf//4AAAAAQhCIQhCEIQQhCAAAA///ve973ve97//gAAAABCEIhCEIQhCCEIQAAAH//973ve973vf/8AAAAAIQiEIQhCEIQghCAAAA//3ve93vfe97//gAAAAhCEQhCEIQhCEEIQAAAH/+973e9733ve/8AAAAEIRCEIQhCEIQghCAAAA//3ve73ve+973//AAAAhCIQhCGMQhCEEIQAAAH/+973e973vve//4AAAEIRCEIYxjGIQhBCEAAA///ve73ve9773v/AAAABCIQhDGMYxCEIIQgAAAP/973e973vfe9//wAAAIRCEIYxjGMQhCCEAAAB///e93ve9733vf+AAABCEQhDGMYxjEIQQhAAAAf/73u973ve+973/gAAAQiEIQxjGMYxCEEIQAAD//+97ve973vve//4AAAEIhCGMYxjGIQhBCAAAA//3ve73ve9773v/AAAAhCIQhjGMYxiEIQQgAAAP/973e9BAhCAAAf//3ve97//gAAAAhCEQQhCAAAA//3ve97//gAAAQhCIQhCEEIQAAD//+973v/+AAABCEQhCCEIAAAD//+973vf/8AAAAEIhCEIQQhAAAP//73vf/8AAAAEIQiEIQQhAAAAf//3ve97/wAAAAQhEIQghCEAAAB///+////gAAAAhEIQhCCEIAAB///e973v/+AAAACEIQhCEIQAAAH//973//+AAABCEQhCEIQghAAAAf///////4AAAAIQhCEIQgAAH//973ve973/gAAAAhCIQhBCEIAAAAH///8AAAAEIRCEIQhCEIIQAAD//+973ve//4AAAAAAAAAAAA///ve973ve/8AAACEQhCGMQhCCEIAAAAAAAAAAABCEIhCEIQQhAAAP/973e973vve//4AAAAAAAAAAAA///////4AAAEIRCGMYxjGMQhBCAAAAB///gAAAAAAAAQAAAAAf//3u973ve9773/gAAAAhCEIQhCEAAAAAAAAAAAAhCIQhjGMYxCEEIAAB//ve973ve//4AAAAAAAAAH//973ve973v//////+AAAACEIhCEIQghCAAP//73ve97/wAAAAQhCEIQhAAAAf//3ve97//gAAAQiEIQhCCEIAAB///+97///AAAABCEQhCEEIQAAD//+973v/+AAABCEQhCEEIQgAAH//973ve//4AAAEIQiEEIQgAAAP//73ve//4AAAAIQiEIQhCCEAAAB//////4AAAAIQhEIQghCEAAA///ve973vf/8AAACEIQhCEAAAAD////////AAAAhCIQhCEIQghCAAAf//////8AAAAAIQhCEIQAAAH/+973e+973/gAAAQhCIQghCEAAAAD///+AAAAAEIRCEIQhCEEIAAB///e973vf/8AAAAAAAAAAAAA///ve973v/+AAABCIQhjGMQhCCEAAAAAAAAAAAAACEIQhCEIQAAAH/+93ve9733vf+AAAAAEIQhAAAAAAD///+AAAACEQhDGMYxjGIQghAAAP///////8AAAAAAAAAAAP//73e973ve997/wAAEIRCEIQhCCEIQAAAAAAAAAQiEIYxjGMYhBCAAAf/73u973vve9///e973//+AAAAAAIQhEIQhCEEIQgAAAAf//3ve973ve//4AAAAAAhCEQhCEIQghCEAAAB///e973ve973//AAAAACEIRCEIQhCEEIQAAAAP//73ve973ve//4AAAAIQhEIQhCEIQghCAAAA///ve973ve973//AAAABCEQhCEIQhCEEIQAAAH//973u9773ve//4AAAAIQiEIQhCEIQghCAAAA///ve93ve+973//AAAABCIQhCEIQhCEEIQAAAH//973e973vve//4AAAAIRCEIQxjEIQhBCEAAA///ve73ve9973v/AAAABCIQhCGMYxCEIIQgAAH//973e973vfe9//wAAAIQiEIYxjGMQhCCEAAAB//ve93ve9773vf+AAABCEQhDGMYxiEIQQhAAAP//73u973ve+97//gAAAQiEIQxjGMYhCEEIAAAD//+97ve973vve/8AAACEIhCGMYxjGIQhBCAAAA//3vd73ve9773v/AAAAhEIQhjGMYxiEIIQgAAH//973e973ve+97/wAAAIRCEMYxjGMYhCCEIAAB//wUQhCEEIAAB///+97///AAAABCEIhBCEIAAB///e973vf+AAABCEIhCEIIQgAAAP//73vf/8AAACEIhCEIIQgAAAP//73ve9//wAAAIQiEIQhBCAAAA///ve///wAAAAQhEIQhBCEAAAB//ve973v/AAAABCEQhBCEIAAAD////////AAAABCEQhCEIQQgAAH//973vf//4AAAAIQhCEIQgAAAP//73ve9/4AAAEIRCEIQhBCEAAAB///////wAAAAQhCIQQhCAAAf//3ve973vf+AAAACEIQhCEIAAAAH//////gAAAQhEIQxjGIQghAAAAf///vf///wAAAAAAAAAAAB///e93ve+973/gAAAQiEIQhCEEIQAAAAAAAAAAACEIhCEMQhCEEIAAB//ve93vve9//wAAAAAAAAAAf//3ve973v/AAAAhEIQxjGMYxCEEIQAAAAAAAAAAACEIQhCEIAAAD//e93ve973vfe/8AAAAAAAAAAAAAAAAAAAAAAACEQhDGMYxjGMQghAAAAf///////4AAAAAAAAAAP//73u970AAA///////4AAAAIQiEIQhCCEIAAB//ve973v/AAAAhCEIQhCEAAAB///e973v/+AAABCIQhCEIIQgAAH///73//+AAAACEIhCEIQQgAAAP/973ve//4AAAEIRCEIQQhAAAAf//3ve9//wAAAAQhEIQQhCAAAf//3ve97//gAAAAhCIQhCEEIQAAD///////gAAAAhCIQhCEEIQAAD//+973ve9/4AAAAIQhCEIAAAAH//973vf/8AAACEIhCEIQhCCEIAAAD////8AAAAAIQhCEIQhAAAAf/73u9733vf/8AAAAEIQhCEAAAAD//////wAAAAQiEIYxjGIQghAAAAf///////4AAAAAABAAAAAB///e97vfe97/wAAAIQiEIQhCCEIAAAAAAAAAAAACEIhCEIQhBCEAAA//3vd73vve9/4AAAAAAAAAAAAB////////gAAAQiEIYxjGMYxCCEAAAAAAAAAAAAAAAAQhCAAAAB//vd73vOd73vvf+AAABCEIQhCEAAAAAAAAAAAABCIQxjGQgxjGIQQgAD//+973ve///ve973ve///wAAAAABCEIhCEIQghCEIAAAD///973ve973//+AAAAAEIQiEIQhCEEIQgAAAAf//3ve973ve//4AAAAAQhCIQhCEIQghCEAAAB///e973ve973//AAAAACEIhCEIQhCEEIQgAAAP/973ve973ve//4AAAAIQhEIQhCEIQghCAAAA///ve97ve+973//AAAABCEQhCEIQhCEIIQgAAH//973u9733ve//4AAAAIQiEIQhCEIQhBCEAAA///ve93ve9973v/AAAABCEQhCGMYxCEIIQgAAAP/973u973vfe9//wAAAIQiEIQxjGIQhCCEAAAB//ve93ve9773vf+AAABCEQhCGMYxiEIQQhAAAP//73u973ve+97/wAAAAQiEIQxjGMYhCEEIAAAD//e97ve973vve/8AAACEIhCGMYxjGIQghCAAAf//3vd73ve9973//AAAAhEIQhjGMYxCEIIQgAAH//973e973vfe9/4AAAEIRCEMYxjGMQhCCEAAAB//ve93ve9733vf+AAABCIQhDGMYxjEIQQhAAI9//wAAEIRCEIQhBCAAAA///////4AAAAIQiEIQhBCEAAA//3ve973//AAAAhCEIQhCEAAAB///e973v/AAAABCIQhCEEIQAAD///973v/+AAAACEIhCEIQQgAAAP//73vf/8AAAAEIRCEIQQhAAAAf//3ve97//gAAAQhCEIQhAAAAf//3ve97//gAAAQhEIQhCEEIQAAAH//////gAAAAhCEQhBCEIAAB///e973ve9/4AAAAIQhCEIQAAAAP//////+AAAACEQhCGMQhCCEAAA////////wAAAAAhCEIQgAAAP/973ve973v/AAAAhCIQhCEEIQAAAAAf/8AAAAAAQhEIQhCEIIQAAD//+973ve97/wAAAAAAAAAAAAD///973vf/8AAACEQhDGMYxiEIIQAAAAP/+AAAAAAAQhCEIQgAAAP/97ve973vfe9/4AAAEIQhCEIAAAAAAAAAAAAAEIRCGMYxjGMYhBCAAAf//3ve9///gAAAAAAAAAf//3vd73ve9973/gAAIQiEIQhCEIQQhAAAAAAAAAhCIQhDGMYhCAEIQhCEIQAAD//e973ve/8AAACEIRCEIQQhCAAAf///ve//4AAAEIRCEIQQhAAAAf//3ve97//gAAAAhEIQhCCEAAAB///e97//gAAAAhCIQhCCEIAAAD//+973vf+AAABCEIhCEEIQAAAH///73v//8AAACEIhCEIQQhAAAP//73ve///wAAAIQhCEIQhAAAAf//3ve9//wAAAIQiEIQhCCEIAAAD///////gAAAABCEIQhCEAAA///ve973ve/8AAAAEIQiEEIQgAAAAf////gAAAAhCIQhDEIQghCAAAf//3ve97//gAAAAAAAAAAAAH/+973ve973/gAAAQiEIQhCEIIQgAAAAAAAAAAAAIQiEIQhCCEIAAB//ve73ve+973/gAAAAAAAAAAB////973//AAAABCIQxjGMYxiEIIQAAAAAAAAAAAAAAQhCEIAAAAH/+93ve973vfe/8AAAAEIQhCEIAAAAAAAAAAAAAEIhCGMYxjGMQghAAAP//73ve9///gAAAAAAAAAf//3ve93vfe97/wAAAIRCGMYxiEIQQgEIQhBCEIAAAAH//973ve973//+AAAAAAIQhEIQhCEEIQgAAAAf//3ve973ve///wAAAAAhCEQhCEIQghCEAAAAD//+973ve973//AAAAACEIRCEIQhCEEIQgAAAP//73ve973ve//4AAAAAQhEIQhCEIQghCEAAAB///e973ve973//AAAABCEIhCEIQhCEIIQgAAAP/973vd733ve9/4AAAAIQiEIQhCEIQhBCEAAAB//ve93ve9973v/AAAABCEQhCEIQhCEIIQgAAAP/973u973vfe9//wAAAIQiEIQxjGIQhCCEAAAB//ve93ve9773vf+AAABCEQhCGMYxiEIQQhAAAP//73u973ve+97/wAAAAQiEIQxjGMYhCEEIAAAD//e97ve9733ve/8AAACEIhCGMYxjEIQghCAAAf//3vd73ve9973//AAAAhEIQhjGMYxCEIIQAAAH/+973e973vfe9/4AAAEIRCEMYxjGMQhBCEAAAB//ve73ve9733vf+AAABCIQhDGMYxjEIQQhAAAP//73u973ve9973/gAAAQiCQAAEIRCEIQghCAAAA/////AAAABCEQhCEIQhBCAAP/97ve9773v/AAAABCEIQgAAAP//73ve97/wAAEIhDGQhBjGIQQgAD///////gAAAQhEIQhBCEAAf97vOc5znO99/4AACEQhCEIIQgAAH//////gAAIRDGQhSlIQYxBAAH/+93ve997/wAAAIQhCEIAA//3e85vfOc733wACEQxjIQgxjEIIQAAD///+AAABEIZCEIQgxiCAAP+73nOc5znO+98AAACEIQhAAAP+93ve9733vgAEQhkIUpSlIQYxBCAAP/973v/AAAQiEIYxCEEAAf93vN73ve98533/gAEIhDGMQghAAH//973//AAARDGQhSlKUpBjEEAP/93vOc73vv/AAAQhCEIAAB/3u85ze985zvv/AAIhkIQpSEIMQggAAH///8AAACIQxkIQhBjEIIAf93nN73ve+c77/wAAEIQhCAAAf/73e973vvfAAIRDIUpjGMUpBiEEAAf//3v/+AAABCEQhCEEIAA/7veb3vWt75zvvgAAIRCEIQhBCAAAA///whCAAAA//3ve733vf+AAABCIQhDGIQhBCAAAA////gAAAAhEIQhiEIQQgAD//e73ve9733v/AAAAhCEIQgAAH/+973ve/8AAACIQxjIQhBjGIQQAB///e9//wAAAIQiEIQQhAAH/+73vOc5zne+98AABCIQhCEIIQAAD//////wAAEIhjGQhCEIMYghAD/vd73ve997/wAAEIQhCEAAA/73e85znO9974ABCIZCEIQhBjEEIAA/////AAAAhEIYxjGMYxBCAH/d5ze973vne++AAAhCEIQhAAAP/973e997/wACIYyFKYxjFKQYggAD//e973v/AAAAhEIQhBCAAP+7zm9a1rW98774ABCIQxjGMQghAAAP/////gAAIhkIUpjGKUgxCCAH/d73nOd733v/AAAAhCEIAA//3ec3ve98733wACIYyEIQhCEGIQQgAAH///8AABCIYxkIQgxiCAH/+7zm973vnO9974AACEIQhCEAAf/73u9973wAAEQxkIUpSlKQgxCCAAP/973ve/8AAACEIQhCAAAf93vOc3ve+c733xCEIQhCCEIAAAD//+973ve973v/+AAAAAEIRCEIQhCEIQQhAAAAf//3ve973ve///wAAAAQhCIQhCEIQhCCEIAAB///e973ve973//AAAAACEIhCEIQhCEIQQgAAAP//73ve973vf//4AAAAAQhEIQhCEIQhBCEAAAB///e973ve97//gAAAABCEIhCEIQhCEEIQAAAH//973ve973v//8AAAAAIQiEIQhCEIQghCAAAA//3ve973ve9//wAAAAAhCEQhCEIQhCCEIAAAD//+973ve973//AAAAACEIRCEIQhCEIQQhAAAP//73ve973ve//4AAAAIQhEIQhCEIQhBCEAAA///ve93vfe973/gAAAABCEQhCEIQhCEIIQAAAH/+97ve9773vf/8AAAAEIRCEIQhjEIQhBCAAAf/73u973ve+97//gAAAAhEIQhDGMYhCEEIQAAD//e73ve9733vf/8AAACEIhCEMYxjGIQghCAAP/973e973ve+97/wAAAAQiEIQxjGMYxCEEIAAB//vd73ve9733vf+AAAACEQhDGMYwvvfe9//wAAAIQhCEIAAAAH///////AAAAhEIQxjGMYxCCEAAf//3ve//4AAAAIQhCEIAAAD//e73ve9733vgAAARCEMYxCEEIAAAD////8AAACEQhjGMYxiEEIAA/73e95zve+98AAACEIQhCAAAf/73u973vvfAAARCGQhCEIQYxBCAAP//////AAAAhCIQhCEIIQA//3ec3ve98533vgAAIRCEIQghAAAP//73vf+AAAiGMhSlKUpSDEIIAf/73e9733v/AAAAhCEIQgAD/u95ve973znffAAARDGMhCDGMQggAAH////4AACEQyEKUpSEGIQQA/7vec5vnOc773wAAAIQhCEAAf/7vec5znfe+AARCGQhSlKUhBjEEIAA///v/+AAABEIYxjGIQQAB/3e83ve973znff+AAQiEIQhCCEAAf/73vf/8AAhEMZClKUpSkIMQQAB/3u973vfe/8AABCEIQgAD//d7znN73znO+98AAiEMhCEIQYxCCAAAf//4AAAEIhDGQhCEGMQggB/3u85ve975zvv/AAAAhCEAAAB8AAhCEQghCEAAA//3u973vve/8AAACEIRCEEIQAAAH//////gAAAQiEMYxjGMQghAAH/+973ve97/wAAAAQhCEIAAB//vd73ve997/wAAEQhjGMYxiEEIAAAD///+AAABCIQxjGMYxCCAAP+93vOc5zve+/8AAACEIQhAAAP/97ve9773/gAEIhjIQhCEIQYhBAAAP/973//AAAQiEIQhCCEAAf97vOc3ve+c733wAAEIhCGIQghAAH//973/gAAARCGQhClKUhBiEEAP/93ved733vgAAAQhCEIAAB/3u95znOc53vvgAAIhkIQpSEGMQQgAD////8AAACIQxkIQhBjEIIAf93nN73ve+c774AAAEIQhCAAAf/73e973vvfAAIhjIUpjGMUpBiCEAP//73vf+AAABCIQhCEEIAA/7vOb1rWtb3zvvgAAIhCGMQhBCAAAf/////+AAAiGQhSmMYpSDGIIAf97ve973vvf+AAAACEIQAAD/vd5ze975zvffAAIhDGQhCEIMYhBAAAAf/8AAAAEIhjGQhBjEIIAA/7vec5sAAACEIhCEIQhCEIQQgAAAP//73ve973ve//4AAAAAQhEIQhCEIQhCCEAAAB///e973ve973//AAAAACEIhCEIQhCEIIQgAAAP//73ve973vf//4AAAAAQhEIQhCEIQhBCEAAAB///e973ve97//gAAAABCEIhCEIQhCEIIQAAAH//973ve973v//8AAAAAIQiEIQhCEIQghCAAAA///ve973ve9//wAAAAAhCEQhCEIQhCCEIAAAD//+973ve973//+AAAACEIRCEIQhCEIQQhAAAP//73ve973ve//4AAAAAQhEIQhCEIQhBCEAAAB//ve973ve97//gAAAABCEQhCEIQhCEIIQAAAH/+973e9973vf/8AAAAEIRCEIQhCEIQghCAAAf/73vd73vfe97//gAAAAhEIQhCGMYhCEEIQAAD//e93ve9773vf+AAAACEIhCEMYxjEIQghAAAP/973e973ve+97/wAAAAQiEIQxjGMYxCEEIAAB//vd73ve9733vf+AAABCEQhDGMYxjGIQghAAAP+97ve973ve+97/wAAAM973ve973v/AAAABCEIQAAAAP/973ve9/4AAAEIhDGMYxjEIQQAAAH/////wAAAAQhEIQghCAAP/97ve85zve+9/4AACEQhCEEIQAAD//////wAAAIRCGMhCEIMYhBAAH/+93ve+97/wAAAIQhCEAAA//3u97znO9773wACEQxjIQgxjEEIAAB////+AAABCIQxjGMYxCCAAP+73nN73zne+/8AABCEIQhAAAP/973e9773/gAEQxkKUpSlIQYhBAAH/+973v/AAAAhEIQhCCEAAf93nN71rW98773wACEQhjGIQghAAAP//////AAIRDIUpTGKUpBiCAH/+73ve9733v/AAAAhCEIAAB/3e83ve9753vvgAEQxkIQhCEGMQQgAAH///8AABCIYyEIQhBjEEAP+73nN73vfOd774AAAEIQhCAAAf97ve9733vgAAIhkIUpSlKUgxiCEAP//73vf/8AABCIQhCCEAAf97vOb3ve9853vvgAAIhDGMYxCCEAAA/////AAAQiGMhClKUhCDEEIAf97vec5zvfe/8AAACEIAAAAAABCEQhCEIQQgAAH/+97ve+97//gAAAQhCEIQgAAAP//73ve//4AACEQhjGMYxiEEIAAB///e9///gAAAQhCEIQhAAH/+93vOc5zvff+AAAhEIQhCEIIQAAAH/////wAAEIhjIQhCEGMQQgB//vd73ve997/wAAAIQhCEAAf/73e85zne+98AABEMYyEIQgxiEEIAA/////+AAAhEMYxjGMYghAD/vd5zm975znfe+AAAhCIQQhAAH/+97ve+9/4AACIYyEKUpSkIMYggAD//e973v/AAAQiEIQghAAH/+7zm973vfOd974ABCIYxjGMQghAAH/////wAAEIhjIQpSlIQgxBAAH/d5znOc533vgAAAQhCEAAA/73e85znOd773wACIZCFKUpSkGMQQAB////+AAABCIQxjGMYxCCAH/d5ze9a1vfOd98AABCEIQhCAAAf/73ve973wAAEQyFKYxjGKQgxBAAH/e973vf+AAABCEIQhCAAP/93nN71re98773wACIQxjGMYhBCAAAA///wAAAARDGQhSlKQgxiCAH/+97//gAAAAhCIQhCEIQhCEEIQAAD//+973ve973v//8AAAAEIRCEIQhCEIQghCAAAf//3ve973ve9//wAAAAAhCIQhCEIQhCEEIAAAD//+973ve973v/+AAAAAEIRCEIQhCEIQQhAAAAf//3ve973ve///wAAAAQhCIQhCEIQhCCEIAAB///e973ve97///AAAAACEIhCEIQhCEIIQgAAAP//73ve973vf/8AAAAAIQhEIQhCEIQghCAAAA///ve973ve9///gAAAABCEQhCEIQhCEEIQAAD//+973ve973v/+AAAAAEIRCEIQhCEIQQhAAAAf/73ve973ve///wAAAAQhEIQhCEIQhCCEIAAB//ve93ve+973//AAAABCEQhCEIQhCEIQQgAAH//973e9733ve//4AAAAIQiEIQhjGIQhBCEAAA//3vd73ve9973/gAAAAhCIQhDGMYxCEIIQAAD//e93ve973vve/8AAAAEIhCEMYxjGMQhBCAAAf/73e973ve9973/gAAAQhEIQxjGMYxiEIIQAAD//e73ve973vveDQA//3ve973v/+AAAACEIQgAAAP//73ve973//AAAQiEMYxjGIQghAAAP////wAAAAQiEIQhCEEIAA//3u97zne9773wAAAIQhCEIQAAD//+973v/AAAAiEMZCEIQgxiEEAAA//3ve97/wAAAIQhCEIQAAD/vd7znOc53vvfAAARCGMYxjEIIAAB/////8AAACIQxkIQhCDGIIQA/73e85znO99/4AAAEIQhAAAP/97ve853vfe+AAQiGQhSlKQgxiCEAAf/////AAAAhEIYxjGIQQAB/3ec3vWt73zvvfAAIQiEIQQhAAH//973ve/8AAiEMhSmMYxSkGIIQA/73u9773v/AAAQhCIIQgAD/u95veta1vfO++AAQiGMYxjGMQggAAH////4AACEQyEKUpSlIMQQAB/3e85znOd773/gAAAQhCAAAf/7vec5znO+98AAiGMhClKUhCDEIIAAB////+AAABEIYxjGMQggB//u85ve973zne++AAAhCIQhBCAAAf/73ve/8AABEIZCFKUpSkIMQggAD/ve73vve/8AAACEIf/AAAAACEQhCEIQhBCAAAf/73ve973//AAAABCEIQgAAAP//73ve973/gAAIRCGMYxjGIQQgAAH//////gAAAQhEIQhCCEAAf/7ve85znO99/4AACEIhCEIIQAAAH//973//AAARCGQhCEIQYxCCAAP+973e+97/wAAAIQhCEIAAB/3e85zfOc733/gAEQhjGMYxjEIIQAAD///+AAABEIYyEIQhBiEEAP/93vOc5zne+9/4AACEIQhAAAP+93vOc73vvgAAIhjIQpSlIQgxCCAAP//73//AAAQiEMYxiEEIAf97vOb3ve98533vgAAIhCEIQghAAH/+973v/AAARCGQhSlKUpCDEIIAf97ve9733v/AAAQhCEIQAB/3u85ze975zvffAAIhDIQhCEIMQggAAH///8AAACIQxkIQhCDGIIQA/7vOb3ve+c773wAAEIQhCAAAf/73e973vff+AARDIQpTGMUpCDEEAAf/////+AAABCIQhCEIIQAB/3eb3vWtb3zvffAAAQiEIQghCAAAf/////+AAAhEMhClKUpSEGIIPe973v//8AAAAEIRCEIQhCEIQghCAAAf//3ve973ve9///gAAAAhCIQhCEIQhCEEIQAAD//+973ve973v/+AAAAAEIRCEIQhCEIQQhAAAAf//3ve973ve///wAAAAAhCIQhCEIQhCCEIAAAD//+973ve973//AAAAACEIRCEIQhCEIQQgAAAP//73ve973vf//4AAAAAQhEIQhCEIQhBCEAAAB///e973ve97//gAAAABCEIhCEIQhCEEIQAAAH//973ve973v/+AAAAAEIQiEIQhCEIQghCAAAf//3ve973ve9//wAAAAAhCIQhCEIQhCCEIAAAD//e973ve973//AAAAACEIhCEIQhCEIQQgAAAP/973u9733ve//4AAAAIQiEIQhCEIQhBCEAAA//3ve73ve+973//AAAABCIQhCGMYxCEIIQgAAH/+97ve973vve/8AAAAEIRCEIYxjGIQhBCAAAf/73u973ve9973/gAAAAhEIQhjGMYxiEIIQAAD//e73ve973vve/8AAACEIhCGMYxjGMQhBCAAAf/73e973vQ4QQgAAH//973vf/8AAAAEIQhCEAAAB//vd73ve+9/4AACEQhCEIQhBCEAAAB////AAAABEIQxjGMYhBAAAP+93ve973vvf+AAABCEIQgAAH/+93ve997/wAAEQhjIQhCDGMQggAAH/////wAAAIRCEIQhCCAAP/93vOc5znOd974AACEQhCEIIQAAD//e97//gAAIhDGQhClIQgxCCAAP+93ve997/wAAEIQhCEIAA//3e85znOc733vgAEQhkIQhBjEIIAAB////+AAABEIYyEIQhBjEEAP+93nN73vnO998AAACEIQhAAAP+93ve973vvgAAIhkKUxjFKUgxBCAH//97///AAAQiEIQxCEEIAf93nN61rWt7533wAAEIhCEIQghAAH//973v/AAARDIQpjGMYpSDEEAP/97ve9733v/AAAAhCEIQAB/3u83ve973zvv/AAIhjIQhCDGMQQgAAH///8AAACIQyEIQhCDEIIAf93vOc3znOd77/wAAAIQhCAAAf/73e973vvfAAIRDIQhSlKQhBiEEAAA/////+AAABCH/////4AAAAIRCEMYxjEIQQgAD//+973v/+AAAACEIQhCAAAA//3u973vfe98AABCIQhjGMQhBCAAAf////gAAAAhEIQxjGIQghAAH/e73vOd733v/AAAAhCEIQgAAH/+973ve9/4AACIQyEIQhCDGIQQAB///e97//gAAAQiEIQghCAH/+7zm973vnO+98AABEIQhCEIIQAAD//////wAAEQhkIUpSlIQYghAD/vd73ve997/wAAAIQhCEAAf/7vOc3vfOd774ABEIYyEIQhBjEIIAAB////AAAAiEMZCEIQYxBAAH/d7zm973zne+/8AABCEIQhAAH/+73ve977/wACIYyEKUpSlIQYhBAAH/+973v/AAAQiEIQhBCAAP+73m973ve+c77/wACEQxjGMQghAAH/////wAAAIhjIQpSlKQgxiCAH/+73nOc53vvgAAAQhCEAAA//3e85znOc733/gAEQyEKUpSEGMQQgAD///+AAABCIQxjIMYxiCEAP+73m973ve+d974AACEIQhCAAAf/73ve973/gAEIhkIUpSlKX//e973ve973//AAAABCEIhCEIQhCEIIQgAAAP//73ve973ve//4AAAAIQhEIQhCEIQhBCEAAAB//ve973ve97///AAAABCEIhCEIQhCEIIQgAAH//973ve973vf/8AAAAAIQiEIQhCEIQghCAAAA///ve973ve9///gAAAAhCEQhCEIQhCEEIQAAD//+973ve973//+AAAAAEIRCEIQhCEIQQhAAAAf//3ve973ve//4AAAAAQhCIQhCEIQhBCEAAAB///e973ve97///AAAAACEIhCEIQhCEIIQgAAH//973ve973vf/8AAAAAIQiEIQhCEIQghCAAAA//3ve973ve97//gAAAAhCIQhCEIQhCEEIQAAD//e97ve9973v/+AAAACEIhCEIQhCEIQghAAAP//73u973vfe9//wAAAAQhEIQhjGMQhCCEIAAB//ve73ve9773v/+AAABCEQhCGMYxjEIQQhAAH/+97ve973vfe9/4AAAAIRCEIYxjGMYhCCEAAA//3u973ve9773v/AAAABCIQhjGMYxjEIQQgAAH/+90PEIQhBCAAAA///////4AAAAIQhCEIQgAAH/+93ve9773vgAAAQhEIQhCCEAAAB/////8AAACEQhjGMYxjEIIAA//3vd73vve/8AAACEIQhAAAP/97ve873vff+AAAiEMYxjGMYhBCAAAf////gAAARCGMYxjGIQQAB/3u95znOc733v/AAAQhCEIQAAD//e73vfe/8AAhEMZCEKUhCDGIIQAB//ve97/wAAEIRCEIQQgAD/vd5zm973zne+/8AAiEMYxjEIIQAB//////4AACIQxkIUpSkIMYggB//u95znO9974AAAEIQhCAAP/97vec5znO99/4ABEMhClKUhBjEEAAA/////AAAQiEMYyEGMYhBAD/u85veta3vnfe+AAAhCEIQgAAH/+97ve+974ABCIZClMYxjFIMYggB//ve973/gAAAQhEIQghAAH/d7ze9a1re+d98AABEIYxjGIQQgAAH/////wAAEQhkIUpSlKQYxBAD/vd7znO9773/gAAAAhCAAAA/73ec5znOd774ABCIYyEIQhCDGIIQAAAH//AAAABB////97///AAAAhEIYxjGMQhBCAAAf//////8AAAAEIQhCEIAAB//ve73ve9773/gAAIRCEIQhBCAAAA/////+AAABCIQxjGMYxiEEIAf/73e973vvf+AAABCEIQgAAAP/97ve973vvfAAARCGMhCEIMYghAAAP/////gAAAQiEIYxiEIIAA/73ec3ve+c733wAAEIRCEEIQAAD//+973vf+AAAiGQhSlKUpCDEEAAf/73ve97/wAAAIQiEIIQAB/3u83ve973zvffAAIRDGMYxjEIIQAAD////8AABCIZCFKUpSEGIIAA/7vec5znO9974AAAEIQhAAAP+93nOb5znfe+AARDGQhSlKQgxiCEAAf/////AAAQiGMZCDGIQQA//3ec3ve975zvffAAAQiEIQQhAAH/+973ve+AAAiGMhClKUpSEGMQQAB/3u9733v/AAAQhEIIQgAD/vd5ze973vnO+/8AAiEMZCEGMQghAAH///8AAACEQxkIQhCEIMQggB/3u85zfOc733/gAAAQhAAAAf/73e95zve+98AAhEMhClAAAP//73ve973ve///wAAAAQhEIQhCEIQhCCEAAAB///e973ve973//AAAAACEIhCEIQhCEIIQgAAAP//73ve973ve//4AAAAAQhEIQhCEIQhBCEAAAB///e973ve97///AAAABCEIhCEIQhCEIIQgAAH//973ve973vf/8AAAAAIQiEIQhCEIQghCAAAA///ve973ve9//wAAAAAhCEQhCEIQhCEEIQAAD//+973ve973//+AAAAAEIRCEIQhCEIQQhAAAAf/73ve973ve//4AAAAAQhCIQhCEIQhBCEAAAB///e973ve97///AAAABCEIhCEIQhCEIIQgAAH//973ve973vf/8AAAAAIQiEIQhCEIQghCAAAf//3ve73vfe97//gAAAAhCIQhCEIQhCEEIQAAD//e93ve9773vf+AAAACEIhCEIYxjEIQghAAAP/973e973ve+97/wAAAAQiEIQxjGMYhCEEIAAB//vd73ve9733vf+AAABCEQhCGMYxjGIQghAAAP/97ve973ve+97/wAAAIQiEIYxjGMYxCEEIAAEQf/73u973ve9773/gAAAAAAAAAA////e9///gAAAQiEMYyEIQgxjEIIQAAD////8AAAAEIQhCEIAAB//vd73nOc5zvfe/8AABCIQhCCEIAAAAH//AAAAACEQhjIQhCEGMQghAD//e73vfe9/4AAAAAAAAAAP/97ve85znO9974AACIQxjIQYxiEEIAAAD/wAAAAAhEIYxkIMYxCCAAP+73nOc5znfe+AAAACEIQAAAH/+93ve9733vgAAIhjIQpSlIQYhBAAH//////gAAAQiEMYxjEIIAA/7veb3ve98733wAAEIhCEIIQgAD//e973ve/8AAiEMhSlKUpCDEEIAf/73ve97/wAAAIRCEIQghAAH/d5ze973znfe+AAQiGMYxjEIIQAB//ve973/gAEIhkIUpSkIMYggB/3u973ve99/4AACEQhCEIIAA/73ec5vfOd774ABCIYyEIQgxiCEAAf/73ve98AABEIZCEIQgxiCAAP+73nOc5zvff+AAAhEIQhCCAAP/93vOc53vv/AAIhjIQhCEIMYggAD//e973vf+AAQAAAAAAAEIQiEIQghCAAP/93vec5znO997/wAAAAAAAAAAAAD///////gAAIRDGQhCEIQgxiEEAAAB/////8AAAAAAQhCEAAAB/3u85ze+c53vvfAAAQhEIQhCCEIAAAAH//+AAABCIYyEIQhCDGIQQAB//vd73vfe9/4AAAAIQgAAAP/93vOc5zne+98AABEIYxjGMYxCCEAAAB///gAAAQiEMZCEGMYghAD//d7znOc53vff+AAABCEIQgAAH/e73ve997/wACEQxkIQhCEIMQggAAH/+973/gAAIRCEMYxCCEAAf93vOc3vfOd77/wACEQhCEIQQgAD//e973v/AAARCGQhClKQhBiEEAP/97ve9773wAAEIhCEIQQgAD/u95zm985zvffAAIRDGMhBjGIIQA//3ve9/4AACEQxkIQhCEGMQQAB/3e85znO99/4ABCIQhCCEAAf/7vec5znO99/4ABEMZCEIQgxiCAAP/973vf+AAAhEIYyEIQYxCCAH/e7zm975zvffAAARCEIQhBAAH/+93ve9733vgAEIhkIUpQhCEIAAAAAP////ve973vf//4AAAAIQhEIQhCEIQQhCAAAAAD///973ve973//+AAAACEIhCEIQhCEEIQgAAAAA////e973ve9///gAAAAhCIQhCEIQhBCEIAAAAAP///3ve973vf/8AAAAAIQiEIQhCEIQQhCAAAAAD///973ve973//AAAABCEIhCEIQhCCEIQgAAAAf///ve973ve9//wAAAAQhCIQhCEIQghCEAAAAAH///73ve973v//8AAAAEIRCEIQhCEIIQhAAAAAB///+973ve97//gAAAABCEQhCEIQhCCEIQAAAAAf///ve973vf//4AAAAAQhEIQhCEIQQhCEAAAAAH///73ve97///+AAAACEIQiEIQhCCEIQgAAAAAB////973vf///wAAAAAhCEIhCEIQQhCEIAAAAAAf//////////+AAAAAAIQhCEQhBCEIQhAAAAAAAH//////////wAAAAAACEIQhCEIQhCEIAAAAAAAB/////////+AAAAAAAAhCEIQhCEIQhAAAAAAAAAA///////4AAAAABIQQgAD//+97ve9973v/+AAAAAAAAA//3vd73vfe/8AAACEQhjGMYxjGIQghAAAAAAAAAACEIhCEIQghAAAP/97vec5znO997/wAAAIQhCEAAAB///e9//wAAAIRDGMhCEIQgxiEEAAf//3ve//4AAAEIQhCEAAA//3u95znOc53vvfAAARCEMYxCEEIAAB////AAAABCIYxkIQhCDGIQQAB/3e973ve+98AAAAEIQgAAAP/93vec5zne+98AAhEMZCEIQgxCCAAAf////gAAAQiEMYyEGMYhBAD/vd5ze975zvvfAAAQhCEIQgAD//e73ve9773wACEQyEKUpSkIMQQgB///e97/wAAAIRCGMYxiEEAAf93nN73ve+d774ABCIQhCEIIQAB//ve933vf+AARDGQpSlKUhBiCAH/+93ve+974AAAEIhCEIQQgAD/u95ve975zvvgAAIhDGMYxiEEIAA//3ve97/wAAEQyEIUpSEGIIQA/73e85zve+/8AABCIQhCEEIAf/7vec5znO+98AAiEMZCEIMYxBCAAP/973ve/8AAAAAAAACEIRCEIYxiEIIQAB//vd73nO9773v/AAAAAAAAAAB///e973ve/8AABCIYyEIQhCDGIQQgAAAAAAAAAAAEIQiEIQQhAAH/e7znN73znO99/4AAAEIQhCEAAAAD//////wAAEIhjIQpSlIQYxBCAAP/973ve//4AAAAIQhCEAAA/7vec3ve+c733/gAEIhCGMYhCCEIAAB////+AAAhEMZCEKQhBjEEIAf/7ve973vfe/8AAACEIQhAAAP+73nOc5zvff+AARCGMhCEIMYxBCAAP/////gAAARCGMZCDGMQQgB/3u85znOc53vvgAAAQiEIQQgAD//e73ve+9/4ABEIZCEKUpCEGIQQAB/3ve973/gAAIhCGMYhBCAAP+73nN73vnO998AABEIYxjGIQQAB//ve973vgAAIhDIQhSlIQYxBCAH/e73ve9974AACEQhCEIIQAB/3e85znOc533vgAEQhjIQhBjEEAAf/73ve9/4AACIYyEIQhCDEIIAf/7vec5zne++AAAhEIQhCCEAP/93vec5zve++AAAiGMQhCEIIQhAAAAAAD///973ve973//AAAABCEIhCEIQhCCEIQAAAAAf////e973ve9//wAAAAQhCIQhCEIQghCEAAAAAH///73ve973v//8AAAAEIRCEIQhCEIIQhAAAAAB///+973ve97///AAAABCEQhCEIQhCCEIQAAAAAf///ve973ve///wAAAAQhEIQhCEIQghCEAAAAAH///73ve973v/+AAAAAEIRCEIQhCEIIQhAAAAA////e973ve97//gAAAAhCEQhCEIQhBCEIQAAAAP///3ve973vf//4AAAAIQhEIQhCEIQQhCAAAAAD///973ve973//AAAAACEIRCEIQhCCEIQgAAAAA////+973ve///wAAAAAhCEQhCEIQghCEAAAAAAP////ve973//+AAAAAAIQhEIQhCCEIQhAAAAAAD////////////gAAAAACEIQhEIIQhCEIAAAAAAA///////////8AAAAAAQhCEIQhCEIQhAAAAAAAAP/////////wAAAAAAAAIQhCEIQhCEIAAAAAAAAAH///////AATIMYxCCAAAf//3ve973//+AAAAAAAAA///vd73nO9733vgAAAQiEIYxjGIQghCAAAAAAAAACEQhjGMYxiEEIAA//3u973ve9773/gAAAAAAAAAA//3vd733vf+AAAhEMYyEIQhBjEIIQAAD///+AAAACEQhCEIIQgAD//d7znOc5zne+98AABCEQhCCEAAA////f//4AACEQxkIQhCEIQYhBAAH/e93vfe/8AAACEIQhCAAAf97vec5znOc773wAAEQxjGMYxCCEAAA/////AAAAiEMZCEIQhBiEEAP/93vOc5zvfe+AAAhCEIQgAAH/e73nOc53vvfAAIhDIQpSkIQYghAAH/////wAAAIRCGMZBjGIQQA//3ec3ve98733wAAEIhCEIIQAB//vd73ve+98AABEMhClKUpCDEIIAf/73ve97/wAAEIhDGMYhBCAH/d7ze973vne++AAQiEMYxiEEIAA//3ve973vgAAIhkIUpSlIQYggAD/vd73ve+98AABCIQhCEIIQA//3ec3ve+c77/wACIQxjGMYxCCAAP//73veAAAAAAAAAAAEIRCEMYxjGMYhBCAAP/97ve9773v/AAAAAAAAAA///ve73ve9773/gAAIhDGQhCDGMQghAAAAAAAAAACEIhCEMYxCEEIAf/7vec5znOd773wAAAAAAAAAAA///ve973v/AAARCGQhSlKUhBjEEIAAB/////8AAAAEIRCEIIQAB//u85ve973znff+AAAhEIQhBCEAAAB//////4AACIYyEKUpSkIMQQgB//ve73vve/8AAACEIQhCAAP/93vOb3vfOd9/4ABCIYxjGMYxCCAAAf/////AAAQiGMhCEIQgxBCAH/e73nOc53vvfAAAAhCEIQgAAH/d7znOc733/gAEQhkIQhCEGMQggAD//+973/gAAIhDGMYxjEIIAf97vOc3vnOd77/wACEQhCEIQQAB//vd73vfe+AAAiGMhClKQhBiEEAAf973e997/wAAEQhjGMQggAD/vd5zm975zvffAAARCGMYxjEIIAA/73ve97/wAAEQxkIQpCEIMQQgB/3u97zve+98AABEIQhCEEIAf/7vec5znOd974ABCEQhCEIQhBCEIAAAAAP////ve973vf//4AAAAIQhEIQhCEIQQhCAAAAAD////73ve973//+AAAACEIhCEIQhCEEIQgAAAAA////e973ve9///gAAAAhCIQhCEIQhBCEIAAAAAP///3ve973vf//4AAAAIQiEIQhCEIQQhCAAAAAD///973ve973//AAAAACEIhCEIQhCEEIQgAAAAf///ve973ve9//wAAAAQhCIQhCEIQhBCEIAAAAH///73ve973vf/8AAAAEIQiEIQhCEIIQhAAAAAB///+973ve97///AAAABCEQhCEIQhCCEIQAAAAAf///ve973ve//4AAAAAQhEIQhCEIQQhCEAAAAAH///73ve973//+AAAAAEIRCEIQhCEEIQgAAAAAB////973ve///wAAAAAhCEIhCEIQghCEIAAAAAAf////+9/////8AAAAAIQhCEQhCCEIQhAAAAAAAH///////////gAAAAACEIQhCEIQhCEIAAAAAAAB/////////+AAAAAAAAhCEIQhCEIQhAAAAAAAAAA/////FBkIQhCEGMQghAAAAf////gAAAAAAAIQAAAAP+93vOc5znO997/wAAAIQiEIQQhCAAAAAAAAAAAIRCGMhCEIQYxCCEAAf/73vd973vf+AAAAAAAAAB//vd7znOc733vgAAIRCGMYxjGMQghAAAAAAAAAAAEQhjGMYxjEIIAA//3e95znOd773/gAAAQhCEAAA//3vd73vve+AAAiEMZCEIQhBjEIIAAB//////4AACEQhCEIQQgAD//d7znN75zne+/8AABEIQhCEEIAA//3ve9/4AACEQxkIQpSkIQYhBAD//e73ve+98AAACEQhBCEAAf/7vec5vfOc773wACIQxkIQYxiCEAAf//3//+AAAiEMZCEIQhBiEEAP+93nOc5zvff+AAAhEIQQhAAH/e73nOc53vvfAAIhDIQpSkIMYggAD//e973/gAAIRDGMhCDGIQQAB/3ec3ve+c733wAAEQhCEIIQAB//vd73ve+9/4ABEMZClKUpCDEEAAf/73ve97/wAAEQhDGMYhBCAH/+7zm973vne++AAQiEMYxiEEIAA//3gAAAAAf////gAAAAhCIQxjGQhBjGIQggAAH///////AAAAAAAAAAAAH/+93ve85zne9974AACEQhCEIQghCAAAAAAAAAAAIRCGMYyEGMYxBCAAP+93ve9733vf+AAAAAAAAAB//ve73ve9773/gAEIhjIQhCEGMQghAAAAAAAAAAAEIhCGMYxiEEIAf97vOb3vfOc773wAAAIQhCEAAAB//ve973vf+AARCGQhSlKUhBjEEAAf///vf/8AAACEIhCEIQQgAD/u85ve973znffAAAQiEIQhCCEAAA///ve9/4AACIYyEKUpSkIMQQAB/3vd73vfe/8AABCEQhBCEAAf93vOb3vfOd9/4ABEIYxkGMYxBCAAP//73v/+AAAiGMhCFIQgxBCAH/e73nOc53vvfAAAQhEIQghAAH/e7znOc533vgAEQhkIQhCEGMQQgAD//e973/gAAIhDGQhBjEIIAf97vOc5vnOd774AACEQhCEIQQAB//u973vfe+AAAiGMhCFKQhBiEEAP/97ve997/wACEQhjGMQghAD/vd5znN85zvQAAAAQhCIQhCEIQghCEAAAAAH////3ve973v//8AAAAEIQiEIQhCEIIQhAAAAAB///+973ve97///AAAABCEQhCEIQhCCEIQAAAAAf///ve973ve///wAAAAQhEIQhCEIQghCEAAAAAH///73ve973v/+AAAAAEIRCEIQhCEIIQhAAAAA////e973ve97//gAAAAhCEQhCEIQhCCEIQAAAAP///3ve973ve//4AAAAIQhEIQhCEIQQhCAAAAAD///973ve973//+AAAACEIhCEIQhCEEIQgAAAAA////e973ve9//wAAAAAhCIQhCEIQhBCEIAAAAAP///3ve973v//8AAAAAIQiEIQhCEIIQhCAAAAAD///973ve97///AAAABCEIhCEIQhBCEIQAAAAAf////+973v///4AAAAAQhCEQhCEIIQhCEAAAAAH////////////AAAAAAEIQhCIQghCEIQgAAAAAAD//////////4AAAAAABCEIQhCEIQhCEAAAAAAAA//////////AAAAAAAAQhCEIQhCEIQgAAAAAAAABUAQiEMZCEIQYxiEEIAAAAAAAAAAABCEIQhCEIQAB//u95znOc53vff+AAAAAEIQgAAAAA/////+AAABCIYyEIUpCEGMQggAAH///7///+AAAAAEIQgAAAP+93nOb3znO9974AACEQhCEIQhBCAAAAB//wAAAIRCGQhCEIQYxCCAAP+93ve9733vf+AAAACEIAAAD/vd7znOc733/gAEIhDGQhCDGMQghAAAP///4AAAEIhjGMYxjEEIAf/7vec5znOd773wAAAIQhCEIAAB/3u973vvf+AAQiGMhCFKQhBjEEIAf/73ve9/4AACEQhCEIQQgAD/u95zm975znfe+AAQiEMYxiEEIAA//3ve974AACEQxkIUpSEIMQggB//u973ve+98AABCIQhCCEAAf97vOc5znOd774ABCIYyEIQYxCCAAP/973vf+AAAiEMZCEIQgxiCAAP+73nOc5zvvfAAAQiEIQghAAH/e73nOc53vv/AAIhjIQpSEIMQQgB//ve973/gAAIhDGMhBjGIQQA/73ec3vfOd774AACIQhCEIIQAB8AAAAAAP//73ve9//wAAAIRCGMYxjGMYxCCEIAAAAAAAAAAABCEIQhCEAAA//3u97znOc73vvf+AAAhCEIQhAAAAA////gAAAAhEIYxkIQhCDGIQQgAD/ve973vf+AAAAAEIAAAAH/+93vOc5zne+98AABCIYxjGMYhBCAAAAAAAAAAAIRCGMZCEIMYhBAAH/e7znOc53vv/AAAABCEAAAB//vd73ve9773wAAEQxkIUpSEGMQQgAAH///8AAAAEIhDGMYxiEEAAf93nN73vfOd774AACEIRBCEIAA//3vd733vfAAARDGQpSlKUhBiCAAP/973ve/8AAACEQhCEIQQgB/3u85ve975zvv/AAIRCGMYxCCEAAf//3ve9/4AACIYyFKUpSEGIQQA/73e973vfe+AAABCIQhCCEAAf93vOb3vnO998AAiEMZCEIMYhBAAH//973vf+AAAiGMhCEIQYxBAD//d7znOc733vgAAIRCEIQghAAH/d7znOc733wAAEQxkIQhCDGIQQAB//ve973/gAAIhDGQhBjEEIAf93vOc5z3v//8AAAAEIQiEIQhCEIIQhAAAAAB////973ve97///AAAABCEQhCEIQhCCEIQAAAAAf///ve973ve///wAAAAQhEIQhCEIQghCEAAAAAH///73ve973v/+AAAAAEIRCEIQhCEIIQhAAAAAB///+973ve97//gAAAAhCEQhCEIQhCCEIQAAAAP///3ve973ve//4AAAAIQhEIQhCEIQQhCEAAAAD///973ve973v/+AAAACEIRCEIQhCEEIQgAAAAA////e973ve9///gAAAAhCIQhCEIQhBCEIAAAAAP///3ve973vf/8AAAAAIQiEIQhCEIIQhCAAAAAD///973ve97///AAAAACEIhCEIQhCCEIQAAAAAA////+973vf//4AAAAAQhCEQhCEIQQhCEAAAAAAP////ve9////+AAAAAEIQhEIQhBCEIQgAAAAAAD///////////wAAAAABCEIQhCEIQhCEAAAAAAAA//////////+AAAAAAAQhCEIQhCEIQgAAAAAAAAP////////4AAAAAAAAAIQhCEIQhCEAAAAAY73ve973vfe9/4AAAEIQhCEAAAAAH/gAAAAACEQhDGMhCEGMYhBCAAP/973ve//4AAAAAAAAAAAf/73e97znO9773wAAEIhDGMYxCEEIAAAAAAAAAAAhEIYxjGMYxiEEAAf97vec5zve+/8AAAAAAAAAAH/+97ve973vvfAAARDGQhCEIQYxBCAAAA///wAAAAQiEIYxjEIQQAB/3e83ve9853vvgAAAQhCEIQAAAH/+973ve/8AABEMZClKUpSEGIIQAB//ve97//gAAIQiEIQhBAAH/e7zm973vnO+98AAhEIQxiEIIQAAD//e973/gAAIhjIUpSlIQYhBAD//d73ve997/wAAEIRCEEIQAB/3e85ve+c733wACIQxkIQgxjEEIAA//3ve9/4AACIYyEIQhBjEEAP/93vOc5zne+/8AABCIQhCCEAAf93vOc5zvffAAARDGQhCEIQYhBAAH/+973vf+AAAiEMZCDGMQQgB/3e85zfOc733vgAAIhCGMQhBAAH/e73ve9974ABCIZCEKUhCDGIIAA/73u9733vgAAIRCAAAAAAAAQhCEAAAB//u95znOc53vvf+AAAACEIQhCEIAAAAAAAAAAABCIQxkIQhCEGMQQgAD//+973ve//4AAAAAAAAAAP/97vec5znO99/4AACEQhjGMYxCEEIAAAAAAAAAAQiEMYyEIMYhBCAAP+93vec53vfe/8AAAAEIQAAAH/+93ve9773/gAEIhjGQhCEIMYhBCAAP/////gAAARCEMYxCEEIAf/7vec5znOc733/gAAIRCEIQQgAD//e973vf+AAAiEMhCFKUhCDEIIAA/73u9973/gAAIRCEIQQgAD//d7znN75zne++AAAiEMYxjGIQQAB///e9//wAAEQhjIQhCEIMYggAD/u95znOd774AACEIhCCEIAA/73e85znOd774AACIYyEIQhBjEEAAf/73vf/8AABEIYyEIQgxiCEAP+73nN73znfe+AAAiEIQhBCAAP/93ve873vvfAAIhjIQpSlIQYggAD//e973v/AAAQiEMYxjGIQQAB/3ec3ve98733wACEQhDGIQggAD//e93ve+9/4ABEMZCFKUpCDAAAAAB///+973ve9///gAAAAhCEQhCEIQhBCEIAAAAAP////ve973vf//4AAAAIQhEIQhCEIQQhCAAAAAD///973ve973//+AAAACEIhCEIQhCEEIQgAAAAA////e973ve9///gAAAAhCIQhCEIQhBCEIAAAAAP///3ve973vf/8AAAAAIQiEIQhCEIQQhCAAAAAD///973ve973//AAAABCEIhCEIQhCCEIQgAAAAf////e973ve9//wAAAAQhCIQhCEIQghCEAAAAAH///73ve973v//8AAAAEIQiEIQhCEIIQhAAAAAB///+973ve97//gAAAABCEIhCEIQhBCEIQAAAAAf////e973vf//4AAAAAQhCIQhCEIIQhCAAAAAAH////3ve9////AAAAAAEIQiEIQhBCEIQgAAAAAB////////////wAAAAABCEIQiEEIQhCEAAAAAAAf//////////+AAAAAAAQhCEIQhCEIQgAAAAAAAH/////////4AAAAAAAAEIQhCEIQhCEAAAAAAAAAD///////gAAAAAAAAAB"},{"bdsAlm":"MboqAAAqAMrrJQAAAl4AfrXZAELWA/+kVkoAAACBFEoDpwAAAAABKgDK6wUAAAjY/9j32v+4UVT/qZLDAAAAZxszAnsACQAAAioAyuvJAAAHgP/mVuf/xmLC/6ECzwAAAH4T2wCsAAwAAAMqAMrrUwAAA0//kW/IAD8p9P+gTgwAAACGEyr/d//3AAAEKgDK6tgAAAew/7lKNP/Nh1b/og0MAAAAbhXD/HcACQAABSoAyuZ7AAAhvv+QK3z/z6bG/+jibv///3EDCgFuAAcAAAYqAMrrTwAAGlz/ksKY/4E1MAA4Haj///8jxrH8pwAKAAAHKgDK6vwAABUOAH3arwA874T/kc9T////Q1Lw/+L/9wAACCoAyutTAABkTf+iBoL/tsLK/+q7+v///3IGk/zb//EAAAkqAMrsFQAATRX/m1cNAG9IVwA349n///8kyC7////7AAAKKgClFMIAAA9O/72PBP/mzT8AW5PO///9xhrxAhsABQAACyEApRSzAAAH7v/CmAUAN5KoAFsSlP///cQZ5P8N//4AAAwqAMrpeQAAJwn/nx0fABOAHP+Qk7X///88Oi8BxAABAAANJgClFKgAAAt8//FYjAAEaKv/r1nQ///9pRUFAqwAGQAADyoAyutsAAA7lf+lAQL/wcfi/+i7mf///3QNKf4d//kAABIqAKUUmQAACM//24iD/+QcOP+vaOP///2eFr38QQAAAAATKgClFKAAAAdw/+viBf/xyI3/r29v///9nxa7/oL/9QAAFCoApRSbAAAHLv/kpgD/mtVs/696Rv///Z4WQ/wOAAAAABUqAKUUmgAABa3//aJ9/6Gf4v+veX7///2eFkX/2QAEAAAWKgClFMwAAADO/9GToP/71KkABLHj///9pgHo/NMAAAAAFyoApRS8AAAE0gAfch7/7dK8AASv/////aYB5wPZ//4AABgqAKUUlQAAA/8AHOsz/8/yHwADuLD///2pAuUBigADAAAZKgClFJIAAAa6ABvFYwAQ85MAA78F///9qALt/t3//wAAGioApRSUAAAF7wAysyUAImRuAFpoQf///awK9wE6AAEAABsqAKUUsQAAAFv/4z3//45vlQBaZa////2rCuIA8AABAAAcKgClFI8AAAJAADSpAf/hI5sAWMf3///9qQmlARoAAQAAHSoApRSKAAAExAAbJEMAHCceAFjNFP///akJnv/E//4AAB8qAKUUmAAABfL/3ERaACNec/+vJHX///2eFfH9iP/+AAAgKgClFJkAAASn//AiwABPrLj/ryMz///9nRX2/AQAAQAAISoApRSVAAAFdAAh6Er/kpxpAFjbbf///acIbAGxAAIAACIqAKUUlAAAB3sAF9CD/9pKsQBY2t////2nCHgBlf/+AAAjKgClFNQAAAUG/8rowf+iUSsABKXZ///9qALaADcAAwAAJCoApRS4AAAEQP/q1uL/wmHKAASkW////agC3PwS//4AACUqAMrsKwAADy//linOAC1FAv+QgIz///9FKMEAnQABAAAmKgDK7Y8AABpq/5JV3v/bYGP/5dHd////bw11//gAAAAAJyoAyuvDAAAeOwB97VX/mIhmAD2tw////zAYB/+7//8AACgqAKUUkgAADnT/ypzFAFYlmv+vRD////2dFTH8Nf/+AAApKgClFJQAAAzp/9RaR/+MOqL/r0pN///9nRU2/i8AAAAAKioApRSLAAAFIAAenwkAeM5cAFjLxP///aQGcABHAAAAACsqAKUUlQAABuMAHRh8/7hMegBYz+b///2lBr0B0wADAAAsKgClFJcAAANxAAg+2gBFL1kABNIV///9qwVs/6z//wAALSoApRSgAAAGJAAJlnj/gkrpAATXvf///asFcP9t//8AADcXAMrpzgAAJbT/h1wcAEHkTf+TNl7///8R7aYBtAABAAA4FwClFKwAAAPQ/9bH3//6q8L/0gA2///9sRYFAbQAAQAAORgApRSLAAAFugAlUQUAIGUBAFV01////ZYVKvwA/8wAADoqAMrrNgAAAwT/8u/E/6/s2P+/350AAAAKFy0AAQAAAAA7KgDK66IAAADw/+/JFv/FJQj/gx4IAAAAZhleAAAAAAAAPCoAyur9AAAEu//W9Xj/7zD4/4ePEwAAAH0HlwAAAAAAAD0qAMrrBgAAAx7/hhI9/65ecgA8fpj////xGewAAAAAAAA="},{"gloAlm":"GAYAAABtAQn/82iaAAki/QAAI6z/60DiHwIF6m3/6wEBAG0CBP/xwYoAC5CGAAAthP/rP/IfCPWnmAAFAQEAbQMNAA/ZgAAOAQIAACnr/+s/9iAI26q1/+cBAQBtBA4ADhlkABBejgAAMNv/6z/eIAUsu3b/xAEBAG0FCQAMUMMAEruyAAAxKf/rP8kgAuerj//eAQEAbQYE//jwnAAB2UYAACNU/+tADx4BH2fBACkBAQBtBw3/90pjAAQ68AAAKhb/6z9rHgfCq6IAAAABAG0IDv/1kOgABn/BAAAqP//rP+YdCdq2cAATAQEAbQkG//7PBQAIJLwAAA69/+tAS+sHYo6U/9EBAQBtCgH//UccAApDKQAAHtD/6z/s6wb+B5gAJwEBAG0LCP/7XcwADMzZAAAk/P/rP/HrAeygff/5AQEAbQwH//lSMQAPiHUAAB/I/+tAOuoDkM63//YBAQBtDQb/950VABGzgQAAHp//6z/Y6QIrOMIADAEBAG0OAQAElqwAAKsgAAAZNv/rQELsAjOenv/6AQEAbQ8IAALFCgADHhwAAB4c/+tAO+4Cj7jx/+sBAQBtEAcAANm4AAWaAQAAKDH/60Bc7AMUj4T/+gEBAG0RDAAKPtEAB2SeAAA3QP/rQFL3As2HYP/sAQEAbRIFAAiPAgAJsDIAAD1X/+tANfYFH/O4/9wBAQBtEwsAByI5AAvDvQAAQ0r/6z/39ADALFgARwEBAG0UCgAE54IADrVnAABDof/rQEL2BCj6xwAdAQEAbRUMAALCVQARSlMAADvr/+s/FPkBtm9lABgBAQBtFgUAAQxLABO9pgAAJoz/60Bq+AO30kX/4gEBAG0XCwAOL3IAAlbuAABACP/rPxb0AfsqaAAfAQEAbRgKAAwoXAAE4tcAACg8/+tAMPYB3bGXAA0BAQ=="},{"gloAux":"GAABwAH8wAIFwAMGwAQBwAX8wAYFwAcGwAj+wAn5wAoAwAv/wAz+wA35wA4AwA//wBAEwBH9wBIDwBMCwBQEwBX9wBYDwBcCwA=="},{"gloRti":"AwaAABiAABmAAA=="},{"bdsRti":"BwqAACKAAC+AADGAADeAADiAADmAAA=="},{"galRti":"BgUQAA0IAA8MABEIABYIAB8QAA=="},{"gpsUtc":"//////////4AewAGABIAiQAHABI="},{"gpsAlm":"AAYfAYM3AHt2yf1iAAAAoQ1MAG1+DP/PDuX/tmrG/igAAgIrxgB7gWj9UgAAAKENi/+bq+wAK4OxACbsRgFPAAYDFugAe3Se/UMAAAChDaj/x6Pz/4gV+P+fATkBZwACBC85AHt48P1HAAAAoQxe/5mZqAAyW4r/uucy/04AAAUZIAB7hVn9cwAAAKEMhgBxdjv/42s/AFsSTwFJ//sGlnsAe2uy/VcAAAChDNH/8OwV/6kftwA3uHT/jP/+B01/AHtth/00AAAAoQx8AETfIAAOgOb/q3zfAIoABggV2AB7cGn9PAAAAKENB//FOdAAUVFL/74mmQCuAAQJTCUAe4Ey/VIAAAChDRv/m5EW/5+NIf/8koj/9f//CgoeAHt2Cf1eAAAAoQ02AHLXp/+Y7Gn/jbPx/WD//QtI1gB7c7T9QAAAAKEM5wAeWzMAOp1zABohR/32//8MQQYAe3ju/UwAAAChDNv/y/c2ACWo1/+gh+sCowABDSNBAHto3P01AAAAoQ0cAByRx/+IaoUAGnzDAY8AAw5/MgB7YUv9IwAAAKEMm//ADTIANQ/z/4UTfwCeAAEPck0Ae3Ng/T4AAAChDasAHxX3ACIXAf/R+8/+uAADEG3MAHt3zf1KAAAAoQ1EAEi1jv/J/oT/rMGBAukAABEglgB7e3P9ZQAAAKEMlgBxpkX/g/OSAFrtTP2O//4ST6YAe3dE/UoAAAChDS4ASoRXAGZq4f/+2SUB7QABEx38AHttjv07AAAAoQ23/5RhMP+WTVUAbbGiAY4AABTOmgB7cwv9ZAAAAKENQwBtNWX/6BnM/6cD/wCFAAAVdaMAe3Ls/UEAAAChDTkAHzhf/9GtCP/BoNn//v/+FiFRAHt+Cv1QAAAAoQ1L/5pkw/+HcLcAKz5lANcAAxd8lQB7YQT9RwAAAKENW//s/xUAJ6xvAGGg9v4c//8YYHQAe2vf/TkAAAChDDYAGtjHACxSHgAYEHECBgAAGUhzAHtfXv0qAAAAoQx/ABhUZwAWBWD/9zAcAKz//xpm/wB7c2X9PgAAAKEM/QBF7/sAIAFz/67xpv/r//8bA44Ae3Ls/V8AAAChDLr/745nAEbgfP/8tu3/JP/8HBclAHt5Xv1KAAAAoQx1AElRNQBmBPf/rV34/YkAAB05xgB7YgP9SgAAAKEM3f/w+Fn/mq8RADHezP5aAAIeVgcAe25N/VoAAAChDVH/8cqNABtIFwAUg47/EQAAHz9eAHtyp/1BAAAAoQzd/8XQ2v+o2Nj/yYDO/XgAAA=="},{"galAlm":"Fw+Zh8AHAQAX/8r/8AAAAAsdAx4KPRoAPwABAgAU/6j/8AAAAAvHXvMgvMX/x///AwAa/6j/8AAAABTHYMx0Qtf/Ov/+BAAU/6j/8AAAAAzHX9DS/tcJtQABBgAb/6j/8AAAAA3HX9uklK3/xP//BwAW/8f/8AAAAA3HXOjKp9D/ef/+CAAb/8f/8AAAAAzHXOd2CQj/KP/8CQAQAHf/8gAAAA1yDTVOIHL+vP//CgAjAGj/8gAAAAxyLR49JjQGLv/vCwAhAGj/8gAAAA9yLQ3NVzX98//7DAASAHj/8gAAAA5yIf0fyFj/9QAADgASAHj/8gAAAA1yIPP38fb/zf//EgAa/8X/8AAAABLHkcZqbNr/jgATFAAK/8j/8AAAAAgc40A8udT+y///FwAq/7z/8AAAAAsdAyhJcsH+if/6GAAE/8j/8AAAAAYc4wI6eIAAAgAAGQAKAFX/8gAAAAtyIvLPsfAA4QADGgAL/8j/8AAAAAgc4xbnA5//VP/9HQAd/7z/8AAAAAwdAi1QDWz/kP/1HgAE/8j/8AAAAAcc4thN4i//9QAAIAAEAHj/8gAAABFyIP9Hh1QABgAAIQAMAHf/8gAAAAtyDT6hxx7/yP//IwAUAHj/8gAAAA5yIAGvJAz/j///"},{"gpsIon":"JwH9/0QC+wU="},{"gpsRti":"CQUAAAAAAAYnACABAwAAAAILAgIAAAACCwMCAAAAAgsEAgAAAAILBQIAAAACCwYCAAAAAgsHAgAAAAILCAIAAAACCwkCAAAAAgsKAgAAAAILCwIAAAACCwwCAAAAAgsNAgAAAAILDgIAAAACCw8CAAAAAgsQAgAAAAILEQIAAAACCxICAAAAAgsTAgAAAAILFAIAAAACCxUCAAAAAgsWAgAAAAILFwIAAAACCxgCAAAAAgsZAgAAAAILGgIAAAACCxsCAAAAAgscAgAAAAILHQIAAAACCx4CAAAAAgsfAgAAAAILIAIAAAACCw=="}]}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/server_pgnss_decode_demo.c b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/server_pgnss_decode_demo.c
new file mode 100644 (file)
index 0000000..4b75f2f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag 2024-2024. All rights reserved.
+ * Description: pgnss decode demo on server
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sys/time.h>
+#include <dlfcn.h>
+
+#define XGNSS_LIB_PATH        "./libpgnss_decoder.so"    // 请自行配置解码库路径
+#define XGNSS_SEED_FILE_PATH  "./demo_data/EE_7days.dat" // 请自行配置种子文件完整路径
+#define XGNSS_OUTPUT_PATH_1   "./demo_data/output1/"     // 请自行配置解码后星历存放位置
+#define XGNSS_OUTPUT_PATH_2   "./demo_data/output2/"     // 请自行配置解码后星历存放位置
+#define HOUR_TO_SECONDS       3600
+#define PARSE_HOURS           24
+
+// 根据解码库接口文件,声明接口函数类型
+typedef int32_t (*LibFuncGetValidTime)(const char *, uint32_t *, uint32_t *);
+typedef int32_t (*LibFuncParseSeed)(const char *, const char *, uint32_t, uint32_t);
+
+void PgnssGenerateDemo(bool mergeEphFiles)
+{
+    printf("\n[XGNSS] ==== parsing pgnss seed %s merge eph files. ====\n", mergeEphFiles ? "with" : "without");
+
+    // 加载解码库
+    void *handle = dlopen(XGNSS_LIB_PATH, RTLD_LAZY);
+    char const *errStr = dlerror();
+    if (handle == NULL) {
+        printf("[XGNSS] error: module=%s\n%s\n", XGNSS_LIB_PATH, errStr != NULL ? errStr : "unknown");
+        return;
+    }
+    printf("[XGNSS] load pgnss lib succeed.\n");
+
+    // 获取接口函数
+    LibFuncGetValidTime libGetValidTime = (LibFuncGetValidTime)dlsym(handle, "GetPgnssDataValidTime");
+    LibFuncParseSeed libParseSeed;
+    if (mergeEphFiles) {
+        libParseSeed = (LibFuncParseSeed)dlsym(handle, "ParsePgnssDataByLessFiles");
+    } else {
+        libParseSeed = (LibFuncParseSeed)dlsym(handle, "ParsePgnssData");
+    }
+    printf("[XGNSS] load pgnss lib function succeed.\n");
+
+    if (libGetValidTime == NULL || libParseSeed == NULL) {
+        printf("[XGNSS] error: couldn't find symbol\n");
+        dlclose(handle);
+        return;
+    }
+
+    // 查询种子可支持预测的星历的起止unix时间
+    uint32_t seedStartTime = 0;
+    uint32_t seedEndTime = 0;
+    int32_t ret = libGetValidTime(XGNSS_SEED_FILE_PATH, &seedStartTime, &seedEndTime);
+    if (ret != 0) {
+        printf("[XGNSS] error: get valid time error. ret=%d\n", ret);
+        dlclose(handle);
+        return;
+    }
+    printf("[XGNSS] get seeds valid time: start=%u, end=%u\n", seedStartTime, seedEndTime);
+
+    // 获取当前UNIX时间(0时区)
+#ifdef USE_REAL_TIME
+    struct timeval currTime;
+    gettimeofday(&currTime, NULL);
+    uint32_t ts = currTime.tv_sec;
+#else
+    uint32_t ts = seedStartTime;
+#endif
+
+    // 设定时间,一次最多解码出24小时的星历,如需解码更多星历,请拆分多次调用解码函数
+    int32_t hours = PARSE_HOURS;
+
+    // 确保时间不超出种子可预测的有效时间,如果超出有效时间,可以考虑重新下载种子文件
+    if (ts < seedStartTime || ts + hours * HOUR_TO_SECONDS > seedEndTime) {
+        printf("[XGNSS] error: set time invalid. set start=%u, set end=%u\n", ts, ts + hours * HOUR_TO_SECONDS);
+        dlclose(handle);
+        return;
+    }
+
+    // 解码种子文件,得到解码后的星历
+    printf("[XGNSS] start parsing pgnss seed ...\n");
+    if (mergeEphFiles) {
+        ret = libParseSeed(XGNSS_SEED_FILE_PATH, XGNSS_OUTPUT_PATH_1, ts, hours);
+    } else {
+        ret = libParseSeed(XGNSS_SEED_FILE_PATH, XGNSS_OUTPUT_PATH_2, ts, hours);
+    }
+
+    if (ret != 0) {
+        printf("[XGNSS] Parse Pgnss Data failed, err=%d\n", ret);
+    } else {
+        printf("[XGNSS] Parse Pgnss Data succeed.\n");
+    }
+    dlclose(handle);
+}
+
+int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
+{
+    // PGNSS数据解析(合并文件输出方式,可减少生成的星历文件数量),详细说明见XGNSS开发指南
+    PgnssGenerateDemo(true);
+
+    // PGNSS数据解析(多文件输出方式),详细说明见XGNSS开发指南
+    PgnssGenerateDemo(false);
+}
diff --git a/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_download_demo/server_pgnss_download_demo.py b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_download_demo/server_pgnss_download_demo.py
new file mode 100644 (file)
index 0000000..c87f7c2
--- /dev/null
@@ -0,0 +1,140 @@
+#!/usr/bin/env python\r
+# coding:utf-8\r
+# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
+import requests\r
+import time\r
+import calendar\r
+import hmac\r
+import base64\r
+\r
+\r
+# 网络连接相关\r
+HOST = r'geo-drcn.platform.dbankcloud.cn'  # 域名\r
+PORT = 443  # 端口号\r
+URI = r'/higeo/v1/xgnss/pgnss'  # uri路径\r
+\r
+# 鉴权认证相关\r
+APP_ID = r''  # 账号,请联系销售代表获取\r
+APP_SECRET = b''  # 密钥,请联系销售代表获取\r
+UUID = r''  # 每台设备的唯一标识码,请根据产品进行适配\r
+\r
+# 请求参数\r
+PERIOD = r''  # 一次性请求数据的天数,可选项(1,3,7,14,28),默认7天\r
+\r
+\r
+class PgnssRequest:\r
+    def __init__(self):\r
+        self.ts = 0\r
+        self.qry_str = ''\r
+        self.signature = ''\r
+        self.url = ''\r
+        self.session = requests.session()\r
+\r
+    def format_req_str(self):\r
+        qry_str = ''\r
+        if PERIOD and PERIOD != '7':\r
+            # period默认值7,则无需填写\r
+            qry_str += f'period={PERIOD}'\r
+        self.qry_str = qry_str\r
+\r
+    def gen_auth_str(self):\r
+        # 构造待签名字符串\r
+        str_to_sign = f'GET&{URI}&{self.qry_str}&&appid={APP_ID}&timestamp={self.ts}'\r
+        # 计算签名HMAC值\r
+        h1 = hmac.new(key=APP_SECRET, digestmod='sha256')\r
+        h1.update(str_to_sign.encode('utf-8'))\r
+        b1 = base64.b64encode(h1.digest())\r
+        signature = b1.decode('utf-8')\r
+        self.signature = signature\r
+\r
+    def update_session(self):\r
+        # 填充完整url\r
+        self.url = r'https://{}:{}{}{}{}'.format(HOST, PORT, URI, '?' if self.qry_str else '', self.qry_str)\r
+        # 组装请求消息头\r
+        self.session.headers.update(\r
+            {\r
+                'X-Request-ID': f'{UUID}',\r
+                'Authorization': f'HMAC-SHA256 appid={APP_ID},timestamp={self.ts},signature={self.signature}'\r
+            }\r
+        )\r
+\r
+    def connect_session(self):\r
+        try:\r
+            print(f'正在连接服务器...')\r
+            rsp = self.session.get(url=self.url, verify=False, timeout=(3, 27))\r
+            print(f'Pgnss请求结果:{rsp.status_code},结果码:{rsp.reason}, 响应长度:{len(rsp.content)}')\r
+\r
+            # 处理响应值\r
+            if rsp.status_code == 200:\r
+                # 响应200表示请求成功\r
+                print(r'响应内容:')\r
+                # 响应内容的Pgnss辅助数据保存成文件,后续配合解码库使用\r
+                with open(r'.\EE.dat', 'wb') as f:\r
+                    f.write(rsp.content)\r
+                    print(f'EE.dat下载成功')\r
+            elif rsp.status_code == 401:\r
+                if rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'unix时间戳异常,请检查服务器下发的响应消息头中“X-Auth-Timestamp”与请求消息头的'\r
+                          r'“Authorization”中的“timestamp”是否相差很大')\r
+                    print(r'请检查“timestamp”是否取用正确的UNIX时间戳,单位是毫秒')\r
+                    # 如设备本身无时间系统,可在此处取用服务器下发的“X-Auth-Timestamp”进行重新请求\r
+                    print(f'响应消息头:{rsp.headers}')\r
+                    server_ts = rsp.headers.get('X-Auth-Timestamp', 0)\r
+                    self.ts = server_ts\r
+                    # 签名认证\r
+                    self.gen_auth_str()\r
+                    # 更新请求消息头\r
+                    self.update_session()\r
+                    # 重新请求\r
+                    rsp2 = self.session.get(url=self.url, verify=False, timeout=(3, 27))\r
+                    print(f'Pgnss重新请求结果:{rsp2.status_code},结果码:{rsp2.reason}, 响应长度:{len(rsp2.content)}')\r
+\r
+                elif rsp.reason == 'authorization is missed':\r
+                    print(r'“Authorization”字段异常,请检查请求消息头是否正确填写“Authorization”字段')\r
+                elif rsp.reason == 'appid is missed':\r
+                    print(r'“appid”字段异常,请检查请求消息头的“Authorization”中是否正确填写“appid”字段')\r
+                elif rsp.reason == 'timestamp is invalid':\r
+                    print(r'“timestamp”字段异常,请检查请求消息头的“Authorization”中是否正确填写“timestamp”字段')\r
+                elif rsp.reason == 'signature is invalid':\r
+                    print(r'“signature”字段异常,请检查请求消息头的“Authorization”中已填写“signature”字段')\r
+                elif rsp.reason == "Can't get the keys of appid":\r
+                    print(r'“appid”无效,请检查请求消息头的“Authorization”中的“appid”的合法性')\r
+                elif rsp.reason == 'SignatureInvalid':\r
+                    print(r'“signature”异常,请检查请求消息头的“Authorization”中的“signature”正确性,'\r
+                          r'检查appid和app_secret是否匹配')\r
+                elif rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'异常,请检查')\r
+                elif rsp.reason == 'TimestampMoreEarlierOrLater':\r
+                    print(r'异常,请检查')\r
+            self.session.close()\r
+        except requests.exceptions.SSLError as e:\r
+            print(e)\r
+            print('请检查网络是否通畅')\r
+        except requests.exceptions.ProxyError as e:\r
+            print(e)\r
+            print('请检查网络是否通畅')\r
+        except Exception as e:\r
+            print(e)\r
+\r
+    def request(self, ts=0):\r
+        self.ts = ts\r
+\r
+        # step1. 构造规范化请求字符串\r
+        self.format_req_str()\r
+\r
+        # step2. 构造鉴权信息字符串\r
+        self.gen_auth_str()\r
+\r
+        # step3. 构造HTTP GET请求\r
+        self.update_session()\r
+        print(f'请求URL:{self.url}')\r
+\r
+        # step4. 发送请求\r
+        self.connect_session()\r
+\r
+\r
+if __name__ == '__main__':\r
+    # 获取当前UNIX时间,单位毫秒\r
+    now = calendar.timegm(time.gmtime()) * 1000\r
+    pgnss = PgnssRequest()\r
+    pgnss.request(now)\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5b80af7
--- /dev/null
@@ -0,0 +1,41 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "agnss_sample")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/agnss_sample.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/agnss_encode.c
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+CONFIG_AGNSS_SAMPLE
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+)
+
+set(WHOLE_LINK
+true
+)
+
+set(BUILD_AS_OBJ
+false
+)
+
+set(MAIN_COMPONENT
+false
+)
+build_component()
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.c b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.c
new file mode 100644 (file)
index 0000000..9309437
--- /dev/null
@@ -0,0 +1,252 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: agnss encode\r
+ * Author:\r
+ * Create:\r
+ */\r
+#include "agnss_encode.h"\r
+#include <stdio.h>\r
+#include <dirent.h>\r
+#include <string.h>\r
+#include "securec.h"\r
+#include "gnss_datatypes.h"\r
+#include "tiot_service_interface.h"\r
+\r
+#define GNSS_ENCODE_BUFF_MAX_LEN 9300\r
+#define FILE_PATH_LEN            1024\r
+#define INJECT_SLEEP_MS_TIME     500\r
+#define REPORT_MAX_BYTES         10000\r
+#define LISTEN_TIME_THR          1000\r
+#define AGNSS_FILE_MAX_SIZE      1024000\r
+#define AGNSS_DATA_PATH          "/user/xgnss/AGNSS.dat" // 可自行配置路径\r
+\r
+// 监听消息\r
+static uint8_t g_ackBuff[REPORT_MAX_BYTES] = { 0 };\r
+\r
+/* 计算命令内容校准和 */\r
+static uint16_t CalcChecksum(uint8_t *buff, uint16_t len)\r
+{\r
+    uint16_t checksum = 0;\r
+    uint16_t i = 0;\r
+    while (i++ < len) {\r
+        checksum += *buff;\r
+        buff++;\r
+    }\r
+    return checksum;\r
+}\r
+\r
+/* AGNSS计算内容校准和, 校验和模256,与芯片侧的命令校验和计算不可混用 */\r
+uint8_t CalcAgnssCheckSum(uint8_t *data, uint16_t len)\r
+{\r
+    uint8_t sum = 0;\r
+    for (uint16_t i = 0; i < len; i++) {\r
+        sum += data[i];\r
+    }\r
+    return sum;\r
+}\r
+\r
+int32_t AgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime)\r
+{\r
+    uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN);\r
+    if (buff == NULL) {\r
+        printf("\nerror: malloc failed in AgnssInjectUtcTime\n");\r
+        return 0;\r
+    }\r
+    memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN);\r
+\r
+    GnssMsg *hdr = (GnssMsg *)buff;\r
+    hdr->cmd = CMD_XGNSS_INJECT_UTC_TIME;\r
+    hdr->sequence = 0;\r
+    errno_t copyRet = memcpy_s(hdr->data, (GNSS_ENCODE_BUFF_MAX_LEN - sizeof(GnssMsg)), utcTime, sizeof(GnssUtcTime));\r
+    if (copyRet != EOK) {\r
+        printf("\nmemcpy UtcTime failed! Errno is %d\n", copyRet);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+    hdr->dataLength = sizeof(GnssUtcTime);\r
+    hdr->checkSum = CalcChecksum(hdr->data, hdr->dataLength);\r
+    int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + hdr->dataLength));\r
+    if (ret < 0) {\r
+        printf("\nerror: AgnssInjectUtcTime error: %d\n", ret);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+\r
+    free(buff);\r
+    return 1;\r
+}\r
+\r
+static uint16_t FillGnssMessageData(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)\r
+{\r
+    errno_t ret = memcpy_s(outBuff, outLen, inBuff, inLen);\r
+    if (ret != EOK) {\r
+        printf("memcpy XgnssData failed! Errno is %d", ret);\r
+        return 0;\r
+    }\r
+\r
+    return inLen;\r
+}\r
+\r
+static int32_t EncodeGnssMsg(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)\r
+{\r
+    uint16_t len = FillGnssMessageData(inBuff, inLen, outBuff, outLen);\r
+    if (len > 0) {\r
+        return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+static void ListenAck(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    for (;;) {\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_ackBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_ackBuff;\r
+            // 二进制消息类型\r
+            if (type[0] == 0) {\r
+                g_ackBuff[ret] = '\0';\r
+                printf("%s\n", (char *)&g_ackBuff[MSG_CONTENT_IDX]);\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= 1) {\r
+            printf("\ncnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+static int32_t EncodeAndInjectCmd(tiot_handle handle, GnssCmdType cmdType, uint8_t* inBuff, uint32_t inLen)\r
+{\r
+    // 获取GNSS业务消息头\r
+    int32_t len = 0;\r
+    uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN);\r
+    if (buff == NULL) {\r
+        printf("\nerror: malloc failed in EncodeAndInjectCmd\n");\r
+        return 0;\r
+    }\r
+    memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN);\r
+\r
+    GnssMsg *gnssHdr = (GnssMsg *)buff;\r
+    len += sizeof(GnssMsg);\r
+\r
+    gnssHdr->sequence = 0;\r
+\r
+    int32_t retLen = EncodeGnssMsg(inBuff, inLen, buff + len, (GNSS_ENCODE_BUFF_MAX_LEN - len));\r
+    if (retLen != 1) {\r
+        printf("\nerror: Encode Cmd failed: %d\n", cmdType);\r
+        free(buff);\r
+        return retLen;\r
+    }\r
+    gnssHdr->cmd = cmdType;\r
+    gnssHdr->dataLength = inLen;\r
+    gnssHdr->checkSum = CalcChecksum(gnssHdr->data, gnssHdr->dataLength);\r
+    int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + gnssHdr->dataLength));\r
+    if (ret < 0) {\r
+        printf("\nerror: Inject Cmd failed: %d\n", cmdType);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    printf("\nInject Cmd SUCCESS: %x\n", cmdType);\r
+    free(buff);\r
+    return 1;\r
+}\r
+\r
+void ProcAndInjectAgnssCmd(tiot_handle handle, uint16_t dataType, uint8_t *data, uint16_t dataLen)\r
+{\r
+    /* 1.根据AGNSS dataType类型,转换为芯片侧消息类型 */\r
+    const struct {\r
+        AgnssDataType agnssDataType;    // AGNSS type类型,\r
+        GnssCmdType innerType;            // 芯片侧消息类型\r
+    } table[] = {\r
+        {AGNSS_GPS_INJECT_EPH, CMD_AGNSS_INJECT_NAV},\r
+        {AGNSS_GPS_INJECT_UTC, CMD_AGNSS_INJECT_UTC},\r
+        {AGNSS_GPS_INJECT_ION, CMD_AGNSS_INJECT_IONO},\r
+        {AGNSS_GPS_INJECT_RTI, CMD_AGNSS_INJECT_RTI},\r
+        {AGNSS_GLO_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV},\r
+        {AGNSS_GLO_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI},\r
+        {AGNSS_GLO_INJECT_AUX, CMD_AGNSS_INJECT_GANSS_AUXI},\r
+        {AGNSS_BDS_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV},\r
+        {AGNSS_BDS_INJECT_ION, CMD_AGNSS_INJECT_GANSS_ADDL_IONO},\r
+        {AGNSS_BDS_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI},\r
+        {AGNSS_GAL_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV},\r
+        {AGNSS_GAL_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI}\r
+    };\r
+    uint16_t cmdType = 0;\r
+    // 2.遍历对应关系表\r
+    for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) {\r
+        if (dataType == table[i].agnssDataType) {\r
+            cmdType = (uint16_t)table[i].innerType;\r
+            // 3.找到对应芯片侧消息类型,并下发消息\r
+            EncodeAndInjectCmd(handle, cmdType, data, dataLen);\r
+            break;\r
+        }\r
+    }\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+}\r
+\r
+void AgnssInjectAllContent(tiot_handle handle, uint8_t *buff, int32_t len)\r
+{\r
+    int32_t remainLen = len;\r
+    // tlv\r
+    while ((uint32_t)remainLen >= sizeof(AgnssDataHeader) + sizeof(AgnssDataTail)) {\r
+        AgnssDataHeader *header = (AgnssDataHeader *)buff;\r
+        uint16_t dataLen = header->len;\r
+        if ((uint32_t)remainLen < sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen) {\r
+            printf("AgnssInjectAllContent: remainLen %d and dataLen %d not match\n", remainLen, dataLen);\r
+            return;\r
+        }\r
+        uint8_t localCheckSum = CalcAgnssCheckSum((uint8_t *)header, (header->data - (uint8_t *)header) + dataLen);\r
+        uint8_t checkSum = ((AgnssDataTail *)(header->data + dataLen))->checkSum;\r
+        if (localCheckSum != checkSum) {\r
+            printf("AgnssInjectAllContent: local CheckSum %d and CheckSum %d not match\n", localCheckSum, checkSum);\r
+            return;\r
+        }\r
+        ProcAndInjectAgnssCmd(handle, header->dataType, header->data, dataLen);\r
+        buff += sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen;\r
+        remainLen -= sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen;\r
+    }\r
+}\r
+\r
+void ProcAgnssFileContent(tiot_handle handle)\r
+{\r
+    char fileName[] = AGNSS_DATA_PATH;\r
+    FILE *fp = fopen(fileName, "rb");\r
+    if (fp == NULL) {\r
+        printf("\nerror: open file failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    fseek(fp, 0, SEEK_END);\r
+    int32_t len = ftell(fp);\r
+    fseek(fp, 0, SEEK_SET);\r
+    if (len < 0 || len > AGNSS_FILE_MAX_SIZE) {\r
+        fclose(fp);\r
+        printf("\nerror: get file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    uint8_t *buff = (uint8_t *)malloc(len);\r
+    if (buff == NULL) {\r
+        fclose(fp);\r
+        printf("\nerror: malloc file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    int32_t dataSize = fread(buff, len, 1, fp);\r
+    if (dataSize < 0) {\r
+        fclose(fp);\r
+        printf("\nerror: read file failed: %s\n", fileName);\r
+        free(buff);\r
+        return;\r
+    }\r
+    fclose(fp);\r
+    AgnssInjectAllContent(handle, buff, len);\r
+    free(buff);\r
+}\r
+\r
+void AgnssInject(tiot_handle handle)\r
+{\r
+    // 处理AGNSS文件,向芯片注入Agnss辅助数据\r
+    ProcAgnssFileContent(handle);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.h b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.h
new file mode 100644 (file)
index 0000000..bbef153
--- /dev/null
@@ -0,0 +1,15 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: agnss encode\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef AGNSS_ENCODE_H\r
+#define AGNSS_ENCODE_H\r
+\r
+#include "gnss_datatypes.h"\r
+#include "tiot_service_interface.h"\r
+\r
+int32_t AgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime);\r
+void AgnssInject(tiot_handle handle);\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.c b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.c
new file mode 100644 (file)
index 0000000..537608d
--- /dev/null
@@ -0,0 +1,193 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: agnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#include "agnss_sample.h"\r
+#include <stdio.h>\r
+#include "securec.h"\r
+#include "tiot_service_interface.h"\r
+#include "pm_definition.h"\r
+#include "gnss_datatypes.h"\r
+#include "agnss_encode.h"\r
+\r
+#define AGNSS_FIXMODEALL_NMEADEF_SAMPLE            0\r
+\r
+#ifndef ARRAY_SIZE\r
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\r
+#endif\r
+\r
+#define MSG_TYPE_BINRY              0\r
+#define MSG_TYPE_ASCII              1\r
+#define LISTEN_DATA_MAX_LINES       1000\r
+#define REPORT_MAX_BYTES            10000\r
+\r
+static FILE* g_gnssLogFp = NULL;\r
+static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 };\r
+\r
+typedef int32_t (*GnssCfgFunc)(tiot_handle handle);\r
+\r
+typedef struct {\r
+    uint16_t    sampleId;\r
+    GnssCfgFunc cfgHandle;\r
+} GnssSamplesCfgTable;\r
+\r
+static int32_t QryVersion(tiot_handle handle)\r
+{\r
+    const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};\r
+    // 查询版本号\r
+    int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion));\r
+    if (ret < 0) {\r
+        printf("error: QryVersion error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+// 注入AGNSS,使用默认配置启动\r
+int32_t InjectAgnss(tiot_handle handle)\r
+{\r
+    const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03};\r
+\r
+    // 配置log级别:info级别。\r
+    int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo));\r
+    if (ret < 0) {\r
+        printf("error: cfgLogLevelInfo error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 注入UTC时间, 注入Agnss辅助数据前必须先注入参考时间\r
+    GnssUtcTime utcTime = {2024, 3, 22, 10, 0, 0, 0, 1}; // 需要用当前的UTC时间替换\r
+    ret = AgnssInjectUtcTime(handle, &utcTime);\r
+    if (ret == 0) {\r
+        printf("error: AgnssInjectUtcTime failed!\n");\r
+        return 0;\r
+    }\r
+    printf("AgnssInjectUtcTime success!\n");\r
+\r
+    // AGNSS注入\r
+    // 注意,默认AGNSS文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换\r
+    AgnssInject(handle);\r
+\r
+    return 1;\r
+}\r
+\r
+static const GnssSamplesCfgTable g_gnssSamplesCfg[] = {\r
+    {AGNSS_FIXMODEALL_NMEADEF_SAMPLE, InjectAgnss},\r
+};\r
+\r
+static int32_t StartGnss(tiot_handle handle)\r
+{\r
+    const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,\r
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 启动GNSS\r
+    int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd));\r
+    if (ret < 0) {\r
+        printf("error: start gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("start gnss\n");\r
+    return 1;\r
+}\r
+\r
+static int32_t StopGnss(tiot_handle handle)\r
+{\r
+    const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 停止GNSS\r
+    int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd));\r
+    if (ret < 0) {\r
+        printf("error: stop gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("stop gnss\n");\r
+    return 1;\r
+}\r
+\r
+static void ListenGnssData(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    // 写日志\r
+    for (;;) {  // 写日志条件\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, 1000);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_gnssServiceBuff;\r
+            if (type[0] == MSG_TYPE_ASCII) {\r
+                g_gnssServiceBuff[ret] = '\0';\r
+                printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+                fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= LISTEN_DATA_MAX_LINES) {\r
+            printf("cnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+void AgnssExecuteSamples(void)\r
+{\r
+    uapi_pm_add_sleep_veto(PM_ID_SYS);\r
+    printf("enter gnss samples\n");\r
+    // Step1: init\r
+    int32_t ret = tiot_service_init();\r
+    if (ret != 0) {\r
+        printf("tiot service init fail\n");\r
+    }\r
+\r
+    // 打开日志文件\r
+    g_gnssLogFp = fopen("/user/gnss.log", "w");\r
+    if (g_gnssLogFp == NULL) {\r
+        printf("error: open log file error\n");\r
+        return;\r
+    }\r
+    printf("before open tiot service\n");\r
+\r
+    // Step2: power on gnss\r
+    tiot_handle handle = tiot_service_open("gn71", NULL);\r
+    if (handle == 0) {\r
+        printf("open tiot service fail\n");\r
+        return;\r
+    }\r
+    printf("open tiot service success\n");\r
+\r
+    int32_t cfgRet;\r
+    // ---- loop ----------\r
+    for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) {\r
+        cfgRet = 0;\r
+        if (g_gnssSamplesCfg[i].sampleId == i) {\r
+            // Step3: config gnss\r
+            if (g_gnssSamplesCfg[i].cfgHandle != NULL) {\r
+                cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle);\r
+            }\r
+            if (cfgRet == 0) {\r
+                continue;\r
+            }\r
+            printf("cfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId);\r
+            QryVersion(handle);\r
+\r
+            // Step4: start gnss\r
+            if (StartGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+            // Step5: listening gnss data\r
+            ListenGnssData(handle);\r
+            // Step6: stop gnss\r
+            if (StopGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+        }\r
+    }\r
+    // ---------------------\r
+    // Step7: power off gnss\r
+    tiot_service_close(handle);\r
+    // 关日志文件\r
+    fclose(g_gnssLogFp);\r
+    g_gnssLogFp = NULL;\r
+    // Step8: deinit\r
+    tiot_service_deinit();\r
+    uapi_pm_remove_sleep_veto(PM_ID_SYS);\r
+    printf("finish gnss samples\n");\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.h b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.h
new file mode 100644 (file)
index 0000000..8c8823b
--- /dev/null
@@ -0,0 +1,12 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: agnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef AGNSS_SAMPLE_H\r
+#define AGNSS_SAMPLE_H\r
+\r
+void AgnssExecuteSamples(void);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/gnss_datatypes.h b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/gnss_datatypes.h
new file mode 100644 (file)
index 0000000..97607f9
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: gnss datatypes\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef GNSS_DATATYPES_H\r
+#define GNSS_DATATYPES_H\r
+\r
+#include <stdint.h>\r
+\r
+#define MSG_CONTENT_IDX             2\r
+\r
+// 消息类型\r
+typedef enum {\r
+    CMD_AGNSS_INJECT_REF_LOC = 0x0302,         // 位置预测注入\r
+    CMD_AGNSS_INJECT_NAV = 0x0303,             // 星历数据注入\r
+    CMD_AGNSS_INJECT_IONO = 0x0304,            // 电离层参数注入\r
+    CMD_AGNSS_INJECT_UTC = 0x0305,             // UTC时间注入\r
+    CMD_AGNSS_INJECT_RTI = 0x0306,             // 完好性信息注入\r
+    CMD_AGNSS_INJECT_GANSS_ADDL_IONO = 0x0308, // 非GPS电离层参数注入\r
+    CMD_AGNSS_INJECT_GANSS_NAV = 0x0309,       // 非GPS星历数据注入\r
+    CMD_AGNSS_INJECT_GANSS_RTI = 0x030A,       // 非GPS完好性信息注入\r
+    CMD_AGNSS_INJECT_GANSS_AUXI = 0x030C,      // 频点对应关系注入,GLONASS\r
+    CMD_XGNSS_INJECT_UTC_TIME = 0x0404,        // 最开始注入的UTC时间\r
+    CMD_BUTT,\r
+} GnssCmdType;\r
+\r
+typedef enum {\r
+    AGNSS_GPS_INJECT_EPH = 0x0002,\r
+    AGNSS_GPS_INJECT_UTC = 0x0003,\r
+    AGNSS_GPS_INJECT_ION = 0x0004,\r
+    AGNSS_GPS_INJECT_RTI = 0x0005,\r
+    AGNSS_GLO_INJECT_EPH = 0x0022,\r
+    AGNSS_GLO_INJECT_RTI = 0x0025,\r
+    AGNSS_GLO_INJECT_AUX = 0x0026,\r
+    AGNSS_BDS_INJECT_EPH = 0x0042,\r
+    AGNSS_BDS_INJECT_ION = 0x0044,\r
+    AGNSS_BDS_INJECT_RTI = 0x0045,\r
+    AGNSS_GAL_INJECT_EPH = 0x0062,\r
+    AGNSS_GAL_INJECT_RTI = 0x0065\r
+} AgnssDataType;\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+    uint16_t  cmd;          // 消息类型\r
+    uint16_t  checkSum;     // 校验和,只计算实际数据部分,不包含头\r
+    uint16_t  sequence;     // 序列号,host下发\r
+    uint16_t  dataLength;   // 数据长度,实际数据的长度,不包含头\r
+    uint8_t   data[0];\r
+} GnssMsg;\r
+\r
+typedef struct {\r
+    uint16_t year;          // YYYY\r
+    uint8_t  month;         // MM, 1~12\r
+    uint8_t  day;           // DD, 1~31\r
+    uint8_t  hour;          // hh, 0~23\r
+    uint8_t  minute;        // mm, 0~59\r
+    uint8_t  second;        // ss, 0~59\r
+    uint16_t ms;            // ms, 0~999\r
+    uint8_t  valid;         // 0: invalid, 1: valid\r
+} GnssUtcTime;\r
+\r
+typedef struct {\r
+    uint16_t dataType;\r
+    uint16_t len;\r
+    uint8_t data[0];\r
+} AgnssDataHeader;\r
+\r
+typedef struct {\r
+    uint8_t checkSum;\r
+} AgnssDataTail;\r
+\r
+#pragma pack()\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b82dac6
--- /dev/null
@@ -0,0 +1,40 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "gnss_sample")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/gnss_sample.c
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+CONFIG_GNSS_SAMPLE
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+)
+
+set(WHOLE_LINK
+true
+)
+
+set(BUILD_AS_OBJ
+false
+)
+
+set(MAIN_COMPONENT
+false
+)
+build_component()
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.c b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.c
new file mode 100644 (file)
index 0000000..18e1d8a
--- /dev/null
@@ -0,0 +1,228 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2024. All rights reserved.\r
+ * Description: gnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#include "gnss_sample.h"\r
+#include <stdio.h>\r
+#include "securec.h"\r
+#include "tiot_service_interface.h"\r
+#include "pm_definition.h"\r
+\r
+#define COLDSTART_FIXMODEGPS_NMEAALL_SAMPLE        0\r
+#define AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE        1\r
+\r
+#ifndef ARRAY_SIZE\r
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\r
+#endif\r
+#define MSG_CONTENT_IDX             2\r
+#define MSG_TYPE_BINRY              0\r
+#define MSG_TYPE_ASCII              1\r
+#define LISTEN_DATA_MAX_LINES       1000\r
+#define REPORT_MAX_BYTES            10000\r
+#define LISTEN_TIME_THR             1000\r
+\r
+static FILE* g_gnssLogFp = NULL;\r
+static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 };\r
+\r
+typedef int32_t (*GnssCfgFunc)(tiot_handle handle);\r
+\r
+typedef struct {\r
+    uint16_t    sampleId;\r
+    GnssCfgFunc cfgHandle;\r
+} GnssSamplesCfgTable;\r
+\r
+int32_t CfgColdStartFixModeGpsNmeaAll(tiot_handle handle)\r
+{\r
+    const uint8_t cfgColdStartCmd[] = {0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01};\r
+    const uint8_t cfgFixModeGpsCmd[] = {0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,\r
+        0x00, 0x00, 0x00};\r
+    const uint8_t cfgNmeaAllCmd[] = {0x03, 0x00, 0x04, 0x01, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, 0xff,\r
+        0x00};\r
+    // 配置启动模式:冷启动模式。\r
+    int32_t ret = tiot_service_write(handle, cfgColdStartCmd, sizeof(cfgColdStartCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgColdStartCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 配置使能的GNSS星座:GPS。\r
+    ret = tiot_service_write(handle, cfgFixModeGpsCmd, sizeof(cfgFixModeGpsCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgFixModeGpsCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 配置上报NMEA类型:PNT/ZDA/VTG/RMC/GSV/GSA/GLL/GGA。\r
+    ret = tiot_service_write(handle, cfgNmeaAllCmd, sizeof(cfgNmeaAllCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgNmeaAllCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+// 如果有历史信息,自动模式启动会切换到热启动模式,如果无历史信息,则自动模式启动仍然为冷启动\r
+int32_t CfgAutoStartFixModeAllNmeaDefault(tiot_handle handle)\r
+{\r
+    const uint8_t cfgFixModeAllCmd[] = {0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x1f,\r
+        0x00, 0x00, 0x00};\r
+    const uint8_t cfgAutoStartCmd[] = {0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00};\r
+    const uint8_t cfgNmeaDefaultCmd[] = {0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, 0x11,\r
+        0x00};\r
+\r
+    // 配置启动模式:自动模式。\r
+    int32_t ret = tiot_service_write(handle, cfgAutoStartCmd, sizeof(cfgAutoStartCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgAutoStartCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 配置使能的GNSS星座:QZSS/GAL/BDS/GLO/GPS。\r
+    ret = tiot_service_write(handle, cfgFixModeAllCmd, sizeof(cfgFixModeAllCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgFixModeAllCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 配置上报NMEA类型:RMC/GGA。\r
+    ret = tiot_service_write(handle, cfgNmeaDefaultCmd, sizeof(cfgNmeaDefaultCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgNmeaDefaultCmd error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+static int32_t QryVersion(tiot_handle handle)\r
+{\r
+    const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};\r
+    // 查询版本号\r
+    int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion));\r
+    if (ret < 0) {\r
+        printf("\nerror: QryVersion error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+static const GnssSamplesCfgTable g_gnssSamplesCfg[] = {\r
+    {COLDSTART_FIXMODEGPS_NMEAALL_SAMPLE,        CfgColdStartFixModeGpsNmeaAll},\r
+    {AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE,        CfgAutoStartFixModeAllNmeaDefault}\r
+};\r
+\r
+static int32_t StartGnss(tiot_handle handle)\r
+{\r
+    const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,\r
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 启动GNSS\r
+    int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: start gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("\nstart gnss\n");\r
+    return 1;\r
+}\r
+\r
+static int32_t StopGnss(tiot_handle handle)\r
+{\r
+    const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 停止GNSS\r
+    int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: stop gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("\nstop gnss\n");\r
+    return 1;\r
+}\r
+\r
+static void ListenGnssData(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    // 写日志\r
+    for (;;) {  // 写日志条件\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_gnssServiceBuff;\r
+            if (type[0] == MSG_TYPE_ASCII) {\r
+                g_gnssServiceBuff[ret] = '\0';\r
+                printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+                fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= LISTEN_DATA_MAX_LINES) {\r
+            printf("\ncnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+void GnssExecuteSamples(void)\r
+{\r
+    uapi_pm_add_sleep_veto(PM_ID_SYS);\r
+    printf("\nenter gnss samples\n");\r
+    // Step1: init\r
+    int32_t ret = tiot_service_init();\r
+    if (ret != 0) {\r
+        printf("\ntiot service init fail\n");\r
+    }\r
+\r
+    // 打开日志文件\r
+    g_gnssLogFp = fopen("/user/gnss.log", "w");\r
+    if (g_gnssLogFp == NULL) {\r
+        printf("\nerror: open log file error\n");\r
+        return;\r
+    }\r
+    printf("\nbefore open tiot service\n");\r
+\r
+    // Step2: power on gnss\r
+    tiot_handle handle = tiot_service_open("gn71", NULL);\r
+    if (handle == 0) {\r
+        printf("\nopen tiot service fail\n");\r
+        return;\r
+    }\r
+    printf("\nopen tiot service success\n");\r
+\r
+    int32_t cfgRet;\r
+    // ---- loop ----------\r
+    for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) {\r
+        cfgRet = 0;\r
+        if (g_gnssSamplesCfg[i].sampleId == i) {\r
+            // Step3: config gnss\r
+            if (g_gnssSamplesCfg[i].cfgHandle != NULL) {\r
+                cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle);\r
+            }\r
+            if (cfgRet == 0) {\r
+                continue;\r
+            }\r
+            printf("\ncfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId);\r
+            QryVersion(handle);\r
+\r
+            // Step4: start gnss\r
+            if (StartGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+            // Step5: listening gnss data\r
+            ListenGnssData(handle);\r
+            // Step6: stop gnss\r
+            if (StopGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+        }\r
+    }\r
+    // ---------------------\r
+    // Step7: power off gnss\r
+    tiot_service_close(handle);\r
+    // 关日志文件\r
+    fclose(g_gnssLogFp);\r
+    g_gnssLogFp = NULL;\r
+    // Step8: deinit\r
+    tiot_service_deinit();\r
+    uapi_pm_remove_sleep_veto(PM_ID_SYS);\r
+    printf("\nfinish gnss samples\n");\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.h b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.h
new file mode 100644 (file)
index 0000000..9d3d275
--- /dev/null
@@ -0,0 +1,12 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2024. All rights reserved.\r
+ * Description: gnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef GNSS_SAMPLE_H\r
+#define GNSS_SAMPLE_H\r
+\r
+void GnssExecuteSamples(void);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f132ba6
--- /dev/null
@@ -0,0 +1,41 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "pgnss_sample")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/pgnss_sample.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/pgnss_encode.c
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+CONFIG_PGNSS_SAMPLE
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+)
+
+set(WHOLE_LINK
+true
+)
+
+set(BUILD_AS_OBJ
+false
+)
+
+set(MAIN_COMPONENT
+false
+)
+build_component()
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/gnss_datatypes.h b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/gnss_datatypes.h
new file mode 100644 (file)
index 0000000..4d4a9a3
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: gnss datatypes\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef GNSS_DATATYPES_H\r
+#define GNSS_DATATYPES_H\r
+\r
+#include <stdint.h>\r
+\r
+#define MSG_CONTENT_IDX             2\r
+#define LISTEN_TIME_THR             1000\r
+#define REPORT_MAX_BYTES            10000\r
+\r
+// 消息类型\r
+typedef enum {\r
+    CMD_INJECT_HIS_INFO = 0x0101,               // 历史信息注入\r
+    CMD_PGNSS_INJECT_REF_GPS_TIME = 0x0201,     // GPS时间注入\r
+    CMD_PGNSS_INJECT_REF_LOC = 0x0202,          // 参考位置注入\r
+    CMD_PGNSS_INJECT_EPH_GPS = 0x0203,          // GPS星历注入\r
+    CMD_PGNSS_INJECT_EPH_GANSS = 0x0204,        // 非GPS星历注入\r
+    CMD_PGNSS_INJECT_UTC_GPS = 0x0205,          // GPS UTC注入\r
+    CMD_PGNSS_INJECT_RTI_GPS = 0x0206,          // GPS完好性信息注入\r
+    CMD_PGNSS_INJECT_RTI_GANSS = 0x0207,        // 非GPS完好性信息注入\r
+    CMD_PGNSS_INJECT_ION_GPS = 0x0208,          // GPS电离层参数注入\r
+    CMD_PGNSS_INJECT_AUX_GANSS = 0x0209,        // 非GPS频点转换关系信息注入\r
+    CMD_XGNSS_INJECT_UTC_TIME = 0x0404,         // 最开始注入的UTC时间\r
+    CMD_BUTT,\r
+} GnssCmdType;\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+    uint16_t  cmd;          // 消息类型\r
+    uint16_t  checkSum;     // 校验和,只计算实际数据部分,不包含头\r
+    uint16_t  sequence;     // 序列号,host下发\r
+    uint16_t  dataLength;   // 数据长度,实际数据的长度,不包含头\r
+    uint8_t   data[0];\r
+} GnssMsg;\r
+\r
+typedef struct {\r
+    uint16_t year;          // YYYY\r
+    uint8_t  month;         // MM, 1~12\r
+    uint8_t  day;           // DD, 1~31\r
+    uint8_t  hour;          // hh, 0~23\r
+    uint8_t  minute;        // mm, 0~59\r
+    uint8_t  second;        // ss, 0~59\r
+    uint16_t ms;            // ms, 0~999\r
+    uint8_t  valid;         // 0: invalid, 1: valid\r
+} GnssUtcTime;\r
+\r
+typedef struct {\r
+    uint32_t time;          // eph reference time\r
+    uint16_t cmd;           // cmd type to injected eph\r
+    uint32_t len;           // actual length of injected eph\r
+} EphHeadInfo;\r
+\r
+typedef struct {\r
+    uint16_t cmd;           // cmd type to injected other assist info\r
+    uint32_t len;           // actual length of injected other assist info\r
+} OtherAssistHeadInfo;\r
+\r
+#pragma pack()\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.c b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.c
new file mode 100644 (file)
index 0000000..a4815e6
--- /dev/null
@@ -0,0 +1,589 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pgnss encode\r
+ * Author:\r
+ * Create:\r
+ */\r
+#include "pgnss_encode.h"\r
+#include <stdio.h>\r
+#include <dirent.h>\r
+#include <string.h>\r
+#include "securec.h"\r
+#include "tiot_service_interface.h"\r
+#include "gnss_datatypes.h"\r
+\r
+#define GNSS_ENCODE_BUFF_MAX_LEN 9300\r
+#define FILE_PATH_LEN            1024\r
+#define GLO_EPH_VALID_TIME       900\r
+#define OTHER_EPH_VALID_TIME     7200\r
+#define ONE_CENTURY_YEARS        100\r
+#define FOUR_CENTURY_YEARS       400\r
+#define LEAP_YEAR_LENGTH         4\r
+#define UNIX_TIME_START_YEAR     1970    // start year of unix time\r
+#define TIME_UNIT                1000\r
+#define SECONDS_PER_MIN          (60)\r
+#define SECONDS_PER_HOUR         (60 * SECONDS_PER_MIN)\r
+#define SECONDS_PER_DAY          (24 * SECONDS_PER_HOUR)\r
+#define SECONDS_PER_NORMAL_YEAR  (365 * SECONDS_PER_DAY)\r
+#define NON_GLO_GNSS_TYPES       4\r
+#define GLO_EPH_NUM_ONE_FILE     8\r
+#define OTHER_ASSIST_TYPES       7\r
+#define INJECT_SLEEP_MS_TIME     500\r
+#define PGNSS_FILE_MAX_SIZE      1024000\r
+\r
+/** days per month on normal and leap year */\r
+int32_t g_normMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+int32_t g_leapMonthDays[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+// 监听消息\r
+static uint8_t g_ackBuff[REPORT_MAX_BYTES] = { 0 };\r
+\r
+/* 获取begin和end年份之间的闰年数 */\r
+int32_t GetLeapYearNum(uint16_t begin, uint16_t end)\r
+{\r
+    if (end <= begin || end < 1) {\r
+        return 0;\r
+    }\r
+    int32_t numPer400Year = (end - 1) / FOUR_CENTURY_YEARS - begin / FOUR_CENTURY_YEARS;\r
+    int32_t numPer100Year = (end - 1) / ONE_CENTURY_YEARS - begin / ONE_CENTURY_YEARS;\r
+    int32_t numPer4Year = (end - 1) / LEAP_YEAR_LENGTH - begin / LEAP_YEAR_LENGTH;\r
+    return (numPer400Year + numPer4Year - numPer100Year);\r
+}\r
+\r
+/* 闰年判断 */\r
+int32_t CheckIfLeapYear(uint16_t year)\r
+{\r
+    if ((year % ONE_CENTURY_YEARS) == 0) {\r
+        if ((year % FOUR_CENTURY_YEARS) == 0) {\r
+            return 1;\r
+        }\r
+    } else {\r
+        if ((year % LEAP_YEAR_LENGTH) == 0) {\r
+            return 1;\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+/* 将日历时(年月日时分秒) 转换为 unix时间(1970年1月1日起的时间秒数) */\r
+int32_t Utc2UnixTime(GnssUtcTime utcTime, uint32_t *unixTime)\r
+{\r
+    if (unixTime == NULL) {\r
+        printf("\nerror: [Utc2UnixTime] null pointer!\n");\r
+        return 0;\r
+    }\r
+\r
+    if (utcTime.month > 12 || utcTime.valid == 0) {\r
+        printf("\nerror: [Utc2UnixTime] utcTime invalid!\n");\r
+        return 0;\r
+    }\r
+\r
+    // 判断是否为闰年\r
+    int32_t *monthDays = (CheckIfLeapYear(utcTime.year) == 1) ? g_leapMonthDays : g_normMonthDays;\r
+\r
+    // 计算从1970.01.01开始的unix 秒数\r
+    uint32_t timestamp = 0;\r
+    timestamp += (uint32_t)(utcTime.year - UNIX_TIME_START_YEAR) * SECONDS_PER_NORMAL_YEAR;\r
+    timestamp += (uint32_t)GetLeapYearNum(UNIX_TIME_START_YEAR, utcTime.year) * SECONDS_PER_DAY;\r
+\r
+    for (int32_t i = 1; i < utcTime.month; i++) {\r
+        timestamp += (uint32_t)monthDays[i - 1] * SECONDS_PER_DAY;\r
+    }\r
+\r
+    timestamp += (uint32_t)(utcTime.day - 1) * SECONDS_PER_DAY;\r
+    timestamp += (uint32_t)utcTime.hour * SECONDS_PER_HOUR;\r
+    timestamp += (uint32_t)utcTime.minute * SECONDS_PER_MIN;\r
+    uint32_t timestampSec = (uint32_t)(utcTime.second + utcTime.ms / TIME_UNIT);\r
+\r
+    *unixTime = timestamp + timestampSec;\r
+    return 1;\r
+}\r
+\r
+/* 计算命令内容校准和 */\r
+static uint16_t CalcChecksum(uint8_t *buff, uint16_t len)\r
+{\r
+    uint16_t checksum = 0;\r
+    uint16_t i = 0;\r
+    while (i++ < len) {\r
+        checksum += *buff;\r
+        buff++;\r
+    }\r
+    return checksum;\r
+}\r
+\r
+int32_t PgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime, uint32_t* ts)\r
+{\r
+    uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN);\r
+    if (buff == NULL) {\r
+        printf("\nerror: malloc failed in PgnssINjectUtcTime\n");\r
+        return 0;\r
+    }\r
+    memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN);\r
+\r
+    GnssMsg *hdr = (GnssMsg *)buff;\r
+    hdr->cmd = 0x0404;\r
+    hdr->sequence = 0;\r
+    errno_t copyRet = memcpy_s(hdr->data, (GNSS_ENCODE_BUFF_MAX_LEN - sizeof(GnssMsg)), utcTime, sizeof(GnssUtcTime));\r
+    if (copyRet != EOK) {\r
+        printf("\nmemcpy UtcTime failed! Errno is %d\n", copyRet);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+    hdr->dataLength = sizeof(GnssUtcTime);\r
+    hdr->checkSum = CalcChecksum(hdr->data, hdr->dataLength);\r
+    int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + hdr->dataLength));\r
+    if (ret < 0) {\r
+        printf("\nerror: PgnssInjectUtcTime error: %d\n", ret);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+    if (Utc2UnixTime((*utcTime), ts) == 0) {\r
+        printf("\nerror: Utc2UnixTime error\n");\r
+        free(buff);\r
+        return 0;\r
+    }\r
+\r
+    free(buff);\r
+    return 1;\r
+}\r
+\r
+static uint16_t FillGnssMessageData(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)\r
+{\r
+    errno_t ret = memcpy_s(outBuff, outLen, inBuff, inLen);\r
+    if (ret != EOK) {\r
+        printf("memcpy XgnssData failed! Errno is %d", ret);\r
+        return 0;\r
+    }\r
+\r
+    return inLen;\r
+}\r
+\r
+static int32_t EncodeGnssMsg(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)\r
+{\r
+    uint16_t len = FillGnssMessageData(inBuff, inLen, outBuff, outLen);\r
+    if (len > 0) {\r
+        return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+static void ListenAck(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    for (;;) {\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_ackBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_ackBuff;\r
+            // 二进制消息类型\r
+            if (type[0] == 0) {\r
+                g_ackBuff[ret] = '\0';\r
+                printf("%s\n", (char *)&g_ackBuff[MSG_CONTENT_IDX]);\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= 1) {\r
+            printf("\ncnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+static int32_t EncodeAndInjectCmd(tiot_handle handle, GnssCmdType cmdType, uint8_t* inBuff, uint32_t inLen)\r
+{\r
+    // 获取GNSS业务消息头\r
+    int32_t len = 0;\r
+    uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN);\r
+    if (buff == NULL) {\r
+        printf("\nerror: malloc failed in EncodeAndInjectCmd\n");\r
+        return 0;\r
+    }\r
+    memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN);\r
+\r
+    GnssMsg *gnssHdr = (GnssMsg *)buff;\r
+    len += sizeof(GnssMsg);\r
+\r
+    gnssHdr->sequence = 0;\r
+\r
+    int32_t retLen = EncodeGnssMsg(inBuff, inLen, buff + len, (GNSS_ENCODE_BUFF_MAX_LEN - len));\r
+    if (retLen != 1) {\r
+        printf("\nerror: Encode Cmd failed: %d\n", cmdType);\r
+        free(buff);\r
+        return retLen;\r
+    }\r
+    gnssHdr->cmd = cmdType;\r
+    gnssHdr->dataLength = inLen;\r
+    gnssHdr->checkSum = CalcChecksum(gnssHdr->data, gnssHdr->dataLength);\r
+    int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + gnssHdr->dataLength));\r
+    if (ret < 0) {\r
+        printf("\nerror: Inject Cmd failed: %d\n", cmdType);\r
+        free(buff);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    printf("\nInject Cmd SUCCESS: %x\n", cmdType);\r
+    free(buff);\r
+    return 1;\r
+}\r
+\r
+void PgnssSendFileContent(tiot_handle handle, const char *fileName, GnssCmdType cmdType)\r
+{\r
+    FILE *fp = fopen(fileName, "rb");\r
+    if (fp == NULL) {\r
+        printf("\nerror: open file failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    fseek(fp, 0, SEEK_END);\r
+    int32_t len = ftell(fp);\r
+    fseek(fp, 0, SEEK_SET);\r
+    if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {\r
+        fclose(fp);\r
+        printf("\nerror: get file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    uint8_t *buff = (uint8_t *)malloc(len);\r
+    if (buff == NULL) {\r
+        fclose(fp);\r
+        printf("\nerror: malloc file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    int32_t dataSize = fread(buff, len, 1, fp);\r
+    if (dataSize < 0) {\r
+        fclose(fp);\r
+        printf("\nerror: read file failed: %s\n", fileName);\r
+        free(buff);\r
+        return;\r
+    }\r
+    fclose(fp);\r
+    EncodeAndInjectCmd(handle, cmdType, buff, len);\r
+    free(buff);\r
+}\r
+\r
+int32_t FormatFileName(char *fileName, char *dName)\r
+{\r
+    int32_t ret = snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%s", "/user/xgnss/", dName);\r
+    if (ret <= 0) {\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+int32_t GetEphFileName(int32_t ts, const char *prefix, char *fileName)\r
+{\r
+    int32_t interval = (strcmp(prefix, "GLO") == 0) ? GLO_EPH_VALID_TIME : OTHER_EPH_VALID_TIME;\r
+    DIR *dir = opendir("/user/xgnss/");\r
+    if (dir == NULL) {\r
+        printf("Failed to open /user/xgnss directory.\n");\r
+        return 0;\r
+    }\r
+    int32_t time, ret;\r
+    struct dirent *entry;\r
+    for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) {\r
+        // 检查文件名\r
+        if (strstr(entry->d_name, ".eph") != NULL) {\r
+            char *p = strrchr(entry->d_name, '_');\r
+            if (p != NULL) {\r
+                char *q = strstr(entry->d_name, prefix);\r
+                if (q != NULL) {\r
+                    time = atoi(p + 1);\r
+                    if (abs(time - ts) <= interval) {\r
+                        ret = FormatFileName(fileName, entry->d_name);\r
+                        closedir(dir);\r
+                        return ret;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+    closedir(dir);\r
+    return 0;\r
+}\r
+\r
+void PgnssSendEphFile(tiot_handle handle, const char *prefix, GnssCmdType cmdType, uint32_t ts)\r
+{\r
+    char fileName[FILE_PATH_LEN] = {0};\r
+    int32_t ret = GetEphFileName(ts, prefix, fileName);\r
+    if (ret == 0) {\r
+        printf("\nerror: GetEphFileName failed\n");\r
+        return;\r
+    }\r
+    printf("\nGetEphFileName success\n");\r
+    PgnssSendFileContent(handle, fileName, cmdType);\r
+}\r
+\r
+void PgnssInjectAllEph(tiot_handle handle, uint32_t ts)\r
+{\r
+    PgnssSendEphFile(handle, "GPS", CMD_PGNSS_INJECT_EPH_GPS, ts);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GPS eph success\n");\r
+    PgnssSendEphFile(handle, "GLO", CMD_PGNSS_INJECT_EPH_GANSS, ts);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GLO eph success\n");\r
+    PgnssSendEphFile(handle, "BDS", CMD_PGNSS_INJECT_EPH_GANSS, ts);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send BDS eph success\n");\r
+    PgnssSendEphFile(handle, "GAL", CMD_PGNSS_INJECT_EPH_GANSS, ts);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GAL eph success\n");\r
+    PgnssSendEphFile(handle, "QZS", CMD_PGNSS_INJECT_EPH_GANSS, ts);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send QZS eph success\n");\r
+}\r
+\r
+void PgnssInjectOtherAssist(tiot_handle handle)\r
+{\r
+    PgnssSendFileContent(handle, "/user/xgnss/GPS_UTC.dat", CMD_PGNSS_INJECT_UTC_GPS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GPS_UTC success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/GPS_RTI.dat", CMD_PGNSS_INJECT_RTI_GPS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GPS_RTI success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/GPS_ION.dat", CMD_PGNSS_INJECT_ION_GPS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GPS_ION success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/GLO_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GLO_RTI success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/GLO_AUX.dat", CMD_PGNSS_INJECT_AUX_GANSS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GLO_AUX success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/BDS_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send BDS_RTI success\n");\r
+    PgnssSendFileContent(handle, "/user/xgnss/GAL_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS);\r
+    osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    printf("send GAL_RTI success\n");\r
+}\r
+\r
+void PgnssInject(tiot_handle handle, uint32_t ts)\r
+{\r
+    // 注入Pgnss辅助数据\r
+    PgnssInjectAllEph(handle, ts);\r
+    PgnssInjectOtherAssist(handle);\r
+}\r
+\r
+\r
+// 以下为使用PGNSS解析数据合并输出接口生成的星历文件进行注入的代码\r
+int32_t GetNonGloEphFileName(int32_t ts, char *fileName)\r
+{\r
+    const char prefix[] = "NonGlo";\r
+    DIR *dir = opendir("/user/xgnss/");\r
+    if (dir == NULL) {\r
+        printf("Failed to open /user/xgnss directory.\n");\r
+        return 0;\r
+    }\r
+    int32_t time, ret;\r
+    int32_t minDist = OTHER_EPH_VALID_TIME;\r
+    int32_t closestTime = 0;\r
+    struct dirent *entry;\r
+    for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) {\r
+        // 检查文件名\r
+        if (strstr(entry->d_name, ".eph") != NULL) {\r
+            char *p = strrchr(entry->d_name, '_');\r
+            if (p != NULL) {\r
+                char *q = strstr(entry->d_name, prefix);\r
+                if (q != NULL) {\r
+                    time = atoi(p + 1);\r
+                    // 查找星历文件时间戳与当前时间相差2小时以内且距离最近的\r
+                    if (abs(time - ts) < minDist) {\r
+                        minDist = abs(time - ts);\r
+                        closestTime = time;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+    if (closestTime != 0) {\r
+        ret = snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%d%s", "/user/xgnss/NonGlo_", closestTime,\r
+            ".eph");\r
+        printf("closest eph fileName:%s\n", fileName);\r
+        closedir(dir);\r
+        return ((ret <= 0) ? 0 : 1);\r
+    }\r
+    closedir(dir);\r
+    return 0;\r
+}\r
+\r
+int32_t GetGloEphFileName(int32_t ts, char *fileName)\r
+{\r
+    const char prefix[] = "GLO";\r
+    DIR *dir = opendir("/user/xgnss/");\r
+    if (dir == NULL) {\r
+        printf("Failed to open /user/xgnss directory.\n");\r
+        return 0;\r
+    }\r
+    int32_t ephTime, ret;\r
+    struct dirent *entry;\r
+    for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) {\r
+        // 检查文件名\r
+        if (strstr(entry->d_name, ".eph") != NULL) {\r
+            char *p = strrchr(entry->d_name, '_');\r
+            if (p != NULL) {\r
+                char *q = strstr(entry->d_name, prefix);\r
+                if (q != NULL) {\r
+                    ephTime = atoi(p + 1);\r
+                    printf("ephTime:%ld, ts:%ld\n", ephTime, ts);\r
+                    // 当前时间大于GLO星历文件时间戳,则需要选取相差2小时以内的星历\r
+                    // 当前时间小于GLO星历文件时间戳,则需要选取相差小于15分钟的星历\r
+                    if (((ts - ephTime) >= 0 && abs(ephTime - ts) < OTHER_EPH_VALID_TIME) ||\r
+                        ((ts - ephTime) <= 0 && abs(ephTime - ts) < GLO_EPH_VALID_TIME)) {\r
+                        ret = FormatFileName(fileName, entry->d_name);\r
+                        printf("glo eph fileName:%s\n", fileName);\r
+                        closedir(dir);\r
+                        return ret;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+    closedir(dir);\r
+    return 0;\r
+}\r
+\r
+void PgnssSendNonGloEph(tiot_handle handle, const char *fileName)\r
+{\r
+    FILE *fp = fopen(fileName, "rb");\r
+    if (fp == NULL) {\r
+        printf("\nerror: open file failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    fseek(fp, 0, SEEK_END);\r
+    int32_t len = ftell(fp);\r
+    fseek(fp, 0, SEEK_SET);\r
+    if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {\r
+        fclose(fp);\r
+        printf("\nerror: get file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    uint8_t *buff = (uint8_t *)malloc(len);\r
+    if (buff == NULL) {\r
+        fclose(fp);\r
+        printf("\nerror: malloc file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    int32_t dataSize = fread(buff, len, 1, fp);\r
+    if (dataSize < 0) {\r
+        fclose(fp);\r
+        printf("\nerror: read file failed: %s\n", fileName);\r
+        free(buff);\r
+        return;\r
+    }\r
+    fclose(fp);\r
+    int32_t fileLen = 0;\r
+    for (int32_t i = 0; i < NON_GLO_GNSS_TYPES && fileLen <= len; i++) {\r
+        EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen);\r
+        EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len);\r
+        fileLen += (ephHdr->len + sizeof(EphHeadInfo));\r
+        osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    }\r
+    free(buff);\r
+}\r
+\r
+void PgnssSendGloEph(tiot_handle handle, const char *fileName, int32_t ts)\r
+{\r
+    FILE *fp = fopen(fileName, "rb");\r
+    if (fp == NULL) {\r
+        printf("\nerror: open file failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    fseek(fp, 0, SEEK_END);\r
+    int32_t len = ftell(fp);\r
+    fseek(fp, 0, SEEK_SET);\r
+    if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {\r
+        fclose(fp);\r
+        printf("\nerror: get file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    uint8_t *buff = (uint8_t *)malloc(len);\r
+    if (buff == NULL) {\r
+        fclose(fp);\r
+        printf("\nerror: malloc file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    int32_t dataSize = fread(buff, len, 1, fp);\r
+    if (dataSize < 0) {\r
+        fclose(fp);\r
+        printf("\nerror: read file failed: %s\n", fileName);\r
+        free(buff);\r
+        return;\r
+    }\r
+    fclose(fp);\r
+    int32_t fileLen = 0;\r
+    for (int32_t i = 0; i < GLO_EPH_NUM_ONE_FILE && fileLen <= len; i++) {\r
+        EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen);\r
+        printf("glo eph, time:%u, ts:%d\n", ephHdr->time, ts);\r
+        if (abs((int32_t)ephHdr->time - ts) < GLO_EPH_VALID_TIME) {\r
+            EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len);\r
+            osal_msleep(INJECT_SLEEP_MS_TIME);\r
+            break;\r
+        }\r
+        fileLen += (ephHdr->len + sizeof(EphHeadInfo));\r
+    }\r
+    free(buff);\r
+}\r
+\r
+void PgnssInjectAllEphLessFiles(tiot_handle handle, uint32_t ts)\r
+{\r
+    char fileName[FILE_PATH_LEN] = {0};\r
+    if (GetNonGloEphFileName(ts, fileName) == 0) {\r
+        printf("\nerror: GetNonGloEphFileName failed\n");\r
+        return;\r
+    }\r
+    PgnssSendNonGloEph(handle, fileName);\r
+    if (GetGloEphFileName(ts, fileName) == 0) {\r
+        printf("\nerror: GetGloEphFileName failed\n");\r
+        return;\r
+    }\r
+    PgnssSendGloEph(handle, fileName, ts);\r
+}\r
+\r
+void PgnssSendOtherAssistInfo(tiot_handle handle, const char *fileName)\r
+{\r
+    FILE *fp = fopen(fileName, "rb");\r
+    if (fp == NULL) {\r
+        printf("\nerror: open file failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    fseek(fp, 0, SEEK_END);\r
+    int32_t len = ftell(fp);\r
+    fseek(fp, 0, SEEK_SET);\r
+    if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {\r
+        fclose(fp);\r
+        printf("\nerror: get file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    uint8_t *buff = (uint8_t *)malloc(len);\r
+    if (buff == NULL) {\r
+        fclose(fp);\r
+        printf("\nerror: malloc file len failed: %s\n", fileName);\r
+        return;\r
+    }\r
+    int32_t dataSize = fread(buff, len, 1, fp);\r
+    if (dataSize < 0) {\r
+        fclose(fp);\r
+        printf("\nerror: read file failed: %s\n", fileName);\r
+        free(buff);\r
+        return;\r
+    }\r
+    fclose(fp);\r
+    int32_t fileLen = 0;\r
+    for (int32_t i = 0; i < OTHER_ASSIST_TYPES && fileLen <= len; i++) {\r
+        OtherAssistHeadInfo *otherHdr = (OtherAssistHeadInfo *)(buff + fileLen);\r
+        EncodeAndInjectCmd(handle, otherHdr->cmd, (buff + fileLen + sizeof(OtherAssistHeadInfo)), otherHdr->len);\r
+        fileLen += (otherHdr->len + sizeof(OtherAssistHeadInfo));\r
+        osal_msleep(INJECT_SLEEP_MS_TIME);\r
+    }\r
+    free(buff);\r
+}\r
+\r
+void PgnssInjectOtherAssistLessFiles(tiot_handle handle)\r
+{\r
+    PgnssSendOtherAssistInfo(handle, "/user/xgnss/AssistInfo.dat");\r
+}\r
+\r
+// 注入PGNSS解析数据合并输出接口生成的星历文件\r
+void PgnssInjectLessFiles(tiot_handle handle, uint32_t ts)\r
+{\r
+    // 注入Pgnss辅助数据\r
+    PgnssInjectAllEphLessFiles(handle, ts);\r
+    PgnssInjectOtherAssistLessFiles(handle);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.h b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.h
new file mode 100644 (file)
index 0000000..a666edc
--- /dev/null
@@ -0,0 +1,16 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pgnss encode\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef PGNSS_ENCODE_H\r
+#define PGNSS_ENCODE_H\r
+\r
+#include "gnss_datatypes.h"\r
+#include "tiot_service_interface.h"\r
+\r
+int32_t PgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime, uint32_t* ts);\r
+void PgnssInject(tiot_handle handle, uint32_t ts);\r
+void PgnssInjectLessFiles(tiot_handle handle, uint32_t ts);\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.c b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.c
new file mode 100644 (file)
index 0000000..21bd335
--- /dev/null
@@ -0,0 +1,223 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pgnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#include "pgnss_sample.h"\r
+#include <stdio.h>\r
+#include "securec.h"\r
+#include "tiot_service_interface.h"\r
+#include "pm_definition.h"\r
+#include "gnss_datatypes.h"\r
+#include "pgnss_encode.h"\r
+\r
+#define PGNSS_FIXMODEALL_NMEADEF_SAMPLE            0\r
+#define PGNSS_LESS_FILES_FIXMODEALL_NMEADEF_SAMPLE 1\r
+\r
+#ifndef ARRAY_SIZE\r
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\r
+#endif\r
+#define MSG_TYPE_BINRY              0\r
+#define MSG_TYPE_ASCII              1\r
+#define LISTEN_DATA_MAX_LINES       1000\r
+\r
+static FILE* g_gnssLogFp = NULL;\r
+static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 };\r
+\r
+typedef int32_t (*GnssCfgFunc)(tiot_handle handle);\r
+\r
+typedef struct {\r
+    uint16_t    sampleId;\r
+    GnssCfgFunc cfgHandle;\r
+} GnssSamplesCfgTable;\r
+\r
+static int32_t QryVersion(tiot_handle handle)\r
+{\r
+    const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};\r
+    // 查询版本号\r
+    int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion));\r
+    if (ret < 0) {\r
+        printf("\nerror: QryVersion error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+// 注入PGNSS,使用默认配置启动\r
+int32_t InjectPgnssCfgAutoStartFixModeAndNmeaDefault(tiot_handle handle)\r
+{\r
+    const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03};\r
+\r
+    // 配置log级别:info级别。\r
+    int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgLogLevelInfo error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 注入UTC时间, 注入Pgnss辅助数据前必须先注入参考时间\r
+    GnssUtcTime utcTime = {2024, 2, 26, 6, 0, 0, 0, 1}; // 需要用当前的UTC时间替换\r
+    uint32_t ts = 0;\r
+    ret = PgnssInjectUtcTime(handle, &utcTime, &ts);\r
+    if (ret == 0) {\r
+        printf("\nerror: PgnssInjectUtcTime failed!\n");\r
+        return 0;\r
+    }\r
+    printf("\nPgnssInjectUtcTime success!\n");\r
+\r
+    // PGNSS注入\r
+    // 注意,默认PGNSS星历文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换\r
+    PgnssInject(handle, ts);\r
+\r
+    return 1;\r
+}\r
+\r
+// 注入PGNSS,使用默认配置启动\r
+int32_t InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault(tiot_handle handle)\r
+{\r
+    const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03};\r
+\r
+    // 配置log级别:info级别。\r
+    int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo));\r
+    if (ret < 0) {\r
+        printf("\nerror: cfgLogLevelInfo error: %d\n", ret);\r
+        return 0;\r
+    }\r
+\r
+    // 注入UTC时间, 注入Pgnss辅助数据前必须先注入参考时间\r
+    GnssUtcTime utcTime = {2024, 3, 14, 12, 0, 0, 0, 1}; // 需要用当前的UTC时间替换\r
+    uint32_t ts = 0;\r
+    ret = PgnssInjectUtcTime(handle, &utcTime, &ts);\r
+    if (ret == 0) {\r
+        printf("\nerror: PgnssInjectUtcTime failed!\n");\r
+        return 0;\r
+    }\r
+    printf("\nPgnssInjectUtcTime success!\n");\r
+\r
+    // PGNSS注入\r
+    // 注意,默认PGNSS星历文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换\r
+    PgnssInjectLessFiles(handle, ts);\r
+\r
+    return 1;\r
+}\r
+\r
+static const GnssSamplesCfgTable g_gnssSamplesCfg[] = {\r
+    {PGNSS_FIXMODEALL_NMEADEF_SAMPLE,            InjectPgnssCfgAutoStartFixModeAndNmeaDefault},\r
+    {PGNSS_LESS_FILES_FIXMODEALL_NMEADEF_SAMPLE, InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault}\r
+};\r
+\r
+static int32_t StartGnss(tiot_handle handle)\r
+{\r
+    const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,\r
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 启动GNSS\r
+    int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: start gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("\nstart gnss\n");\r
+    return 1;\r
+}\r
+\r
+static int32_t StopGnss(tiot_handle handle)\r
+{\r
+    const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 停止GNSS\r
+    int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd));\r
+    if (ret < 0) {\r
+        printf("\nerror: stop gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    printf("\nstop gnss\n");\r
+    return 1;\r
+}\r
+\r
+static void ListenGnssData(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    // 写日志\r
+    for (;;) {  // 写日志条件\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_gnssServiceBuff;\r
+            if (type[0] == MSG_TYPE_ASCII) {\r
+                g_gnssServiceBuff[ret] = '\0';\r
+                printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+                fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= LISTEN_DATA_MAX_LINES) {\r
+            printf("\ncnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+void PgnssExecuteSamples(void)\r
+{\r
+    uapi_pm_add_sleep_veto(PM_ID_SYS);\r
+    printf("\nenter gnss samples\n");\r
+    // Step1: init\r
+    int32_t ret = tiot_service_init();\r
+    if (ret != 0) {\r
+        printf("\ntiot service init fail\n");\r
+    }\r
+\r
+    // 打开日志文件\r
+    g_gnssLogFp = fopen("/user/gnss.log", "w");\r
+    if (g_gnssLogFp == NULL) {\r
+        printf("\nerror: open log file error\n");\r
+        return;\r
+    }\r
+    printf("\nbefore open tiot service\n");\r
+\r
+    // Step2: power on gnss\r
+    tiot_handle handle = tiot_service_open("gn71", NULL);\r
+    if (handle == 0) {\r
+        printf("\nopen tiot service fail\n");\r
+        return;\r
+    }\r
+    printf("\nopen tiot service success\n");\r
+\r
+    int32_t cfgRet;\r
+    // ---- loop ----------\r
+    for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) {\r
+        cfgRet = 0;\r
+        if (g_gnssSamplesCfg[i].sampleId == i) {\r
+            // Step3: config gnss\r
+            if (g_gnssSamplesCfg[i].cfgHandle != NULL) {\r
+                cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle);\r
+            }\r
+            if (cfgRet == 0) {\r
+                continue;\r
+            }\r
+            printf("\ncfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId);\r
+            QryVersion(handle);\r
+\r
+            // Step4: start gnss\r
+            if (StartGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+            // Step5: listening gnss data\r
+            ListenGnssData(handle);\r
+            // Step6: stop gnss\r
+            if (StopGnss(handle) == 0) {\r
+                continue;\r
+            }\r
+        }\r
+    }\r
+    // ---------------------\r
+    // Step7: power off gnss\r
+    tiot_service_close(handle);\r
+    // 关日志文件\r
+    fclose(g_gnssLogFp);\r
+    g_gnssLogFp = NULL;\r
+    // Step8: deinit\r
+    tiot_service_deinit();\r
+    uapi_pm_remove_sleep_veto(PM_ID_SYS);\r
+    printf("\nfinish gnss samples\n");\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.h b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.h
new file mode 100644 (file)
index 0000000..b274e1e
--- /dev/null
@@ -0,0 +1,12 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pgnss sample\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef PGNSS_SAMPLE_H\r
+#define PGNSS_SAMPLE_H\r
+\r
+void PgnssExecuteSamples(void);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/CMakeLists.txt
new file mode 100644 (file)
index 0000000..48579a0
--- /dev/null
@@ -0,0 +1,40 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "realtime_pdr_sample")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/pdr_sample.c
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+    CONFIG_REALTIME_PDR_SAMPLE
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+)
+
+set(WHOLE_LINK
+true
+)
+
+set(BUILD_AS_OBJ
+false
+)
+
+set(MAIN_COMPONENT
+false
+)
+build_component()
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/gnss_datatypes.h b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/gnss_datatypes.h
new file mode 100644 (file)
index 0000000..51c5631
--- /dev/null
@@ -0,0 +1,67 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: gnss datatypes\r
+ * Author:\r
+ * Create:\r
+ */\r
+#ifndef GNSS_DATATYPES_H\r
+#define GNSS_DATATYPES_H\r
+\r
+#include <stdint.h>\r
+\r
+#define MSG_CONTENT_IDX             2\r
+\r
+// 消息类型\r
+typedef enum {\r
+    CMD_INJECT_HIS_INFO = 0x0101,               // 历史信息注入\r
+    CMD_PGNSS_INJECT_REF_GPS_TIME = 0x0201,     // GPS时间注入\r
+    CMD_PGNSS_INJECT_REF_LOC = 0x0202,          // 参考位置注入\r
+    CMD_PGNSS_INJECT_EPH_GPS = 0x0203,          // GPS星历注入\r
+    CMD_PGNSS_INJECT_EPH_GANSS = 0x0204,        // 非GPS星历注入\r
+    CMD_PGNSS_INJECT_UTC_GPS = 0x0205,          // GPS UTC注入\r
+    CMD_PGNSS_INJECT_RTI_GPS = 0x0206,          // GPS完好性信息注入\r
+    CMD_PGNSS_INJECT_RTI_GANSS = 0x0207,        // 非GPS完好性信息注入\r
+    CMD_PGNSS_INJECT_ION_GPS = 0x0208,          // GPS电离层参数注入\r
+    CMD_PGNSS_INJECT_AUX_GANSS = 0x0209,        // 非GPS频点转换关系信息注入\r
+    CMD_XGNSS_INJECT_UTC_TIME = 0x0404,         // 最开始注入的UTC时间\r
+    CMD_BUTT,\r
+} GnssCmdType;\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+    uint16_t  cmd;          // 消息类型\r
+    uint16_t  checkSum;     // 校验和,只计算实际数据部分,不包含头\r
+    uint16_t  sequence;     // 序列号,host下发\r
+    uint16_t  dataLength;   // 数据长度,实际数据的长度,不包含头\r
+    uint8_t   data[0];\r
+} GnssMsg;\r
+\r
+typedef struct {\r
+    uint16_t year;          // YYYY\r
+    uint8_t  month;         // MM, 1~12\r
+    uint8_t  day;           // DD, 1~31\r
+    uint8_t  hour;          // hh, 0~23\r
+    uint8_t  minute;        // mm, 0~59\r
+    uint8_t  second;        // ss, 0~59\r
+    uint16_t ms;            // ms, 0~999\r
+    uint8_t  valid;         // 0: invalid, 1: valid\r
+} GnssUtcTime;\r
+\r
+typedef struct {\r
+    uint32_t time;          // eph reference time\r
+    uint16_t cmd;           // cmd type to injected eph\r
+    uint32_t len;           // actual length of injected eph\r
+} EphHeadInfo;\r
+\r
+typedef struct {\r
+    uint16_t cmd;           // cmd type to injected other assist info\r
+    uint32_t len;           // actual length of injected other assist info\r
+} OtherAssistHeadInfo;\r
+\r
+typedef struct {\r
+    uint16_t cmd;\r
+    uint16_t status;\r
+} GnssAck;\r
+#pragma pack()\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.c b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.c
new file mode 100644 (file)
index 0000000..60cc00d
--- /dev/null
@@ -0,0 +1,452 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pdr sample. 本文件中的魔鬼数字均是示例的输入。\r
+ */\r
+\r
+#include "pdr_sample.h"\r
+#include <stdio.h>\r
+#include "securec.h"\r
+#include "tiot_service_interface.h"\r
+#include "pm_definition.h"\r
+#include "gnss_datatypes.h"\r
+#include "pdr_interface.h"\r
+\r
+#define ONE_LINE_SIZE   500\r
+#define SENSOR_AXIS_X   0\r
+#define SENSOR_AXIS_Y   1\r
+#define SENSOR_AXIS_Z   2\r
+#define SENSOR_AXIS_NUM 3\r
+#define ACC_TYPE        1\r
+#define GYRO_TYPE       2\r
+#define MSG_TYPE_BINRY  0\r
+#define MSG_TYPE_ASCII  1\r
+#define SLEEP_TIME            1000\r
+#define EXECUTE_MAX_TIMES     1000\r
+#define LISTEN_TIME_THR       1000\r
+#define REPORT_MAX_BYTES      10000\r
+#define REPORT_GNSS_LOC_CMD   0x1002\r
+#define REPORT_PDR_COMN_CMD   0x100b\r
+#define REPORT_REPLAY_CMD     0xf001\r
+#define ACK_CMD               0xff01\r
+\r
+static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 };\r
+static tiot_handle g_handle = 0;\r
+static uint8_t g_isGnssLoc = 0;\r
+static uint8_t g_isPdrComn = 0;\r
+static FILE* g_sensorFile = NULL;\r
+static FILE* g_gnssFile = NULL;\r
+\r
+static void ListenAck(tiot_handle handle)\r
+{\r
+    int32_t i = 0;\r
+    for (;;) {\r
+        // 监听\r
+        int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_gnssServiceBuff;\r
+            // 二进制消息类型\r
+            if (type[0] == 0) {\r
+                g_gnssServiceBuff[ret] = '\0';\r
+            }\r
+            i++;\r
+        }\r
+        if (i >= 1) {\r
+            printf("\ncnt enough\n");\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+// sensor数据从文件读取。每行对应一个采样时刻,依次为x/y/z轴数据。加速度计单位:m/s2,陀螺仪单位:rad/s\r
+static bool AssembleSensorData(SensorData *sensorSet, uint8_t sensorType)\r
+{\r
+    FILE *fp;\r
+    if (sensorType == ACC_TYPE) {\r
+        fp = fopen("/user/pdr_sample_acc.txt", "r");\r
+    } else if (sensorType == GYRO_TYPE) {\r
+        fp = fopen("/user/pdr_sample_gyro.txt", "r");\r
+    } else {\r
+        printf("SENSOR TYPE ERR\n");\r
+        return false;\r
+    }\r
+\r
+    if (fp == NULL) {\r
+        printf("OPEN SENSOR FILE ERR\n");\r
+        return false;\r
+    }\r
+\r
+    char buff[ONE_LINE_SIZE] = {0};\r
+    int i = 0;\r
+    int j = 0;\r
+    float num[SENSOR_AXIS_NUM] = {0.0};\r
+    char *token = NULL;\r
+    char *nextToken = NULL;\r
+\r
+    while (fgets(buff, ONE_LINE_SIZE, fp) != NULL) {\r
+        token = strtok_s(buff, " ", &nextToken);\r
+        j = 0;\r
+        while (token != NULL) {\r
+            if (j >= SENSOR_AXIS_NUM) {\r
+                (void)fclose(fp);\r
+                return false;\r
+            }\r
+            num[j] = atof(token);\r
+            token = strtok_s(NULL, " ", &nextToken);\r
+            j++;\r
+        }\r
+        if (j != SENSOR_AXIS_NUM) {\r
+            printf("SENSOR AXIS NUM ERR\n");\r
+            (void)fclose(fp);\r
+            return false;\r
+        }\r
+\r
+        sensorSet->sensors[i].timestamp = 1679389794007 + 10 * (int64_t)i;\r
+        sensorSet->sensors[i].x = num[SENSOR_AXIS_X];\r
+        sensorSet->sensors[i].y = num[SENSOR_AXIS_Y];\r
+        sensorSet->sensors[i].z = num[SENSOR_AXIS_Z];\r
+        sensorSet->sensors[i].status = 0;\r
+        i++;\r
+    }\r
+    sensorSet->cnt = i;\r
+    (void)fclose(fp);\r
+    return true;\r
+}\r
+\r
+static void AssembleGnssData(GnssLocInfo *locInfo, GnssPdrCommInfo *gnssState)\r
+{\r
+    locInfo->timestamp = 1679389795000;\r
+    locInfo->flags = 63;\r
+    locInfo->longitude = 1825717451;\r
+    locInfo->latitude = 573764623;\r
+    locInfo->clkBias = 18578227782;\r
+    locInfo->clkDrift = 928111185;\r
+    locInfo->altitude = 381.298279;\r
+    locInfo->speede = -510312;\r
+    locInfo->speedn = -1449305;\r
+    locInfo->speedu = 36950;\r
+    locInfo->heading = 3.480144;\r
+    locInfo->posAcc = 3.834757;\r
+    locInfo->speedAcc = 1.2345;\r
+\r
+    gnssState->context = 6;\r
+    gnssState->isStatic = 0;\r
+    gnssState->pvtState = 1;\r
+    gnssState->ems = 3.710260;\r
+    gnssState->hdop = 0.663898;\r
+    gnssState->inuseNum = 21;\r
+    gnssState->qop = 3.834757;\r
+}\r
+\r
+int32_t CfgReportAndStartGnss(tiot_handle handle)\r
+{\r
+    const uint8_t cfgRptGnssLocCmd[] = {0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02};\r
+    const uint8_t cfgRptPdrComnCmd[] = {0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0e, 0x10, 0x01, 0x00, 0x01};\r
+    const uint8_t cfgCloseNmeaCmd[] = {0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00,\r
+        0x00, 0x00};\r
+    const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,\r
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    // 配置上报GNSS定位信息\r
+    int32_t ret = tiot_service_write(handle, cfgRptGnssLocCmd, sizeof(cfgRptGnssLocCmd));\r
+    if (ret < 0) {\r
+        printf("error: cfg report gnss location error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    // 配置上报PDR COMMON信息\r
+    ret = tiot_service_write(handle, cfgRptPdrComnCmd, sizeof(cfgRptPdrComnCmd));\r
+    if (ret < 0) {\r
+        printf("error: cfg report pdr common error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    // 配置关闭NMEA消息输出(避免每秒上报过多消息,导致获取sensor数据的短时间内就撑满消息队列)\r
+    ret = tiot_service_write(handle, cfgCloseNmeaCmd, sizeof(cfgCloseNmeaCmd));\r
+    if (ret < 0) {\r
+        printf("error: cfg close nmea error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    // 启动GNSS\r
+    ret = tiot_service_write(handle, startCmd, sizeof(startCmd));\r
+    if (ret < 0) {\r
+        printf("error: start gnss error: %d\n", ret);\r
+        return 0;\r
+    }\r
+    ListenAck(handle);\r
+    printf("start gnss\n");\r
+    return 1;\r
+}\r
+\r
+int32_t GnssStartAndReport(void)\r
+{\r
+    printf("enter gnss samples\n");\r
+    // Step1: init\r
+    int32_t ret = tiot_service_init();\r
+    if (ret != 0) {\r
+        printf("tiot service init fail\n");\r
+        return 0;\r
+    }\r
+\r
+    // Step2: power on gnss\r
+    g_handle = tiot_service_open("gn71", NULL);\r
+    if (g_handle == 0) {\r
+        printf("open tiot service fail\n");\r
+        return 0;\r
+    }\r
+    printf("open tiot service success\n");\r
+\r
+    // Step3: cfg report and start gnss\r
+    if (CfgReportAndStartGnss(g_handle) == 0) {\r
+        printf("CfgReportAndStartGnss fail\n");\r
+        return 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+void DecodeAndAssembleGnssLoc(const uint8_t *buff, uint32_t len, GnssLocInfo *locInfo)\r
+{\r
+    if (len != sizeof(GnssLocInfo)) {\r
+        printf("DecodeAndAssembleGnssLoc: len=%u expect=%u\n", len, sizeof(GnssLocInfo));\r
+        return;\r
+    }\r
+    (void)memcpy_s(locInfo, sizeof(GnssLocInfo), buff, sizeof(GnssLocInfo));\r
+    g_isGnssLoc = 1;\r
+}\r
+\r
+void DecodeAndAssemblePdrComn(const uint8_t *buff, uint32_t len, GnssPdrCommInfo *pdrComn)\r
+{\r
+    if (len != sizeof(GnssPdrCommInfo)) {\r
+        printf("DecodeAndAssemblePdrComn: len=%u expect=%u\n", len, sizeof(GnssPdrCommInfo));\r
+        return;\r
+    }\r
+    (void)memcpy_s(pdrComn, sizeof(GnssPdrCommInfo), buff, sizeof(GnssPdrCommInfo));\r
+    g_isPdrComn = 1;\r
+}\r
+\r
+void DecodeTimeSyncAck(const uint8_t *buff, uint32_t len)\r
+{\r
+    if (len != sizeof(GnssAck)) {\r
+        printf("DecodeTimeSyncAck failed: len:%u, expect:%u\n", len, sizeof(GnssAck));\r
+        return;\r
+    }\r
+    GnssAck *ack = (GnssAck*)buff;\r
+    if (ack->cmd != 0x3 || ack->status != 0x0) {\r
+        printf("DecodeTimeSyncAck failed: cmd:%x, statuc:%x\n", ack->cmd, ack->status);\r
+        return;\r
+    }\r
+    // 接收到时间校准的ACK\r
+    // 记录此时MCU的时间戳,即可根据芯片上报的deltaTime得到芯片上报对应的MCU时间\r
+}\r
+\r
+// buff指向GnssMsg类型,len为GnssMsg包长度\r
+void DecodeBinaryGnss(const uint8_t *buff, GnssRptRslt *gnssRptRslt)\r
+{\r
+    GnssMsg *msg = (GnssMsg*)buff;\r
+    printf("DecodeBinaryGnss: gnss msg type:%x, len:%u\n", msg->cmd, msg->dataLength);\r
+    if (msg->cmd == REPORT_PDR_COMN_CMD) { // PDR COMMON信息\r
+        DecodeAndAssemblePdrComn(buff + sizeof(GnssMsg), msg->dataLength, &(gnssRptRslt->gnssState));\r
+    } else if (msg->cmd == REPORT_GNSS_LOC_CMD) { // GNSS定位信息\r
+        g_isGnssLoc = 0;\r
+        g_isPdrComn = 0;\r
+        (void)memset_s(gnssRptRslt, sizeof(GnssRptRslt), 0, sizeof(GnssRptRslt));\r
+        DecodeAndAssembleGnssLoc(buff + sizeof(GnssMsg), msg->dataLength, &(gnssRptRslt->locInfo));\r
+    } else if (msg->cmd == ACK_CMD) { // GNSS回ACK信息\r
+        DecodeTimeSyncAck(buff + sizeof(GnssMsg), msg->dataLength);\r
+    }\r
+}\r
+\r
+void PdrDemo(void)\r
+{\r
+    // 1.获取PDR版本号\r
+    printf("PDR VERSION: %s\n", GetPdrVersion());\r
+\r
+    // 2.初始化PDR。仅在开始调用一次。\r
+    int32_t initRetVal = InitPdrFusion();\r
+    if (initRetVal != RET_OK) {\r
+        printf("PDR INIT ERR\n");\r
+        return;\r
+    }\r
+\r
+    // 3.获取sensor和gnss数据,执行PDR主流程。每秒调用一次。\r
+    EpochSensorData *sensorData = (EpochSensorData *)malloc(sizeof(EpochSensorData));\r
+    if (sensorData == NULL) {\r
+        printf("SENSOR DATA MALLOC ERR");\r
+        return;\r
+    }\r
+\r
+    (void)memset_s(sensorData, sizeof(EpochSensorData), 0, sizeof(EpochSensorData));\r
+    GnssRptRslt gnssRptRslt;\r
+    PdrResult pdrRslt;\r
+    (void)memset_s(&gnssRptRslt, sizeof(gnssRptRslt), 0, sizeof(gnssRptRslt));\r
+    (void)memset_s(&pdrRslt, sizeof(pdrRslt), 0, sizeof(pdrRslt));\r
+\r
+    sensorData->sensorSts = SENSOR_SYNC_SUCC;\r
+    sensorData->utcMs = 1679389795000;\r
+    // 获取100Hz acc数据\r
+    bool isAccSucc = AssembleSensorData(&sensorData->sensorDataSet.accl, ACC_TYPE);\r
+    if (!isAccSucc) {\r
+        printf("ACC DATA ERR\n");\r
+        free(sensorData);\r
+        return;\r
+    }\r
+    // 获取100Hz gyro数据\r
+    bool isGyroSucc = AssembleSensorData(&sensorData->sensorDataSet.gyro, GYRO_TYPE);\r
+    if (!isGyroSucc) {\r
+        printf("GYRO DATA ERR\n");\r
+        free(sensorData);\r
+        return;\r
+    }\r
+\r
+    // 获取gnss数据\r
+    AssembleGnssData(&gnssRptRslt.locInfo, &gnssRptRslt.gnssState);\r
+\r
+    // PDR融合\r
+    int32_t execRetVal = ExecutePdrFusion(sensorData, &gnssRptRslt, &pdrRslt);\r
+    if (execRetVal == RET_OK) {\r
+        printf("PDR SUCCESS. time: %llu, valid: %d, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f\n",\r
+               pdrRslt.timeStampMs,\r
+               pdrRslt.posLla.valid, pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt,\r
+               pdrRslt.speed, pdrRslt.heading);\r
+    } else {\r
+        printf("PDR ERR. CODE: %d\n", execRetVal);\r
+    }\r
+\r
+    // 4.停止PDR。仅在结束调用一次。\r
+    int32_t quitRetVal = QuitPdrFusion();\r
+    if (quitRetVal != RET_OK) {\r
+        printf("PDR QUIT ERR\n");\r
+    }\r
+    free(sensorData);\r
+}\r
+\r
+void GetSensorData(EpochSensorData *sensorData)\r
+{\r
+    // 获取时间戳与sensor状态\r
+    // 获取100Hz acc数据\r
+    // 获取100Hz gyro数据\r
+    return;\r
+}\r
+\r
+void InjectSensorTimeSyncCmd(tiot_handle handle)\r
+{\r
+    const uint8_t cfgSyncCmd[] = {0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x10, 0x01, 0x00, 0x01};\r
+    int32_t ret = tiot_service_write(handle, cfgSyncCmd, sizeof(cfgSyncCmd));\r
+    if (ret < 0) {\r
+        printf("error: cfg sync cmd error: %d\n", ret);\r
+        return;\r
+    }\r
+    return;\r
+}\r
+\r
+void PdrDemoRealTime(void)\r
+{\r
+    uapi_pm_add_sleep_veto(PM_ID_SYS);\r
+    // 1.获取PDR版本号\r
+    printf("PDR VERSION: %s\n", GetPdrVersion());\r
+\r
+    // 2.初始化PDR。仅在开始调用一次。\r
+    int32_t initRetVal = InitPdrFusion();\r
+    if (initRetVal != RET_OK) {\r
+        printf("PDR INIT ERR\n");\r
+        return;\r
+    }\r
+\r
+    EpochSensorData *sensorData = (EpochSensorData *)malloc(sizeof(EpochSensorData));\r
+    if (sensorData == NULL) {\r
+        printf("SENSOR DATA MALLOC ERR");\r
+        return;\r
+    }\r
+\r
+    // 3.配置上报信息并启动GNSS\r
+    if (GnssStartAndReport() == 0) {\r
+        free(sensorData);\r
+        printf("GnssStartAndReport fail\n");\r
+        return;\r
+    }\r
+\r
+    g_sensorFile = fopen("/user/pdr_data.bin", "wb");\r
+    if (g_sensorFile == NULL) {\r
+        free(sensorData);\r
+        printf("OPEN REPLAY FILE ERR\n");\r
+        return;\r
+    }\r
+    g_gnssFile = fopen("/user/gnss_data.bin", "wb");\r
+    if (g_gnssFile == NULL) {\r
+        free(sensorData);\r
+        (void)fclose(g_sensorFile);\r
+        g_sensorFile = NULL;\r
+        printf("OPEN REPLAY FILE ERR\n");\r
+        return;\r
+    }\r
+    size_t wRet;\r
+\r
+    // 下发PDR时间校准命令\r
+    osal_msleep(SLEEP_TIME);\r
+    InjectSensorTimeSyncCmd(g_handle);\r
+    // 4.获取sensor和gnss数据,执行PDR主流程。每秒调用一次。\r
+    int32_t i = 0;\r
+    while (1) {\r
+        GnssRptRslt gnssRptRslt;\r
+        // 监听GNSS数据,将上报数据填充到gnssRptRslt.gnssState\r
+        int32_t ret = tiot_service_read(g_handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);\r
+        if (ret > 0) {\r
+            uint16_t *type = (uint16_t *)g_gnssServiceBuff;\r
+            if (type[0] == MSG_TYPE_BINRY) {\r
+                DecodeBinaryGnss(g_gnssServiceBuff + MSG_CONTENT_IDX, &gnssRptRslt);\r
+            }\r
+        }\r
+        if (g_isPdrComn == 1 && g_isGnssLoc == 1) {\r
+            printf("gnssRptRslt gnssState deltaTime: %d, pvtState: %u, qop: %.3f, gnssRptRslt locInfotime: %llu,"\r
+                "valid: %d, lat: %lld, lon: %lld, alt: %.3f\n", (int32_t)(gnssRptRslt.gnssState.deltaTime),\r
+                gnssRptRslt.gnssState.pvtState, gnssRptRslt.gnssState.qop, gnssRptRslt.locInfo.timestamp,\r
+                gnssRptRslt.locInfo.flags, gnssRptRslt.locInfo.latitude, gnssRptRslt.locInfo.longitude,\r
+                gnssRptRslt.locInfo.altitude);\r
+            (void)memset_s(sensorData, sizeof(EpochSensorData), 0, sizeof(EpochSensorData));\r
+            // 获取sensor数据\r
+            GetSensorData(sensorData);\r
+            // GNSS数据和sensor数据写进文件\r
+            wRet = fwrite(sensorData, sizeof(EpochSensorData), 1, g_sensorFile);\r
+            if (wRet != 1) {\r
+                printf("write sensorData fail\n");\r
+                break;\r
+            }\r
+            wRet = fwrite(&gnssRptRslt, sizeof(GnssRptRslt), 1, g_gnssFile);\r
+            if (wRet != 1) {\r
+                printf("write gnssRptRslt fail\n");\r
+                break;\r
+            }\r
+            PdrResult pdrRslt;\r
+            (void)memset_s(&pdrRslt, sizeof(pdrRslt), 0, sizeof(pdrRslt));\r
+            // PDR融合\r
+            int32_t execRetVal = ExecutePdrFusion(sensorData, &gnssRptRslt, &pdrRslt);\r
+            if (execRetVal == RET_OK) {\r
+                printf("PDR SUCCESS. time: %llu, valid: %d, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f\n",\r
+                    pdrRslt.timeStampMs,\r
+                    pdrRslt.posLla.valid, pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt,\r
+                    pdrRslt.speed, pdrRslt.heading);\r
+            } else {\r
+                printf("PDR ERR. CODE: %d\n", execRetVal);\r
+            }\r
+            g_isPdrComn = 0;\r
+            g_isGnssLoc = 0;\r
+            // 设置执行次数\r
+            if (i >= EXECUTE_MAX_TIMES) {\r
+                printf("\ncnt enough\n");\r
+                break;\r
+            }\r
+            i++;\r
+        }\r
+    }\r
+\r
+    // 4.停止PDR。仅在结束调用一次。\r
+    int32_t quitRetVal = QuitPdrFusion();\r
+    if (quitRetVal != RET_OK) {\r
+        printf("PDR QUIT ERR\n");\r
+    }\r
+    free(sensorData);\r
+    (void)fclose(g_sensorFile);\r
+    g_sensorFile = NULL;\r
+    (void)fclose(g_gnssFile);\r
+    g_gnssFile = NULL;\r
+    uapi_pm_remove_sleep_veto(PM_ID_SYS);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.h b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.h
new file mode 100644 (file)
index 0000000..17f7558
--- /dev/null
@@ -0,0 +1,18 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: pdr demo\r
+ */\r
+#ifndef PDR_SAMPLE_H\r
+#define PDR_SAMPLE_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+\r
+void PdrDemo(void);\r
+void PdrDemoRealTime(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_acc.txt b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_acc.txt
new file mode 100644 (file)
index 0000000..b3b9626
--- /dev/null
@@ -0,0 +1,100 @@
+7.598692417 0.158006832 -1.833836913\r
+7.342529774 0.213069826 -1.735681176\r
+7.127066135 0.237010255 -1.627949238\r
+7.019333839 0.239404291 -1.570492148\r
+6.818234444 0.304043472 -1.592038631\r
+6.550101757 0.387834966 -1.587250471\r
+6.265210629 0.438109875 -1.632737279\r
+6.064110756 0.433321774 -1.690194368\r
+5.961166859 0.378258795 -1.745257378\r
+5.968348980 0.203493655 -1.752439499\r
+6.025805950 0.031122558 -1.714134812\r
+6.068899155 -0.052668944 -1.623161077\r
+6.061717033 -0.067033201 -1.575280309\r
+6.147902489 -0.038304687 -1.592038631\r
+6.310697079 -0.038304687 -1.565704107\r
+6.629105091 -0.184341311 -1.510641098\r
+7.139036179 -0.404593259 -1.532187462\r
+7.883583546 -0.564994156 -1.565704107\r
+8.661647797 -0.675120115 -1.558521986\r
+9.341555595 -0.802004397 -1.558521986\r
+10.861772537 -0.979163587 -1.766803741\r
+11.685323715 -1.110835910 -1.896082044\r
+12.183284760 -1.067743182 -1.967903376\r
+12.427476883 -0.869037569 -1.965509295\r
+12.650122643 -0.703848660 -1.982267618\r
+13.023593903 -0.802004397 -1.917628407\r
+13.377912521 -1.034226537 -1.771591783\r
+13.658015251 -1.106047869 -1.690194368\r
+13.985999107 -1.077319384 -1.613584995\r
+14.349893570 -1.046196818 -1.630343318\r
+14.675483704 -1.070137262 -1.613584995\r
+14.876583099 -1.017468214 -1.735681176\r
+14.991497040 -0.964799345 -1.982267618\r
+15.027407646 -0.900160134 -2.221671820\r
+15.041771889 -0.825944841 -2.331797838\r
+14.936433792 -0.734971166 -2.183367252\r
+14.503111839 -0.675120115 -1.898476124\r
+13.717865944 -0.526689470 -1.405303240\r
+12.695610046 -0.265738755 -0.859461427\r
+11.682929993 0.028728515 -0.361500502\r
+10.837832451 0.232222170 0.023940429\r
+10.133983612 0.354318351 0.256162584\r
+9.693479538 0.205887690 0.402199209\r
+9.485198021 -0.160400882 0.423745602\r
+9.410983086 -0.564994156 0.363894522\r
+9.317615509 -0.981557608 0.253768563\r
+9.166790962 -1.446002007 0.146036625\r
+8.934568405 -1.886505842 0.122096188\r
+8.764591217 -2.252794504 0.162794918\r
+8.632919312 -2.530503511 0.280103028\r
+8.472517967 -2.710056543 0.306437492\r
+8.278600693 -2.824970722 0.308831543\r
+8.077501297 -2.856093168 0.248980463\r
+7.869219303 -2.846517086 0.308831543\r
+7.744729042 -2.748361349 0.454868168\r
+7.795003891 -2.607112885 0.651179671\r
+8.015255928 -2.441923857 0.840309083\r
+8.295358658 -2.370102644 1.041408658\r
+8.525186539 -2.377284765 1.098865747\r
+8.697558403 -2.504168987 0.988739729\r
+9.401406288 -2.822576761 0.598510742\r
+9.980765343 -2.913550377 0.371076673\r
+10.615186691 -2.935096741 0.189129397\r
+11.070055008 -2.980583429 0.004788086\r
+11.292700768 -2.999735832 -0.172371089\r
+11.290307045 -3.011706114 -0.363894522\r
+11.275942802 -3.016494036 -0.653573751\r
+11.591956139 -3.064374924 -0.969587386\r
+12.255105972 -3.303779364 -1.168292999\r
+12.980501175 -3.536001444 -1.264054656\r
+13.346789360 -3.749071360 -1.388544917\r
+13.169630051 -3.782588005 -1.642313480\r
+12.791371346 -3.615004778 -2.171396971\r
+13.006834984 -3.507272959 -2.793848038\r
+14.053031921 -3.488120556 -3.318143606\r
+15.580431938 -3.497696877 -3.626975060\r
+16.810970306 -3.550365686 -3.471362352\r
+16.767877579 -3.605428696 -2.903974056\r
+15.288358688 -3.480938435 -2.089999437\r
+13.296514511 -3.289415121 -1.405303240\r
+11.637442589 -3.217593670 -1.163504839\r
+10.883318901 -3.308567286 -1.309541464\r
+11.096388817 -3.634157181 -1.809896469\r
+11.991761208 -3.763435602 -2.530503511\r
+13.100203514 -3.603034735 -3.188865185\r
+13.863903046 -3.313355446 -3.720342875\r
+14.251737595 -3.052404881 -4.194363117\r
+14.531841278 -2.779483795 -4.438555717\r
+14.826308250 -2.556837797 -4.371522427\r
+15.005861282 -2.305463314 -4.050720692\r
+14.814337730 -2.054088831 -3.514455080\r
+14.132035255 -1.881717801 -3.040434599\r
+13.207935333 -1.764409661 -2.674145937\r
+12.482540131 -1.647101521 -2.346162081\r
+12.118645668 -1.589644551 -2.178579092\r
+12.006125450 -1.654283643 -2.183367252\r
+12.020489693 -1.778773904 -2.377284765\r
+12.015701294 -1.860171437 -2.619082928\r
+11.884029388 -1.910446286 -2.793848038\r
+11.682929993 -1.920022488 -2.858487368
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_gyro.txt b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_gyro.txt
new file mode 100644 (file)
index 0000000..1876c6a
--- /dev/null
@@ -0,0 +1,100 @@
+1.809382796 1.616349459 2.758667469\r
+1.676214218 1.589471340 2.662150621\r
+1.529606581 1.544267297 2.552195072\r
+1.359786034 1.486845970 2.422691584\r
+1.180191636 1.434311628 2.290744543\r
+0.990823388 1.384220600 2.145358801\r
+0.790459633 1.323134065 1.985311985\r
+0.580321968 1.242499948 1.817934990\r
+0.359188765 1.145983219 1.634675384\r
+0.140499011 1.044579506 1.431868076\r
+-0.072082095 0.941954195 1.210734844\r
+-0.254119933 0.828333259 0.987158239\r
+-0.399505854 0.701273322 0.755029440\r
+-0.516791999 0.552222192 0.514348507\r
+-0.608421803 0.376292974 0.271224171\r
+-0.678060412 0.185703039 0.012217305\r
+-0.730594814 -0.026878070 -0.266337246\r
+-0.766025007 -0.254119933 -0.560774267\r
+-0.794124782 -0.465479314 -0.864985168\r
+-0.819781125 -0.656069279 -1.174082994\r
+-0.874759018 -1.080009699 -1.800830722\r
+-0.888198078 -1.284038782 -2.102598190\r
+-0.864985168 -1.447750568 -2.361604929\r
+-0.817337692 -1.580919266 -2.581516504\r
+-0.786794424 -1.727526903 -2.761110783\r
+-0.778242290 -1.887573600 -2.904053450\r
+-0.747699022 -2.028072596 -3.016452551\r
+-0.697608113 -2.141693592 -3.095865011\r
+-0.626747727 -2.236988544 -3.147177696\r
+-0.541226625 -2.318844557 -3.164281845\r
+-0.432492584 -2.372600555 -3.152064562\r
+-0.305432618 -2.375044107 -3.112969160\r
+-0.183259577 -2.323731422 -3.055547953\r
+-0.079412483 -2.240653753 -2.977357149\r
+-0.013439035 -2.118480682 -2.893057823\r
+-0.013439035 -1.954768777 -2.807536602\r
+-0.087964594 -1.762957096 -2.718350410\r
+-0.238237441 -1.568701982 -2.625498772\r
+-0.469144493 -1.401324868 -2.525316954\r
+-0.761138082 -1.285260439 -2.410474300\r
+-1.089783549 -1.231504321 -2.279749155\r
+-1.444085479 -1.226617455 -2.131919622\r
+-1.792278647 -1.254717231 -1.988977194\r
+-2.106263399 -1.292590857 -1.858252048\r
+-2.373822212 -1.303586364 -1.749518037\r
+-2.580294847 -1.269377947 -1.668883801\r
+-2.706132889 -1.205847979 -1.620014668\r
+-2.741563082 -1.125213742 -1.587027907\r
+-2.698802710 -1.044579506 -1.576032281\r
+-2.582738161 -0.962723613 -1.573588848\r
+-2.420248032 -0.873537302 -1.574810624\r
+-2.228436470 -0.775798857 -1.573588848\r
+-2.021963835 -0.680503905 -1.563814998\r
+-1.817934990 -0.593761027 -1.544267297\r
+-1.634675384 -0.537561417 -1.510058880\r
+-1.486845970 -0.518013716 -1.463633060\r
+-1.380555391 -0.516791999 -1.403768301\r
+-1.312138557 -0.514348507 -1.337794900\r
+-1.274264932 -0.498466045 -1.263269305\r
+-1.247386813 -0.476474881 -1.191187263\r
+-1.142318010 -0.467922777 -1.083674908\r
+-1.065348983 -0.458148926 -1.043357849\r
+-0.994488597 -0.420275271 -0.994488597\r
+-0.929736912 -0.345749736 -0.934623837\r
+-0.879645944 -0.249233022 -0.855211318\r
+-0.846659243 -0.157603234 -0.753807724\r
+-0.825889826 -0.101403631 -0.627969444\r
+-0.824668050 -0.094073243 -0.481361806\r
+-0.821002901 -0.116064392 -0.316428185\r
+-0.808785558 -0.124616511 -0.129503429\r
+-0.755029440 -0.079412483 0.069638640\r
+-0.669508278 0.000000000 0.288328379\r
+-0.549778700 0.057421334 0.518013716\r
+-0.390953749 0.013439035 0.746477306\r
+-0.206472456 -0.074525557 0.965167105\r
+-0.025656341 -0.122173049 1.169196010\r
+0.116064392 -0.079412483 1.347568750\r
+0.226020142 0.057421334 1.496619821\r
+0.340862811 0.208915904 1.621236324\r
+0.483805269 0.272445887 1.732413769\r
+0.668286562 0.223576680 1.866804123\r
+0.910189211 0.101403631 2.002416134\r
+1.199739337 -0.019547688 2.113593817\r
+1.540602088 -0.078190751 2.214997292\r
+1.892460465 -0.009773844 2.306627035\r
+2.204001665 0.178372651 2.381152630\r
+2.448347807 0.416610092 2.450791359\r
+2.602285862 0.647517145 2.504547358\r
+2.674367905 0.846659243 2.536312580\r
+2.675589800 1.025031924 2.565634012\r
+2.580294847 1.194852352 2.610837936\r
+2.415361166 1.318247199 2.674367905\r
+2.241875410 1.364672899 2.757445574\r
+2.086715698 1.332907915 2.860070944\r
+1.946216702 1.253495455 2.981022358\r
+1.820378423 1.165530920 3.119077921\r
+1.715309620 1.106887817 3.254689932\r
+1.637118816 1.088561893 3.379306555\r
+1.572367072 1.112996459 3.488040447\r
+1.510058880 1.161865711 3.572340012
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d10eb98
--- /dev/null
@@ -0,0 +1,43 @@
+#===============================================================================
+# @brief    cmake make file
+# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "replay_pdr_sample")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/hipdr_test_run.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/hipdr_test_save_log.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/hipdr_test_config.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/hipdr_test_main.c
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+    CONFIG_REPLAY_PDR_SAMPLE
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+)
+
+set(WHOLE_LINK
+true
+)
+
+set(BUILD_AS_OBJ
+false
+)
+
+set(MAIN_COMPONENT
+false
+)
+build_component()
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.c b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.c
new file mode 100644 (file)
index 0000000..7287168
--- /dev/null
@@ -0,0 +1,36 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 用于配置回放参数\r
+ * Create: 2024-04-01\r
+ */\r
+#include "hipdr_test_config.h"\r
+#include <stdio.h>\r
+#include <strings.h>\r
+#include <libgen.h>\r
+#include "securec.h"\r
+\r
+// 输入一个sensor文件和一个gnss上报数据文件\r
+void SetDefaultFilePath(SimulatePdrConfig* cfg)\r
+{\r
+    char* path = "/user";\r
+\r
+    (void)sprintf_s(cfg->replayFileSensor, sizeof(cfg->replayFileSensor) - 1, "%s/%s", path, "pdr_data.bin");\r
+    (void)sprintf_s(cfg->replayFileGnss, sizeof(cfg->replayFileGnss) - 1, "%s/%s", path, "gnss_data.bin");\r
+    (void)sprintf_s(cfg->logPath, sizeof(cfg->logPath) - 1, "%s", path);\r
+}\r
+\r
+void PrintSimulateInfo(const SimulatePdrConfig* cfg)\r
+{\r
+    printf("------------------- Simulate Info PDR single thread----------------------\n");\r
+    printf("sensor file: %s\n", cfg->replayFileSensor);\r
+    printf("gnss file: %s\n", cfg->replayFileGnss);\r
+    printf("log path   : %s\n", cfg->logPath);\r
+    printf("--------------------------------------------------------\n");\r
+}\r
+\r
+void ParseConfigParams(SimulatePdrConfig* cfg)\r
+{\r
+    (void)memset_s(cfg, sizeof(SimulatePdrConfig), 0, sizeof(SimulatePdrConfig));\r
+    SetDefaultFilePath(cfg);\r
+    PrintSimulateInfo(cfg);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.h b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.h
new file mode 100644 (file)
index 0000000..9456dac
--- /dev/null
@@ -0,0 +1,19 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 用于配置回放参数\r
+ * Create: 2024-04-01\r
+ */\r
+#ifndef HIPDR_TEST_CONFIG_H\r
+#define HIPDR_TEST_CONFIG_H\r
+\r
+#define FILE_PATH_LEN 1024\r
+\r
+typedef struct {\r
+    char replayFileSensor[FILE_PATH_LEN];   // 用于回放的二进制文件名称(包含路径)SENSOR\r
+    char replayFileGnss[FILE_PATH_LEN];     // 用于回放的二进制文件名称(包含路径)GNSS\r
+    char logPath[FILE_PATH_LEN];            // 生成回放日志的路径\r
+} SimulatePdrConfig;\r
+\r
+void ParseConfigParams(SimulatePdrConfig* cfg);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.c b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.c
new file mode 100644 (file)
index 0000000..a080418
--- /dev/null
@@ -0,0 +1,59 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 主流程框架\r
+ * Create: 2024-04-01\r
+ */\r
+\r
+#include "hipdr_test_main.h"\r
+// 引用标准头文件\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stddef.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include "securec.h"\r
+// 引用LIB库接口文件\r
+#include "pdr_interface.h"\r
+// 引用内部接口文件\r
+#include "hipdr_test_config.h"\r
+#include "hipdr_test_save_log.h"\r
+#include "hipdr_test_run.h"\r
+\r
+int PdrReplay(void)\r
+{\r
+    // 读取配置参数\r
+    SimulatePdrConfig cfg = {0};\r
+    ParseConfigParams(&cfg);\r
+\r
+    if (access(cfg.replayFileSensor, F_OK) != 0 || access(cfg.replayFileGnss, F_OK) != 0) {\r
+        printf("error: replay file not exist\n");\r
+        return -1;\r
+    }\r
+\r
+    printf("-- start to run simulate hipdr...\n");\r
+    // 打开日志文件\r
+    if (OpenHipdrLogFile(&cfg) != 0) {\r
+        printf("open log file error.\n");\r
+        return -1;\r
+    }\r
+\r
+    // 注册日志接口\r
+    RegPdrLogHandle(LogImpl);\r
+\r
+    int32_t initRetVal = InitPdrFusion();\r
+    if (initRetVal != RET_OK) {\r
+        printf("PDR INIT ERR\n");\r
+        CloseHipdrLogFile();\r
+        return -1;\r
+    }\r
+    RunHiPdr(&cfg);\r
+    int32_t quitRetVal = QuitPdrFusion();\r
+    if (quitRetVal != RET_OK) {\r
+        printf("PDR QUIT ERR\n");\r
+    }\r
+    // 关闭日志文件\r
+    CloseHipdrLogFile();\r
+\r
+    printf("-- finish simulate hipdr.\n");\r
+    return 0;\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.h b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.h
new file mode 100644 (file)
index 0000000..e66e546
--- /dev/null
@@ -0,0 +1,12 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 主流程框架\r
+ * Create: 2024-04-01\r
+ */\r
+\r
+#ifndef HIPDR_TEST_MAIN_H\r
+#define HIPDR_TEST_MAIN_H\r
+\r
+int PdrReplay(void);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.c b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.c
new file mode 100644 (file)
index 0000000..5f99c22
--- /dev/null
@@ -0,0 +1,75 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 运行仿真环境,调用业务代码\r
+ * Create: 2024-04-01\r
+ */\r
+#include "hipdr_test_run.h"\r
+#include <stdio.h>\r
+#include <stddef.h>\r
+#include <string.h>\r
+#include <math.h>\r
+#include "securec.h"\r
+#include "pdr_interface.h"\r
+\r
+#define PI                          3.1415926535897932384626433832795\r
+#define R2D                         (180 / PI)\r
+\r
+// 仿真主代码在这儿实现,如适配运行环境和适配注入数据\r
+void RunHiPdr(SimulatePdrConfig* cfg)\r
+{\r
+    // 读取仿真数据\r
+    FILE* fileSensor = fopen(cfg->replayFileSensor, "rb");\r
+    if (fileSensor == NULL) {\r
+        printf("open file error");\r
+        return;\r
+    }\r
+    FILE* fileGnss = fopen(cfg->replayFileGnss, "rb");\r
+    if (fileGnss == NULL) {\r
+        (void)fclose(fileSensor);\r
+        printf("open file error");\r
+        return;\r
+    }\r
+\r
+    // 获取文件容量\r
+    (void)fseek(fileSensor, 0, SEEK_END);\r
+    size_t size = ftell(fileSensor);\r
+    if (size == 0) {\r
+        (void)fclose(fileSensor);\r
+        (void)fclose(fileGnss);\r
+        return;\r
+    }\r
+    (void)fseek(fileSensor, 0, SEEK_SET);\r
+\r
+    (void)fseek(fileGnss, 0, SEEK_END);\r
+    size = ftell(fileGnss);\r
+    if (size == 0) {\r
+        (void)fclose(fileSensor);\r
+        (void)fclose(fileGnss);\r
+        return;\r
+    }\r
+    (void)fseek(fileGnss, 0, SEEK_SET);\r
+\r
+    // 逐历元读取数据\r
+    EpochSensorData sensorData;\r
+    (void)memset_s(&sensorData, sizeof(sensorData), 0, sizeof(sensorData));\r
+    GnssRptRslt gnssRptRslt;\r
+    (void)memset_s(&gnssRptRslt, sizeof(gnssRptRslt), 0, sizeof(gnssRptRslt));\r
+    PdrResult pdrRslt;\r
+    int32_t execRetVal;\r
+\r
+    while (fread(&sensorData,  sizeof(EpochSensorData),  1, fileSensor) > 0 &&\r
+           fread(&gnssRptRslt, sizeof(GnssRptRslt), 1, fileGnss) > 0) {\r
+        (void)memset_s(&pdrRslt, sizeof(PdrResult), 0, sizeof(PdrResult));\r
+        execRetVal = ExecutePdrFusion(&sensorData, &gnssRptRslt, &pdrRslt);\r
+        if (execRetVal == RET_OK) {\r
+            printf("PDR SUCCESS. time: %llu, valid: %d, src: %u, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f",\r
+                pdrRslt.timeStampMs, pdrRslt.posLla.valid, pdrRslt.src,\r
+                pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt,\r
+                pdrRslt.speed, pdrRslt.heading);\r
+        } else {\r
+            printf("PDR ERR. CODE: %d\n", execRetVal);\r
+        }\r
+    }\r
+    (void)fclose(fileSensor);\r
+    (void)fclose(fileGnss);\r
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.h b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.h
new file mode 100644 (file)
index 0000000..8664654
--- /dev/null
@@ -0,0 +1,13 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 运行仿真环境,调用业务代码\r
+ * Create: 2024-04-01\r
+ */\r
+#ifndef HIPDR_TEST_RUN_H\r
+#define HIPDR_TEST_RUN_H\r
+\r
+#include "hipdr_test_config.h"\r
+\r
+void RunHiPdr(SimulatePdrConfig* cfg);\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.c b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.c
new file mode 100644 (file)
index 0000000..e0b766c
--- /dev/null
@@ -0,0 +1,51 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 存储日志\r
+ * Create: 2024-04-01\r
+ */\r
+\r
+#include "hipdr_test_save_log.h"\r
+#include <stdio.h>\r
+#include <time.h>\r
+#include "securec.h"\r
+\r
+static FILE* g_pdrLogFp = NULL;\r
+\r
+// 日志实现函数\r
+int LogImpl(const char *logLevel, const char* fmt, ...)\r
+{\r
+    if (g_pdrLogFp == NULL) {\r
+        return -1;\r
+    }\r
+\r
+    va_list va;\r
+    va_start(va, fmt);\r
+    (void)fprintf(g_pdrLogFp, "[%s] ", logLevel);\r
+    (void)vfprintf(g_pdrLogFp, fmt, va);\r
+    va_end(va);\r
+    return 0;\r
+}\r
+\r
+int OpenHipdrLogFile(const SimulatePdrConfig* cfg)\r
+{\r
+    printf("enter OpenHipdrLogFile\n");\r
+    char pathName[FILE_PATH_LEN] = {0};\r
+    (void)sprintf_s(pathName, sizeof(pathName) - 1, "%s/pdr_test.log", cfg->logPath);\r
+    g_pdrLogFp = fopen(pathName, "w");\r
+    printf("open pathName: %s\n", pathName);\r
+\r
+    if (g_pdrLogFp == NULL) {\r
+        printf("error: open log file error(%s)\n", pathName);\r
+        return -1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+void CloseHipdrLogFile(void)\r
+{\r
+    if (g_pdrLogFp == NULL) {\r
+        return;\r
+    }\r
+    (void)fclose(g_pdrLogFp);\r
+    g_pdrLogFp = NULL;\r
+}\r
diff --git a/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.h b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.h
new file mode 100644 (file)
index 0000000..bb4e129
--- /dev/null
@@ -0,0 +1,17 @@
+ /*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved.\r
+ * Description: 存储日志\r
+ * Create: 2024-04-01\r
+ */\r
+\r
+#ifndef HIPDR_TEST_SAVE_LOG_H\r
+#define HIPDR_TEST_SAVE_LOG_H\r
+\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include "hipdr_test_config.h"\r
+\r
+int  OpenHipdrLogFile(const SimulatePdrConfig* cfg);\r
+void CloseHipdrLogFile(void);\r
+int LogImpl(const char *logLevel, const char* fmt, ...);\r
+#endif
\ No newline at end of file