From 0cf6d3b1135e9528253237b79ec1f9761a5a2bbd Mon Sep 17 00:00:00 2001 From: SnickerSun Date: Mon, 16 Dec 2024 17:12:36 +0800 Subject: [PATCH] =?utf8?q?=E6=B7=BB=E5=8A=A0gs21=20sdk=E6=BA=90=E7=A0=81?= =?utf8?q?=20GS21=5F1.10.100?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../server_agnss_download_demo.py | 146 ++ .../driver/tiot_driver/CMakeLists.txt | 75 + .../GS21_1.10.100/driver/tiot_driver/Makefile | 194 ++ .../driver/tiot_driver/common/CMakeLists.txt | 20 + .../common/controller/CMakeLists.txt | 11 + .../common/controller/tiot_controller.c | 157 ++ .../common/controller/tiot_controller.h | 152 ++ .../controller/tiot_controller_helper.h | 52 + .../common/controller/tiot_device_info.h | 78 + .../tiot_driver/common/fw_load/CMakeLists.txt | 46 + .../cfg_handle_priv/tiot_cfg_handle_priv.c | 170 ++ .../cfg_handle_priv/tiot_cfg_handle_priv.h | 53 + .../common/fw_load/tiot_firmware.c | 277 ++ .../common/fw_load/tiot_firmware.h | 118 + .../common/fw_load/tiot_firmware_utils.h | 58 + .../common/interface/CMakeLists.txt | 20 + .../board_internal/tiot_board.h | 61 + .../board_internal/tiot_board_log.h | 81 + .../board_internal/tiot_board_xmit.h | 64 + .../board_internal/tiot_board_xmit_ops.c | 62 + .../board_internal/tiot_board_xmit_ops.h | 87 + .../board_porting/gnss_board_port.h | 84 + .../board_porting/tiot_board_misc_port.h | 112 + .../board_porting/tiot_board_pin_port.h | 100 + .../board_porting/tiot_board_uart_port.h | 122 + .../board_interface/osal_porting/tiot_osal.h | 436 ++++ .../device_interface/tiot_service_interface.c | 248 ++ .../device_interface/tiot_service_interface.h | 108 + .../tiot_service_interface_ext.h | 98 + .../common/libboundscheck/CMakeLists.txt | 28 + .../common/libboundscheck/include/securec.h | 629 +++++ .../libboundscheck/include/securectype.h | 585 +++++ .../common/libboundscheck/src/Makefile | 196 ++ .../common/libboundscheck/src/fscanf_s.c | 53 + .../common/libboundscheck/src/fwscanf_s.c | 52 + .../common/libboundscheck/src/gets_s.c | 71 + .../common/libboundscheck/src/input.inl | 2229 +++++++++++++++++ .../common/libboundscheck/src/memcpy_s.c | 555 ++++ .../common/libboundscheck/src/memmove_s.c | 123 + .../common/libboundscheck/src/memset_s.c | 510 ++++ .../common/libboundscheck/src/output.inl | 1720 +++++++++++++ .../common/libboundscheck/src/scanf_s.c | 51 + .../common/libboundscheck/src/secinput.h | 181 ++ .../common/libboundscheck/src/securecutil.c | 81 + .../common/libboundscheck/src/securecutil.h | 574 +++++ .../common/libboundscheck/src/secureinput_a.c | 38 + .../common/libboundscheck/src/secureinput_w.c | 75 + .../libboundscheck/src/secureprintoutput.h | 146 ++ .../libboundscheck/src/secureprintoutput_a.c | 112 + .../libboundscheck/src/secureprintoutput_w.c | 41 + .../common/libboundscheck/src/snprintf_s.c | 110 + .../common/libboundscheck/src/sprintf_s.c | 58 + .../common/libboundscheck/src/sscanf_s.c | 58 + .../common/libboundscheck/src/strcat_s.c | 101 + .../common/libboundscheck/src/strcpy_s.c | 353 +++ .../common/libboundscheck/src/strncat_s.c | 119 + .../common/libboundscheck/src/strncpy_s.c | 145 ++ .../common/libboundscheck/src/strtok_s.c | 116 + .../common/libboundscheck/src/swprintf_s.c | 48 + .../common/libboundscheck/src/swscanf_s.c | 54 + .../common/libboundscheck/src/vfscanf_s.c | 64 + .../common/libboundscheck/src/vfwscanf_s.c | 67 + .../common/libboundscheck/src/vscanf_s.c | 63 + .../common/libboundscheck/src/vsnprintf_s.c | 138 + .../common/libboundscheck/src/vsprintf_s.c | 67 + .../common/libboundscheck/src/vsscanf_s.c | 87 + .../common/libboundscheck/src/vswprintf_s.c | 62 + .../common/libboundscheck/src/vswscanf_s.c | 79 + .../common/libboundscheck/src/vwscanf_s.c | 64 + .../common/libboundscheck/src/wcscat_s.c | 107 + .../common/libboundscheck/src/wcscpy_s.c | 86 + .../common/libboundscheck/src/wcsncat_s.c | 113 + .../common/libboundscheck/src/wcsncpy_s.c | 107 + .../common/libboundscheck/src/wcstok_s.c | 112 + .../common/libboundscheck/src/wmemcpy_s.c | 71 + .../common/libboundscheck/src/wmemmove_s.c | 70 + .../common/libboundscheck/src/wscanf_s.c | 52 + .../tiot_driver/common/pm/CMakeLists.txt | 18 + .../common/pm/pm_default/CMakeLists.txt | 7 + .../common/pm/pm_default/tiot_pm_default.c | 288 +++ .../common/pm/pm_default/tiot_pm_default.h | 110 + .../common/pm/pm_slave/CMakeLists.txt | 7 + .../common/pm/pm_slave/tiot_pm_slave.c | 139 + .../common/pm/pm_slave/tiot_pm_slave.h | 95 + .../driver/tiot_driver/common/pm/tiot_pm.c | 149 ++ .../driver/tiot_driver/common/pm/tiot_pm.h | 182 ++ .../tiot_driver/common/pm/tiot_pm_wakelock.c | 72 + .../tiot_driver/common/pm/tiot_pm_wakelock.h | 74 + .../common/sys_msg_handler/CMakeLists.txt | 14 + .../sys_msg_handler/tiot_sys_msg_handle.c | 24 + .../sys_msg_handler/tiot_sys_msg_handle.h | 30 + .../tiot_sys_msg_slave_handle.c | 30 + .../sys_msg_handler/tiot_sys_msg_types.h | 139 + .../common/transfer/CMakeLists.txt | 21 + .../packet_handle/tiot_packet/CMakeLists.txt | 8 + .../packet_handle/tiot_packet/tiot_packet.c | 919 +++++++ .../packet_handle/tiot_packet/tiot_packet.h | 205 ++ .../tiot_packet/tiot_packet_manager.c | 90 + .../tiot_packet/tiot_packet_manager.h | 213 ++ .../tiot_driver/common/transfer/tiot_xfer.c | 493 ++++ .../tiot_driver/common/transfer/tiot_xfer.h | 247 ++ .../common/transfer/tiot_xfer_utils.c | 84 + .../common/transfer/tiot_xfer_utils.h | 42 + .../tiot_driver/common/utils/CMakeLists.txt | 15 + .../common/utils/circ_buf/tiot_circ_buf.h | 207 ++ .../common/utils/circ_queue/CMakeLists.txt | 11 + .../common/utils/circ_queue/tiot_circ_queue.c | 124 + .../common/utils/circ_queue/tiot_circ_queue.h | 105 + .../common/utils/fileops/CMakeLists.txt | 11 + .../common/utils/fileops/tiot_fileops.c | 93 + .../common/utils/fileops/tiot_fileops.h | 90 + .../tiot_driver/common/utils/list/tiot_list.h | 182 ++ .../common/utils/misc/CMakeLists.txt | 11 + .../tiot_driver/common/utils/misc/tiot_misc.c | 55 + .../tiot_driver/common/utils/misc/tiot_misc.h | 46 + .../tiot_driver/common/utils/tiot_types.h | 66 + .../tiot_driver/device/gnss/CMakeLists.txt | 31 + .../driver/tiot_driver/device/gnss/Makefile | 16 + .../device/gnss/firmware/gnss_fw_file_array.c | 17 + .../device/gnss/firmware/gnss_fw_file_array.h | 29 + .../device/gnss/gnss_device_info.c | 157 ++ .../device/gnss/gnss_device_info.h | 42 + .../tiot_driver/device/gnss/gnss_service.c | 434 ++++ .../tiot_driver/device/gnss/gnss_service.h | 54 + .../product_porting/CMakeLists.txt | 12 + .../tiot_driver/product_porting/Makefile | 4 + .../menu_configs/config0/readme.txt | 1 + .../menu_configs/config0/tiot_autoconfig.h | 17 + .../menu_configs/config0/tiot_defconfig | 101 + .../menu_configs/config1/readme.txt | 1 + .../menu_configs/config1/tiot_autoconfig.h | 17 + .../menu_configs/config1/tiot_defconfig | 100 + .../menu_configs/config2/readme.txt | 1 + .../menu_configs/config2/tiot_autoconfig.h | 19 + .../menu_configs/config2/tiot_defconfig | 100 + .../menu_configs/config3/readme.txt | 1 + .../menu_configs/config3/tiot_autoconfig.h | 20 + .../menu_configs/config3/tiot_defconfig | 100 + .../product_porting/menu_configs/readme.md | 20 + .../product_porting/porting/CMakeLists.txt | 20 + .../product_porting/porting/gnss_board_port.c | 32 + .../product_porting/porting/porting.mk | 5 + .../porting/tiot_board_log_port.h | 49 + .../porting/tiot_board_misc_port.c | 35 + .../porting/tiot_board_pin_port.c | 37 + .../porting/tiot_board_uart_port.c | 45 + .../product_porting/porting/tiot_osal_port.c | 109 + .../gnss_board_port.c | 189 ++ .../gnss_misc_device.c | 149 ++ .../porting_gnss_demo_kernel/porting.mk | 7 + .../tiot_board_log_port.h | 52 + .../tiot_board_misc_port.c | 113 + .../tiot_board_pin_irq_helper.c | 51 + .../tiot_board_pin_irq_helper.h | 48 + .../tiot_board_pin_port.c | 88 + .../tiot_board_uart_port.c | 205 ++ .../porting_gnss_demo_kernel/tiot_dts_node.h | 50 + .../porting_gnss_demo_kernel/tiot_osal_port.c | 363 +++ .../porting_gnss_demo_rtos/gnss_board_port.c | 67 + .../tiot_board_log_port.h | 52 + .../tiot_board_misc_port.c | 52 + .../tiot_board_pin_port.c | 69 + .../tiot_board_uart_port.c | 146 ++ .../tiot_osal_port_freertos_demo.c | 312 +++ .../tiot_osal_port_nonos_demo.c | 155 ++ .../tiot_osal_port_rtos_demo.c | 265 ++ .../porting_gnss_demo_sparta/CMakeLists.txt | 19 + .../gnss_board_port.c | 77 + .../tiot_board_log_port.h | 46 + .../tiot_board_misc_port.c | 45 + .../tiot_board_pin_port.c | 112 + .../tiot_board_uart_port.c | 193 ++ .../product_porting/tiot_autoconfig.h | 17 + .../product_porting/tiot_defconfig | 101 + .../fw_img_format1/file_array/gnss_cfg.bin | 905 +++++++ .../file_array/gnss_fw_file_array.c | 29 + .../file_array/gnss_fw_file_array.h | 29 + .../firmware/fw_img_format1/gnss_config.bin | Bin 0 -> 14469 bytes .../fw_img_format2/gnss_config_array.c | 1497 +++++++++++ .../GS21_1.10.100/pdr/include/pdr_interface.h | 156 ++ .../zhihui/GS21_1.10.100/pdr/libpdr_fusion.a | Bin 0 -> 945100 bytes .../pgnss/pgnss_decoder/libpgnss_decoder.so | Bin 0 -> 196256 bytes .../pgnss_decoder/pgnss_decoder_interface.h | 61 + .../server_pgnss_decode_demo/build_and_run.sh | 26 + .../pgnss/server_pgnss_decode_demo/clean.sh | 5 + .../demo_data/EE_7days.dat | 1 + .../server_pgnss_decode_demo.c | 106 + .../server_pgnss_download_demo.py | 140 ++ .../sample/agnss_sample/CMakeLists.txt | 41 + .../sample/agnss_sample/agnss_encode.c | 252 ++ .../sample/agnss_sample/agnss_encode.h | 15 + .../sample/agnss_sample/agnss_sample.c | 193 ++ .../sample/agnss_sample/agnss_sample.h | 12 + .../sample/agnss_sample/gnss_datatypes.h | 76 + .../sample/gnss_sample/CMakeLists.txt | 40 + .../sample/gnss_sample/gnss_sample.c | 228 ++ .../sample/gnss_sample/gnss_sample.h | 12 + .../sample/pgnss_sample/CMakeLists.txt | 41 + .../sample/pgnss_sample/gnss_datatypes.h | 65 + .../sample/pgnss_sample/pgnss_encode.c | 589 +++++ .../sample/pgnss_sample/pgnss_encode.h | 16 + .../sample/pgnss_sample/pgnss_sample.c | 223 ++ .../sample/pgnss_sample/pgnss_sample.h | 12 + .../sample/realtime_pdr_sample/CMakeLists.txt | 40 + .../realtime_pdr_sample/gnss_datatypes.h | 67 + .../sample/realtime_pdr_sample/pdr_sample.c | 452 ++++ .../sample/realtime_pdr_sample/pdr_sample.h | 18 + .../realtime_pdr_sample/pdr_sample_acc.txt | 100 + .../realtime_pdr_sample/pdr_sample_gyro.txt | 100 + .../sample/replay_pdr_sample/CMakeLists.txt | 43 + .../replay_pdr_sample/hipdr_test_config.c | 36 + .../replay_pdr_sample/hipdr_test_config.h | 19 + .../replay_pdr_sample/hipdr_test_main.c | 59 + .../replay_pdr_sample/hipdr_test_main.h | 12 + .../sample/replay_pdr_sample/hipdr_test_run.c | 75 + .../sample/replay_pdr_sample/hipdr_test_run.h | 13 + .../replay_pdr_sample/hipdr_test_save_log.c | 51 + .../replay_pdr_sample/hipdr_test_save_log.h | 17 + 218 files changed, 29168 insertions(+) create mode 100644 code/sdk/zhihui/GS21_1.10.100/agnss/server_agnss_download_demo/server_agnss_download_demo.py create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/Makefile create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller_helper.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_device_info.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware_utils.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_log.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/gnss_board_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_misc_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_pin_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_uart_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/osal_porting/tiot_osal.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface_ext.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securec.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securectype.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/Makefile create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fwscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/gets_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/input.inl create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memcpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memmove_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memset_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/output.inl create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/scanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secinput.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_a.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_w.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_a.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_w.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/snprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcat_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncat_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strtok_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfwscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsnprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswprintf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vwscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscat_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncat_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcstok_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemcpy_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemmove_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wscanf_s.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_slave_handle.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_types.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_buf/tiot_circ_buf.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/list/tiot_list.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/tiot_types.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/Makefile create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/Makefile create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/readme.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_autoconfig.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_defconfig create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/readme.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_autoconfig.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_defconfig create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/readme.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_autoconfig.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_defconfig create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/readme.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_autoconfig.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_defconfig create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/readme.md create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/gnss_board_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/porting.mk create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_log_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_misc_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_pin_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_uart_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_osal_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_board_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_misc_device.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/porting.mk create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_log_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_misc_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_uart_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_dts_node.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_osal_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/gnss_board_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_log_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_misc_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_pin_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_uart_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_freertos_demo.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_nonos_demo.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_rtos_demo.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/gnss_board_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_log_port.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_misc_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_pin_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_uart_port.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_autoconfig.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_defconfig create mode 100644 code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_cfg.bin create mode 100644 code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/gnss_config.bin create mode 100644 code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format2/gnss_config_array.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/pdr/include/pdr_interface.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/pdr/libpdr_fusion.a create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/libpgnss_decoder.so create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/pgnss_decoder_interface.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/build_and_run.sh create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/clean.sh create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/demo_data/EE_7days.dat create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/server_pgnss_decode_demo.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_download_demo/server_pgnss_download_demo.py create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/gnss_datatypes.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/gnss_datatypes.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/gnss_datatypes.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_acc.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_gyro.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/CMakeLists.txt create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.h create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.c create mode 100644 code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.h 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 index 000000000..e4f959ea9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/agnss/server_agnss_download_demo/server_agnss_download_demo.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# coding:utf-8 +# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. +import requests +import time +import calendar +import hmac +import base64 +import binascii + + +# 网络连接相关 +HOST = r'geo-drcn.platform.dbankcloud.cn' # 域名 +PORT = 443 # 端口号 +URI = r'/higeo/v1/xgnss/agnss' # uri路径 + +# 鉴权认证相关 +APP_ID = r'' # 账号,请联系销售代表获取 +APP_SECRET = b'' # 密钥,请联系销售代表获取 +UUID = r'' # 每台设备的唯一标识码,请根据产品进行适配 + +# 请求参数 +CONSTELLATION = r'' # 掩码表示卫星模式,0x1=GPS,0x2=GLONASS,0x4=BEIDOU,0x8=GALILEO,默认15表示全模 +DATATYPE = r'' # 掩码表示请求的数据类型,0x1=星历,0x2=UTC模型,0x4=电离层参数,0x8=实时完好性信息,0x10=频点对应关系,默认31表示全部数据 + + +class AgnssRequest: + def __init__(self): + self.ts = 0 + self.qry_str = '' + self.signature = '' + self.url = '' + self.session = requests.session() + + def format_req_str(self): + qry_str = '' + if CONSTELLATION and CONSTELLATION != '15': + # constellation默认值15,则无需填写 + qry_str += f'constellation={CONSTELLATION}' + if DATATYPE and DATATYPE != '31': + # datatype默认值31,则无需填写 + qry_str += f'&datatype={DATATYPE}' if qry_str else f'datatype={DATATYPE}' + self.qry_str = qry_str + + def gen_auth_str(self): + # 构造待签名字符串 + str_to_sign = f'GET&{URI}&{self.qry_str}&&appid={APP_ID}×tamp={self.ts}' + # 计算签名HMAC值 + h1 = hmac.new(key=APP_SECRET, digestmod='sha256') + h1.update(str_to_sign.encode('utf-8')) + b1 = base64.b64encode(h1.digest()) + signature = b1.decode('utf-8') + self.signature = signature + + def update_session(self): + # 填充完整url + self.url = r'https://{}:{}{}{}{}'.format(HOST, PORT, URI, '?' if self.qry_str else '', self.qry_str) + # 组装请求消息头 + self.session.headers.update( + { + 'X-Request-ID': f'{UUID}', + 'Authorization': f'HMAC-SHA256 appid={APP_ID},timestamp={self.ts},signature={self.signature}' + } + ) + + def connect_session(self): + try: + print(f'正在连接服务器...') + rsp = self.session.get(url=self.url, verify=False, timeout=(3, 27)) + print(f'Agnss请求结果:{rsp.status_code},结果码:{rsp.reason}, 响应长度:{len(rsp.content)}') + + # 处理响应值 + if rsp.status_code == 200: + # 响应200表示请求成功 + print(r'响应内容:') + # 响应内容的Agnss辅助数据是二进制码流,转换成16进制打印 + print(binascii.hexlify(rsp.content)) + print(f'Agnss辅助数据请求成功') + with open(r'.\AGNSS.dat', 'wb') as f: + f.write(rsp.content) + elif rsp.status_code == 401: + if rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'unix时间戳异常,请检查服务器下发的响应消息头中“X-Auth-Timestamp”与请求消息头的' + r'“Authorization”中的“timestamp”是否相差很大') + print(r'请检查“timestamp”是否取用正确的UNIX时间戳,单位是毫秒') + # 如设备本身无时间系统,可在此处取用服务器下发的“X-Auth-Timestamp”进行重新请求 + print(f'响应消息头:{rsp.headers}') + server_ts = rsp.headers.get('X-Auth-Timestamp', 0) + self.ts = server_ts + # 签名认证 + self.gen_auth_str() + # 更新请求消息头 + self.update_session() + # 重新请求 + rsp2 = self.session.get(url=self.url, verify=False, timeout=(3, 27), proxies=PROXIES) + print(f'Agnss重新请求结果:{rsp2.status_code},结果码:{rsp2.reason}, 响应长度:{len(rsp2.content)}') + + elif rsp.reason == 'authorization is missed': + print(r'“Authorization”字段异常,请检查请求消息头是否正确填写“Authorization”字段') + elif rsp.reason == 'appid is missed': + print(r'“appid”字段异常,请检查请求消息头的“Authorization”中是否正确填写“appid”字段') + elif rsp.reason == 'timestamp is invalid': + print(r'“timestamp”字段异常,请检查请求消息头的“Authorization”中是否正确填写“timestamp”字段') + elif rsp.reason == 'signature is invalid': + print(r'“signature”字段异常,请检查请求消息头的“Authorization”中已填写“signature”字段') + elif rsp.reason == "Can't get the keys of appid": + print(r'“appid”无效,请检查请求消息头的“Authorization”中的“appid”的合法性') + elif rsp.reason == 'SignatureInvalid': + print(r'“signature”异常,请检查请求消息头的“Authorization”中的“signature”正确性,' + r'检查appid和app_secret是否匹配') + elif rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'异常,请检查') + elif rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'异常,请检查') + self.session.close() + except requests.exceptions.SSLError as e: + print(e) + print('请检查网络是否通畅') + except requests.exceptions.ProxyError as e: + print(e) + print('请检查网络是否通畅') + except Exception as e: + print(e) + + def request(self, ts=0): + self.ts = ts + + # step1. 构造规范化请求字符串 + self.format_req_str() + + # step2. 构造鉴权信息字符串 + self.gen_auth_str() + + # step3. 构造HTTP GET请求 + self.update_session() + print(f'请求URL:{self.url}') + + # step4. 发送请求 + self.connect_session() + + +if __name__ == '__main__': + # 获取当前UNIX时间,单位毫秒 + now = calendar.timegm(time.gmtime()) * 1000 + agnss = AgnssRequest() + agnss.request(now) 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 index 000000000..6958bd1a7 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/CMakeLists.txt @@ -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 index 000000000..bf18c6fa9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/Makefile @@ -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 index 000000000..08498a642 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/CMakeLists.txt @@ -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 index 000000000..89ea3c576 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/CMakeLists.txt @@ -0,0 +1,11 @@ +#=============================================================================== +# @brief cmake make file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +set( + tiot_controller_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/tiot_controller.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_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 index 000000000..3fe85a052 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.c @@ -0,0 +1,157 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: TIoT device controller. \n + * + * History: \n + * 2023-03-17, Create file. \n + */ + +#include +#include "tiot_device_info.h" +#include "tiot_controller.h" +#include "tiot_board_log.h" + +#define CTRL_OPEN_COUNT_MAX 0xFFFFFFFFU + +int32_t tiot_controller_init(tiot_controller *ctrl, tiot_controller_info *info) +{ + int32_t ret; + tiot_board_info *board_info = info->board_info; + const tiot_device_info *device_info = info->dev_info; + + if ((ctrl == NULL) || (ctrl->state == TIOT_CONTROLLER_INIT)) { + return -1; + } + + /***** 软件初始化 *****/ + /* 初始化open状态互斥锁. */ + ret = osal_mutex_init(&ctrl->open_mutex); + if (ret != 0) { + goto mutex_init_fail; + } + + /* 注册:1) PM状态机,如为NULL则使用默认状态机. + 2)板级PM管脚信息,依据产品不同而不同. */ + ret = tiot_pm_init(&ctrl->pm, board_info->hw_info.pm_info, + device_info->pm_event_map, device_info->pm_event_map_size); + if (ret != 0) { + goto pm_init_fail; + } + + /* 注册:1)固件加载回调,加载前 + 加载后,用于注册不同加载协议或设置波特率等,依据芯片不同而不同. */ + ret = tiot_firmware_init(&ctrl->firmware, &device_info->exec_cbs); + if (ret != 0) { + goto fw_init_fail; + } + + /* 注册:1) 接收回调 */ + ret = tiot_xfer_init(&ctrl->transfer, board_info->hw_info.xmit_id, &device_info->xfer_info); + if (ret != 0) { + goto xfer_init_fail; + } + + /* device info必须为静态分配变量. */ + ctrl->dev_info = device_info; + ctrl->state = TIOT_CONTROLLER_INIT; + ctrl->dev_cus = (uintptr_t)info->dev_cus; + + return 0; + +xfer_init_fail: + tiot_xfer_deinit(&ctrl->transfer); + memset_s((void *)&ctrl->transfer, sizeof(tiot_xfer_manager), 0, sizeof(tiot_xfer_manager)); +fw_init_fail: + memset_s((void *)&ctrl->firmware, sizeof(tiot_fw), 0, sizeof(tiot_fw)); +pm_init_fail: + memset_s((void *)&ctrl->pm, sizeof(tiot_pm), 0, sizeof(tiot_pm)); + osal_mutex_destroy(&ctrl->open_mutex); +mutex_init_fail: + return ret; +} + +int32_t tiot_controller_open(tiot_controller *ctrl, void *param) +{ + int32_t ret = 0; + if (ctrl == NULL) { + tiot_print_dbg("[TIoT]device is null.\n"); + return -1; + } + osal_mutex_lock(&ctrl->open_mutex); + if (ctrl->state == TIOT_CONTROLLER_UNINIT) { + tiot_print_err("[TIoT]dev state wrong %d.\r\n", ctrl->state); + ret = -1; + goto out; + } + if (ctrl->open_count == CTRL_OPEN_COUNT_MAX) { + tiot_print_err("[TIoT]reach max open count.\r\n"); + ret = -1; + goto out; + } + ctrl->open_count++; + if (ctrl->state == TIOT_CONTROLLER_OPEN) { + /* 重复调用open仅添加计数. */ + goto out; + } + ctrl->state = TIOT_CONTROLLER_OPENING; /* 中间状态,受mutex锁保护,不需要在open内判断. */ + if (ctrl->ops.open(ctrl, param) != 0) { + ctrl->open_count--; + ctrl->state = TIOT_CONTROLLER_INIT; + ret = -1; + goto out; + } + ctrl->state = TIOT_CONTROLLER_OPEN; +out: + osal_mutex_unlock(&ctrl->open_mutex); + return ret; +} + +bool tiot_controller_check_opened(tiot_controller *ctrl) +{ + bool ret = true; + if (ctrl == NULL) { + tiot_print_dbg("[TIoT]device is null.\n"); + return false; + } + osal_mutex_lock(&ctrl->open_mutex); + if (ctrl->state != TIOT_CONTROLLER_OPEN) { + tiot_print_dbg("[TIoT]device not opened.\n"); + ret = false; + } + osal_mutex_unlock(&ctrl->open_mutex); + return ret; +} + +void tiot_controller_close(tiot_controller *ctrl) +{ + if (ctrl == NULL) { + tiot_print_dbg("[TIoT]device is null.\n"); + return; + } + osal_mutex_lock(&ctrl->open_mutex); + if ((ctrl->state != TIOT_CONTROLLER_OPEN) && (ctrl->state != TIOT_CONTROLLER_OPENING)) { + tiot_print_dbg("[TIoT]device is not opening or not opened.\n"); + osal_mutex_unlock(&ctrl->open_mutex); + return; + } + /* 打开状态且open_count >=1时,减少open_count计数; 当open_count减少后变为0时,实际调用close操作. */ + ctrl->open_count--; + if (ctrl->open_count == 0) { + ctrl->ops.close(ctrl); + ctrl->state = TIOT_CONTROLLER_INIT; + } + osal_mutex_unlock(&ctrl->open_mutex); +} + +void tiot_controller_deinit(tiot_controller *ctrl) +{ + if ((ctrl == NULL) || (ctrl->state == TIOT_CONTROLLER_UNINIT)) { + return; + } + + tiot_xfer_deinit(&ctrl->transfer); + tiot_pm_deinit(&ctrl->pm); + osal_mutex_destroy(&ctrl->open_mutex); + (void)memset_s((void *)ctrl, sizeof(tiot_controller), 0, sizeof(tiot_controller)); + ctrl->state = TIOT_CONTROLLER_UNINIT; +} 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 index 000000000..64a0dd3cb --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller.h @@ -0,0 +1,152 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: TIoT device controller header. \n + * + * History: \n + * 2023-03-17, Create file. \n + */ + +#ifndef TIOT_CONTROLLER_H +#define TIOT_CONTROLLER_H + +#ifndef __KERNEL__ +#include +#endif +#include "tiot_board.h" +#include "tiot_pm.h" +#include "tiot_firmware.h" +#include "tiot_xfer.h" +#include "tiot_device_info.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_controller Controller + * @ingroup tiot_common + * @{ + */ + +/** + * @brief TIoT controller state. + */ +typedef enum { + TIOT_CONTROLLER_UNINIT, + TIOT_CONTROLLER_INIT, + TIOT_CONTROLLER_OPENING, + TIOT_CONTROLLER_OPEN, +} tiot_controller_state; + +/** + * @brief TIoT controller info provided outside. + */ +typedef struct { + tiot_board_info *board_info; /*!< Board infomations. */ + const tiot_device_info *dev_info; /*!< Reserved device info, must be allocated staticly. */ + const tiot_dev_customize *dev_cus; /*!< Reserved device customize. */ +} tiot_controller_info; + +struct _tiot_controller; + +/** + * @brief TIoT controller ops. + */ +typedef struct { + int32_t (* open)(struct _tiot_controller *ctrl, void *param); + void (* close)(struct _tiot_controller *ctrl); + int32_t (* write)(struct _tiot_controller *ctrl, const uint8_t *data, + uint32_t len, const tiot_xfer_tx_param *param); + int32_t (* read)(struct _tiot_controller *ctrl, uint8_t *buff, uint32_t buff_len, const tiot_xfer_rx_param *param); + int32_t (* pm_ctrl)(struct _tiot_controller *ctrl, uint8_t cmd); +} tiot_controller_ops; + +/** + * @brief TIoT device controller. + */ +typedef struct _tiot_controller { + uint32_t state; /*!< Current state. */ + tiot_pm pm; /*!< Power Manangement module. */ + tiot_fw firmware; /*!< Firmware module. */ + tiot_xfer_manager transfer; /*!< Transfer manager modele. */ + const tiot_device_info *dev_info; /*!< Reserved device info, must be allocated staticly. */ + tiot_controller_ops ops; /*!< Controller ops, open, close, write, read. */ + volatile uint32_t open_count; /*!< open count. */ + osal_mutex open_mutex; /*!< open state mutex. */ + uintptr_t dev_cus; /*!< device customize. */ +} tiot_controller; + +/** + * @brief TIoT find controller by pin from controllers. + * @param [in] ctrls TIoT controller instances array. + * @param [in] ctrl_num TIoT controller instances num. + * @param [in] pin Pin number. + * @param [in] pin_type Pin type. + * @return if found controller, return controller pointer, else return NULL. + */ +static inline tiot_controller *tiot_find_controller_by_pin(tiot_controller *ctrls, uint8_t ctrl_num, + uint32_t pin, uint32_t pin_type) +{ + const uint32_t *pm_info; + uint8_t i; + for (i = 0; i < ctrl_num; i++) { + pm_info = ctrls[i].pm.pm_info; + if (pm_info[pin_type] == pin) { + return &ctrls[i]; + } + } + return NULL; +} + +/** + * @brief TIoT controller init. + * @param [in] ctrl TIoT controller instance. + * @param [in] info TIoT controller information. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_controller_init(tiot_controller *ctrl, tiot_controller_info *info); + +/** + * @brief TIoT controller open, if already opened, add open count only. + * @param [in] ctrl TIoT controller instance. + * @param [in] param TIoT controller open param. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_controller_open(tiot_controller *ctrl, void *param); + +/** + * @brief TIoT controller check opened or not, must be used after init. + * @param [in] ctrl TIoT controller instance. + * @return true if Opened; + * false if not opened. + */ +bool tiot_controller_check_opened(tiot_controller *ctrl); + +/** + * @brief TIoT controller close, if opened multiple times, only remove open count. + * @param [in] ctrl TIoT controller instance. + */ +void tiot_controller_close(tiot_controller *ctrl); + +/** + * @brief TIoT controller deinit. + * @param [in] ctrl TIoT controller instance. + */ +void tiot_controller_deinit(tiot_controller *ctrl); + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..e0e02e1a1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_controller_helper.h @@ -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 index 000000000..cd4f54f88 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/controller/tiot_device_info.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Device info header. \n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#ifndef TIOT_DEVICE_INFO_H +#define TIOT_DEVICE_INFO_H + +#include "tiot_pm.h" +#include "tiot_firmware.h" +#include "tiot_xfer.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_device Device Interface + * @ingroup tiot_common_interface + * @{ + */ + +/** + * @brief Device common timing specs. + */ +typedef struct { + const uint32_t power_on_wait_ms; /*!< Before power on wait time. */ + const uint32_t boot_time_ms; /*!< Boot wait time. */ + const uint32_t init_time_ms; /*!< Init time wait time. */ + const uint32_t wakeup_pulse_ms; /*!< Wakeup pin pulse time. */ + const uint32_t wakeup_wait_ms; /*!< Wakeup wait time. */ + const uint32_t baud_change_wait_us; /*!< Baudrate change wait time. */ +} tiot_device_timings; + +struct _tiot_controller; + +/** + * @brief Device infomations to be registed in driver. + */ +typedef struct { + /*!< Power management event map, set NULL if use default event map. */ + tiot_pm_event_entry *pm_event_map; + uint8_t pm_event_map_size; + /*!< Firmware callback called before and after commands execute. */ + const tiot_fw_ops exec_cbs; + + /*!< Transfer */ + tiot_xfer_device_info xfer_info; + + /*!< Tiot packet sys msg handle. */ + void (*pkt_sys_msg_handle)(struct _tiot_controller *ctrl, uint8_t code); + + tiot_device_timings timings; +} tiot_device_info; + +typedef struct { + uintptr_t start_data; + uintptr_t curr_data; + uintptr_t end_data; + uint32_t unit_data_len; +} tiot_dev_customize; + +/** + * @} + */ + +#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/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt new file mode 100644 index 000000000..4f6793eed --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/CMakeLists.txt @@ -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 index 000000000..b69bf1d85 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.c @@ -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 index 000000000..23a4069a5 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/cfg_handle_priv/tiot_cfg_handle_priv.h @@ -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 index 000000000..0219376e6 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.c @@ -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 +#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 index 000000000..37d184d79 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware.h @@ -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 index 000000000..a4b7e0f98 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/fw_load/tiot_firmware_utils.h @@ -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 index 000000000..fc47d8935 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/CMakeLists.txt @@ -0,0 +1,20 @@ +#=============================================================================== +# @brief cmake make file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +set( + tiot_interface_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_internal/tiot_board_xmit_ops.c + ${CMAKE_CURRENT_SOURCE_DIR}/device_interface/tiot_service_interface.c +) + +set( + interface_header_lists + "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_internal" + "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/board_porting" + "${CMAKE_CURRENT_SOURCE_DIR}/board_interface/osal_porting" + "${CMAKE_CURRENT_SOURCE_DIR}/device_interface" +) + +set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${interface_header_lists}" CACHE INTERNAL "tiot header list" FORCE) +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 index 000000000..cae119bd4 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board.h @@ -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 index 000000000..9de1f1fee --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_log.h @@ -0,0 +1,81 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board log header. \n + * + * History: \n + * 2023-03-24, Create file. \n + */ +#ifndef TIOT_BOARD_LOG_H +#define TIOT_BOARD_LOG_H + +#include "tiot_board_log_port.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_board_internal_log Board Log + * @ingroup tiot_common_interface_board_internal + * @{ + */ + +#define TIOT_LOG_ALERT 0 /*!< Log level alert. */ +#define TIOT_LOG_ERR 1 /*!< Log level error. */ +#define TIOT_LOG_WARNING 2 /*!< Log level warning. */ +#define TIOT_LOG_INFO 3 /*!< Log level info. */ +#define TIOT_LOG_DEBUG 4 /*!< Log level debug. */ + +#ifndef TIOT_BOARD_LOG_LEVEL +#define TIOT_BOARD_LOG_LEVEL TIOT_LOG_INFO +#endif + +/* 宏定义 */ +#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_DEBUG +#define TIOT_PRINT_FUNCTION_NAME BOARD_PRINT_FUNCTION_NAME +#define tiot_print_dbg(s, ...) board_print_dbg(s, ##__VA_ARGS__) +#else +#define TIOT_PRINT_FUNCTION_NAME +#define tiot_print_dbg(s, ...) +#endif + +#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_INFO +#define tiot_print_info(s, ...) board_print_info(s, ##__VA_ARGS__) +#define tiot_print_suc(s, ...) board_print_suc(s, ##__VA_ARGS__) +#else +#define tiot_print_info(s, ...) +#define tiot_print_suc(s, ...) +#endif + +#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_WARNING +#define tiot_print_warning(s, ...) board_print_warning(s, ##__VA_ARGS__) +#else +#define tiot_print_warning(s, ...) +#endif + +#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_ERR +#define tiot_print_err(s, ...) board_print_err(s, ##__VA_ARGS__) +#else +#define tiot_print_err(s, ...) +#endif + +#if TIOT_BOARD_LOG_LEVEL >= TIOT_LOG_ALERT +#define tiot_print_alert(s, ...) board_print_alter(s, ##__VA_ARGS__) +#else +#define tiot_print_alert(s, ...) +#endif + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..6a23acb3c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board transmit io common header. \n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#ifndef TIOT_BOARD_XMIT_H +#define TIOT_BOARD_XMIT_H + +#include "tiot_types.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_board_internal_xmit Board Transmit + * @ingroup tiot_common_interface_board_internal + * @{ + */ + +/** + * @brief Transmit handle, compatible for board transmit handle. + */ +typedef void *tiot_xmit_handle; + +/** + * @brief Universal transmit config, compatible for all types of transmit io. + */ +struct tiot_xmit_config; + +/** + * @brief Transmit object. + */ +typedef struct { + uintptr_t id; /*!< Transmit io id. + If board io operations use index, set this id in port open interface. */ + tiot_xmit_handle handle; /*!< Transmit handle compatible for board io handle. + If board io operations use handle, set this handle in port open interface. */ +} tiot_xmit; + +/** + * @brief Transmit callbacks, registed in port open interface. + */ +typedef struct { + /*!< Rx data receive notify callback when use asynchronous board interface to read data. */ + void (*rx_notify)(tiot_xmit *xmit, uint8_t *data, uint32_t len); +} tiot_xmit_callbacks; + +/** + * @} + */ + +#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_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 index 000000000..32741b1a2 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.c @@ -0,0 +1,62 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board Transmit select. \n + * + * History: \n + * 2023-03-27, Create file. \n + */ +#include "tiot_board_xmit_ops.h" + +const tiot_xmit_ops g_tiot_xmit_ops_map[TIOT_XMIT_TYPE_BUTT] = { +#ifdef CONFIG_XMIT_WITH_UART + { + .open = tiot_board_uart_open, + .close = tiot_board_uart_close, + .write = tiot_board_uart_write, + .read = tiot_board_uart_read, + .set_config = tiot_board_uart_set_config, +#ifdef CONFIG_UART_RX_MODE_BUFFED + .rx_mode = TIOT_XMIT_RX_MODE_BUFFED, +#else + .rx_mode = TIOT_XMIT_RX_MODE_POLL, +#endif + }, +#endif +#ifdef CONFIG_XMIT_WITH_SPI + { + .open = tiot_board_spi_open, + .close = tiot_board_spi_close, + .write = tiot_board_spi_write, + .read = tiot_board_spi_read, + .set_config = tiot_board_spi_set_config, +#ifdef CONFIG_SPI_RX_MODE_BUFFED + .rx_mode = TIOT_XMIT_RX_MODE_BUFFED, +#else + .rx_mode = TIOT_XMIT_RX_MODE_POLL, +#endif + }, +#endif +#ifdef CONFIG_XMIT_WITH_I2C + { + .open = tiot_board_i2c_open, + .close = tiot_board_i2c_close, + .write = tiot_board_i2c_write, + .read = tiot_board_i2c_read, + .set_config = tiot_board_i2c_set_config, +#ifdef CONFIG_I2C_RX_MODE_BUFFED + .rx_mode = TIOT_XMIT_RX_MODE_BUFFED, +#else + .rx_mode = TIOT_XMIT_RX_MODE_POLL, +#endif + }, +#endif +}; + +const tiot_xmit_ops *tiot_xmit_get_ops(tiot_xmit_type type) +{ + if (type >= TIOT_XMIT_TYPE_BUTT) { + return NULL; + } + return &g_tiot_xmit_ops_map[type]; +} \ 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 index 000000000..fa8bca9bf --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_internal/tiot_board_xmit_ops.h @@ -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 index 000000000..3667f94e8 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/gnss_board_port.h @@ -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 index 000000000..55f976cae --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_misc_port.h @@ -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 index 000000000..e2a88b257 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_pin_port.h @@ -0,0 +1,100 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board pin porting header. \n + * + * History: \n + * 2023-03-24, Create file. \n + */ +#ifndef TIOT_BOARD_PIN_PORT_H +#define TIOT_BOARD_PIN_PORT_H + +#include "tiot_types.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_board_porting_pin Board Pin Port + * @ingroup tiot_common_interface_board_porting + * @{ + */ + +/** + * @brief Pin none, board port should use this macro if pin is not connected. + */ +#define TIOT_PIN_NONE 0xFFFFFFFFU +#define TIOT_PIN_UART_WAKEUP_NUM 0x80000000U /* 用于uart rx唤醒. */ + +/** + * @brief Pin level enum. + */ +typedef enum { + TIOT_PIN_LEVEL_LOW, /*!< 0: Pin level low. */ + TIOT_PIN_LEVEL_HIGH /*!< 1: Pin level high. */ +} tiot_pin_level; + +/** + * @brief Pin interrupt enable enum. + */ +typedef enum { + TIOT_PIN_INT_DISABLE, /*!< 0: Pin interrupt disable. */ + TIOT_PIN_INT_ENABLE /*!< 1: Pin interrupt enable. */ +} tiot_pin_int_enable; + +/** + * @brief Pin interrupt callback type, need input corresponding pin. + */ +typedef void (* tiot_pin_int_callback)(uint32_t pin); + +/** + * @brief Board set pin level interface. + * @param [in] pin Pin id. + * @param [in] level Pin level, see @ref tiot_pin_level. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level); + +/** + * @brief Board get current pin level interface. + * @param [in] pin Pin id. + * @param [out] level Current pin level, see @ref tiot_pin_level. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level); + +/** + * @brief Board pin interrupt enable interface. + * @param [in] pin Pin id. + * @param [in] int_enable Interrupt enable or disable, see @ref tiot_pin_int_enable. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable); + +/** + * @brief Board pin interrupt callback register interface. + * @note Porting should ensure this callback is called when enters pin irq if interrupt enabled. + * @param [in] pin Pin id. + * @param [in] int_cb Registed interrupt callback, see @ref tiot_pin_int_callback. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb); + +/** + * @} + */ + +#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_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 index 000000000..406cb485c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/board_porting/tiot_board_uart_port.h @@ -0,0 +1,122 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board UART porting header. \n + * + * History: \n + * 2023-03-24, Create file. \n + */ +#ifndef TIOT_BOARD_UART_PORT_H +#define TIOT_BOARD_UART_PORT_H + +#include "tiot_board_xmit.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_board_porting_uart Board UART Port + * @ingroup tiot_common_interface_board_porting + * @{ + */ + +#define TIOT_UART_ATTR_DATABIT_8 0 /*!< UART word length is 8 data bits per frame. */ +#define TIOT_UART_ATTR_DATABIT_7 1 /*!< UART word length is 7 data bits per frame. */ +#define TIOT_UART_ATTR_DATABIT_6 2 /*!< UART word length is 6 data bits per frame. */ +#define TIOT_UART_ATTR_DATABIT_5 3 /*!< UART word length is 5 data bits per frame. */ +#define TIOT_UART_ATTR_DATABIT_BUTT 4 /*!< UART word length butt. */ + +#define TIOT_UART_ATTR_PARITY_NONE 0 /*!< no UART parity bit. */ +#define TIOT_UART_ATTR_PARITY_ODD 1 /*!< odd UART parity bit. */ +#define TIOT_UART_ATTR_PARITY_EVEN 2 /*!< even UART parity bit. */ +#define TIOT_UART_ATTR_PARITY_MARK 3 /*!< UART parity bit is always 1. */ +#define TIOT_UART_ATTR_PARITY_SPACE 4 /*!< UART parity bit is always 0. */ +#define TIOT_UART_ATTR_PARITY_BUTT 5 /*!< UART parity bit butt. */ + +#define TIOT_UART_ATTR_STOPBIT_1 0 /*!< UART has 1 stop bit. */ +#define TIOT_UART_ATTR_STOPBIT_1P5 1 /*!< UART has 1.5 stop bits. */ +#define TIOT_UART_ATTR_STOPBIT_2 2 /*!< UART has 2 stop bits. */ +#define TIOT_UART_ATTR_STOPBIT_BUTT 3 /*!< UART stop bits butt. */ + +#define TIOT_UART_ATTR_FLOW_CTRL_DISABLE 0 /*!< UART flow control is disabled. */ +#define TIOT_UART_ATTR_FLOW_CTRL_ENABLE 1 /*!< UART flow control enabled. */ + +/** + * @brief Uart attribute. + * + */ +typedef struct { + uint16_t data_bits : 4; + uint16_t parity : 4; + uint16_t stop_bits : 4; + uint16_t flow_ctrl : 4; + uint16_t reserved : 16; +} tiot_uart_attr; + +/** + * @brief Uart config. + * + */ +typedef struct tiot_xmit_config { + uint32_t baudrate; /*!< UART baudrate. */ + tiot_uart_attr attr; /*!< UART attribute. */ +} tiot_uart_config; + +/** + * @brief Board UART open interface. + * @param [in] xmit Transmit object. + * @param [in] cb Transmit callbacks. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cb); + +/** + * @brief Board UART close interface. + * @param [in] xmit Transmit object. + */ +void tiot_board_uart_close(tiot_xmit *xmit); + +/** + * @brief Board UART write interface. + * @param [in] xmit Transmit object. + * @param [in] buff Data buff. + * @param [in] len Data length. + * @return zero or postive for writen OK length; + * negtive if write FAIL. + */ +int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len); + +/** + * @brief Board UART blocking read interface. + * @param [in] xmit Transmit object. + * @param [in] buff Read buff. + * @param [in] len Expected read length. + * @return zero or postive for read OK length; + * negtive if read FAIL or cannot implemented. + */ +int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len); + +/** + * @brief Board UART config interface. + * @param [in] xmit Transmit object. + * @param [in] config UART config, see @ref tiot_uart_config. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config); + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..0a78cb121 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/board_interface/osal_porting/tiot_osal.h @@ -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 index 000000000..643b39aae --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.c @@ -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, ¶m); +} + +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, ¶m); +} + +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 index 000000000..506a0f54b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface.h @@ -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 +#include +#include +#else +#include +#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 index 000000000..37bcd4158 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/interface/device_interface/tiot_service_interface_ext.h @@ -0,0 +1,98 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * Description: \n + * + * History: \n + * 2024-01-29, Create file. \n + */ +#ifndef TIOT_SERVICE_INTERFACE_EXT_H +#define TIOT_SERVICE_INTERFACE_EXT_H + +#include "tiot_service_interface.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_service_ext Service Interface Ext + * @ingroup tiot_common_interface + * @{ + */ + +/** + * @brief TIoT Tx param, for tiot_service_write_ext. + */ +typedef struct { + uint32_t subsys; /*!< Write for which sub system, varies for different device. */ +} tiot_service_tx_param; + +/** + * @brief TIoT Rx param, for tiot_service_read_ext. + */ +typedef struct { + uint32_t timeout_ms; /*!< Wait timeout ms. */ + uint32_t subsys; /*!< Read for which sub system, varies for different device. */ +#ifdef __KERNEL__ + struct file *filp; /*!< for poll */ + poll_table *poll_wait; /*!< for poll */ +#endif +} tiot_service_rx_param; + +typedef enum { + TIOT_PM_CTRL_SUSPEND_PREPARE, + TIOT_PM_CTRL_SUSPEND, + TIOT_PM_CTRL_RESUME_PREPARE, + TIOT_PM_CTRL_RESUME, + TIOT_PM_CTRL_BUTT +} tiot_service_pm_ctrl_cmd; + +/** + * @brief TIoT Service Write Message extende interface. + * @param [in] data Data need to send. + * @param [in] len Data length. + * @param [in] param Write Param, see @ref tiot_service_tx_param. + * @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_ext(tiot_handle handle, const uint8_t *data, + uint32_t len, const tiot_service_tx_param *param); + +/** + * @brief TIoT Service Read Message extended interface. + * @param [in/out] buff User read buff. + * @param [in] buff_len User read buff size. + * @param [in] param Read Param, see @ref tiot_service_rx_param. + * @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_ext(tiot_handle handle, uint8_t *buff, uint32_t buff_len, const tiot_service_rx_param *param); + +/** + * @brief TIoT Service Pm Control interface. + * @param [in] handle Service instance handle, should be return by tiot_service_open. + * @param [in] cmd Service pm ctrl cmd. + * @return return 0 if success else return -1. + */ +int32_t tiot_service_pm_ctrl(tiot_handle handle, tiot_service_pm_ctrl_cmd cmd); + +/** + * @} + */ + +#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/libboundscheck/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt new file mode 100644 index 000000000..39d8819ea --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/CMakeLists.txt @@ -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 index 000000000..d93305600 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securec.h @@ -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 +#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 +#else +#include +#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 index 000000000..69e79c2f9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/include/securectype.h @@ -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 +#include +#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 +#endif +#if SECUREC_HAVE_STRING_H +#include +#endif +#if SECUREC_HAVE_STDLIB_H +#include +#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 +#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 index 000000000..6513bc423 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/Makefile @@ -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 index 000000000..d3c7f06c1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * 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 index 000000000..bd0f12a96 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/fwscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * 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 index 000000000..d12495aa0 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/gets_s.c @@ -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 */ + } +} + +/* + * + * 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. + * + * + * buffer Storage location for input string. + * destMax The size of the buffer. + * + * + * buffer is updated + * + * + * 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 index 000000000..9727d5e89 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/input.inl @@ -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 +#endif +#else +#if !defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT) +#include +#ifdef SECUREC_FOR_WCHAR +#include /* 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 index 000000000..612f6e242 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memcpy_s.c @@ -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 + +/* + * + * The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy + * + * + * dest buffer is updated. + * + * + * 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 index 000000000..ff61fca91 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memmove_s.c @@ -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 + +/* + * + * The memmove_s function copies count bytes of characters from src to dest. + * This function can be assigned correctly when memory overlaps. + * + * dest Destination object. + * destMax Size of the destination buffer. + * src Source object. + * count Number of characters to copy. + * + * + * dest buffer is updated. + * + * + * 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 index 000000000..226fb175d --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/memset_s.c @@ -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; +} + +/* + * + * 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. + * + * + * dest Pointer to destination. + * destMax The size of the buffer. + * c Character to set. + * count Number of characters. + * + * + * dest buffer is updated. + * + * + * 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 index 000000000..9392efaaf --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/output.inl @@ -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, "ient, &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, "ient, &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 index 000000000..fa5470b85 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/scanf_s.c @@ -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" + +/* + * + * 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. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * 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 index 000000000..176ee05d9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secinput.h @@ -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 index 000000000..935cf3583 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.c @@ -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 +#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 index 000000000..7e3bd691f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/securecutil.h @@ -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 index 000000000..8a1e67813 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_a.c @@ -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 index 000000000..12c9ef813 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureinput_w.c @@ -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 +#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 index 000000000..a00b10dff --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput.h @@ -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 index 000000000..b2b4b6a65 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_a.c @@ -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 +#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 index 000000000..672c0184c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/secureprintoutput_w.c @@ -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 +#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 index 000000000..b8b83dc5b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/snprintf_s.c @@ -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 +/* + * + * 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. + * + * + * 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. + * + * + * strDest is updated + * + * + * 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 +/* + * + * 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. + * + * + * 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. + * + * + * strDest is updated + * + * + * 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 index 000000000..a0398532d --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sprintf_s.c @@ -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" + +/* + * + * 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. + * + * + * strDest Storage location for output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * 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 index 000000000..b441329e1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/sscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * 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 index 000000000..13b56a8c8 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcat_s.c @@ -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; +} + +/* + * + * 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. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * 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 index 000000000..78f2e6f77 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strcpy_s.c @@ -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); +} + +/* + * + * 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. + * + * + * strDest Location of destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * 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 index 000000000..e9d0b94a3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncat_s.c @@ -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; +} + +/* + * + * 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. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * 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 index 000000000..fe8b29137 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strncpy_s.c @@ -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); +} + +/* + * + * 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. + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * 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 index 000000000..e5689e885 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/strtok_s.c @@ -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; +} + +/* + * + * 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 + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls + * to strtok_s + * + * context is updated + * + * 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 index 000000000..09d77a2fc --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swprintf_s.c @@ -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" + +/* + * + * The swprintf_s function is the wide-character equivalent of the sprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * 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 index 000000000..e5b8bbfc7 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/swscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * 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 index 000000000..214ee6a21 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..1ab9c3cb5 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vfwscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..61480a697 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..a4bec703f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsnprintf_s.c @@ -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 +/* + * + * 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. + * + * + * 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. + * + * + * strDest is updated + * + * + * 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 +/* + * + * 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. + * + * + * 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. + * + * + * strDest is updated + * + * + * 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 index 000000000..23bf04aa9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsprintf_s.c @@ -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" + +/* + * + * 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. + * + * + * strDest Storage location for the output. + * destMax Size of strDest + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * 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 index 000000000..a19abe2b9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vsscanf_s.c @@ -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 +#endif + +/* + * + * vsscanf_s + * + * + * + * 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. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..29715fc62 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswprintf_s.c @@ -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" + +/* + * + * The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * 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 index 000000000..bab53a3e1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vswscanf_s.c @@ -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))); +} + +/* + * + * 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. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..b39f9bc74 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/vwscanf_s.c @@ -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" + +/* + * + * 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. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * 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 index 000000000..fa7d847c2 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscat_s.c @@ -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; +} + +/* + * + * 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. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * 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 index 000000000..8c4a4af8b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcscpy_s.c @@ -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; + } +} + +/* + * + * 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 + + * + * strDest Destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * 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 index 000000000..33e53a324 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncat_s.c @@ -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; +} + +/* + * + * 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. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * 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 index 000000000..463f90e16 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcsncpy_s.c @@ -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; + } +} + +/* + * + * 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 + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * 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 index 000000000..063ca6917 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wcstok_s.c @@ -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; +} + +/* + * + * wcstok_s + * + * + * + * The wcstok_s function is the wide-character equivalent of the strtok_s function + * + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls to + * wcstok_s. + * + * + * context is updated + * + * 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 index 000000000..2f2b4a33c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemcpy_s.c @@ -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" + +/* + * + * The wmemcpy_s function copies n successive wide characters + * from the object pointed to by src into the object pointed to by dest.t. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy. + * + * + * dest buffer is updated. + * + * + * 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 index 000000000..88bb97b90 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wmemmove_s.c @@ -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" + +/* + * + * The wmemmove_s function copies n successive wide characters from the object pointed + * to by src into the object pointed to by dest. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Source object. + * count Number of bytes or character to copy. + * + * + * dest is updated. + * + * + * 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 index 000000000..badb04efa --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/libboundscheck/src/wscanf_s.c @@ -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" + +/* + * + * + * 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. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * 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 index 000000000..6d6660d58 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/CMakeLists.txt @@ -0,0 +1,18 @@ +#=============================================================================== +# @brief cmake make file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +set( + tiot_pm_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm.c + ${CMAKE_CURRENT_SOURCE_DIR}/tiot_pm_wakelock.c +) + +add_subdirectory(pm_default) + +if(DEFINED CONFIG_DEV_TIOT_SLAVE) +add_subdirectory(pm_slave) +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_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 index 000000000..3f3d898cb --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/CMakeLists.txt @@ -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 index 000000000..01a60ef2c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.c @@ -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 index 000000000..b9d4f9f61 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_default/tiot_pm_default.h @@ -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 index 000000000..cdc63caba --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/CMakeLists.txt @@ -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 index 000000000..7e8669b36 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.c @@ -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 index 000000000..7c15a973f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/pm_slave/tiot_pm_slave.h @@ -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 index 000000000..10a51fe9e --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.c @@ -0,0 +1,149 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Power Manager module. \n + * + * History: \n + * 2023-03-27, Create file. \n + */ + +#include "tiot_pm.h" +#include "tiot_pm_wakelock.h" +#include "tiot_osal.h" +#include "securec.h" +#include "tiot_controller.h" +#include "tiot_board_log.h" + +typedef struct { + tiot_pm *pm; + uint16_t state; +} pm_wait_state; + +/* 传入的event_map必须为静态申请数组 */ +int32_t tiot_pm_init(tiot_pm *pm, const uint32_t *pm_info, + const tiot_pm_event_entry *event_map, uint8_t event_map_size) +{ + if ((pm == NULL) || (pm_info == NULL) || (event_map == NULL) || (event_map_size == 0)) { + tiot_print_dbg("[TIoT][pm]pm or pm info or event_map is NULL.\n"); + return -1; + } + if (osal_wait_init(&pm->state_wait) != OSAL_SUCCESS) { + tiot_print_err("[TIoT][pm]pm wait init fail.\n"); + return -1; + } + + /* 外部确保为静态变量 */ + pm->pm_info = pm_info; + pm->event_map = event_map; + pm->event_map_size = event_map_size; + + /* 此队列仅用于处理中断内产生pm事件情况,按产生顺序排序,预计不会同时在多个中断内产生pm事件,预留8个已经足够. */ + (void)memset_s(pm->event_queue_buff, TIOT_PM_EVENT_BUFF_MAX, 0, TIOT_PM_EVENT_BUFF_MAX); + tiot_circ_queue_init(&pm->event_queue, TIOT_PM_EVENT_BUFF_MAX, + sizeof(tiot_pm_event), (uintptr_t)pm->event_queue_buff); + pm->is_in_event = 0; + pm->work_vote = 0; + pm->state = TIOT_PM_STATE_POWEROFF; + return 0; +} + +static int32_t tiot_pm_handle_event(tiot_pm *pm, tiot_pm_event event) +{ + tiot_pm_retcode ret = TIOT_PM_EVTRET_NEXT_STATE; + /* 取对应事件的 [判断条件 - 执行处理 - 设置下个状态] 流程 */ + const tiot_pm_event_entry *entry = &pm->event_map[event]; + + /* 当前状态不符合tag mask条件, 不需要处理,直接返回OK */ + if ((pm->state & entry->condition_mask) == 0) { + tiot_print_dbg("[TIoT][pm]state %x not match condition %x, ignore event\n", pm->state, entry->condition_mask); + return 0; + } + + /* pm处理过程持唤醒锁,防止pm未转换完状态就直接进sleep。 */ + tiot_pm_wake_lock(); + + /* 当前状态符合tag mask条件,执行对应事件处理 */ + /* 约定:handler为空不需要处理,例如上报业务消息说明芯片处于WORK状态,只需要切换状态即可 */ + if (entry->handler != NULL) { + ret = entry->handler(pm); + } + + if (ret == TIOT_PM_EVTRET_NEXT_STATE) { + /* 处理成功,设为下一个状态 */ + tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, next_st: %x.\n", event, pm->state, entry->next_state); + pm->state = entry->next_state; + /* 切换状态时保证设置event. */ + osal_wait_wakeup_interruptible(&pm->state_wait); + } else if (ret == TIOT_PM_EVTRET_FAIL) { + /* 处理失败,返回false. */ + tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, event fail.\n", event, pm->state); + tiot_pm_wake_unlock(); + return -1; + } else { /* ret == TIOT_PM_EVTRET_KEEP_STATE */ + /* 处理成功,保持当前状态 */ + tiot_print_dbg("[TIoT][pm]evt:%x, st:%x, keep state.\n", event, pm->state); + } + tiot_pm_wake_unlock(); + + return 0; +} + +int32_t tiot_pm_set_event(tiot_pm *pm, tiot_pm_event event) +{ + int32_t ret; + tiot_pm_event *event_node; + + if ((pm == NULL) || (event >= TIOT_PM_EVENT_MAX) || (event >= pm->event_map_size)) { + tiot_print_dbg("[TIoT][pm]pm is NULL or illegal event.\n"); + return -1; + } + + tiot_circ_queue_enqueue(&pm->event_queue, (uintptr_t)&event); + /* 依靠队列防止pm事件处理嵌套,此处不使用互斥锁(可能在中断内产生事件),也不使用自旋锁(不能保证提供自旋锁) */ + if (pm->is_in_event == 1) { + return 0; + } + + do { + event_node = (tiot_pm_event *)tiot_circ_queue_dequeue(&pm->event_queue); + if (event_node == NULL) { + return 0; + } + pm->is_in_event = 1; + ret = tiot_pm_handle_event(pm, *event_node); + pm->is_in_event = 0; + if (ret != 0) { + tiot_circ_queue_clear(&pm->event_queue); + break; + } + } while (event_node != NULL); + + return ret; +} + +static int pm_wait_state_condition(const void *param) +{ + pm_wait_state *wait_state = (pm_wait_state *)param; + return (wait_state->pm->state == wait_state->state); +} + +int32_t tiot_pm_wait_state(tiot_pm *pm, uint16_t state, uint32_t wait_timeout) +{ + pm_wait_state wait_state = { 0 }; + if (state == TIOT_PM_STATE_INVALID) { + return -1; + } + wait_state.pm = pm; + wait_state.state = state; + return osal_wait_timeout_interruptible(&pm->state_wait, pm_wait_state_condition, &wait_state, wait_timeout); +} + +void tiot_pm_deinit(tiot_pm *pm) +{ + tiot_circ_queue_clear(&pm->event_queue); + osal_spin_lock_destroy(&pm->event_queue.lock); + osal_wait_destroy(&pm->state_wait); + (void)memset_s(pm->event_queue_buff, TIOT_PM_EVENT_BUFF_MAX, 0, TIOT_PM_EVENT_BUFF_MAX); + pm->state = TIOT_PM_STATE_INVALID; + pm->work_vote = 0; +} \ 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 index 000000000..587d6c714 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm.h @@ -0,0 +1,182 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Power Manager module header. \n + * + * History: \n + * 2023-03-27, Create file. \n + */ +#ifndef TIOT_PM_H +#define TIOT_PM_H + +#include "tiot_types.h" +#include "tiot_circ_queue.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_pm Power Manager + * @ingroup tiot_common + * @{ + */ + +#define TIOT_PM_EVENT_BUFF_MAX 8 + +/** + * @brief TIoT PM tags. + */ +typedef enum { + TIOT_PM_TAG_INVALID = 0, /*!< Invalid PM tag. */ + TIOT_PM_TAG_POWEROFF = ((uint16_t)1 << 0), /*!< Power off tag. */ + TIOT_PM_TAG_POWERON = ((uint16_t)1 << 1), /*!< Power on tag. */ + /* Low power tags. */ + TIOT_PM_TAG_CAN_WORK = ((uint16_t)1 << 2), /*!< Low power can work tag. */ + TIOT_PM_TAG_CAN_SLEEP = ((uint16_t)1 << 3), /*!< Low power can sleep tag. */ + TIOT_PM_TAG_CAN_WAKEUP = ((uint16_t)1 << 4), /*!< Low power can wakeup tag. */ + TIOT_PM_TAG_CAN_ALLOW_SLEEP = ((uint16_t)1 << 5), /*!< Low power can allow sleep tag. */ + TIOT_PM_TAG_MAX = (uint16_t)0xFFFF /* PM tag max. */ +} tiot_pm_tag; + +/** + * @brief TIoT PM states. + */ +typedef enum { + TIOT_PM_STATE_INVALID = 0, /*!< Invalid PM state. */ + TIOT_PM_STATE_POWEROFF = TIOT_PM_TAG_POWEROFF, /*!< Power off state. */ + TIOT_PM_STATE_POWERON = TIOT_PM_TAG_POWERON, /*!< Power on state. */ + /* Low power states */ + /*!< Low power init state, can work, can sleep. */ + TIOT_PM_STATE_INIT = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WORK | TIOT_PM_TAG_CAN_SLEEP, + /*!< Low power work state, can sleep, can allow sleep. */ + /*!< Host: WORK -> SLEEPING -> SLEEP (正常睡眠流程,等待sleep ack) + WORK -> SLEEP (非S3状态,不等待sleep ack) + Device: WORK -> SLEEPING -> SLEEP (Device主动请求睡眠) + WORK -> SLEEP (S3状态,Host强制要求睡眠) */ + TIOT_PM_STATE_WORK = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_SLEEP | TIOT_PM_TAG_CAN_ALLOW_SLEEP, + /*!< Low power sleep state, can work, can be waked up. */ + TIOT_PM_STATE_SLEEP = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WORK | TIOT_PM_TAG_CAN_WAKEUP, + /*!< Low power waking state, can be waked up. */ + TIOT_PM_STATE_WAKING = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_WAKEUP, + /*!< Low power sleeping state, can allow sleep. */ + TIOT_PM_STATE_SLEEPING = TIOT_PM_TAG_POWERON | TIOT_PM_TAG_CAN_SLEEP +} tiot_pm_state; + +/** + * @brief Tiot PM event types. + */ +typedef enum { + /* OUTPUT */ + TIOT_PM_EVENT_POWEROFF, /*!< Power off. */ + TIOT_PM_EVENT_POWERON, /*!< Power on. */ + TIOT_PM_EVENT_WAKEUP, /*!< Host: wakeup device. + Device: wakeup host(pull up dev_wkup_host gpio). */ + /* INPUT,for host to manage device lowpower */ + TIOT_PM_EVENT_WAKEUP_ACK, /*!< Host: send disallow sleep cmd to ack(device wakeup host). + Device: handle the ack of disallow sleep cmd. */ + TIOT_PM_EVENT_REQUEST_SLEEP, /*!< Host: send allow sleep cmd. + Device: send request sleep cmd to request sleep. */ + TIOT_PM_EVENT_SLEEP_ACK, /*!< Host: handle the ack of allow sleep cmd. + Device: pull down dev_wkup_host gpio to ack (host allow sleep cmd). */ + TIOT_PM_EVENT_REQUEST_SLEEP_ACK, /*!< Combine TIOT_PM_EVENT_REQUEST_SLEEP and TIOT_PM_EVENT_SLEEP_ACK */ + TIOT_PM_EVENT_REPORT_WORK, /*!< Device transmit port report message. */ + /* Vote */ + TIOT_PM_EVENT_WORK_VOTE_UP, /*!< Host keep device at work state. */ + TIOT_PM_EVENT_WORK_VOTE_DOWN, /*!< Host not keep device at work state. */ + TIOT_PM_EVENT_MAX +} tiot_pm_event; + +/** + * @brief Tiot PM event retcode. + */ +typedef enum { + TIOT_PM_EVTRET_FAIL = -1, /* Event handle failed. */ + TIOT_PM_EVTRET_NEXT_STATE = 0, /* Change to next state. */ + TIOT_PM_EVTRET_KEEP_STATE = 1, /* Keep current state. */ +} tiot_pm_retcode; + +struct _tiot_pm; + +/** + * @brief Tiot PM event handler. + */ +typedef tiot_pm_retcode (* tiot_pm_event_handler)(struct _tiot_pm *pm); + +/** + * @brief Tiot PM event handle entry. + */ +typedef struct { + uint16_t condition_mask; /*!< Enter event condition, could be combination of PM tags. */ + uint16_t next_state; /*!< Next PM state. */ + tiot_pm_event_handler handler; /*!< PM event handler, NULL mean this event don't need operation. */ +} tiot_pm_event_entry; + +/** + * @brief Tiot PM control block. + */ +typedef struct _tiot_pm { + uint16_t state; /*!< Current PM state. */ + uint16_t work_vote; /*!< Host require device work vote. */ + const uint32_t *pm_info; /*!< PM board info, pin indexs. */ + osal_wait state_wait; /*!< PM state wait, used for wait some state. */ + tiot_circ_queue_t event_queue; /*!< PM event queue for syncing events. */ + /*!< PM event queue buffer. */ + tiot_pm_event event_queue_buff[TIOT_PM_EVENT_BUFF_MAX]; + volatile uint8_t is_in_event; /*!< PM event processing. */ + uint8_t event_map_size; /*!< PM event handle map size. */ + /*!< PM event handle map, must point to static allocated array. */ + const tiot_pm_event_entry *event_map; +} tiot_pm; + +/** + * @brief PM control block init. + * @param [in] pm PM control block. + * @param [in] pm_info Pointer to board PM info, static allocated, from device saved board info. + * @param [in] event_map Registed PM event handle map, static allocated, from *_device_info.c. + * @param [in] event_map_size Registed PM event handle map size. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_pm_init(tiot_pm *pm, const uint32_t *pm_info, + const tiot_pm_event_entry *event_map, uint8_t event_map_size); + +/** + * @brief Set event to PM control block. + * @param [in] pm PM control block. + * @param [in] event PM event. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_pm_set_event(tiot_pm *pm, tiot_pm_event event); + +/** + * @brief PM control block wait for state. + * @param [in] pm PM control block. + * @param [in] state PM state,caller must ensure state is valid. + * @param [in] wait_timeout Wait timeout, shound not be too long. + * @return negative if wait state fail; + * zero if wait state timeout; + * postive if wait state OK. + */ +int32_t tiot_pm_wait_state(tiot_pm *pm, uint16_t state, uint32_t wait_timeout); + +/** + * @brief PM control block deinit. + * @param [in] pm PM control block. + */ +void tiot_pm_deinit(tiot_pm *pm); + +/** + * @} + */ + +#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/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 index 000000000..1101a77af --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.c @@ -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 index 000000000..f29b86a0c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/pm/tiot_pm_wakelock.h @@ -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 index 000000000..9631fb6f9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/CMakeLists.txt @@ -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 index 000000000..f72d88c2f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.c @@ -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 index 000000000..154645ab4 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_handle.h @@ -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 index 000000000..7b359ff6f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_slave_handle.c @@ -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 index 000000000..7c5cb36d3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/sys_msg_handler/tiot_sys_msg_types.h @@ -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 index 000000000..7ca327843 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/CMakeLists.txt @@ -0,0 +1,21 @@ +set( + tiot_transfer_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/tiot_xfer.c + ${CMAKE_CURRENT_SOURCE_DIR}/tiot_xfer_utils.c +) + +set( + tiot_transfer_header_list + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(DEFINED CONFIG_XFER_PACKET_TIOT) +add_subdirectory(packet_handle/tiot_packet) +endif() + +if(DEFINED CONFIG_XFER_PACKET_NCI) +add_subdirectory(packet_handle/nci_packet) +endif() + +set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${tiot_transfer_src_list}" CACHE INTERNAL "tiot src list" FORCE) +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 index 000000000..5ec32712b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/CMakeLists.txt @@ -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 index 000000000..746933fae --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.c @@ -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), + ¶m->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 index 000000000..9fa18d770 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet.h @@ -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 index 000000000..9f11492ae --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.c @@ -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 index 000000000..29605bbed --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/packet_handle/tiot_packet/tiot_packet_manager.h @@ -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 index 000000000..1b82ac89f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.c @@ -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), + ¶m->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 index 000000000..1fe2165c9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer.h @@ -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 +#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 index 000000000..03937754c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.c @@ -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 index 000000000..748e53f37 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/transfer/tiot_xfer_utils.h @@ -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 index 000000000..7f5d5bcf3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/CMakeLists.txt @@ -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 index 000000000..d1e538dd9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_buf/tiot_circ_buf.h @@ -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 index 000000000..4b0bdb438 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/CMakeLists.txt @@ -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 index 000000000..f56f4a64c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.c @@ -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 +#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 index 000000000..5d2d668a6 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/circ_queue/tiot_circ_queue.h @@ -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 index 000000000..40434cf17 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/CMakeLists.txt @@ -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 index 000000000..c2179c1a0 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.c @@ -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 index 000000000..131269cc6 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/fileops/tiot_fileops.h @@ -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 index 000000000..717b5bad3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/list/tiot_list.h @@ -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 index 000000000..d20f3a5af --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/CMakeLists.txt @@ -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 index 000000000..2e2c61f49 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.c @@ -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 index 000000000..4f7e441c2 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/misc/tiot_misc.h @@ -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 index 000000000..4854c71c8 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/common/utils/tiot_types.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: TIoT types. \n + * + * History: \n + * 2023-06-01, Create file. \n + */ +#ifndef TIOT_TYPES_H +#define TIOT_TYPES_H + +#ifdef __KERNEL__ +/* 内核类型可能与编译器stdint.h冲突. */ +#include +#include +#else +#include +#endif + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_common_interface_types TIoT types. + * @ingroup tiot_common_interface + * @{ + */ +#ifndef NULL +#define NULL ((void*)0) +#endif + +/* container */ +#undef tiot_offsetof +#ifdef __compiler_offsetof +#define tiot_offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER) +#else +#define tiot_offsetof(TYPE, MEMBER) ((int)(unsigned long)&((TYPE *)0)->MEMBER) +#endif + +#ifdef _MSC_VER +#define tiot_container_of(ptr, type, member) ((type *)((char *)(const void *){ptr} - tiot_offsetof(type, member))) +#else +#define tiot_container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)((char *)__mptr - tiot_offsetof(type, member)); }) +#endif + +#define tiot_unused(var) \ + do { \ + (void)(var); \ + } while (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/device/gnss/CMakeLists.txt b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt new file mode 100644 index 000000000..adbe7fb4e --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/CMakeLists.txt @@ -0,0 +1,31 @@ +#=============================================================================== +# @brief cmake make file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +if(DEFINED CONFIG_DEV_GNSS) +set( + device_include_list + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +set( + device_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/gnss_device_info.c + ${CMAKE_CURRENT_SOURCE_DIR}/gnss_service.c +) + +if(DEFINED CONFIG_FILE_BY_ARRAY) +list( + APPEND device_src_list + ${CMAKE_CURRENT_SOURCE_DIR}/firmware/gnss_fw_file_array.c +) + +list( + APPEND device_include_list + "${CMAKE_CURRENT_SOURCE_DIR}/firmware" +) +endif() + +set(TIOT_HEADER_LIST "${TIOT_HEADER_LIST}" "${device_include_list}" CACHE INTERNAL "tiot header list" FORCE) +set(TIOT_SRC_LIST "${TIOT_SRC_LIST}" "${device_src_list}" CACHE INTERNAL "tiot src list" FORCE) +endif() 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 index 000000000..fc031188b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/Makefile @@ -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 index 000000000..362a4d6fc --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.c @@ -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 index 000000000..36312d908 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/firmware/gnss_fw_file_array.h @@ -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 index 000000000..38578d924 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.c @@ -0,0 +1,157 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: GNSS device info. \n + * + * History: \n + * 2023-03-25, Create file. \n + */ + +#include "gnss_device_info.h" +#include "tiot_pm_default.h" +#include "tiot_board_uart_port.h" +#include "tiot_board_log.h" +#include "tiot_controller.h" +#include "tiot_board_pin_port.h" +#include "tiot_cfg_handle_priv.h" +#include "tiot_sys_msg_handle.h" +#ifdef CONFIG_FILE_BY_ARRAY +#include "gnss_fw_file_array.h" +#endif + +#define GNSS_POWERON_WAIT_MS 1 /* Wait time before power on. */ +#define GNSS_BOOT_TIME_MS 200 /* Power on ==> Boot time. */ +#define GNSS_INIT_TIME_MS 600 /* Boot ==> Init time. */ +#define GNSS_WAKEUP_PULSE_MS 1 /* GPIO wake up pulse. */ +#define GNSS_WAKEUP_WAIT_MS 50 /* Wake up wait ms. */ +#define GNSS_BAUD_CHANGE_WAIT_US 11000 /* Baudrate change wait μs. */ + +#ifdef CONFIG_GNSS_TCXO_FREQ_38P4M +#define GNSS_WAKEUP_PIN_INIT_LEVEL TIOT_PIN_LEVEL_LOW +#else +#define GNSS_WAKEUP_PIN_INIT_LEVEL TIOT_PIN_LEVEL_HIGH +#endif + +#ifdef CONFIG_GNSS_UART_WITH_FLOWCTRL +#define GNSS_UART_ATTR_FLOW_CTRL TIOT_UART_ATTR_FLOW_CTRL_ENABLE +#else +#define GNSS_UART_ATTR_FLOW_CTRL TIOT_UART_ATTR_FLOW_CTRL_DISABLE +#endif + +#define GNSS_DEFAULT_UART_CONFIG \ +{ \ + 115200, \ + { .data_bits = TIOT_UART_ATTR_DATABIT_8, \ + .parity = TIOT_UART_ATTR_PARITY_NONE, \ + .stop_bits = TIOT_UART_ATTR_STOPBIT_1, \ + .flow_ctrl = GNSS_UART_ATTR_FLOW_CTRL \ + } \ +} + +static inline int32_t gnss_pin_set_level_if_exist(uint32_t pin, uint32_t pin_level) +{ + if (pin != TIOT_PIN_NONE) { + return tiot_board_pin_set_level(pin, pin_level); + } + return 0; +} + +static tiot_pm_retcode gnss_pm_power_on(tiot_pm *pm) +{ + uint32_t wakeup_device_pin = pm->pm_info[TIOT_PIN_HOST_WAKEUP_DEVICE]; + /* GNSS板级连接唤醒管脚时,上拉或下拉 */ + if (gnss_pin_set_level_if_exist(wakeup_device_pin, GNSS_WAKEUP_PIN_INIT_LEVEL) != 0) { + tiot_print_err("[TIoT][pm]set wkup pin level %d fail.\n", GNSS_WAKEUP_PIN_INIT_LEVEL); + return TIOT_PM_EVTRET_FAIL; + } + if (tiot_pm_default_power_on(pm) == TIOT_PM_EVTRET_FAIL) { + return TIOT_PM_EVTRET_FAIL; + } + if (gnss_pin_set_level_if_exist(wakeup_device_pin, TIOT_PIN_LEVEL_LOW) != 0) { + tiot_print_err("[TIoT][pm]set wkup pin level low fail.\n"); + return TIOT_PM_EVTRET_FAIL; + } + return TIOT_PM_EVTRET_NEXT_STATE; +} + +static const tiot_pm_event_entry g_gnss_pm_event_map[TIOT_PM_EVENT_MAX] = { + { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_POWEROFF, tiot_pm_default_power_off }, + /* 上电后等待init消息或业务消息才说明进入work状态 */ + /* GNSS板级连接唤醒管脚时,上电特殊处理 */ + { TIOT_PM_TAG_POWEROFF, TIOT_PM_STATE_INIT, gnss_pm_power_on }, +#ifdef CONFIG_GNSS_WAKEUP_TYPE_UART + /* 只有sleep态才需要唤醒 */ + { TIOT_PM_TAG_CAN_WAKEUP, TIOT_PM_STATE_WAKING, tiot_pm_default_wakeup_device_by_uart }, +#else + /* 只有sleep态才需要唤醒 */ + { TIOT_PM_TAG_CAN_WAKEUP, TIOT_PM_STATE_WAKING, tiot_pm_default_wakeup_device_by_gpio }, +#endif + /* 有device wakeup host管脚时,通过此管脚说明已唤醒,且需要下发disallow消息 */ + { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_WORK, tiot_pm_default_wakeup_ack_handle }, + /* 接收到request sleep消息,下发allow sleep消息 */ + { TIOT_PM_TAG_CAN_ALLOW_SLEEP, TIOT_PM_STATE_SLEEPING, tiot_pm_default_request_sleep_handle }, + /* 接收到dev wkup host gpio拉低,需要释放唤醒锁 */ + { TIOT_PM_TAG_CAN_SLEEP, TIOT_PM_STATE_SLEEP, tiot_pm_default_sleep_ack_handle }, + /* 非S3状态,下发allow sleep并释放唤醒锁 */ + { TIOT_PM_TAG_CAN_ALLOW_SLEEP, TIOT_PM_STATE_SLEEP, tiot_pm_default_request_sleep_ack_handle }, + /* 上报init消息或业务消息说明唤醒成功 */ + { TIOT_PM_TAG_CAN_WORK, TIOT_PM_STATE_WORK, NULL }, + { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_INVALID, tiot_pm_default_work_vote_up }, + { TIOT_PM_TAG_POWERON, TIOT_PM_STATE_INVALID, tiot_pm_default_work_vote_down } +}; + +static void gnss_firmware_before_load(tiot_fw *fw) +{ + /* 加载前设置为固件加载默认波特率 */ + tiot_uart_config gnss_firmware_load_config = GNSS_DEFAULT_UART_CONFIG; + tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware); + tiot_xfer_manager *xfer = &ctrl->transfer; + if (tiot_xfer_set_config(xfer, &gnss_firmware_load_config) != 0) { + tiot_print_dbg("[TIoT:fw]config before load fail.\r\n"); + } + /* 加载前先清掉rx_buff */ +#ifdef CONFIG_XFER_DEFAULT_RX_BUFF + if (xfer->xmit_ops->rx_mode == TIOT_XMIT_RX_MODE_BUFFED) { + circ_buf_flush(&xfer->rx_buff); + } +#endif +} + +static void gnss_firmware_after_load(tiot_fw *fw) +{ + /* 加载过程中可能切换波特率,加载后设置为业务默认波特率 */ + tiot_uart_config gnss_transfer_config = GNSS_DEFAULT_UART_CONFIG; + tiot_controller *ctrl = tiot_container_of(fw, tiot_controller, firmware); + tiot_xfer_manager *xfer = &ctrl->transfer; + if (tiot_xfer_set_config(xfer, &gnss_transfer_config) != 0) { + tiot_print_dbg("[TIoT:fw]config after load fail.\r\n"); + } +} + +static int gnss_rx_wait_func(const void *param) +{ + (void)param; + /* GNSS通过UART上报数据,不需要拉高管脚来通知读取 */ + return 0; +} + +static const tiot_device_info g_gnss_device_info = { + .pm_event_map = (tiot_pm_event_entry *)g_gnss_pm_event_map, + .pm_event_map_size = sizeof(g_gnss_pm_event_map) / sizeof(tiot_pm_event_entry), + .exec_cbs = { gnss_firmware_before_load, gnss_firmware_after_load, tiot_fw_ext_cmd_handle_priv, NULL }, + .xfer_info = { TIOT_XMIT_TYPE_UART, gnss_rx_wait_func }, + .pkt_sys_msg_handle = tiot_pkt_sys_msg_handle, + .timings = { + .power_on_wait_ms = GNSS_POWERON_WAIT_MS, + .boot_time_ms = GNSS_BOOT_TIME_MS, + .init_time_ms = GNSS_INIT_TIME_MS, + .wakeup_pulse_ms = GNSS_WAKEUP_PULSE_MS, + .wakeup_wait_ms = GNSS_WAKEUP_WAIT_MS, + .baud_change_wait_us = GNSS_BAUD_CHANGE_WAIT_US, + } +}; + +const tiot_device_info *gnss_device_get_info(void) +{ + return &g_gnss_device_info; +} 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 index 000000000..5356fbda1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_device_info.h @@ -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 index 000000000..6a570e531 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.c @@ -0,0 +1,434 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: \n + * + * History: \n + * 2023-03-31, Create file. \n + */ +#include "gnss_service.h" +#include "gnss_device_info.h" +#include "gnss_board_port.h" +#include "tiot_board_log.h" +#include "tiot_controller.h" +#include "tiot_controller_helper.h" +#include "tiot_packet.h" +#include "tiot_sys_msg_types.h" +#include "tiot_board_pin_port.h" +#include "tiot_board_uart_port.h" +#include "tiot_board_misc_port.h" +#include "tiot_board.h" +#include "tiot_service_interface.h" + +#ifndef CONFIG_BOARD_DYNAMIC_ALLOC +/* 加载 & 数据收发复用buffer,不同时使用 */ +/* 数据收发需求 ~10K用于缓存数据. */ +/* 固件加载时 ~3K用于保存解析后命令, ~128字节用于加载回复接收. */ +#define GNSS_FW_LOAD_REUSE_BUFF_START 0U +#define GNSS_FW_LOAD_RX_BUFF_START GNSS_FW_LOAD_REUSE_BUFF_START +#define GNSS_FW_LOAD_RX_BUFF_SIZE 128U + +#define GNSS_FW_LOAD_REUSE_BUFF_END (GNSS_FW_LOAD_RX_BUFF_START + GNSS_FW_LOAD_RX_BUFF_SIZE) + +#define GNSS_COMMON_BUFF_MAX ((CONFIG_GNSS_PACKET_BUFF_MAX > GNSS_FW_LOAD_REUSE_BUFF_END) ? \ + CONFIG_GNSS_PACKET_BUFF_MAX : GNSS_FW_LOAD_REUSE_BUFF_END) +#endif + +#define GNSS_PACKET_QUEUE_NODES 8 + +typedef enum { + GNSS_RX_SUBSYS_0 = 0, + GNSS_RX_SUBSYS_MAX +} gnss_rx_subsys_id; + +typedef enum { + GNSS_PLT_SWITCH_GUART_BPS = 0, + GNSS_PLT_SWITCH_DBGUART_BPS, + GNSS_PLT_SWITCH_UART_SELECT, + GNSS_PLT_SWITCH_HSO_OR_SDT, + GNSS_PLT_SWITCH_DBGUART_SKIP, + GNSS_PLT_CMD_MAXSIZE +} gnss_plt_cmd; + +typedef struct { + uint32_t bps; + uint32_t cr_crg; +} tiot_plt_guart_para; + +typedef struct { + uint8_t frame_start; + uint8_t func_type; + uint8_t prime_id; + uint8_t reserved; + uint16_t frame_len; + uint16_t sn; +} tiot_plt_om_header; + +typedef struct { + uint16_t cmd; + uint16_t para_len; +} tiot_plt_cmd_header; + +#pragma pack(push, 1) +typedef struct { + tiot_plt_om_header om_header; + tiot_plt_cmd_header cmd_header; + tiot_plt_guart_para para; + uint8_t tail; +} tiot_plt_guart_cmd; +#pragma pack(pop) + +#define tiot_plat_guart_baud_cmd(bps, flow_ctrl) \ +{ \ + .om_header = { 0x7e, 0x0c, 0x00, 0x00, 0x15, 0x00 }, \ + .cmd_header = { GNSS_PLT_SWITCH_GUART_BPS, sizeof(tiot_plt_guart_para) }, \ + .para = { (bps), \ + ((flow_ctrl) == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ? 0xC301 : 0x301 \ + }, \ + .tail = 0x7e \ +} + +static tiot_controller g_gnss_controllers[CONFIG_GNSS_DEV_NUM] = { 0 }; +static tiot_packet_context g_gnss_pkt_ctx[CONFIG_GNSS_DEV_NUM]; +static tiot_packet g_gnss_pkt_queue_nodes[CONFIG_GNSS_DEV_NUM][GNSS_PACKET_QUEUE_NODES]; +static tiot_packet_queue g_gnss_pkt_queues[CONFIG_GNSS_DEV_NUM][GNSS_RX_SUBSYS_MAX]; + +#ifndef CONFIG_BOARD_DYNAMIC_ALLOC +static uint8_t g_gnss_common_buff_mem[CONFIG_GNSS_DEV_NUM][GNSS_COMMON_BUFF_MAX]; +#endif + +static uint16_t gnss_packet_manager_match_func(uint32_t subsys_code) +{ + if ((subsys_code == GNSS_FIRST_MSG) || (subsys_code == GNSS_COMMON_MSG) || + (subsys_code == GNSS_LAST_MSG) || (subsys_code == MSG_BUTT)) { + return GNSS_RX_SUBSYS_0; + } + return GNSS_RX_SUBSYS_MAX; +} + +static void gnss_device_wakeup_host_cb(uint32_t pin) +{ + (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_DISABLE); + tiot_controller *cur_ctrl = tiot_find_controller_by_pin(g_gnss_controllers, CONFIG_GNSS_DEV_NUM, + pin, GNSS_PIN_DEVICE_WAKEUP_HOST); + if (cur_ctrl != NULL) { + tiot_pm_set_event(&cur_ctrl->pm, TIOT_PM_EVENT_WAKEUP_ACK); + } + (void)tiot_board_pin_enable_int(pin, TIOT_PIN_INT_ENABLE); +} + +static int32_t gnss_change_uart_config(tiot_xfer_manager *xfer, tiot_uart_config *uart_cfg) +{ + tiot_plt_guart_cmd uart_cmd = tiot_plat_guart_baud_cmd(uart_cfg->baudrate, uart_cfg->attr.flow_ctrl); + tiot_xfer_tx_param param = { SUBSYS_OM }; + int32_t ret = tiot_xfer_send(xfer, (const uint8_t *)&uart_cmd, sizeof(tiot_plt_guart_cmd), ¶m); + if (ret != sizeof(tiot_plt_guart_cmd)) { + tiot_print_err("[TIOT]set user baudrate cmd fail.\r\n"); + return -1; + } + ret = tiot_xfer_set_config(xfer, uart_cfg); + if (ret != 0) { + tiot_print_err("[TIOT]set user baudrate fail.\r\n"); + return -1; + } + return 0; +} + +static inline int32_t gnss_send_host_need_wakeup(tiot_controller *ctrl) +{ + int32_t ret; + const uint8_t host_need_wakeup_cmd = SYS_PL_PM_SET_WAKEUP_HOST_VALID; + const tiot_xfer_tx_param param = { SUBSYS_SYS }; + ret = tiot_xfer_send(&ctrl->transfer, &host_need_wakeup_cmd, sizeof(uint8_t), ¶m); + if (ret != sizeof(uint8_t)) { + tiot_print_err("[TIOT]set host need wakeup cmd fail.\r\n"); + return -1; + } + return 0; +} + +static int32_t gnss_send_change_buadrate(tiot_controller *ctrl, uint32_t new_buadrate) +{ + const tiot_device_timings *timings = &ctrl->dev_info->timings; + tiot_uart_config uart_config = { 0 }; + (void)tiot_xfer_get_config(&ctrl->transfer, &uart_config); + /* 配置用户波特率 */ + if (uart_config.baudrate == new_buadrate) { + return 0; + } + uart_config.baudrate = new_buadrate; + if (gnss_change_uart_config(&ctrl->transfer, &uart_config) != 0) { + tiot_print_err("[TIoT]send change buadrate fail\n"); + return -1; + } + /* 切换波特率后等待波特率稳定,device或host? */ + tiot_board_udelay(timings->baud_change_wait_us); + return 0; +} + +static int32_t gnss_service_packet_init(tiot_controller *ctrl, uint8_t dev_id) +{ + int32_t ret; +#ifndef CONFIG_BOARD_DYNAMIC_ALLOC + tiot_packet_buffer pkt_buff = { g_gnss_common_buff_mem[dev_id], CONFIG_GNSS_PACKET_BUFF_MAX, 0 }; +#endif + tiot_packet_context_param param = { + .flags = TIOT_PKT_FLAGS_SUPPORT_ASCII, + .rx_manager_info = { g_gnss_pkt_queues[dev_id], GNSS_RX_SUBSYS_MAX, gnss_packet_manager_match_func }, + .buff = NULL + }; +#ifndef CONFIG_BOARD_DYNAMIC_ALLOC + param.buff = &pkt_buff; +#endif + g_gnss_pkt_queues[dev_id][GNSS_RX_SUBSYS_0].queue_nodes = g_gnss_pkt_queue_nodes[dev_id]; + g_gnss_pkt_queues[dev_id][GNSS_RX_SUBSYS_0].queue_size = GNSS_PACKET_QUEUE_NODES; + tiot_packet_context *pkt_ctx = &g_gnss_pkt_ctx[dev_id]; + ret = tiot_packet_init(pkt_ctx, &ctrl->transfer, ¶m); + if (ret != 0) { + tiot_print_err("[TIOT]packet init fail.\r\n"); + } + return ret; +} + +static int32_t gnss_service_install_packet(tiot_controller *ctrl, uint8_t dev_id) +{ + tiot_xfer_packet_ops gnss_packet_ops = { + .read_out = tiot_packet_read_out, + .rx_data_store = tiot_packet_rx_data_store, + .tx_push = tiot_packet_tx_push, + }; + const tiot_device_timings *timings = &ctrl->dev_info->timings; + /* 收发模块注册包格式 */ + if (tiot_xfer_install_packet(&ctrl->transfer, (tiot_xfer_packet_ops *)&gnss_packet_ops, + (uintptr_t)&g_gnss_pkt_ctx[dev_id]) != 0) { + tiot_print_err("[TIOT]packet install fail.\r\n"); + return -1; + } + /* 必须等待device UART初始化后才能接收消息, 待确认时间. */ + osal_msleep(timings->init_time_ms); + tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_REPORT_WORK); + return 0; +} + +static inline int32_t gnss_service_custom_msg_send(tiot_controller *ctrl, uint32_t dev_wkup_host_pin, + uint32_t custom_buadrate) +{ + /* 通过管脚有无判断host是否需要唤醒 */ + if (dev_wkup_host_pin != TIOT_PIN_NONE) { + if (gnss_send_host_need_wakeup(ctrl) != 0) { + return -1; + } + } + /* 切换波特率 */ + if (gnss_send_change_buadrate(ctrl, custom_buadrate) != 0) { + return -1; + } + return 0; +} + +static inline int32_t gnss_get_dev_id(tiot_controller *ctrl, uint8_t *dev_id) +{ + uint8_t i; + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + if (ctrl == &g_gnss_controllers[i]) { + *dev_id = i; + return 0; + } + } + tiot_print_err("[TIoT]invalid device\n"); + return -1; +} + +static inline void gnss_set_open_param(tiot_xfer_open_param *xfer_open_param, tiot_service_open_param *param) +{ + if (param == NULL) { + return; + } + xfer_open_param->rx_cbk_param.buff = param->buff; + xfer_open_param->rx_cbk_param.buff_len = param->buff_len; + xfer_open_param->rx_cbk_param.rx_callback = param->rx_callback; +} + +static inline int32_t gnss_firmware_load(tiot_fw *firmware) +{ + int ret = -1; +#ifdef CONFIG_FILE_BY_ARRAY + ret = tiot_firmware_load(firmware, gnss_fw_file_path_get(), TIOT_FW_FILE_ARRAY_CFG_NAME); +#else + ret = tiot_firmware_load(firmware, NULL, gnss_board_get_info()->cfg_path); +#endif + if (ret != 0) { + tiot_print_err("[TIoT]Gnss firmware load fail.\n"); + } + return ret; +} + +static int32_t gnss_service_open(tiot_controller *ctrl, void *param) +{ + int ret = -1; + uint8_t dev_id; + uint32_t dev_wkup_host_pin; + tiot_xfer_open_param xfer_open_param = { 0 }; + if (gnss_get_dev_id(ctrl, &dev_id) != 0) { + return -1; + } + gnss_set_open_param(&xfer_open_param, param); + /* 传输启动 */ + if (tiot_xfer_open(&ctrl->transfer, &xfer_open_param) != 0) { + /* 通信接口打开失败 */ + tiot_print_err("[TIoT]Transfer port open fail\n"); + goto xfer_open_fail; + } + /* 上电 */ + if (tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWERON) != 0) { + /* 上电失败 */ + tiot_print_err("[TIoT]Power on fail\n"); + goto power_on_fail; + } + /* 加载固件 */ + ret = gnss_firmware_load(&ctrl->firmware); + if (ret != 0) { + goto fw_load_fail; + } + /* 使能中断 */ + dev_wkup_host_pin = ctrl->pm.pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST]; + tiot_pin_int_request(dev_wkup_host_pin, gnss_device_wakeup_host_cb); + + ret = gnss_service_packet_init(ctrl, dev_id); + if (ret != 0) { + goto pkt_init_fail; + } + ret = gnss_service_install_packet(ctrl, dev_id); + if (ret != 0) { + goto pkt_install_fail; + } + ret = gnss_service_custom_msg_send(ctrl, dev_wkup_host_pin, CONFIG_GNSS_UART_BAUDRATE); + if (ret != 0) { + goto pkt_install_fail; + } + /* 打开OK */ + tiot_print_suc("[TIoT]Controller open succ.\n"); + return 0; + +pkt_install_fail: + tiot_packet_deinit(&g_gnss_pkt_ctx[dev_id]); +pkt_init_fail: + tiot_pin_int_release(dev_wkup_host_pin); +fw_load_fail: + (void)tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWEROFF); +power_on_fail: + tiot_xfer_close(&ctrl->transfer); +xfer_open_fail: + return ret; +} + +static void gnss_service_close(tiot_controller *ctrl) +{ + uint8_t dev_id; + uint32_t dev_wkup_host_pin; + if (gnss_get_dev_id(ctrl, &dev_id) != 0) { + return; + } + dev_wkup_host_pin = ctrl->pm.pm_info[TIOT_PIN_DEVICE_WAKEUP_HOST]; + (void)tiot_pm_set_event(&ctrl->pm, TIOT_PM_EVENT_POWEROFF); + tiot_pin_int_release(dev_wkup_host_pin); + tiot_xfer_close(&ctrl->transfer); + tiot_xfer_uninstall_packet(&ctrl->transfer); + tiot_packet_deinit(&g_gnss_pkt_ctx[dev_id]); +} + +static int32_t gnss_service_write(tiot_controller *ctrl, const uint8_t *data, + uint32_t len, const tiot_xfer_tx_param *param) +{ + tiot_unused(param); + uint8_t dev_id; + if (gnss_get_dev_id(ctrl, &dev_id) != 0) { + return -1; + } + const tiot_xfer_tx_param tx_param = { SUBSYS_GNSS }; + tiot_pm *pm = &ctrl->pm; + (void)tiot_pm_set_event(pm, TIOT_PM_EVENT_WORK_VOTE_UP); + /* 尝试唤醒device */ + int32_t ret = tiot_pm_set_event(pm, TIOT_PM_EVENT_WAKEUP); + if (ret != 0) { + tiot_print_err("[TIoT]wake up error\n"); + goto vote_down; + } + /* 等待成功唤醒device */ + ret = tiot_pm_wait_state(&ctrl->pm, TIOT_PM_STATE_WORK, ctrl->dev_info->timings.wakeup_wait_ms); + if (ret <= 0) { + tiot_print_warning("[TIoT]wakeup device fail, pm state is 0x%x.\n", pm->state); + } + ret = tiot_xfer_send(&ctrl->transfer, data, len, &tx_param); +vote_down: + (void)tiot_pm_set_event(pm, TIOT_PM_EVENT_WORK_VOTE_DOWN); + return ret; +} + +static int32_t gnss_service_read(tiot_controller *ctrl, uint8_t *buff, uint32_t buff_len, + const tiot_xfer_rx_param *param) +{ + uint8_t dev_id; + if (gnss_get_dev_id(ctrl, &dev_id) != 0) { + return -1; + } + return tiot_xfer_recv(&ctrl->transfer, buff, buff_len, param); +} + +int32_t gnss_service_init(void) +{ + uint8_t i; + int32_t ret; + tiot_board_info per_board_info; + tiot_controller_info ctrl_info; + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + if (gnss_board_init(&i) != 0) { + tiot_print_err("[TIoT]board init fail\n"); + return -1; + } + } + const gnss_board_info *board_info = gnss_board_get_info(); + if (board_info == NULL) { + tiot_print_err("[TIoT]no board info.\n"); + goto deinit; + } + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + per_board_info.hw_info.xmit_id = board_info->hw_infos[i].xmit_id; + per_board_info.hw_info.pm_info = board_info->hw_infos[i].pm_info; + ctrl_info.board_info = &per_board_info; + ctrl_info.dev_info = gnss_device_get_info(); + ctrl_info.dev_cus = 0; + ret = tiot_controller_init(&g_gnss_controllers[i], &ctrl_info); + if (ret != 0) { + tiot_print_err("[TIoT]controller init fail\n"); + goto deinit; + } + } + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + g_gnss_controllers[i].ops.open = gnss_service_open; + g_gnss_controllers[i].ops.close = gnss_service_close; + g_gnss_controllers[i].ops.write = gnss_service_write; + g_gnss_controllers[i].ops.read = gnss_service_read; + g_gnss_controllers[i].ops.pm_ctrl = NULL; + } + return 0; +deinit: + gnss_service_deinit(); + return -1; +} + +void gnss_service_deinit(void) +{ + uint8_t i; + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + tiot_controller_deinit(&g_gnss_controllers[i]); + } + for (i = 0; i < CONFIG_GNSS_DEV_NUM; i++) { + gnss_board_deinit(&i); + } +} + +uintptr_t gnss_service_get_ctrl(uint8_t dev_id) +{ + return (uintptr_t)&g_gnss_controllers[dev_id]; +} 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 index 000000000..3d37a81e1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/device/gnss/gnss_service.h @@ -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 index 000000000..7149394a0 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/CMakeLists.txt @@ -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 index 000000000..c3b9dbf0a --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/Makefile @@ -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 index 000000000..dd5b90727 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/readme.txt @@ -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 index 000000000..aad6a4e76 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_autoconfig.h @@ -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 index 000000000..6816a9bd9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config0/tiot_defconfig @@ -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 index 000000000..98f9a5438 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/readme.txt @@ -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 index 000000000..0fc087880 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_autoconfig.h @@ -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 index 000000000..e1935a291 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config1/tiot_defconfig @@ -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 index 000000000..ecdac4737 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/readme.txt @@ -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 index 000000000..ee02803d9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_autoconfig.h @@ -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 index 000000000..4de7aff26 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config2/tiot_defconfig @@ -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 index 000000000..fbcaf37a8 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/readme.txt @@ -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 index 000000000..96e4f763b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_autoconfig.h @@ -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 index 000000000..243c5bcd6 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/config3/tiot_defconfig @@ -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 index 000000000..cf3aecf56 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/menu_configs/readme.md @@ -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 index 000000000..365837570 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/CMakeLists.txt @@ -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 index 000000000..b024455cd --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/gnss_board_port.c @@ -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 index 000000000..015284db9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/porting.mk @@ -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 index 000000000..690be5d59 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_log_port.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board log port. \n + * + * History: \n + * 2023-05-06, Create file. \n + */ +#ifndef BOARD_LOG_PORT_H +#define BOARD_LOG_PORT_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_board_port_log LOG port + * @ingroup tiot_board_port + * @{ + */ +#define TIOT_LOG_ALERT 0 /*!< Log level alert. */ +#define TIOT_LOG_ERR 1 /*!< Log level error. */ +#define TIOT_LOG_WARNING 2 /*!< Log level warning. */ +#define TIOT_LOG_INFO 3 /*!< Log level info. */ +#define TIOT_LOG_DEBUG 4 /*!< Log level debug. */ + +#define TIOT_BOARD_LOG_LEVEL TIOT_LOG_INFO /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */ + +#define BOARD_PRINT_FUNCTION_NAME /* 此处替换为板级打印接口. */ +#define board_print_dbg(s, ...) /* 此处替换为板级打印接口. */ +#define board_print_info(s, ...) /* 此处替换为板级打印接口. */ +#define board_print_suc(s, ...) /* 此处替换为板级打印接口. */ +#define board_print_warning(s, ...) /* 此处替换为板级打印接口. */ +#define board_print_err(s, ...) /* 此处替换为板级打印接口. */ +#define board_print_alter(s, ...) /* 此处替换为板级打印接口. */ + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..5b9470c7c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_misc_port.c @@ -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 index 000000000..4d0d62de9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_pin_port.c @@ -0,0 +1,37 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board PIN port. \n + * + * History: \n + * 2023-04-20, Create file. \n + */ +#include "tiot_board_pin_port.h" + +int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level) +{ + tiot_unused(pin); + tiot_unused(level); + return 0; +} + +int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level) +{ + tiot_unused(pin); + tiot_unused(level); + return 0; +} + +int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable) +{ + tiot_unused(pin); + tiot_unused(int_enable); + return 0; +} + +int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb) +{ + tiot_unused(pin); + tiot_unused(int_cb); + return 0; +} \ 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 index 000000000..7e1bcfb16 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_board_uart_port.c @@ -0,0 +1,45 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board UART port. \n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#include "tiot_board_uart_port.h" +#include "tiot_board_log.h" + +int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs) +{ + tiot_unused(xmit); + tiot_unused(cbs); + return 0; +} + +void tiot_board_uart_close(tiot_xmit *xmit) +{ + tiot_unused(xmit); +} + +int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len) +{ + tiot_unused(xmit); + tiot_unused(buff); + tiot_unused(len); + return 0; +} + +int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len) +{ + tiot_unused(xmit); + tiot_unused(buff); + tiot_unused(len); + return -1; +} + +int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config) +{ + tiot_unused(xmit); + tiot_unused(config); + return 0; +} 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 index 000000000..0307c3de3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting/tiot_osal_port.c @@ -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 index 000000000..fcff91077 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_board_port.c @@ -0,0 +1,189 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * Description: \n + * + * History: \n + * 2024-01-04, Create file. \n + */ +#include "gnss_board_port.h" +#include +#include +#include +#include +#include +#include +#include "tiot_board_pin_port.h" +#include "tiot_board_pin_irq_helper.h" +#include "tiot_board_log.h" +#include "tiot_dts_node.h" +#include "securec.h" + +#define DTS_NODE_COMPATIBLE "tiot,gnss" + +#define TTY_NAME_MAX 20 +#define CFG_PATH_MAX 200 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) +#define WAKEIN_IRQF (IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND) +#else +#define WAKEIN_IRQF (IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND) +#endif + +typedef struct { + bool optional; /* 是否为可选管脚 */ + const char *prop; /* dts prop */ + const char *name; /* gpio request name */ + int gpio_flags; /* gpio request 初始配置 */ +} tiot_kernel_pin_info; + +static gnss_board_hw_info g_board_hw_info = { 0 }; +static gnss_board_info g_board_info = { + .cfg_path = NULL, /* 如果有文件系统,指向gnss加载配置文件完整路径/相对路径 + 例如:linux下"/sys/xxx/xxx/xxx_config.bin", + windows下".\\config_file_path\\xxx_config.bin" + 如果无文件系统,设为NULL. */ + .hw_infos = &g_board_hw_info +}; + +static const tiot_kernel_pin_info g_board_pin_infos[GNSS_PIN_NUM] = { + { false, DTS_PROP_GPIO_POWEN_ON, NULL, GPIOF_OUT_INIT_LOW }, + { true, DTS_PROP_GPIO_WAKEOUT, NULL, GPIOF_OUT_INIT_LOW }, + { true, DTS_PROP_GPIO_WAKEIN, NULL, GPIOF_IN } +}; + +const gnss_board_info *gnss_board_get_info(void) +{ + return &g_board_info; +} + +static struct device_node *board_find_device_node(uint8_t dev_id) +{ + /* 只使用单个, 忽略dev_id. */ + tiot_unused(dev_id); + struct device_node *np = NULL; + struct device_node *dev_np = NULL; + /* 获取 top dts节点 */ + np = of_find_compatible_node(NULL, NULL, DTS_NODE_TIOT); + if (np == NULL) { + printk("no compatible node.\r\n"); + return NULL; + } + /* 获取子dts节点 */ + dev_np = of_find_compatible_node(np, NULL, DTS_NODE_COMPATIBLE); + if (dev_np == NULL) { + printk("no device compatible node.\r\n"); + return NULL; + } + return dev_np; +} + +static int board_gpio_pins_init(struct device_node *dev_np, uint32_t *pins) +{ + uint8_t i; + int ret; + int gpio_nr; + const tiot_kernel_pin_info *pin_infos = (const tiot_kernel_pin_info *)&g_board_pin_infos; + /* 设置GPIO 初始pinmux. */ + for (i = 0; i < GNSS_PIN_NUM; i++) { + gpio_nr = of_get_named_gpio(dev_np, pin_infos[i].prop, 0); + if (!pin_infos[i].optional && (gpio_nr < 0)) { + printk("non optional gpio no found: [%d].", i); + return -1; + } + if (gpio_nr < 0) { + pins[i] = TIOT_PIN_NONE; + continue; + } + printk("=================== tiot gpio [%d]: [%d].", i, gpio_nr); + ret = gpio_request_one(gpio_nr, pin_infos[i].gpio_flags, NULL); + if (ret != 0) { + printk("gpio request one failed [%d].\r\n", gpio_nr); + return -1; + } + if (pin_infos[i].gpio_flags == GPIOF_IN) { + /* 通过helper管理 irq gpio。 */ + ret = tiot_board_irq_pin_register(gpio_nr, WAKEIN_IRQF); + } + if (ret != 0) { + printk("irq gpio register failed [%d].\r\n", gpio_nr); + return -1; + } + pins[i] = gpio_nr; + } + return ret; +} + +static int board_node_get_prop_string(struct device_node *dev_np, const char *prop, + char *buff, uint32_t buff_len) +{ + errno_t err; + int ret = 0; + int str_len; + const char *str = NULL; + ret = of_property_read_string(dev_np, prop, &str); + if (ret < 0) { + printk("prop %s get failed.\r\n", prop); + return -1; + } else { + printk("prop %s get succ: %s.\r\n", prop, str); + } + str_len = strlen(str); + if (str_len >= buff_len) { + printk("prop %s too long, %d.\r\n", prop, str_len); + return -1; + } + err = memcpy_s(buff, str_len, str, str_len); + if (err != EOK) { + printk("tty_name memcpy fail.\r\n"); + return -1; + } + return ret; +} + +/* gnss板级UART、管脚初始化接口 */ +int32_t gnss_board_init(void *param) +{ + uint8_t dev_id; + int ret; + static char tty_name_backup[TTY_NAME_MAX] = { 0 }; + static char cfg_path_backup[CFG_PATH_MAX] = { 0 }; + struct device_node *dev_np = NULL; + + dev_id = *(uint8_t *)param; + dev_np = board_find_device_node(dev_id); + if (dev_np == NULL) { + return -1; + } + /* 获取tty name. */ + if (board_node_get_prop_string(dev_np, DTS_PROP_TTY_DEV_NAME, tty_name_backup, TTY_NAME_MAX) != 0) { + return -1; + } + g_board_hw_info.xmit_id = (uintptr_t)tty_name_backup; + /* 获取cfg固件文件路径. */ + if (board_node_get_prop_string(dev_np, DTS_PROP_CFG_PATH, cfg_path_backup, CFG_PATH_MAX) != 0) { + return -1; + } + g_board_info.cfg_path = cfg_path_backup; + /* 获取gpio管脚. */ + if (board_gpio_pins_init(dev_np, (uint32_t *)g_board_hw_info.pm_info) != 0) { + /* 失败时释放管脚. */ + gnss_board_deinit(param); + return -1; + } + return 0; +} + +void gnss_board_deinit(void *param) +{ + (void)param; + uint8_t i; + uint32_t *pins = g_board_hw_info.pm_info; + for (i = 0; i < GNSS_PIN_NUM; i++) { + if (pins[i] == TIOT_PIN_NONE) { + continue; + } + gpio_free(pins[i]); + } + tiot_board_irq_pin_release(); +} 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 index 000000000..7e6ba3401 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/gnss_misc_device.c @@ -0,0 +1,149 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: \n + * + * History: \n + * 2023-12-26, Create file. \n + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "tiot_service_interface.h" +#include "tiot_dts_node.h" + +#define DTS_NODE_COMPATIBLE "tiot,gnss" +#define READ_TIMEOUT 1000 +#define TRX_DATA_MAX 9300 + +struct tiot_dev { + struct miscdevice misc; + tiot_handle handle; +} *g_misc_devp; + +static const char *g_device_node_name = NULL; +static const char *g_misc_dev_name = NULL; +static char g_misc_tx_data[TRX_DATA_MAX] = { 0 }; +static char g_misc_rx_data[TRX_DATA_MAX] = { 0 }; + +static struct device_node *misc_find_device_node(void) +{ + struct device_node *np = NULL; + struct device_node *dev_np = NULL; + /* 获取 top dts节点 */ + np = of_find_compatible_node(NULL, NULL, DTS_NODE_TIOT); + if (np == NULL) { + printk("no compatible node.\r\n"); + return NULL; + } + /* 获取子dts节点 */ + dev_np = of_find_compatible_node(np, NULL, DTS_NODE_COMPATIBLE); + if (dev_np == NULL) { + printk("no device compatible node.\r\n"); + return NULL; + } + return dev_np; +} + +static int misc_dev_open(struct inode *inode, struct file *filp) +{ + struct tiot_dev *dev = container_of(filp->private_data, struct tiot_dev, misc); + tiot_handle handle = tiot_service_open("gn71", NULL); + if (handle == 0) { + return -1; + } + dev->handle = handle; + filp->private_data = dev; + return 0; +} + +static int misc_dev_close(struct inode *inode, struct file *filp) +{ + struct tiot_dev *dev = filp->private_data; + tiot_service_close(dev->handle); + dev->handle = 0; + return 0; +} + +static ssize_t misc_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +{ + int read_count; + struct tiot_dev *dev = filp->private_data; + if (count > sizeof(g_misc_rx_data)) { + return -ERANGE; + } + read_count = tiot_service_read(dev->handle, g_misc_rx_data, + sizeof(g_misc_rx_data), READ_TIMEOUT); + if (copy_to_user(buf, g_misc_rx_data, read_count)) { + return -ERANGE; + } + return read_count; +} + +static ssize_t misc_dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) +{ + struct tiot_dev *dev = filp->private_data; + if (count > sizeof(g_misc_tx_data)) { + return -ERANGE; + } + if (copy_from_user(g_misc_tx_data, buf, count)) { + return -ERANGE; + } + return tiot_service_write(dev->handle, g_misc_tx_data, count); +} + +static const struct file_operations tiot_gnss_fops = { + .owner = THIS_MODULE, + .read = misc_dev_read, + .write = misc_dev_write, + .open = misc_dev_open, + .release = misc_dev_close +}; + +static int __init tiot_module_init(void) +{ + int ret; + if (tiot_service_init() != 0) { + return -1; + } + struct device_node *dev_node = NULL; + dev_node = misc_find_device_node(); + if (dev_node == NULL) { + return -1; + } + g_device_node_name = dev_node->name; + ret = of_property_read_string(dev_node, DTS_PROP_MISC_DEV_NAME, &g_misc_dev_name); + of_node_put(dev_node); + + if (g_misc_dev_name) { + g_misc_devp = kzalloc(sizeof(struct tiot_dev), GFP_KERNEL); + if (!g_misc_devp) + return -ENOMEM; + g_misc_devp->misc.minor = MISC_DYNAMIC_MINOR; + g_misc_devp->misc.name = g_misc_dev_name; + g_misc_devp->misc.fops = &tiot_gnss_fops; + ret = misc_register(&g_misc_devp->misc); + if (ret != 0) { + return -1; + } + } + return 0; +} + +module_init(tiot_module_init); + +static void __exit tiot_module_exit(void) +{ + misc_deregister(&g_misc_devp->misc); + tiot_service_deinit(); + kfree(g_misc_devp); + g_misc_devp = NULL; +} + +module_exit(tiot_module_exit); +MODULE_LICENSE("GPL v2"); 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 index 000000000..0f18aa84c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/porting.mk @@ -0,0 +1,7 @@ +tiot-porting-objs += tiot_osal_port.o +tiot-porting-objs += tiot_board_uart_port.o +tiot-porting-objs += tiot_board_pin_irq_helper.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 += 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 index 000000000..6636380ba --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_log_port.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: kernel board log port. \n + * + * History: \n + * 2023-05-06, Create file. \n + */ +#ifndef BOARD_LOG_PORT_H +#define BOARD_LOG_PORT_H + +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_board_port_log LOG port + * @ingroup tiot_board_port + * @{ + */ + +#define TIOT_LOG_ALERT 0 /*!< Log level alert. */ +#define TIOT_LOG_ERR 1 /*!< Log level error. */ +#define TIOT_LOG_WARNING 2 /*!< Log level warning. */ +#define TIOT_LOG_INFO 3 /*!< Log level info. */ +#define TIOT_LOG_DEBUG 4 /*!< Log level debug. */ + +#define TIOT_BOARD_LOG_LEVEL TIOT_LOG_INFO /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */ + +#define BOARD_PRINT_FUNCTION_NAME printk(KERN_INFO KBUILD_MODNAME ":D]%s]", __func__) +#define board_print_dbg(s, args...) printk(KERN_INFO KBUILD_MODNAME ":D]%s]" s, __func__, ##args) +#define board_print_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ":I]%s]" s, __func__, ##args) +#define board_print_suc(s, args...) printk(KERN_INFO KBUILD_MODNAME ":S]%s]" s, __func__, ##args) +#define board_print_warning(s, args...) printk(KERN_WARNING KBUILD_MODNAME ":W]%s]" s, __func__, ##args) +#define board_print_err(s, args...) printk(KERN_ERR KBUILD_MODNAME ":E]%s]" s, __func__, ##args) +#define board_print_alter(s, args...) printk(KERN_ERR KBUILD_MODNAME ":A]%s]" s, __func__, ##args) + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..ad72d85a9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_misc_port.c @@ -0,0 +1,113 @@ +/** + * 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" +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +#include +#endif +#include "securec.h" + +#define TIOT_WAKEUP_LOCK_NAME "tiot_wk" + +typedef struct { + struct wakeup_source ws; + spinlock_t ws_lock; + unsigned long lock_count; +} tiot_kernel_wakelock; + +int32_t tiot_board_wake_lock_init(tiot_board_wakelock *lock) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + if (unlikely(lock == NULL)) { + return -1; + } + tiot_kernel_wakelock *kwakelock = (tiot_kernel_wakelock *)kzalloc(sizeof(tiot_kernel_wakelock), GFP_KERNEL); + if (kwakelock == NULL) { + return -1; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + memset_s((void *)&kwakelock->ws, sizeof(struct wakeup_source), 0, sizeof(struct wakeup_source)); + kwakelock->ws.name = TIOT_WAKEUP_LOCK_NAME; + wakeup_source_add(&kwakelock->ws); +#else + wakeup_source_init(&kwakelock->ws, TIOT_WAKEUP_LOCK_NAME); +#endif + spin_lock_init(&kwakelock->ws_lock); + lock->lock = kwakelock; +#endif + return 0; +} + +void tiot_board_wake_lock(tiot_board_wakelock *lock) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + unsigned long flags; + + if (unlikely((lock == NULL) || (lock->lock == NULL))) { + return; + } + + tiot_kernel_wakelock *kwakelock = lock->lock; + spin_lock_irqsave(&kwakelock->ws_lock, flags); + if (!kwakelock->lock_count) { + __pm_stay_awake(&kwakelock->ws); + } + kwakelock->lock_count++; + spin_unlock_irqrestore(&kwakelock->ws_lock, flags); +#endif +} + +void tiot_board_wake_unlock(tiot_board_wakelock *lock) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + unsigned long flags; + + if (unlikely((lock == NULL) || (lock->lock == NULL))) { + return; + } + + tiot_kernel_wakelock *kwakelock = lock->lock; + spin_lock_irqsave(&kwakelock->ws_lock, flags); + if (kwakelock->lock_count) { + kwakelock->lock_count--; + if (!kwakelock->lock_count) { + __pm_relax(&kwakelock->ws); + } + } + spin_unlock_irqrestore(&kwakelock->ws_lock, flags); +#endif +} + +void tiot_board_wake_lock_destroy(tiot_board_wakelock *lock) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + if (unlikely((lock == NULL) || (lock->lock == NULL))) { + return; + } + + tiot_kernel_wakelock *kwakelock = lock->lock; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + wakeup_source_remove(&kwakelock->ws); + __pm_relax(&kwakelock->ws); +#else + wakeup_source_trash(&kwakelock->ws); +#endif + kfree(kwakelock); +#endif +} + +void tiot_board_udelay(uint32_t us) +{ + udelay(us); +} 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 index 000000000..8b6f6cddf --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.c @@ -0,0 +1,51 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: \n + * + * History: \n + * 2023-12-26, Create file. \n + */ + +#include "tiot_board_pin_irq_helper.h" +#include +#include + +#define TIOT_PIN_IRQ_MAX 16 /* for now this is enough. */ + +static tiot_irq_pin_node g_tiot_board_irq_pin_map[TIOT_PIN_IRQ_MAX] = {{ 0 }}; +static uint32_t g_tiot_board_irq_pin_num = 0; + +int32_t tiot_board_irq_pin_register(uint32_t irq_pin, uint32_t irq_flags) +{ + if (g_tiot_board_irq_pin_num >= TIOT_PIN_IRQ_MAX) { + return -1; + } + tiot_irq_pin_node *cur_node = &g_tiot_board_irq_pin_map[g_tiot_board_irq_pin_num]; + cur_node->pin = irq_pin; + cur_node->irq = gpio_to_irq(irq_pin); + cur_node->irq_flags = irq_flags; + cur_node->callback = NULL; + cur_node->is_enabled = TIOT_PIN_INT_DISABLE; + spin_lock_init(&(cur_node->lock)); + g_tiot_board_irq_pin_num++; + return 0; +} + +tiot_irq_pin_node *tiot_board_irq_pin_node_by_pin(uint32_t pin) +{ + tiot_irq_pin_node *cur_node = NULL; + int i; + for (i = 0; i < g_tiot_board_irq_pin_num; i++) { + cur_node = &g_tiot_board_irq_pin_map[i]; + if (cur_node->pin == pin) { + return cur_node; + } + } + return NULL; +} + +void tiot_board_irq_pin_release(void) +{ + g_tiot_board_irq_pin_num = 0; +} 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 index 000000000..c0bdc3d14 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_irq_helper.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: \n + * + * History: \n + * 2023-12-26, Create file. \n + */ +#ifndef TIOT_BOARD_PIN_IRQ_HELPER_H +#define TIOT_BOARD_PIN_IRQ_HELPER_H + +#include +#include "tiot_types.h" +#include "tiot_board_pin_port.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef struct { + uint32_t pin; + uint32_t irq; + uint32_t irq_flags; + uint32_t is_enabled; + spinlock_t lock; + tiot_pin_int_callback callback; +} tiot_irq_pin_node; + +int32_t tiot_board_irq_pin_register(uint32_t irq_pin, uint32_t irq_flags); + +tiot_irq_pin_node *tiot_board_irq_pin_node_by_pin(uint32_t pin); + +void tiot_board_irq_pin_release(void); + +/* FOR S4 */ +void tiot_board_irq_pin_suspend(void); +/* FOR S4 */ +void tiot_board_irq_pin_resume(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/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 index 000000000..34f5d05a4 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_pin_port.c @@ -0,0 +1,88 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Demo board PIN port. \n + * + * History: \n + * 2023-04-20, Create file. \n + */ + +#include "tiot_board_pin_port.h" +#include +#include +#include +#include "tiot_board_pin_irq_helper.h" + +int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level) +{ + return gpio_direction_output(pin, (int)level); +} + +int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level) +{ + int32_t gpio_level = gpio_get_value(pin); + if (gpio_level < 0) { + return gpio_level; + } + *level = (gpio_level == 0) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH; + return 0; +} + +int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable) +{ + if (pin == TIOT_PIN_NONE) { + return -1; + } + tiot_irq_pin_node *irq_pin_node = tiot_board_irq_pin_node_by_pin(pin); + if (irq_pin_node == NULL) { + return -1; + } + unsigned long flags; + spin_lock_irqsave(&irq_pin_node->lock, flags); + if ((int_enable == TIOT_PIN_INT_ENABLE) && (irq_pin_node->is_enabled == TIOT_PIN_INT_DISABLE)) { + enable_irq(irq_pin_node->irq); + irq_pin_node->is_enabled = TIOT_PIN_INT_ENABLE; + } else if ((int_enable == TIOT_PIN_INT_DISABLE) && (irq_pin_node->is_enabled == TIOT_PIN_INT_ENABLE)) { + disable_irq_nosync(irq_pin_node->irq); + irq_pin_node->is_enabled = TIOT_PIN_INT_DISABLE; + } + spin_unlock_irqrestore(&irq_pin_node->lock, flags); + return 0; +} + +static irqreturn_t tiot_board_gpio_irq_callback(int irq, void *node) +{ + (void)irq; + tiot_irq_pin_node *irq_pin_node = (tiot_irq_pin_node *)node; + /* RESUME TODO */ + if ((irq_pin_node != NULL) && (irq_pin_node->callback != NULL)) { + irq_pin_node->callback(irq_pin_node->pin); + } + return IRQ_HANDLED; +} + +int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb) +{ + int32_t ret; + tiot_irq_pin_node *irq_pin_node = tiot_board_irq_pin_node_by_pin(pin); + if (irq_pin_node == NULL) { + return -1; + } + irq_pin_node->callback = int_cb; + if (irq_pin_node->irq == 0) { + return -1; + } + if (int_cb != NULL) { + ret = request_irq(irq_pin_node->irq, tiot_board_gpio_irq_callback, + irq_pin_node->irq_flags, NULL, irq_pin_node); + if (ret < 0) { + printk("gpio index [%d] irq request fail ret = %d\n", pin, ret); + return -1; + } + /* 默认先关闭中断,需要时再开启 */ + disable_irq_nosync(irq_pin_node->irq); + } else { + free_irq(irq_pin_node->irq, irq_pin_node); + } + return 0; +} 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 index 000000000..df469aeea --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_board_uart_port.c @@ -0,0 +1,205 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Demo board UART port\n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#include "tiot_board_uart_port.h" +#include "tiot_board_log.h" +#include "securec.h" + +#include +#include + +#define TTY_LDISC_MAGIC 0x5403 + +#define TIOT_TTY_RX_ROOM 1024U + +#define TTY_SENT_WAIT_MS 100U + +typedef struct { + tiot_xmit_callbacks cbs; +} tiot_tty_ctrl; + +static tiot_tty_ctrl g_tiot_tty_ctrl = { 0 }; + +static int32_t tiot_tty_ldisc_open(struct tty_struct *tty); +static void tiot_tty_ldisc_close(struct tty_struct *tty); +static void tiot_tty_ldisc_receive(struct tty_struct *tty, const uint8_t *data, char *tty_flags, int32_t count); + +/* 使用内核未使用的LDISC */ +#define N_HW_TIOT (NR_LDISCS - 1) +static struct tty_ldisc_ops g_tiot_ldisc_ops = { + .magic = TTY_LDISC_MAGIC, + .name = "n_tiot", /* 必须以n_开头 */ + .open = tiot_tty_ldisc_open, + .close = tiot_tty_ldisc_close, + .receive_buf = tiot_tty_ldisc_receive, + .owner = THIS_MODULE +}; + +static int32_t tiot_tty_ldisc_open(struct tty_struct *tty) +{ + tiot_print_info("%s enter\n", __func__); + tty->receive_room = TIOT_TTY_RX_ROOM; + + /* Flush any pending characters in the driver and discipline. */ + tty_ldisc_flush(tty); + tty_driver_flush_buffer(tty); + return 0; +} + +static void tiot_tty_ldisc_close(struct tty_struct *tty) +{ + tiot_print_info("%s: entered\n", __func__); + + if (tty->disc_data == NULL) { + tiot_print_err("tty or tty->disc_data is NULL\n"); + return; + } + + /* Flush any pending characters in the driver and discipline. */ + tty_ldisc_flush(tty); + tty_driver_flush_buffer(tty); + + tiot_print_info("tty close done!\n"); +} + +static void tiot_tty_ldisc_receive(struct tty_struct *tty, const uint8_t *data, char *tty_flags, int32_t count) +{ + if (data == NULL || count < 0) { + return; + } + + tiot_xmit *xmit = tty->disc_data; + if (g_tiot_tty_ctrl.cbs.rx_notify) { + g_tiot_tty_ctrl.cbs.rx_notify(xmit, (uint8_t *)data, count); + } +} + +int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cb) +{ + struct tty_struct *tty = NULL; + int ret; + dev_t dev_no; + + tiot_print_info("%s\n", __func__); + ret = tty_dev_name_to_number((const char *)xmit->id, &dev_no); + if (ret != 0) { + tiot_print_err("can't found tty:%s ret=%d\n", (const char *)xmit->id, ret); + return -ENODEV; + } + + /* open tty */ + tty = tty_kopen(dev_no); + if (!tty || IS_ERR(tty)) { + tiot_print_err("open tty %x failed ret=%d\n", dev_no, PTR_ERR_OR_ZERO(tty)); + return -ENODEV; + } + + if (tty->ops->open) { + ret = tty->ops->open(tty, NULL); + } else { + tiot_print_err("tty->ops->open is NULL\n"); + ret = -ENODEV; + } + + if (ret) { + tty_unlock(tty); + xmit->handle = NULL; + return ret; + } + + /* 打开后再配置波特率 */ + tty_unlock(tty); + /* 先注册ldisc再set ldisc */ + tty_register_ldisc(N_HW_TIOT, &g_tiot_ldisc_ops); + tty_set_ldisc(tty, N_HW_TIOT); + /* set ldisc前可能tty已设置ldisc,释放旧ldisc时会同时释放disc_data, 必须在set ldisc后再设置tty->disc_data */ + xmit->handle = tty; + tty->disc_data = xmit; + if (!g_tiot_tty_ctrl.cbs.rx_notify) { + g_tiot_tty_ctrl.cbs.rx_notify = cb->rx_notify; + } + return 0; +} + +void tiot_board_uart_close(tiot_xmit *xmit) +{ + /* close tty */ + struct tty_struct *tty = (struct tty_struct *)xmit->handle; + + tiot_print_info("%s\n", __func__); + + /* close tty */ + if (tty == NULL) { + tiot_print_err("tty is null, ignore\n"); + return; + } + + tty_lock(tty); + if (tty->ops->close) { + tty->ops->close(tty, NULL); + } else { + tiot_print_warning("tty->ops->close is null\n"); + } + tty_unlock(tty); + tty_kclose(tty); + tty_unregister_ldisc(N_HW_TIOT); + (void)memset_s(&g_tiot_tty_ctrl, sizeof(tiot_tty_ctrl), 0, sizeof(tiot_tty_ctrl)); +} + +int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len) +{ + /* 异步接口,但是设置波特率前会自动flush */ + struct tty_struct *tty = (struct tty_struct *)xmit->handle; + return tty->ops->write(tty, buff, len); +} + +int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len) +{ + /* 内核tty无同步读取接口,只通过回调接收 */ + return -1; +} + +int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config) +{ + struct tty_struct *tty = (struct tty_struct *)xmit->handle; + tiot_uart_config *uart_config = config; + struct ktermios ktermios; + + ktermios = tty->termios; + /* close soft flowctrl */ + ktermios.c_iflag &= ~IXON; + + /* set uart cts/rts flowctrl */ + ktermios.c_cflag &= ~CRTSCTS; + /* on to ignore modem status change */ + ktermios.c_cflag |= CLOCAL; + if (uart_config->attr.flow_ctrl == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) { + ktermios.c_cflag |= CRTSCTS; + /* off to respect modem status change */ + ktermios.c_cflag &= ~CLOCAL; + } + + /* set csize */ + ktermios.c_cflag &= ~(CSIZE); + ktermios.c_cflag |= CS8; + + /* set uart baudrate */ + ktermios.c_cflag &= ~CBAUD; + ktermios.c_cflag |= BOTHER; + + /* close parity */ + ktermios.c_iflag &= ~INPCK; + ktermios.c_cflag &= ~PARENB; + ktermios.c_cflag &= ~PARODD; + tty_termios_encode_baud_rate(&ktermios, uart_config->baudrate, uart_config->baudrate); + + /* UART硬件fifo清空后才能切换UART配置,通过tty_wait_until_sent等待 */ + tty_wait_until_sent(tty, TTY_SENT_WAIT_MS); + tty_set_termios(tty, &ktermios); + return 0; +} 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 index 000000000..f1eb5f439 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_dts_node.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * Description: dts nodes. \n + * + * History: \n + * 2024-02-21, Create file. \n + */ +#ifndef TIOT_DTS_NODE_H +#define TIOT_DTS_NODE_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** +tiot { // 总节点名 + compatible = "tiot"; // 匹配名,不可修改 + gn71 { // 子节点名,gn71, 对应tiot_service_open参数 + compatible = "tiot,gnss"; // 匹配名,与对应device匹配,不可修改 + tiot,misc-dev-name = "gn71"; // 默认设备节点名,可自定义 + tiot,tty-dev-name = "ttyXXXN"; // 使用的tty设备节点名 + tiot,power-on-gpio = ; // power on gpio管脚 + tiot,wake-out-gpio = ; // 唤醒对端 gpio管脚 + tiot,wake-in-gpio = ; // 被唤醒 gpio管脚 + tiot,cfg-path = "/path/to/cfg/xxx_cfg.bin"; // 固件文件完整路径(包含文件名) + }; +}; +*/ + +#define DTS_NODE_TIOT "tiot" + +#define DTS_PROP_MISC_DEV_NAME "tiot,misc-dev-name" + +#define DTS_PROP_TTY_DEV_NAME "tiot,tty-dev-name" +#define DTS_PROP_GPIO_POWEN_ON "tiot,power-on-gpio" +#define DTS_PROP_GPIO_WAKEOUT "tiot,wake-out-gpio" +#define DTS_PROP_GPIO_WAKEIN "tiot,wake-in-gpio" + +#define DTS_PROP_CFG_PATH "tiot,cfg-path" + +#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/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 index 000000000..d7692508c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_kernel/tiot_osal_port.c @@ -0,0 +1,363 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * Description: kernel osal port demo. \n + * + * History: \n + * 2024-01-04, Create file. \n + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tiot_osal.h" + +unsigned long osal_msleep(unsigned int msecs) +{ + return msleep_interruptible(msecs); +} + +static unsigned int osal_convert_gfp_flag(unsigned int osal_gfp_flag) +{ + unsigned int gfp_flag = 0; + + if (osal_gfp_flag & OSAL_GFP_KERNEL) { + gfp_flag = GFP_KERNEL; + } else if (osal_gfp_flag & OSAL_GFP_ATOMIC) { + gfp_flag = GFP_ATOMIC; + } else if (osal_gfp_flag & OSAL_GFP_DMA) { + gfp_flag = GFP_DMA; + } else { + gfp_flag = GFP_KERNEL; + } + + if (osal_gfp_flag & OSAL_GFP_ZERO) { + gfp_flag |= __GFP_ZERO; + } + return gfp_flag; +} + +void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag) +{ + unsigned int gfp_flag = osal_convert_gfp_flag(osal_gfp_flag); + return kmalloc(size, gfp_flag); +} + +void osal_kfree(void *addr) +{ + if (addr != NULL) { + kfree(addr); + } +} + +int osal_spin_lock_init(osal_spinlock *lock) +{ + spinlock_t *p = NULL; + + if (lock == NULL || lock->lock != NULL) { + printk("parameter invalid!\n"); + return OSAL_FAILURE; + } + p = (spinlock_t *)kmalloc(sizeof(spinlock_t), GFP_KERNEL); // 8 is malloc size + if (p == NULL) { + printk("kmalloc error!\n"); + return OSAL_FAILURE; + } + spin_lock_init(p); + lock->lock = p; + return OSAL_SUCCESS; +} + +void osal_spin_lock_irqsave(osal_spinlock *lock, unsigned long *flags) +{ + spinlock_t *p = NULL; + unsigned long f; + + if ((lock == NULL) || (flags == NULL) || (lock->lock == NULL)) { + printk("parameter invalid!\n"); + return; + } + + p = (spinlock_t *)(lock->lock); + spin_lock_irqsave(p, f); + + *flags = f; +} + +void osal_spin_unlock_irqrestore(osal_spinlock *lock, unsigned long *flags) +{ + spinlock_t *p = NULL; + + if ((lock == NULL) || (flags == NULL) || (lock->lock == NULL)) { + printk("parameter invalid!\n"); + return; + } + + p = (spinlock_t *)(lock->lock); + spin_unlock_irqrestore(p, *flags); +} + +void osal_spin_lock_destroy(osal_spinlock *lock) +{ + spinlock_t *p = NULL; + + if (lock == NULL) { + printk("parameter invalid!\n"); + return; + } + + p = (spinlock_t *)(lock->lock); + kfree(p); + lock->lock = NULL; +} + +int osal_mutex_init(osal_mutex *mutex) +{ + struct mutex *p = NULL; + + if (mutex == NULL || mutex->mutex != NULL) { + printk("parameter invalid!\n"); + return OSAL_FAILURE; + } + + p = kmalloc(sizeof(struct mutex), GFP_KERNEL); + if (p == NULL) { + printk("kmalloc error!\n"); + return OSAL_FAILURE; + } + + mutex_init(p); + mutex->mutex = p; + + return OSAL_SUCCESS; +} + +int osal_mutex_lock(osal_mutex *mutex) +{ + struct mutex *p = NULL; + + if (mutex == NULL || mutex->mutex == NULL) { + printk("parameter invalid!\n"); + return OSAL_FAILURE; + } + + p = (struct mutex *)(mutex->mutex); + mutex_lock(p); + + return OSAL_SUCCESS; +} + +void osal_mutex_unlock(osal_mutex *mutex) +{ + struct mutex *p = NULL; + + if (mutex == NULL || mutex->mutex == NULL) { + printk("parameter invalid!\n"); + return; + } + + p = (struct mutex *)(mutex->mutex); + + mutex_unlock(p); +} + +void osal_mutex_destroy(osal_mutex *mutex) +{ + struct mutex *p = NULL; + + if (mutex == NULL || mutex->mutex == NULL) { + printk("parameter invalid!\n"); + return; + } + p = (struct mutex *)(mutex->mutex); + kfree(p); + mutex->mutex = NULL; +} + +int osal_wait_init(osal_wait *wait) +{ + wait_queue_head_t *wq = NULL; + if (wait == NULL || wait->wait != NULL) { + printk("parameter invalid!\n"); + return OSAL_FAILURE; + } + wq = (wait_queue_head_t *)kmalloc(sizeof(wait_queue_head_t), GFP_ATOMIC); + if (wq == NULL) { + printk("kmalloc error!\n"); + return OSAL_FAILURE; + } + init_waitqueue_head(wq); + wait->wait = wq; + return OSAL_SUCCESS; +} + +int osal_wait_timeout_interruptible(osal_wait *wait, osal_wait_condition_func func, const void *param, + unsigned long ms) +{ + wait_queue_head_t *wq = NULL; + + if (wait == NULL || wait->wait == NULL) { + printk("parameter invalid!\n"); + return OSAL_FAILURE; + } + + wq = (wait_queue_head_t *)(wait->wait); + + if (func == NULL) { + return wait_event_interruptible_timeout((*wq), OSAL_WAIT_CONDITION_TRUE, msecs_to_jiffies(ms)); + } + + return wait_event_interruptible_timeout((*wq), func(param), msecs_to_jiffies(ms)); +} + +void osal_wait_wakeup_interruptible(osal_wait *wait) +{ + wait_queue_head_t *wq = NULL; + + if (wait == NULL || wait->wait == NULL) { + printk("wait is NULL!\n"); + return; + } + + wq = (wait_queue_head_t *)(wait->wait); + + wake_up_interruptible(wq); +} + +void osal_wait_destroy(osal_wait *wait) +{ + wait_queue_head_t *wq = NULL; + + if (wait == NULL || wait->wait == NULL) { + printk("wait is NULL!\n"); + return; + } + + wq = (wait_queue_head_t *)(wait->wait); + kfree(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) +{ + struct task_struct *k = NULL; + osal_task *p = NULL; + + if (handler == NULL) { + printk("task handler is null!\n"); + return NULL; + } + + p = (osal_task *)kzalloc(sizeof(osal_task), GFP_KERNEL); + if (p == NULL) { + printk("kmalloc error!\n"); + return NULL; + } + + k = kthread_run(handler, data, name); + if (IS_ERR(k)) { + printk("kthread create error! k = %#x!\n", k); + kfree(p); + p = NULL; + return NULL; + } + p->task = k; + return p; +} + +void osal_kthread_destroy(osal_task *task, unsigned int stop_flag) +{ + if (task == NULL || task->task == NULL) { + printk("parameter invalid!\n"); + return; + } + /* note: When you call the Kthread_stop function, the thread function cannot be finished, otherwise it will oops. */ + if (stop_flag != 0 && task->task != NULL) { + kthread_stop((struct task_struct *)(task->task)); + } + task->task = NULL; + kfree(task); +} +#endif + +#ifndef CONFIG_FILE_BY_ARRAY +static struct file *klib_fopen(const char *file, int flags, int mode) +{ + struct file *filp = filp_open(file, flags, mode); + return (IS_ERR(filp)) ? NULL : filp; +} + +static void klib_fclose(struct file *filp) +{ + if (filp != NULL) { + filp_close(filp, NULL); + } + return; +} + +static int klib_fread(char *buf, unsigned long size, struct file *filp) +{ + int readlen; + readlen = kernel_read(filp, buf, size, &filp->f_pos); + return readlen; +} + +void *osal_klib_fopen(const char *file, int flags, int mode) +{ + if (file == NULL) { + printk("file NULL!\n"); + return NULL; + } + + return (void *)klib_fopen(file, flags, mode); +} + +void osal_klib_fclose(void *filp) +{ + if (filp == NULL) { + printk("filp NULL!\n"); + return; + } + + klib_fclose((struct file *)filp); +} + +int osal_klib_fread(char *buf, unsigned long size, void *filp) +{ + if ((buf == NULL) || (filp == NULL)) { + printk("buf&filp NULL!\n"); + return OSAL_FAILURE; + } + + return klib_fread(buf, size, (struct file *)filp); +} + +int osal_klib_fseek(long long offset, int whence, void *filp) +{ + int ret; + loff_t res; + + if (filp == NULL) { + printk("filp NULL!\n"); + return OSAL_FAILURE; + } + + res = vfs_llseek(filp, offset, whence); + ret = (int)res; + if (res != (loff_t)ret) { + ret = OSAL_EOVERFLOW; + } + + return ret; +} +#endif 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 index 000000000..0a4d2b43b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/gnss_board_port.c @@ -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 index 000000000..3a9e60459 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_log_port.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board log port. \n + * + * History: \n + * 2023-05-06, Create file. \n + */ +#ifndef BOARD_LOG_PORT_H +#define BOARD_LOG_PORT_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_board_port_log LOG port + * @ingroup tiot_board_port + * @{ + */ + +#define TIOT_LOG_ALERT 0 /*!< Log level alert. */ +#define TIOT_LOG_ERR 1 /*!< Log level error. */ +#define TIOT_LOG_WARNING 2 /*!< Log level warning. */ +#define TIOT_LOG_INFO 3 /*!< Log level info. */ +#define TIOT_LOG_DEBUG 4 /*!< Log level debug. */ + +#define TIOT_BOARD_LOG_LEVEL TIOT_LOG_INFO /* 驱动日志默认为INFO等级,可按需要替换为其他等级. */ + +/* 适配板级格式化日志接口 */ +#define BOARD_PRINT_FUNCTION_NAME board_log_with_format("%s\r\n", __func__) +#define board_print_dbg(s, args...) board_log_with_format(s, ##args) +#define board_print_info(s, args...) board_log_with_format(s, ##args) +#define board_print_info(s, args...) board_log_with_format(s, ##args) +#define board_print_suc(s, args...) board_log_with_format(s, ##args) +#define board_print_warning(s, args...) board_log_with_format(s, ##args) +#define board_print_err(s, args...) board_log_with_format(s, ##args) +#define board_print_alter(s, args...) board_log_with_format(s, ##args) + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..4532ba674 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_misc_port.c @@ -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 index 000000000..0cee236e7 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_pin_port.c @@ -0,0 +1,69 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board PIN port. \n + * + * History: \n + * 2023-04-20, Create file. \n + */ +#include "tiot_board_pin_port.h" + +#define err2ret(errcode) (((errcode) == ERRCODE_SUCC) ? 0 : -1) + +static tiot_pin_int_callback g_tiot_gpio_callback = NULL; + +int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level) +{ + errcode_t errcode; + uint32_t gpio_level = level == TIOT_PIN_LEVEL_LOW ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH; + errcode = board_gpio_set_level(pin, gpio_level); + return err2ret(errcode); +} + +int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level) +{ + uint32_t gpio_level = board_gpio_get_level(pin); + *level = (gpio_level == GPIO_LEVEL_LOW) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH; + return 0; +} + +int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable) +{ + errcode_t errcode; + if (int_enable == TIOT_PIN_INT_ENABLE) { + errcode = board_gpio_enable_interrupt(pin); + } else { + errcode = board_gpio_disable_interrupt(pin); + } + return err2ret(errcode); +} + +/* 必须向回调内传入触发中断的管脚id. */ +static void board_gpio_callback_adapter(uint32_t pin, uintptr_t param) +{ + (void)param; + board_gpio_clear_interrupt(pin); + if (g_tiot_gpio_callback != NULL) { + g_tiot_gpio_callback(pin); + } +} + +int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb) +{ + /* 仅GNSS唤醒板级管脚使用此接口,必须为上升沿中断. */ + errcode_t errcode; + if (int_cb != NULL) { + errcode = board_gpio_register_isr_func((pin_t)pin, + GPIO_INTERRUPT_RISING_EDGE, + board_gpio_callback_adapter); + } else { + errcode = board_gpio_unregister_isr_func((pin_t)pin); + } + + if (errcode == ERRCODE_SUCC) { + if (g_tiot_gpio_callback == NULL) { + g_tiot_gpio_callback = int_cb; + } + } + return err2ret(errcode); +} \ 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 index 000000000..1980af323 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_board_uart_port.c @@ -0,0 +1,146 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board UART port. \n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#include "tiot_board_uart_port.h" +#include "tiot_board_log.h" + +/* 记录xmit指针,用于板级回调无法传入指针情况. */ +static tiot_xmit *g_tiot_uart_xmit_backup; + +static tiot_xmit_callbacks g_tiot_uart_rx_cbs; + +/* 板级回调内向驱动回调传入UART接收到的数据. */ +static void tiot_uart_rx_callback_demo(const void *buff, uint16_t length) +{ + /* 必须传入xmit指针,此处使用open时备份值. */ + g_tiot_uart_rx_cbs.rx_notify(g_tiot_uart_xmit_backup, (uint8_t *)buff, length); +} + +static void tiot_uart_rx_callback_demo2(const void *ptr, const void *buff, uint16_t length) +{ + /* 必须传入xmit指针,此处板级回调接口传入值. */ + g_tiot_uart_rx_cbs.rx_notify(ptr, (uint8_t *)buff, length); +} + +int32_t tiot_board_uart_open_demo(tiot_xmit *xmit, tiot_xmit_callbacks *cbs) +{ + /* xmit->id即为板级信息配置的UART id, 可按板级接口需要转为 其他区分UART通道方式. */ + errcode_t ret = board_uart_open(xmit->id); + if (ret != ERRCODE_SUCC) { + return -1; + } + g_tiot_uart_rx_cbs = *cbs; + /* 记录xmit指针,用于板级回调无法传入指针情况. */ + g_tiot_uart_xmit_backup = xmit; + board_uart_register_rx_callback(xmit->id, tiot_uart_rx_callback_demo); + return 0; +} + +int32_t tiot_board_uart_open_demo2(tiot_xmit *xmit, tiot_xmit_callbacks *cbs) +{ + /* xmit->id即为板级信息配置的UART id, 可按板级接口需要转为 其他区分UART通道方式. */ + board_uart_handle *handle = board_uart_open_as_handle(xmit->id); + if (handle == NULL) { + return -1; + } + g_tiot_uart_rx_cbs = *cbs; + xmit->handle = handle; + /* 板级注册回调可传入指针情况. */ + board_uart_register_rx_callback_withptr(xmit->id, tiot_uart_rx_callback_demo2, xmit); + return 0; +} + +int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs) +{ + return tiot_board_uart_open_demo(xmit, cbs); +} + +void tiot_board_uart_close(tiot_xmit *xmit) +{ + board_uart_unregister_rx_callback(xmit->id); + board_uart_close(xmit->id); +} + +int32_t tiot_board_uart_write_demo2(tiot_xmit *xmit, const uint8_t *buff, uint32_t len) +{ + if (xmit->handle == NULL) { + return -1; + } + return board_uart_write(xmit->handle, buff, len); +} + +int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len) +{ + return board_uart_write(xmit->id, buff, len); +} + +int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len) +{ + /* 如果通过回调方式将UART接收数据传入驱动回调,此接口可空实现. */ + return board_uart_read(xmit->id, buff, len); +} + +int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config) +{ + /* TIOT UART接口使用的UART配置枚举定义可能和板级定义不同, 在配置时可以进行转换. */ + const uint8_t board_uart_data_bits_map[TIOT_UART_ATTR_DATABIT_BUTT] = { + BOARD_UART_DATA_BIT_8, + BOARD_UART_DATA_BIT_7, + BOARD_UART_DATA_BIT_6, + BOARD_UART_DATA_BIT_5 + }; + const uint8_t board_uart_stop_bits_map[TIOT_UART_ATTR_STOPBIT_BUTT] = { + BOARD_UART_STOP_BIT_1, + BOARD_UART_STOP_BIT_2 + 1, /* Invalid stop bits. */ + BOARD_UART_STOP_BIT_2 + }; + const uint8_t board_uart_parity_map[TIOT_UART_ATTR_PARITY_BUTT] = { + BOARD_UART_PARITY_NONE, + BOARD_UART_PARITY_ODD, + BOARD_UART_PARITY_EVEN, + BOARD_UART_PARITY_EVEN + 1, /* Invalid parity bits. */ + BOARD_UART_PARITY_EVEN + 1 /* Invalid parity bits. */ + }; + errcode_t ret; + if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) || + (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) || + (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) { + return -1; + } + /* 切换UART配置时,必须确保切换配置前的UART数据已从FIFO发送完成. */ + while (board_uart_has_pending_transmissions(xmit->id) == true) {;} + + board_uart_cfg_t cfg = { config->baudrate, + board_uart_data_bits_map[config->attr.data_bits], + board_uart_stop_bits_map[config->attr.stop_bits], + board_uart_parity_map[config->attr.parity], + config->attr.flow_ctrl }; + ret = board_uart_set_config(xmit->id, &cfg); + return (ret == ERRCODE_SUCC) ? 0 : -1; +} + +/* GNSS UART固定使用 data_bit=8, stop_bit=1, parity=None. */ +int32_t tiot_board_uart_set_config_simple(tiot_xmit *xmit, tiot_uart_config *config) +{ + errcode_t ret; + if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) || + (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) || + (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) { + return -1; + } + /* 切换UART配置时,必须确保切换配置前的UART数据已从FIFO发送完成. */ + while (board_uart_has_pending_transmissions(xmit->id) == true) {;} + + board_uart_cfg_t cfg = { config->baudrate, + BOARD_UART_DATA_BIT_8, + BOARD_UART_STOP_BIT_1, + BOARD_UART_PARITY_NONE, + config->attr.flow_ctrl }; + ret = board_uart_set_config(xmit->id, &cfg); + return (ret == ERRCODE_SUCC) ? 0 : -1; +} 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 index 000000000..318cc812c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_freertos_demo.c @@ -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 +#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 index 000000000..34e934cae --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_nonos_demo.c @@ -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 index 000000000..32af73e13 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_rtos/tiot_osal_port_rtos_demo.c @@ -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 index 000000000..b5e118505 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/CMakeLists.txt @@ -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 index 000000000..a13d388df --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/gnss_board_port.c @@ -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 index 000000000..8a87996b1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_log_port.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board log port. \n + * + * History: \n + * 2023-05-06, Create file. \n + */ +#ifndef BOARD_LOG_PORT_H +#define BOARD_LOG_PORT_H + +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/** + * @defgroup tiot_board_port_log LOG port + * @ingroup tiot_board_port + * @{ + */ + +/* 通过printf直接打印,不需要日志时需要注释掉define后半部分. */ +#define BOARD_PRINT_FUNCTION_NAME printf("%s\r\n", __func__) +#define board_print_dbg(s, args...) printf(s, ##args) +#define board_print_info(s, args...) printf(s, ##args) +#define board_print_info(s, args...) printf(s, ##args) +#define board_print_suc(s, args...) printf(s, ##args) +#define board_print_warning(s, args...) printf(s, ##args) +#define board_print_err(s, args...) printf(s, ##args) +#define board_print_alter(s, args...) printf(s, ##args) + +/** + * @} + */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif 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 index 000000000..a7a6e4324 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_misc_port.c @@ -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 index 000000000..aebb1c2a1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_pin_port.c @@ -0,0 +1,112 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board PIN port. \n + * + * History: \n + * 2023-04-20, Create file. \n + */ +#include "tiot_board_pin_port.h" +#include "gpio.h" + +#define uapi_err2ret(errcode) (((errcode) == ERRCODE_SUCC) ? 0 : -1) + +/* TIoT驱动使用中断管脚个数,需要按实际板级情况适配修改。 */ +#define TIOT_INT_PIN_NUMBER 1 +typedef struct { + uint32_t pin; + tiot_pin_int_callback callback; +} tiot_int_pin_map; +/* TIoT驱动使用中断管脚配置,需要按实际使用的中断管脚适配修改。 */ +static tiot_int_pin_map g_tiot_int_pin_map[TIOT_INT_PIN_NUMBER] = { + /* 例如使用XXX唤醒MCU管脚,对应GPIO ID为S_AGPIO_R0. */ + { S_AGPIO_R0, NULL } +}; + +/** + * @brief Board set pin level interface. + * @param [in] pin Pin id. + * @param [in] level Pin level, see @ref tiot_pin_level. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_set_level(uint32_t pin, uint8_t level) +{ + errcode_t errcode; + gpio_level_t gpio_level = (level == TIOT_PIN_LEVEL_LOW) ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH; + errcode = uapi_gpio_set_val((pin_t)pin, gpio_level); + return uapi_err2ret(errcode); +} + +/** + * @brief Board get current pin level interface. + * @param [in] pin Pin id. + * @param [out] level Current pin level, see @ref tiot_pin_level. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_get_level(uint32_t pin, uint8_t *level) +{ + gpio_level_t gpio_level = uapi_gpio_get_val((pin_t)pin); + *level = (gpio_level == GPIO_LEVEL_LOW) ? TIOT_PIN_LEVEL_LOW : TIOT_PIN_LEVEL_HIGH; + return 0; +} + +/** + * @brief Board pin interrupt enable interface. + * @param [in] pin Pin id. + * @param [in] int_enable Interrupt enable or disable, see @ref tiot_pin_int_enable. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_enable_int(uint32_t pin, uint8_t int_enable) +{ + errcode_t errcode; + if (int_enable == TIOT_PIN_INT_ENABLE) { + errcode = uapi_gpio_enable_interrupt((pin_t)pin); + } else { + errcode = uapi_gpio_disable_interrupt((pin_t)pin); + } + return uapi_err2ret(errcode); +} + + +static void tiot_board_gpio_callback(pin_t pin, uintptr_t param) +{ + (void)param; + uapi_gpio_clear_interrupt(pin); + for (uint8_t index = 0; index < TIOT_INT_PIN_NUMBER; index++) { + if ((pin == g_tiot_int_pin_map[index].pin) && (g_tiot_int_pin_map[index].callback != NULL)) { + g_tiot_int_pin_map[index].callback(pin); + break; + } + } +} + +/** + * @brief Board pin interrupt callback register interface. + * @note Porting should ensure this callback is called when enters pin irq if interrupt enabled. + * @param [in] pin Pin id. + * @param [in] int_cb Registed interrupt callback, see @ref tiot_pin_int_callback. + * @return zero if OK; + * non-zero if FAIL. + */ +int32_t tiot_board_pin_register_int_callback(uint32_t pin, tiot_pin_int_callback int_cb) +{ + errcode_t errcode; + if (int_cb != NULL) { + errcode = uapi_gpio_register_isr_func((pin_t)pin, GPIO_INTERRUPT_RISING_EDGE, tiot_board_gpio_callback); + } else { + errcode = uapi_gpio_unregister_isr_func((pin_t)pin); + } + if (errcode != ERRCODE_SUCC) { + return -1; + } + for (uint8_t index = 0; index < TIOT_INT_PIN_NUMBER; index++) { + if (pin == g_tiot_int_pin_map[index].pin) { + g_tiot_int_pin_map[index].callback = int_cb; + break; + } + } + return 0; +} \ 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 index 000000000..b622e29d7 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/porting_gnss_demo_sparta/tiot_board_uart_port.c @@ -0,0 +1,193 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: Board UART port\n + * + * History: \n + * 2023-03-25, Create file. \n + */ +#include "tiot_board_uart_port.h" +#include "tiot_board_log.h" + +#include "uart.h" +#include "uart_porting.h" +#include "pinctrl.h" +#include "pinctrl_porting.h" + +#define TIOT_UAPI_RW_TIMEOUT 0xFFFFFFFF +#define UART_RX_BUFFER_SIZE 56 + +#define TIOT_UAPI_UART_RX_MAX 1024 + +/* TIoT驱动使用MCU UART个数. */ +enum tiot_uart_port { + TIOT_UART_PORT0, + TIOT_UART_NUM, + TIOT_UART_NONE = TIOT_UART_NUM +}; + +enum tiot_uart_pin_type { + UART_PIN_TYPE_TX, + UART_PIN_TYPE_RX, + UART_PIN_TYPE_CTS, + UART_PIN_TYPE_RTS, + UART_PIN_TYPE_NUM +}; + +typedef struct { + tiot_xmit *xmit; + uint8_t flow_ctrl_bk; + uint8_t rx_buff[UART_RX_BUFFER_SIZE]; + const uart_pin_config_t pin_config_orig; + uart_pin_config_t pin_config; + hal_pio_func_t pinmux[UART_PIN_TYPE_NUM]; + uart_rx_callback_t rx_callback; +} tiot_board_uart_port; + +static tiot_xmit_callbacks g_tiot_xmit_cbs; + +/* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加 */ +static void tiot_board_rx_callback0(const void *buff, uint16_t length, bool error); +/* TIoT驱动使用的UART初始信息,需要按实际板级情况适配。 */ +static tiot_board_uart_port g_tiot_board_uart_port[TIOT_UART_NUM] = { + /* TIOT_UART_PORT0. */ + { + .flow_ctrl_bk = TIOT_UART_ATTR_FLOW_CTRL_ENABLE, /* MCU UART默认是否开启流控。 */ + .rx_buff = { 0 }, + .pin_config_orig = { S_MGPIO19, S_MGPIO20, S_MGPIO21, S_MGPIO22 }, /* MCU UART管脚,按实际板级情况适配。 */ + /* MCU UART管脚pinmux,按实际板级情况适配。 */ + .pinmux = { + HAL_PIO_FUNC_UART1, HAL_PIO_FUNC_UART1, + HAL_PIO_FUNC_UART1, HAL_PIO_FUNC_UART1 + }, + .rx_callback = tiot_board_rx_callback0 /* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加。 */ + } + /* TIOT_UART_PORTx... */ +}; + +/* MCU UART bus号与TIoT驱动使用的UART 对应关系,需要按实际情况适配。 */ +static inline enum tiot_uart_port tiot_board_uart_bus_convert_port(uart_bus_t bus) +{ + /* 例如 UART_BUS_0 对应 TIoT驱动使用的第一个UART。 */ + if (bus == UART_BUS_0) { + return TIOT_UART_PORT0; + } + return TIOT_UART_NONE; +} + +static inline void tiot_board_rx_callback_common(tiot_board_uart_port *port, const void *buff, uint16_t length) +{ + g_tiot_xmit_cbs.rx_notify(port->xmit, (uint8_t *)buff, length); +} + +/* MCU UART管脚接收回调,按TIoT驱动使用UART个数适配增加 */ +static void tiot_board_rx_callback0(const void *buff, uint16_t length, bool error) +{ + if (error == false) { + tiot_board_rx_callback_common(&g_tiot_board_uart_port[TIOT_UART_PORT0], buff, length); + } else { + tiot_print_err("[TIoT]uart port0 receive error.\r\n"); + } +} + +static void tiot_board_uart_txrx_pinmux_init(tiot_board_uart_port *port) +{ + /* 防止板级未初始化. */ + uapi_pin_set_mode(port->pin_config.tx_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_TX]); + uapi_pin_set_mode(port->pin_config.rx_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_RX]); +} + +static void tiot_board_uart_switch_flowctrl(tiot_board_uart_port *port) +{ + /* 板级uart初始化不会初始化ctsrts pinmux... */ + if (port->flow_ctrl_bk == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) { + port->pin_config.cts_pin = port->pin_config_orig.cts_pin; + port->pin_config.rts_pin = port->pin_config_orig.rts_pin; + uapi_pin_set_mode(port->pin_config.cts_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_CTS]); + uapi_pin_set_mode(port->pin_config.rts_pin, (pin_mode_t)port->pinmux[UART_PIN_TYPE_RTS]); + } else { + port->pin_config.cts_pin = PIN_NONE; + port->pin_config.rts_pin = PIN_NONE; + } +} + +static int32_t tiot_board_uart_reopen(uart_bus_t bus, tiot_board_uart_port *port, const uart_attr_t *attr) +{ + uart_buffer_config_t buff_cfg = { (uint8_t *)port->rx_buff, UART_RX_BUFFER_SIZE }; + (void)uapi_uart_deinit(bus); + tiot_board_uart_txrx_pinmux_init(port); + tiot_board_uart_switch_flowctrl(port); + errcode_t ret = uapi_uart_init(bus, &(port->pin_config), attr, NULL, &buff_cfg); + if (ret != ERRCODE_SUCC) { + return -1; + } + uapi_uart_register_rx_callback(bus, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE, + TIOT_UAPI_UART_RX_MAX, port->rx_callback); + return 0; +} + +int32_t tiot_board_uart_open(tiot_xmit *xmit, tiot_xmit_callbacks *cbs) +{ + enum tiot_uart_port port_type = tiot_board_uart_bus_convert_port((uart_bus_t)xmit->id); + if (port_type == TIOT_UART_NONE) { + return -1; + } + tiot_board_uart_port *port = &g_tiot_board_uart_port[port_type]; + const uart_attr_t init_attr = { 115200, UART_DATA_BIT_8, UART_STOP_BIT_1, UART_PARITY_NONE, + ((port->flow_ctrl_bk == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ? + UART_FLOW_CTRL_RTS_CTS : UART_FLOW_CTRL_NONE) }; + port->pin_config.tx_pin = port->pin_config_orig.tx_pin; + port->pin_config.rx_pin = port->pin_config_orig.rx_pin; + if (tiot_board_uart_reopen((uart_bus_t)xmit->id, port, &init_attr) != 0) { + return -1; + } + g_tiot_xmit_cbs = *cbs; + port->xmit = xmit; + xmit->handle = port; + return 0; +} + +void tiot_board_uart_close(tiot_xmit *xmit) +{ + uapi_uart_unregister_rx_callback(xmit->id); + (void)uapi_uart_deinit(xmit->id); +} + +int32_t tiot_board_uart_write(tiot_xmit *xmit, const uint8_t *buff, uint32_t len) +{ + return uapi_uart_write_nolock(xmit->id, buff, len, TIOT_UAPI_RW_TIMEOUT); +} + +int32_t tiot_board_uart_read(tiot_xmit *xmit, uint8_t *buff, uint32_t len) +{ + return uapi_uart_read(xmit->id, buff, len, TIOT_UAPI_RW_TIMEOUT); +} + +int32_t tiot_board_uart_set_config(tiot_xmit *xmit, tiot_uart_config *config) +{ + errcode_t ret; + tiot_board_uart_port *port = xmit->handle; + if ((config == NULL) || (config->attr.data_bits >= TIOT_UART_ATTR_DATABIT_BUTT) || + (config->attr.stop_bits >= TIOT_UART_ATTR_STOPBIT_BUTT) || + (config->attr.parity >= TIOT_UART_ATTR_PARITY_BUTT)) { + return -1; + } + if (port == NULL) { + return -1; + } + /* 确保当前无数据正在FIFO内传输,才能修改配置. */ + while (uapi_uart_has_pending_transmissions(xmit->id) == true) {;} + + const uart_attr_t attr = { config->baudrate, UART_DATA_BIT_8, UART_STOP_BIT_1, UART_PARITY_NONE, + ((config->attr.flow_ctrl == TIOT_UART_ATTR_FLOW_CTRL_ENABLE) ? + UART_FLOW_CTRL_RTS_CTS : UART_FLOW_CTRL_NONE) }; + /* 调整流控需要重新init. */ + if (config->attr.flow_ctrl != port->flow_ctrl_bk) { + port->flow_ctrl_bk = config->attr.flow_ctrl; + if (tiot_board_uart_reopen((uart_bus_t)xmit->id, port, &attr) != 0) { + return -1; + } + } + ret = uapi_uart_set_attr(xmit->id, &attr); + return (ret == ERRCODE_SUCC) ? 0 : -1; +} 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 index 000000000..aad6a4e76 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_autoconfig.h @@ -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 index 000000000..6816a9bd9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/driver/tiot_driver/product_porting/tiot_defconfig @@ -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 index 000000000..e11d8f281 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_cfg.bin @@ -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 index 000000000..3e86a613b --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.c @@ -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 index 000000000..bb61c32e5 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format1/file_array/gnss_fw_file_array.h @@ -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 index 0000000000000000000000000000000000000000..9126639b9a3ffdd124eb00dea94f3eb5b8f6478d GIT binary patch literal 14469 zcmeHudt6jy`uKY;?_7Zf4ntyE;|#;q*ik^TtsHO;3aN{Z=yuV?5X)9;w5%<^?t(LC z5Jp;XL>*mign`3;;zZh?{FkKMEYc?*#qyD zGjkNkjbREBBi0NPGc%*8GLBkV1a5os}}Ej#6#fBnl0*Ow0OpxE?!%c#>nb+drA8>YPK%;&Xw?8Ykw?QZ%+}c zGp2AYQGkm|q)x?|r1mw_CyTq<%|LIdsCUn4Mog@Pe^=K7;;tENvNO@)Bk*>0jSAA$ zIZ4cv{l;|)%Ov=jotYE9gZ^{8QapzXTn~?()_OJQR2C-WwBmZziTtpV@q8nqJCy# zqBE2a;@SUOaZPw3tCO3=>JMLOZDw^kY5vT~;!^U8go5%YLSt4SbXkefYj4QW*+Mz0FUQD3DbO(vBV`nej`h)K)KwZC zdy+-tmoi9cW6tobgU7|^$Z#VPw_4WJpu36G6D8@cs>Stj$*V^BSXqMpz~E0 zjroE`XHzlCegva=R*c4bfHs!`DdUvL^JjqlCXEhq44Rh<&+9TYDjB0aU2=46mkd$$ zGPKo(QFsM~mT(GGtdgOVqk+G889J+_Q1-3=4i)%0m*x#(--2&ijmXUO1ZHxtXb~q+ zF;u5vBhG()WOSCn+y01KD83{Cqmmfd=-hBFW;k%Fj-eotWYf+a*CR5^((a8I4uhIQdwgKa_9hE8^<4M zaEPcLj#18OK`Nn=uXc*Lmzr-GQE{S^OVc8EvldM)kG`Ca4T!_N_qI0EF>b*)U(8=$ z-TED+V*;hyagN&ozXx5zv=qaKqri9R@F=CI(*Ru5(A*~ah`QjfqC z8C7GqQ0i>VERR)QA2L23#xD}{Z)_r1T*_XG2{@4JKFo-=zqf%IV7^~?j!aii#thTx zK(~H6eeA&W&1*FFEDA9=95J&-A;apEZyN+3a%Ia{GFy3MdE8IXjt`QV4x&n^u-9h1 zUK|)JtgMRmayVZv=3o9IRuFZi=Ow~dXKzd&j*Kh)+|8;Ypr!!|bL&5|_hif>CFSYCwuPtM%f4ectkQ|O z34bl;$*hD^?kXkKUd-V#Xg&C;yGKcJ_z;wppW1thXTj)EVs7>)_MWX!&Vh32342dF zl*^!eu*cqW7Rra9tn2|i3Ig-;@j;rhNl8Q6>br@=qL0{T<>>Cpg(7m9sdpA_d@+Bv zok%7;c|3wLJWYw93EwCk2VZUTFohmM{1?Sv~2W`Xd4Mlo#_SeM>g+ z&*84nrlfh%ZLL482`w%Uy^`Kffh2|Pj8KS{$D(2(>-a&84fa~3&WK_ZYksC(x*%-% zxBrm>LvU1FU(k%K&?+ijGcnEZPNddiDg|(_EUMAUz=J)3MtO%vxN!@@{L1j)_ye07 z9N-r9+k3;r>2(AJC>e@bQ~5|&77{8z8rM++@z7^Zro-mn9?jGytMKl z2M4Zk<$zxESE(eyCmWV=cg4_b;OT#;EHEqim;O#>*kM$ouv>OCV{Hbv|K=U{q?>nE zys_+$8`_Vyt1Ugut)J{K^yHBFBL1L@&*W1Mv><w*QK6RzY_%mo z+t;z^r+XCT1B~BMS@crOQtT};e}C`o=GYPtg$Q;oRf_`6WQ*B(BXXU_GMwetwjg(Z z9$nRL$5?(_ySmbK9Mg8bhvBZLq3Dn1jvViOY-G*-m>%yXt?vG1VKrgRG{vthvhx9^ z_cp^fGsGg2g&~25-C{&y(-ZHgRbcgu7Ny;2QP^dyye5Q|aWXApjI8>0)Y>(M#14h) z3mKi{Y<|Bnt>t}fme};&--vR%g@CS6sA5-V7~*}Zg8XLMpkQU8d`*Z?W{781hD28J z@CcoU3Xq!49OA%SB(|vlQbISwvvL=srPUE>)JmSi6^oLc_E?AV)pfoOPL9ke z{6%_P6<)x}PQ>hR-dNYs!Nhhb4WoSue<$e~TV+W0DWai&!TmR?Iy$y)8-zk2Fh++` zSiqIYyeU~1X&4LhIOiZFPKM0>&Q5@02be0HFe!!ag&KkAS>SdOh{rqpfdE~G{efOO zcXD!-JMVhNKHOLv$ahD{Kn!dY;9szHH&>Vyt7&i#_;`t!l+Vel5Z!b=# zc(HH8W->F#YsIhrHLtzqL0GY01YrfP425;?J3ps!D6c4UkXQWpAe_3t{wp}^{Xd5@ zlvlJk$ZMQ8$ZOk%^qIuScbp_XgXn$Nk&YRioyRe*N-bqTIEItq7}CaJoCpVq%q>GQ z(VPy4>`zxFh~?`QUt7RwKP8Tv#Y0-by`!6L z3WeC#uv|jFrYbTZc%$+KL|u-xgY~w%|uZU4k8q!zsfK-(LZ?_#6`34sFlmckyDIYF8`J z{Bvm$hk{#frnf7+VnHc8A`C**Q6rOakR%fW_ zKwt(mK17th&68XT<21Hk!19jZSQMFbp;j-N9{F%^9@Jru1BJqzdPLk#^Tve%a6>hw z(RR$r8%mjkjzmuAzq6{6!+rO-j(~x*_!!aj{reIOFn%sKOK~!w0h_{=+h7xo0AmuF zR5;E+T9XP}^!7YUT*0DdIN>50;@*LQNmLIf@5n@a7G$Al#IR|bYu~RbbPI)f1|6#^ znBR;HdR74nAy-FZ3b+ab6R2Yqq?PzYZfs`UGBZPE!S?*7K&3kMIKHBw!@|GL3 zOn9(X98Ig;N-9}61Wx*sx5V6&0i#zxLd<<4Fn_aKxO|8BAmHa*mZU~w))j$ij0q%B z6a7PYyMBajqn-o~n%BR*+)7MbgOh=S4Ezaqvf!E_r*{c2YQ8#a57aTPHJBo`oO9$i z@jT(9#j&e2nQ)T(-Fs8pU7J`+Jt+p<=;+PMWxq&<(?3FuWfaE;k~o=J=Eg-KjfHg} zhdoHQQMB#Z$YK6C@s`|asf5m6S9m0NkqDQ1Mcc^@9ABt+^Q33wWqVIOF|H9xzMznJ zGU^U|)t;wBDLu7_=pC44OdTXzL;Pu^B5ljTOv74&*NGxYU0O>B5=efDQ{uPMowT{t zL7N$)5CzFej{ql<{i(Y`8Nr-P5p&mH z4AT(ffeW>K^y-+`a;pc-|k}We65s#y=+^yB3`qc(zH=3NA zsF{2`-5CMGkg4s)EHx9`sb09!f3X(%ug6jbx&wJS{ryI8_l%U{^pw-Z9T10lcD4p( zVBVnjk~F6k;V$dTSS6a?Xd2Tlnv$D1o`D@ocO%7_M$=ZihbQ8g@7d|2z z2dUR`*uikJ4%#hq&>sn6(GPVBujmc=cJj+1FVo|!7-x11IFs~DyKV)VRDv5L7>#Jj z?7USbOaqm>uTAmtJ|h_|7R}w%jcfH1-{bHsy+H7ZD5k^sc#%aIi@K&@q%gt^@qV0MwnECaM^L-$DaM4+O4b}tjn`usIru71$ z;?*~S`=YEp4NlUh7h;{F`K`UtQh=0kWQdpY5NKYinA_@W@{k#^Ee#G=Jbr-ax^YNM zPCZJ-0hHX?Z#8+uqGx>#&J@9c{MchoZ-MP6yZD5tneA8WF=|*l=AUAE$`Ztrz6A^i z&{HRfw%?by1qe-~x@f!qk4@xw+92wF5Fc$%bP(Pct?;~1ScMIm-NYY525vX_u@3Zh zrP%k`4nw#PiG7lSl1R}HMBm1lvbeBUkurFtCW%A}rP)NSz#lFwhz4-uU zDfzc#vzj-k*J>$nLs7MMax{$)~{tROvPd{P=$o0-Xf?GojyI$}fMRc~MZ^rIeBF@gofa=7oTICaV&7 zf0Y1Xh+rtba(mfrZFLm{ApPz?%hD~gzmNtt~W7c;Z;H@Uz(+~i01uU7|3C$ zr^slsgvulKtneYipdSxXaHC@R3&J8VP)X?UZV*i&9T2KOs)aG~;iC_z*MpTU#H=CF zrx8t4t`hSCXQ;}@CV07J{kKRvfiGoL0N>BBkjRb5p^VTtWrKQ+aYUk1p}ERm1#g@nvE)Mml+xORk}fGmr94!J{3R`Be~COJMNwz2D)$T8jPUZt-b?zV!Y}n1#YwTv zI`;_@jklpB+?@Yqxve~@@S?u4_o7}rTK9pp!HFq+8Aph@f9n;GE_mO%%r`t}*hm`i zh2!LGo!ddSjNRC2W8$2)lm)GbI`ne3Df?leHr=Y#?t|nTuV@pSru7(TQ1RSpds_pL z`glwoES9KN(8)^O!-C_9Ps$RPG(~Y$K9PA$t z)7gv?9ihCMiK6TsRVYQ+4ZfEVsXt~Jbr`1Ap_mmlXB1N`)*?6#iXywh1CqSP2u~$Q zfs%X-ehQ9>h;9K@Yx&Bv;k-^dj_rIu&0WW|6{D^v4$b6;@kDxZlk90GOG|ebMRi%J zd%GsuD3#h8B@?pz>pGG9`Z{{^M~xTLEa8X1|Do0Q!akL=I!-SCeAG75l0I9ieVpL^ zVlS8h#f^c6!w*-L9%6XNo(Bq6))A!omEc5hs2ik_t6IDZn|b=2hHFMlpUu+`^&Ul7DF3W`sf-v^sVZkIpG92?e6AUu)3O2DS35} z(3)b=SXzldn`BQL%6uSDIPs|{NuY7>u;6Jtk;dSE(5to?N_@1>WA=!qw~I-3pzj`{ zKBDRHpTU!gakCm7K-EbhM`8yt8#^G}2@jeMSU|Q0%!jfQXPFKVL&EiAok7jA;Q@fx z7=6|-Vl8W+*hsSIW;g}@=T<3iz|E+&XUYV(&~w-j+Z;g*CTyeJ2j6?`N;+KjxiS9j zfo$bLd6NLIcG)P>3-sjtM4^ZVs2Oo z_yG~b+>|uo1>IGsI(V8n=QQFL8Eh{!&^L#??E$=mz)CvfeOPW}M{>4@Y*ra z{Fj<}$AYFkJ%-hR1kV#418rJNoPSQ%bDQYmv2stZsC%Rff}ZmNAJTp$4WJ>@OtKZh z#N?0M3!aks_kYLj1GAU7mtjR^FSiVX#Fc!w7xRYIJ_MO^%3TQAFE@r$S+s=)NQ)~{ z3a+4^v>o{{yj|xBj@Jvw^P+A0z91f4=*K=}uN9gg!fH})z|`H<+8x%4&1OS9c_XtS zW_OsM1#QuN{~3|K_K2u^S}KK}g%!YrO4vtp$@)>?cfgETUsyUWnlQ$@%1lzAPzGqe zuu)z@;lg7?Pja_Zdt>+Jyfbb0jHX#{Ke=tLZ>$3Xv3(*snh61uF%m+Jf@mCBY*7{h zg-(B2J;H^YTIlq<7E;{mQfcMoKKz^3=HC^88BksaGJHH#VMFY}&y#n_9wA?;~LoJ>Yn%FkX31Qi&-xllJRqAreXxD})s-+tj*pzK9Io9(6kOgkUtQ94L8UAt z=W=(y#w_Vh6P_pOQj;(b4gq8>24k^=is+``y%NmU(ujzOeUx4rTPr+MGKN)gxM#KX zWq^SN@5H|Fi1N$9-oP_fna@kgp%V^ywt?}_MtkMZ zZx>j)8{qXrQaeQn_gV)qZGEjuBO;q7v^_pmEQ-3CPW0Y{pMlV?IvNb~92eBGtgmUz zQjalE!0<}ct*!S4&tT^QF0Bv_k#3~SBt|gqp-9$>*vz>1SXG=qQe`cIaw`kT((PRh zj>$_x=9xe)wVH|j&AAhob>>PE_rCIWNv$JPUT0C4)OFmW*iCek^iJ$QF)(6QgQ7{F zurKDBm~A9T@Q^QJa3L`qghw#l^Cd$R5O#7{XzE^vs>xaucY4~3`IV7ykeauDbJ&8j zUBwvIe2Bp*lnf3SqwQ{D^hEQcpMx1t^{@EEMMG*O+psEz0vl-FE;a}hPp0PxtIg_l zn6d|ASha)L?MI!EhN0jFAkymrw_I{s232FML!p;aO+^bf%T2KG5HG@p*Na8Yl|TmS z{;|Gb6RBI3KlT^Nn;gIz%n5hsOLnr9)dtRyEjnVq4XdnIQzJgK8C7wnXlYEhO&c-M zrc_O|CD3uHm6HBVM*VQLFV1bF{Mc{r>B+e!j z?Qqb0WPd5!in9*|6w#}PiRN3!fjYXx#4_?R4u-CmZCCBg>512bC^?9G#r#)(h)1i3 z1tTqI$J z-vP{<)8ru2LqL;;jsuKDQeOpYsiekIWhSZbAr^fU^FmDFyuHLD*_2$?;K1`a%mgPeqZW0pUy1(77!;&LsRFGp)^m9!C?abXu|($w1q zuM#d9S)CynFV$@#BT@ijL757HW^~OU$v^Xzo0xwv=oY65Pm|48k|xY2eV#OFE2iPX z96^HjEyWwW^{ACV+)=x92E^8A(~Es0)(~?njWyvyYZa~@aJWrE;ht?|gTpy1ZFlfq zZJ35F9o+m2q`o7AedJ9}=7}~fJ#t`-5F9gfe#C$iZ^F-7m$gMmd8|$8??Lv0eSGn0 z^Sh;x$0>spbr~*nW9)qlvJ^YW_YLb90!l&evX6V?-8XiWJXJfPY2$x5#JO8I` z->)qCeHEAi^*;!x$y@YIv2Pb??1>g+e~?9R7Y`yS=y{it#|Y1EZRjk0-!X1=vda*2 z;ie&$y=92+xM@g?x%nvHi1To}Cq=c>JfqkzyvsC#lMnUKo#y9@{UJNe3yPryM)>hg zvq8W6W-^TW3qwMI43A&E)jYS@U6qJt42bGg$MeEDVV3h7=aVJknIl!|dKJat@9q$X z^n@_O`BbgN+YPq0v9R``+uEn}EoW}`zaX3to_BUR7nFSVsI-tVfoHqH->|}|NAceX zFE~#)iHEYFp#fz94tH*Iy%kD@^FS9S^FD`JtL9l>_MsI~ z4OJ^{;w%D@KpTW*k8|9#$5?L00>mT2-TrSRTysn6N*IulcqY^Vqiz+HDbZX=zP$jP zF>!E7d#2nKTWkd%ilf+@=VIv8_$^Y7M7R3AVk!3HWSxus&Vb}C6*!$}D|Y>@mq|<`jjI5rgW3z^8w`rCoiOUim>g{3)aEd61F}S*X8xA$4K%;_}z7x^d2(P#(kG__PucZK;BYKWByz zR9*8X*MT6uP<~YU_=96|1PjNS!{%3tZLgniC?mq+ z7MIWKC)h^*i0%D1g4lGhQ6%1u6W*fvC6E5dTd2g_(M`1tWzoRfibsEjEd+Se-T031 zW(o2Z@>AZ%|A_7LlA*i-zC+r*1Rv(H<-xQBkS3>YQ%m^z)Th8a0KPqG>U%L|SXZXH zD^H{*I9sm~oDPb}Q>7lnxlod4-j6u96b;3hP69zp0zn)F>l-1hKZNYkdXK>i$+s0G z=Kx*|*1<0^U8E1P7fT)<2WBAT?~*lxnDpy?R4=y7nGk*!E*)TqK`GcstY+RYI3cuM zJahkd0$+og;f&Z((IBMp;3ZJvnfGs$^M>$dxauHLEJCL@a}@Pi+#|*D0iN} zw^|#t_o>1{JcZ0~hwvMVEh)k##8@!mMut$_oX`yQZ`k|v!dH;(ec_AHK%=mlW!8dy zG_!OgZh)^0Tmrr$+LA9t2jUk>!2m9*jy@u=>Ma-86yqGqtyMz~!rz=mEiT6){MAw0 zQZPi3QY%(B;ytvXq86R}fPv4B&`?IE18S(c6d=Re=n zC#VRg=NI#$d_0v{l3JW7PoKziW(wXNSWzSr$w?*WsSzpiDl2krxGH~yr(Oj^e^lY15kCfomf&>P@b z?QaRJSNwxB2&_*$;q6`zV9dY1vq69rC)o3oOUdtvCQ@$@a^NoN#rzj4U~g@NuOh+p zk{g8D`-tu{Q8H98u?S?yp*=VLXuJYFu&{ngg7t*q1STAHHvNa8{@CQCWY_Uig~y&%KiK* zT=(R+)D8lf24n7B9eRaxC^2C^3a(1-3i8!5e0D%cl4!FX*>8U2pn1{;w6!_L4 zXmZ*hHFPx{&cdcmI}%GBYX}`~w)crjUb-Mc&u%Qp0W*OusGW~>9&*AGpg51$bK0|F z2?=5p8sJ0v!~z^O-R$q<(J}s57Add4m5wo7MF}4gj+6ha&{UImV?0`t9#k{qqFCbC z+TPmx=w%HEmy|EP_h7GPSg;)T-uNpO@EIy;fA-yk%N2@&@q5OfH4U_1dMETs#lYOS zcSiQw2FJICo+ZomN;z@Gr8T)A)mIPJ=YE|5Zv2WR>7DR@1&mJaKra|mhHP-!r=PTI zQY+aC&gMn!e8#*N(WO!(eZG~>Ly9sHuQtTv)r1Q}EQVVjY$L}(_5;L--+d33_m4rS zpztGv(dFrr7zHXZ!-r?+r76Ev%b={F8MG>6zCs4SV_7+xXepO|hbuv)hs?VDyMq)S zm^JBzBMcsxC87Mcvj!oI2$i9R*Wv-f=dXVdCJ#>fx3jwEUs2M~n-&3qphV&4um54> z{~m?GS^qC7B)t4*84j=~y@pEQKg;mn%^C{f=Q4CJ0W%PGb?8)tM$Mjw!jLu3Kt-S< zze+$F5am~NB+8$$1O9VTusqT73t9{1NzhJ~Jo5j-EaQSi3H~dX16(yy`8^4K5Em`u z09RTBheChzFuDiIa}Wm<{z0N}xROx#08J<)WkS_YDf~a1HB=hL1;-?+2o3)V*JVWT zc2SW(6=)k&J4R0YBqJuH;JJm178SlUdUCpT%;@PUX`{2o(fMHZX6R z`OD{%uCM>>%7nIUzG-G|=RkW5jP1)n=m0!AC?9AC{O<#dOeFn{FbC<`GcdkyLXghx zfqEp&A%8Q?(hFJOUGxDw6HxAllSo^M_Uaq~0>&+xCLtr)#H}V~j67 zX~{sNM~^m{;2(neq)DWXVsfX=oNO|UL8FbyV;3L;0JCA;r%SPpz@-Kr8r}>%EIcxJ a6!2hpH1Pa4|GjV@MP!1}^t|kuy8i{b?X*V# literal 0 HcmV?d00001 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 index 000000000..e2fbc222a --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/firmware/fw_img_format2/gnss_config_array.c @@ -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 index 000000000..9c26cc6bd --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pdr/include/pdr_interface.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * Description: pdr Interface + * Version: v0.0 + * Create: 2023-2-25 + */ +#ifndef PDR_INTERFACE_H +#define PDR_INTERFACE_H + +#include +#include +#include + +// 放大倍数 +#define PVT_REPORT_SCALE (1 << 24) // PVT上报位置的放大系数 +#define COMMON_SCALE (1 << 20) // PVT上报速度的放大系数 + +// PDR返回状态列表 +#define RET_OK 0 +#define RET_NULL_POINTER (-1001) +#define RET_CALLBACK_INVALID (-2001) +#define RET_VERSION_INVALID (-3001) + +// PDR输出数据的来源 +#define GNSS_ONLY 0 +#define PDR_ONLY 1 +#define PDR_FUSION 2 + +// 1.传感器相关 +#define ACCL_GYRO_DATA_TS 0.01 // 加计,陀螺数据采样周期 10 ms +#define SENSOR_BUFFER_SIZE 100 // 存放传感器一次数据的buffer长度 +#define AXIS_NUM 3 // 传感器3轴 + +typedef struct { + int64_t timestamp; // 时间戳,单位:ms + float x; // 传感器X轴数据 + float y; // 传感器Y轴数据 + float z; // 传感器Z轴数据 + int8_t status; // 传感器状态标志位 +} SensorDataPara; + +typedef struct { + SensorDataPara sensors[SENSOR_BUFFER_SIZE]; // 传感器值 + uint32_t cnt; // 每次上报的个数 +} SensorData; + +typedef struct { + SensorData accl; // 加计 + SensorData gyro; // 陀螺仪 + SensorData mag; // 磁力计 +} SensorDataSet; + +typedef enum { + SENSOR_INVALID = 0, // sensor 数据更新失败 + SENSOR_SYNC_SUCC, // sensor 数据更新、时间同步成功 + SENSOR_SYNC_FAIL // sensor 数据更新、时间同步失败 +} SensorSts; + +typedef struct { + SensorSts sensorSts; // sensor数据更新状态 + int64_t utcMs; // GNSS UTC 时间戳, 单位:毫秒, 从 January 1, 1970起 + SensorDataSet sensorDataSet; // 传感器数据集 +} EpochSensorData; + +#pragma pack(1) +// 2.GNSS结果相关 +typedef struct { + uint16_t flags; // bit0:validity of timestamp(1:valid, 0:invalid),...,bit11:validity of speedAcc. + uint64_t timestamp; // 时间戳utc,unix时间,单位ms,从 January 1, 1970起 + int64_t latitude; // 单位:度;放大2^24倍 + int64_t longitude; // 单位:度;放大2^24倍 + int64_t clkBias; // 单位:m;放大2^20倍 + int64_t clkDrift; // 单位:hz;放大2^20倍 + int64_t speede; // 单位:m/s;放大2^20倍 + int64_t speedn; // 单位:m/s;放大2^20倍 + int64_t speedu; // 单位:m/s;放大2^20倍 + float altitude; // 单位:m + float heading; // 单位:弧度 + float posAcc; // 位置精度,单位:m + float speedAcc; // 速度精度,单位:m/s +} GnssLocInfo; // PVT上报的定位定速结果 + +typedef struct { + uint32_t deltaTime; // 收到观测量到pvt结束的时间差,单位: s, 放大2^24倍 + uint8_t context; // 场景识别结果(0:默认,1:隧道,2:遮挡,3:CBD,4:OPEN,5:室内,6:半面天空,7:室内窗边) + uint8_t isStatic; // 是否静态 + uint8_t pvtState; // PVT的状态(0:LSQ,1:KF) + uint16_t inuseNum; // 使用的PSR观测量的个数 + float qop; // 定位性能质量,单位:米。数值越小定位越准确。 + float hdop; // 水平位置精度因子 + float ems; // 伪距残差ems +} GnssPdrCommInfo; // PVT上报的定位定速过程状态 +#pragma pack() + +typedef struct { + GnssLocInfo locInfo; + GnssPdrCommInfo gnssState; +} GnssRptRslt; // PVT上报信息 + +// 3.PDR输出相关 +typedef struct { + double lat; // 纬度,单位: 度 + double lon; // 经度,单位: 度 + float alt; // 高度,单位: 米 + bool valid; // 是否有效 +} LlaCoord; // 大地坐标系 + +typedef struct { + uint8_t src; // PDR输出的数据来源。0: GNSS_ONLY, 1: PDR_ONLY, 2: PDR_FUSION + uint64_t timeStampMs; // 时间戳utc,unix时间,单位ms,从 January 1, 1970起 + float speed; // 速度,单位:米/秒 + float heading; // 航向,单位:度 + LlaCoord posLla; // 位置 lla +} PdrResult; // PDR输出 + +#ifdef _WIN32 +#define PDR_INTERFACE_EXPORT __declspec(dllexport) +#elif __linux__ +#define PDR_INTERFACE_EXPORT __attribute__ ((visibility("default"))) +#else +#define PDR_INTERFACE_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* 对外提供的接口 */ +// 获取PDR版本号。 +PDR_INTERFACE_EXPORT const char* GetPdrVersion(void); + +// 初始化PDR,正常返回0,异常返回错误码。 +PDR_INTERFACE_EXPORT int32_t InitPdrFusion(void); + +/* 函数功能:PDR主流程,正常返回0,异常返回错误码。 + * 函数参数: + * sensorData 入参 传感器数据,接口内部可能改写数据 + * gnssRslt 入参 GNSS结果 + * arState 入参 运动状态识别结果 + * pdrRslt 出参 保存pdr结果 + * 返回值 :正常返回0,异常返回错误码。 + */ +PDR_INTERFACE_EXPORT int32_t ExecutePdrFusion(EpochSensorData *sensorData, const GnssRptRslt *gnssRptRslt, + PdrResult *pdrRslt); + +// 停止PDR,正常返回0,异常返回错误码。 +PDR_INTERFACE_EXPORT int32_t QuitPdrFusion(void); + +// (可选)日志回调函数声明,调用方按此声明实现回调函数,并注册 +typedef int (*HipdrLogFunc)(const char *logLevel, const char* fmt, ...); +PDR_INTERFACE_EXPORT int32_t RegPdrLogHandle(HipdrLogFunc cbFunc); + +#ifdef __cplusplus +} +#endif +#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 index 0000000000000000000000000000000000000000..cdd9289841c2b3b1f253c1cb2fb999ecc8fa0af1 GIT binary patch literal 945100 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%0AM|HIQVL{&CXFHIQVbe}(jN zEhSm$-zUASmt>_MhDIwr$x2^g=t)-kambt9FXBMwpi(*k;_Y=S&V z$}d4KmGY;QX01p+9p%@r6Ef|8>embTY{)7v@5c>7&--zskV&u3p(HCmc|Xd%sOm?U z@eO;lSMEhgR_Ut@J;_Rcj-e-6=`V$xbGlgDNmlw^(iaLn$x8nWWYsSuEByPM25z7%r)4I)+~D}6cS(Na&c($jf4pH2ce%yTsL z(P*hBS*54_QqDNxKgmkJ39?$NNmlw@kkwjEveIuyef8fG^*&7UCLzB|@@65=MEX+s zunZa-rSicf7ebyy8!jAi$n{%=yqwZ(6Y_S*b@Xs=9JHq8V~#6X`H%+1XsIVz>GL4x zl!!Kxtn^>CoHFE9eMhn?XD;dG94A@nJ4r9+ILS)C5wh}!WTk(A^zz4oBrE;nkkvkc zWTk%svf3w*tn@TK)pe6OR-c7lT{n@e($l!jpDf~Oj^URnz0{Me(icE3-7eD8dQyL@ zkV{A}<*SV}*HN0=M4G)M%LjBkLTT<0`lm_0Q^>DDo+RZzkxZKx9Pg7X_0)H2-5^={ zM*XhFtvLp$zf=s(zN?`0^4gPRRnAn%YA-~x(ocu1_Ch2p{Y=RDUg0OnN?#9owA7QV z^s^x=e@IsP`H+=ABrE+w$jTp*m7dN)${+K5bQz^D7ygi}(zj81sV7QB7XA!_T)I=p`G!p6r~W%aUqyPE{v61Y zq`bh;MqoGNsuqWEunYdxSjLkSWbq89(8ue?Z6&k^Xx^rg$p6~$fAB2{W_Rb1M-prUoxsB8=};%zy@?zwiCw*$N9cO$$V*!_8UYX^3JwXnAXyXRUT-VW@3bHc;! z`KPVhpQFa1(@9UJp=<+p^3f1%9vF2~%V zJW06tPUWldcPVrJZ9i5JDI3V#t-O)UJ<22HuJ~SMKE{o)3mvgdp!k>S`K`w>zf$Hp zt;N4qUXQ`=^IrL=^4|DO$|K;%lt&7WeO#IM z%CVMjE$s6JC)@YW$xO?ANg@xsXS$w;-Iob_`>=aHM|mE0&vNej8|`P2@K{y^DP7?w zmG@6Dd4Ddz-p;pu#$%cLYejPT)3=WO^t~zBPo~vzkb2nLACKQxJ?wt6u+J~-eyXs~ zFYKPry&d~&JFxqe_`&L7_m>L$YZvT(wXnZ-!S4BN(9_mu*!?}i{+b56e<9&v_irXV z?Ed3~huyQG#oLG77biUIzC_p`N7y~r>Gao9*ge}T{IxW>?P4hTA-bNxp5LFmdD#7Q zVSmkp-B$_wYbNY|mds<{r?mYl;o_&2PZA#cjPm>hFBI-){(ADyYG#JCIp#U#%sTun zuSIO9q9nhkkdL3w`gDRzjoV5l{eos-_i`zc=5fj{qqSA zyMGC9(}LZR6ErN*uBZ)gT~&vV>8?4IqA z=|5{8cHbl6VfTCD-_$(pp69;zjpw`f4fYJrckcu2epJH4?#JQ(qSJ!iA1&?u+GnlaI?a6VqEY1AB(+Liu!I_kD$Z z+yP|1)Nx_Y48~iZVfTj$`?!GB*Qux+7F6@4vgooYt!?)2q?0zub zmK*GTINp{U?EWxe?;F2=;C+KVGY#KXrv63A_I(zF0l%{w}<& z53u`t@f|b|yMGAZQ9bPbQG6%$u=}SI9(Mmco)d&B|PkY z1>PQC*!^|FKCK(c*tB5J+>Ezr!S3%!c-Z~jc$*gN{z>6@H=UPf$#l7@+*nQg~8J8c0mQpO7F3EDK`Of&g)Whz3 zCOquE1fSA8?0%52Piq*Nv}Rz>9Dv_jJ?#Dn;kcLjX=D;yYRq-&(?K(^`;!vm^82Xi zQq91gX~6eZ54%4-;bHguj%s=z&BN|55%zvwPR6DMd*&*Y~P&+LXDpwoig^Lws7?m#m90J;>|Geht; zUD*Ah!g0Cgxu$M9!KKFh-fMc0W?=V~iE-zU;RCW1*fae0YkG)!*nMNd!|qST57j*E zex6`>PWkc7HwIrUkpdLpUC$eYl%Uf=i8mi65>R*!{+Yhuw31 z{PcdBhuuG&@UZ*m@%w8YcK?>J_w8LW)*sk2{64Ms4R-%Y!o%)A!`lx~!R}kiMq8g& zTVbCT?3rS`EeF{Bt_csj=eq3a5jtP6`&7ci?z!%|F9+EDe!||j1IgHOfITw`Z+(N^ zADZy6`$>3P4zT-~!al7^G6!n^Vb9FLAEX|3-c`^$m7^ zg|PSS8Zx7FT-Y-=;76;6-Tx%vVfR19kI_8r{y|}%)+1zWTCisx$J?}E_s=Cf?EXc( zO$&Daj<8SbeKKRUKd@*1fgh(Hb}yHJZXUNl*vExE(-Lpv!tQ$r`*imtGhW+=J(I>C zq8@hNKjC5b{2p-nP|d^c4-xih9Y$t?W?;`8fwyVF?kk0T+&N?>>bS6HPR1Xm9(I4G za6C!S6cKB|Pl@Mf_CF!|wlppQavm|0lf77wrCH;rK|+e@Z67rN&$EM`;Fj z{|$b+df0t_Yw_P#54&%TKUzKPzCHdJ^|1TBguQRQ$XI`1&+LOgR>y_i4@h{}{b0QH z8FqgF-uec+=Qoto$7%bp`>Dd-x9Mc8Z?I?hJ>~TAIxg(KBH>~8)p+Y0?7lYPVfXX# zCusYy`&02YFR=R`;B8)D_ZJEKyj)7g<^}f5YWxhH7VQ2yy!9D&e6UfZf4D1711-521` z(sp3?Z4w@KzYBh`=3)1{COquE2mWl$!|qcF54#Web2JaTFH3mXeK~%K=3)2y;ceN% z?hnK-)jaHe9DbR4*!=|ja`mwL?YX3hj?38VfX*U+qw$7{~T}YD(wDCysfLS`~3D<54&%Hw{;SB-#+1C_Z{)JuEOrS zCp_$a54^3bu=`#K54+z7Z|f@Teqh4G?uX!QU4`9`NO;)&NW879u=^v0S6bD@Rz8E-JdS((>jxkwGVsd9K1~ncE18|(}LY!h`&^)1-oA( z?9*CHW|d}O&)kB)Og-%We&P6X^&80~xYT$Pezj&`_fO-mP!GF*9)G2J*!?T`tJK5p zU&CLm9(Ml^;rJT$pO8s#sqts{Yc&JA-bs4D6Xn_#4&3?x!U@?Ed@sn=}u* zpONse`&sxOYaVuAlkl+ndHA)Ohutq0_IX)K=4Q>no;eS{PCe}Y8et#z1~Na<4D6X7 z<8M(9yO-TTQM{iX&m$j~qWD(LbcEL{cZGkd+#SA6IR*brxfH%#nd81=4wRF^`4sWb z)gK1`Liu~}9m?N_?^HekzDv0h-k@9q->qB^-=oa2&GEg;KZNg7UIAMlE{1=p{tEb4 z%0EtIZij!Z{%-hw<%biQC*TLvznt)YgdbG@w}k%}{E+&u;El>0>l;6;%ynSmN0bM` zk17v?Hz^+oKc+kZeq8xT_&3VO!A~f2tZe+Gavl7X@&ee7T|Z6Oj~j>mxbd^dJgs@o z?~9*Nz6gF+`6~E1WsZG~pI7F%*7yZwj%AI1tITn#@r%m8hF? zQU5lRQU4nJit^v!-z#(6Y5b~kEUR7o2j%wgYs$O9e^lNbeqFgY{3qqU@Egj*;6E!L z0Kcg`9)3msNtq~je%v@*YW@f^f6@Fj_$}obupO5^OE~>k^>C^AIb_~ezX1M|{F8E; z+@;@95Bo84XOVeV{c`wk$}8dblrM+hSH23iWwI9jK>aQ7hsyWDe^-7S{)aLTl`m%w zUG?S6A+YgBn)x^UPh}1haV!TSN#UbsoTtpk zk(h(>r0`Z37bx>~6&EV=G8z{t^AZ_zu$~lNlH!)iysX5nlzAG*t(AHD#ch;X-Q%{( ztjcjaWgh;xy)qAHyo)l6Ber9?nT^rGg?Ceb4%}UNIc)3g z;q)NQz@_G2Aj83-QeKAbdHNQ-r;husaGDiR3hc)({hiEE^`F7Rl=I|+OU!|#Qg(q^ zNu_W+RlL7)DSUu(IXpu7K$sU8DWin_m@Bx{{CF}4YJMVY^LrGW)^U#!P9LNhxYYa% zGCWbF%z|xx=fk~p+$Q1lNX@{0Y|>d|MydZ1JX-lmc#QJ3!hT#6Tx$MCGGjHvZ)^MU zIlmx3PCe|$;oL)pC$W@=;X{-kgYEOl3-F=pUxp_r{~6{U-03| z-@xTM@BD6eda`=hkAZ0~93P>64|s}lDf~TUjxUO*Djx(-Q=SOh>jS^L?T^BPZjoK24FvC;D=;R(fkUyL7C$y;zs4G;3nnkU|Yv-g%_y59bTw>Cv2bD zI4&aQOjxSW^hsxuNl-t5TQZ9xsR_+O3qFe%Bs@xY|r91$> zOnC%+iuQk`uy`fm-=NIC)Od~ZKVW-L`2xOC{a3KP zKD3gJEb&e1+rhRT?hgN0eSp_0_lIv*9t!iNM9RVNI`xObKT&2sW_*h>`!3^Km1n@~ zmCu5Is(dkgoAPDC>7Qk})cjA#T%^A6EV`Y|qWR;78Oy0Y9qzjBt8WmP^h5h0OK3Y(Ib>)6Bo&$CbCi zzfmrfZN>2u%5C8%mDvvxKc(DNIQ?{%OU?Hr^Njkw@UzM%!Otl#fS*@B8-78V?fLO< zm9K(dRNer;q|EmD_+{m1;FR(Q@b8q_1|Gkn9Lx64`1i`~;8&G*ga4r13w}*`DEvp| z1L4<|+0GpQN%;u)4dwOlpOx>1-&B4Ww%6)s;lHT=1N@fqJMdqXKY`y?{tA9axmB_7 zyUJbQzbWqpzo*;}eqVV%xRdfY_ygtd!5=Emg8!~u1OG$03I0g=2k<|Ym%|?`Ujl!k zd>#BRdNAd+!3MQVa&mH;LDBDcb%gc{!7gFZ> zMRC3|*UX6vluO`3<-K7}R+BOSwr#V6VNQCMG90#Tq?v8$wvBWo-nI>ng>Bp5p>V8y zn*t_hy3ei3Zn zo6dj_&~X>TwVGK9&r?1Rw$HQ|z>_t9F>Ie3FN06l{FShM*18t9&su9>`|Pw9w$D_z z!1lS~HrPH_`~tT3yA80t58emcd*A)Az4vW|?Y(Iee5dy3378FmQl5eBz2gPgUJqY} z{dH2Jv3#$i@Xd?wjjHk?a&4=z)_v#l^Y8Kg|-^?#=Fc`!Q`q_D3xUap+tIl_i{DdXWc zmAAs5E1w}dlj2soK6mIOyoWNIOE~X>0tZ_T`{1SD6qs``C;4wm5~TB@^pI9TRP zd>8d_u*`BiJK3bb!7{9Nsa@5>!7^9iyQznRW!UDN+D$ziEOQH<9d}aTV3|AcJ=DX& zGQYz2R1XKsJc8d{Jsd3a6n+o&aInmacrKnK1rC;Z1wT@kKO8Lc5q@vY!y&EwDZW>h zgJsy1p9<>XV3`7WDyB-+!@)A`@V(W;!7^R(`>2P5WqRWKsE31P()fMV!@)B9;QOkF zgJsI`{nW$3GW+Ap)Wg9tqw)RK!@)9qEKUtj4+qOk!w*ys2g@9XFINu-%T(b9sfUAQ zcnMAoRu2cuEW{5{4+qPfg&(RO4wm7oX=<2yI9P^{s;S}X;b0lQo~8Cv4+qQKgx_C1 z94zxw`~m9WU>QF8r$(rUgJph&KTtg!Eb|EdAoXyt3?Fk-2djsJW%x*%8mS%*mU#s~ zNfvA+K9;4%s)vJRKE{tz4+qQe(I+)tJsd2<$C1<_>fvA+ ze(EE2sCqb9hM(9;O;8U9%W&!K)I{}gundfvCSWAIbe!@)8Y_-X3lV3`{Hk?P@KnN#pb zsfUAQPRCDI4+qPfga5vII9O%{{%G}Zu*{|SW7NaJGOO`iKu8K4EOR@4hUVdLg7Q81 znOP2&c@Tf1dN^3-F?@x3I9TR6{4Diwu*~oAmFnSOnK$uO>fvCS_wd!~;b56h@Uzv! z!7^Xq=ctE+W#S_7bJfGaGOh46>fvCSV*E+!;b56=_>`O}3sfUAQ_Q%(&hl6ECDDv zTKpO6;b57c;eV(e4whlRRq9OjaInln__Nf*!7`kupIWRQ4whlxR_bi^aInm)_;b|5 z!7^{+m#Bw>W!}RtRSyTt{1d-SJsd2v1;1Q994y24fYiC_;b56o`191m!7?53E7Zfm zGTrej)x*IuY5e)>;b57*_zTp-!7_vK7pjMYWe&t&q#h2I8HfLodN^3-aQwyU;b57g z@Rz8EgJovmFI5i*%W#f=YL$98Sf(C-nR+-_hI9E-m#c?^WftRCtA~SS&ck1!9uAhd z1b?M^I9TRt{8j4VV3`~7SF4AEW!B@bQ4a^p+=;(dJsd1^4}NrBW&j*4!~Vq7jhctU z8s%5;H)T0khW(7GAFGFhWjKF7wN^bGEb~wN&FbM`na}a-)Wg9tTxd1*6ZLSg4CnHv zZcz^h%W%$q>Q?n|uuM1ndi8Ly%wG7Ps)vJR`rvO<4+qN(!v9P?94s>ef4h1(SY{ml z=j!2L8TO5)exV)?mYIqlqmK(5EW>`%)ZLng!v^IB{5@F?mN^}NuX;FGhW)Ck`_#k1 zGUwxesU8lNS%v?VdN^3-TKuoo!@)9Z@%O8TgJo{RKcF5Cmf3)RP(2(h^8o%K^>DBZ z=isL{s)vJRp2t6|9uAgy75|8OI9TR&{8(MiaIg&fYE!?_JRBZZ-iCi7%fT}2w@p2% z9uAgihkr^v94ylX|Fn8ISY{9WGwR`BnNs|->fvCSGW>Ju;b56^{5YL2I9O&P{$ z;U#7E`KErCQ(h{uuK#F59;Ay8TK8gUQ-VT%PhhF zQ9T?i!~W&e>+0cPnM?71QV$2qu-`fLhI%+yW)1$&>fvA+_D84QR1XKs+=2g#dN^3- zSNONo!@)9-;{U214wiWm|F(KKSmt^BJL=(JnOE`es)vJRUdMBws1!I@hI95)A8H;B zA1H6b|2@mWGKHfvCSJ@6l^hl6EG@t>%NgJsI_|56VJ z%ar2}vGo>jnThz%H4lf)%2V)LvK%bKdH1O=)Wg9tGw@s0!@)9D_%GGN!7?Y|x2cDN zWg75bsfUAQIFCN{wR$*MW(ocq^>DDv`FPptPl1DFF2l#_;b0lgsZZsphl6F-;`7zR z!7}XMPZg+#gJtf<7pjMYWgfs6sfUAQ9>cd#4+qO|JV2_YdN^3-_jnFMmjVaNyoqnE z9uAgyAKykj94zw*zO8yVSY|7}oq9M}Ca;b7_Uhqanb!DS)Wg9t9D9)B0@zaEV3}_C z4(j1xnZ58G)x*IuoP(e0q#h2I8HDew9uAh_xP?>~^>DBZ$10?{s)vJRCgXQi4+qOk z$9Gc?2g}UB@1`COmYI$3t{x7Ssl#(&Zz*uF%tCxm^>DDvnfTq+!@)Ak@q4I;gJph% z-%~vtEORBkL_HiVb1nW*eI0;7~Xg}d#na%kAnumk!`}hVwKs_8R)1s|-PR@`52g`77d#YSL z94xaNevo=NSY|K$VD)gY%s%)b>fvCSf%u{7;b56z_+jedV40El;p*XF8IBK0?WZ0N zmYIUzUp*Ww!*L_21JuL8GAH6ksE31P=HfX?MG71&GarADdN^2S5&mHHaInl`{7Ch1 zu*`D&DD`l#%!T;T>fvCSRroRL;b56-@nhA)!7^*{DDvTlmT9;b55$@kgkKgJn1dCN)Jp94zxC{(I`- zV41j`_^ImQV40TqY3ku%nO*Qls)vJRy5Nse4+qQafuF7(4wm73_SE;)!@)9~&z?G3 zJsd1E6n~6*I9TRj{ITlcV3|Yl$Ek;dWhUVd)5j4GmZ`#@sChWdR6ZGBk>y~S2K+4b zaInnj_)7I~u*{kGNjhCPSY|bTuIAw|NBMeuO_qaYIA=U{l6p8;<~IDv>fvCS4ftC1 zaInn%_<8E#V3|$$I`wd{%rp3U^>DDv@9^{0!@)9d;7?Hx2h02o-=H22miZXps2&cM z*@ACU4+qOc?Zq!p4+qP%#4l722g`K8pQ;`Xme~!zNIe`Zlfs{-9uAi2gFjt894s>k z{{!`Ku*?DYGt|SuGGp*RR1XKsOv0b39uAf{3V)V*I9O%|ezAHuScdbgQ)jD(gJtI9 z&ruHt%QWE+*Yy()mbn0buIAyeT={bRd07sYxemWVJsd2v4!=@894vD?{(SXtu*|*q z3)I8GG7sP{R1XKsJdVFeJsd2NnuT>8R%W$4`>N@psu*~83>(#@-GSl%lsE31PIBz<&Mm-!X zGaG-SdN^374u6w+I9O&O{>SR!V41VfvCS=kT|yhl6Ea z#{XPB94zxX{uk=uU>S}%Ox>X#4wm^4f2VplSmsmwUFzXr8IDm*ZBP#f%M=!izgs;V zEYl8uk9s&*rYrtl^>DDvp7{IJ!@)AW@xN3L2g?k=|4Ka^EHfPcYxQuj%t-wG>fvCS zL+}r%hl6FN;2%^E2g@9Te@HzXEK`Bss2&cM;dsl`!|LH+nFjnL>fvA+j>AknsvZuO zS&HAJ9uAhd0RNbJI9TQ~{Nw83V3}+2zflhd%dEvep&kyF`5FF6^>DBZ$9$%qQV$2q zJb-^%Jsd3aIQ|*+aInnt_-EC_!7>~#ntDz>94zxD{(1Fqu*`e-7u3VSG9Tf8s~!%P z*^GZtJsd3aHU1^_aIj2a2k|efhl6F>;D4tc4wmVRe?>hUEYl4?S>Ko8V3`5DCE9sX_gaInm&_;=L9 z!7_{S@2ZD`WzNI@O+6eea|!-E^>DDvRrvSS!@)8);y+Li2g|I-f2bY~mbnA}clB_v z%&+kOP!9*oJc9p7Jsd3aH2$CJ;b57U@gJ*)gJoXFf1(}^mU$chFZFP+%-`|k1rf7)3T%ZEt-eJ=gP(SFR~mg(+$5>Jsd1kg8x!I94yltzfC zW;p(9^>DDvLHKXf!@)A+@sZ9K94s>#AFGFhWv1iv)Wg9tGw}SFm=rizW;VV+Jsd1k zhc8qQ2g@|zzo#A!mRX5!tsV|`jO(TNHtOMEnXB<_)x*IuH{silvJE(_)Wj5hEs)vJRp2l}l4+qPfvCSf8)EUhl6Fd;<DD` zkbC1x)Wg9teeu)O!@)A$WP0(D>U+XP^dO2#->&{U)0Q4 z@_);6srf20)}OiX`1%$rs_paQCU?*Q$cjTbWdcRM(BKu4r1& zP(5mD(vurs)6m#7sp7Qih8>3;v0!II4ykTBeA3}HbrY%<$&6@^vppL%b=v&u>Z&pI zbuwoaHFeu{TSu)}lo>TU&Y0SY#>Sf2HMxD5P*>A5YU=cg?dI>O`7+7sX|**~)!(nF ztExYBe0@&Wr&d?i |9y?Rt-Q_aGfrqh!1EM1s3ufD!%?$qkW1+`5R>c&(w99~~l z{hgU3n&wvTkebpUb2n=0gu2=Fhfhk5KCN2xv?l3g(vF#1U3v0OCuegcBh*wLUf)zx zUpHp^#Wtm(zH<9VN9H0siFzIbR;hty17(U@Et@oRW+e|oS?;4;cIv=PWB)NX>)UhL zHKXj*@^5V|k(!lB$%gt=S%MO`*RKLciiprC>8?Cmc&L0{b zb9O_;JWNev<-)Rxrly9PSqqw^;s2uakSwn*_EsJ7UY#uZY7j+xi6kd45t)*k(^n{Y zO_HH<7}9^t^_5KSbh~C+)_*?Tu{pVkQXjpO+`-}sb9?KAlkL4M?b*j584^X_-i^Y^ z_KM}$C2x<9bPQvDH_9#9-T+w`W#YVed%qTuY;TRU*G(M#<71w;$4464^F?-|v`5Yh zISPkBC8xVca#Imje7YQ>m7MNQjNSpOMD|N7*#cat1P(p$V2Z?9KQdmH{N z>#2ljkA8Z42j{f+l(fgZdGYr4&uMR)w0FNa+UqViZ?7V!y^XTc-Q$hPy|>55x#axb z_ZPWFmCbL@M0;oEw6{vG!LBJFLI z9P?WuH=kcV`^sPQ>*REKQgH5)7w_MrIqlu|w#=`*0MTAbZr&c7mXhu5FDs|)GHEW} z9-pllXQT~zSw7Pb5T?Do<>u|Ni6hzGq0-*bHV${*9-B^*?G=0wMX$X&1Xpi;P+bhp$?`>(1?<-!sy?#0EUHf4a@tK+S`pC`O z8=KSK6nQf4Z257TYqEbQew1B)eG~2R@t^LL%Z)Na+WTpue;~Ii%gJ4)w3R3A2xIP; z7UhDR+@X@=^}>tiHss`vmt2*HFwBFDG}>K2h|bY`gQ~ zxxqQpy`@JS_1;ydJ50hp-HAEv^*$hq-t@-g-rF0O)7}f^am07SF_PI&Zr)zz8kth( zIYwzI4=%^nd!apUoN~{-=gP;*xz`@D48v=4`d2HtWFbR2dndVpopc!gJ$HuW=<7(N zl-@()XoEc-2T9%M@wYfc3jb!c_`OeO{ z+FpFR{mX}zB+I~IYgF5Qjsc2%gBvCNN_IP*r5*M@jejx25w%bFm~6f^YOOJ%Km=PBWdag)PF%^!@&Nt8fMO|DIY#; z;LOIVlLwX!m|4BBzIFlMIs4D6sj8~2X59Xb)eQ@4Dytj&H#RJsIj63%vH$$4hW?H9 z3mPh`!I`rcF!}y-Yw*=|3u_wc>-gF=v%$Z6_djVt)tu^?^5sju)s|KM=gHSEXqvyE zNjg|jS9MzdipqNFhgSM!CjLL`QZ#2~O(WmEYbv7!b&WN1>Z+?sD(A{3gaz_#efZ3# zhz$Ul;p1y7=0x&cJyDyDivHJ&_&8Zl@}u_hKaRg_-%kE#o($Cgyz zHU8%%{r~I(9YqzjwN0nZuWl@x%d4J78d36>P1DC zR5nu_7Z!Ua)~rS{uXo=_$(Jkn#qILi^ZF+*0o#?)XUFH|jc%KHr}?g7qYjhNGGF+k zc$8p4abd&4LFF~&^9RhF$G_S9tK{Dz*oR!5&!R@9`MV3NyDTqG#rnw>@ zeNR@Uo_v*Oc;ZDllP}ora|f?U%y+hE-QS0Nc=pvwhi5<2Ws|g#FRw(~x3}|pb}Sv9 zZC~rz_M2bXGF{Bie2U8UHuIQgt1^B00+lHFnNLAkAVp}sgFvGe}6VCR1`h6UA`!KMe0W+^6yCfghXAc%_Tpx)u6d5 z%aixIY{{3U^Ql$oQ%70f@~kcHI>_V6cW;Ugm&ZHjIbSwuKuJ_4?@6=kx%xrsz`GPMcCAWCb3}&`B#wE)1CAMkt zoh;r<{TP^$q)e1soX%i0S?=Z`Dv}I_{pqh=*#s{lE6ISR#JA{lAtUPTpRGd5qHb zA`X}Oi}Qc8zbU&rX8TV_iM>wSui9menf+A%2X3wBDIyPpypn3s?;}=`JAX&sOPE}~ z4a&_ijKXTiD)XOm10|C?U0X$DNOrn?g;~!>%8k-l)=fTT@I1zI;~~yG2j$-9W3=$j z+8ZZ6+1}VhdyMPt%@9t`#}ujiJPI~*Rf6&4&IGLZIHyY8nL*FVZD%>2>&gCc?(o~< zm|va--oNvNlkH8CiakALNOsr~;beP9OC!GgSZ?0lY8!`P6n25j*Y@TDa=X#)J@>e* zAp19`G(&E^<(dci3Soi_rs6vOjFVYF=Q?oZ{m)^3fb^4GPFR*dbiLn3c=SXOe)gy^^_RSn}a-_}nk zX{@emtZyh`cX3Hg-NFjlhrUdY~dk36BGvU2~DUJLq`%sH*09+JU{ z2IPx)$^3@u`LaK{y0Nijc12BXHBESlqhqsp%uXM3vL$?ZEydiK?t|os-+sy2LWK^7^osv@uMw zyGkoI@7>tc)~3xtVs|UEUYG8sJ&3qAF)t?aKl9w?MR&)NH%eR_58>%%FA#Bt^K@j{ za^~-Ba+njDy!QOkl6|tH+ES*HsGhKWwLz-9pJhs3*K@Y3cH1JFSEeX$Pg-pq^Y$0D z`5XVGw6%j#qc)qhgIQ>82gYSS_T_h?q4wV}j!ZzBlb=nJxh`%c|2hos8TZe8I+xAM zQ9MAuY-M=h+*Z8iMwv?a3mv1*BPBwK`*oPxD(;gRjkkq(UmcC3kmJ55wu-u(EY$Ta z`BxQnUMP2&v3l>?Ely=dx|d)&^A#X^65gAmcO&IqZL=JTGyDRX(#}!mN35-ai!*al z$l{f`D(L)2A8>ZY6vdgh-Igsn+fi3h!P?A#76qAQQaGhV-WS@J@{a}6o?f)4_4Y5b zFtzo9UHVF(c%b~-^~53$0G8d;QYqR;yZ$lUN4x$dyl?B~t{3&q&PGu`oeds`qO#7J zOlI8vU9$NB9FVMwplD#vESHyLdC=Y&=4Zu<25W!#*{`A@9Bdp#m%&4)M4j#DucCrm zb*5W(9>s7e1y^^Lty+pV=)kw_Wha-?W*D_7 zo#=+GG?{MnY8&nH2N{3Yyh0A7mbZGj6&|8vW>^j}%zVQsJghU1J*D9MUAQ`GaYy;r zdH2lHkX|3$;n1G(0hvY)5f_ipMl$Q{fjSpc@dp)0or5+cKg!g(m2{61587px3@)A{ z|2nhkP>P1_aw>JYNGY7K%ejPT=zqUC_djm4{a6oA#u_rrW zY%y{8C3v{3pFGq&c$p=u4>C*99`9+g+d&sMw4kX{7GyRgn+*~V2DNeX>nrCbA0Ots zQ968x!+h`76gg_OxsQBujT)o@>8y0&P{O5`MpRiYpB{r|3u40ZHM;%d-)x5f4c12~i?$FBY zTGknI*>6G;l(i|bA57kNbTs>_Bmo;K(|BD)?RHa<&)tcgWbNa^p1uQYU)xDm*h+Vn zvDd7Hd}@sg%kt04+!yLDGS3wk+3vMgc7IHMQ6|^T6RnE!8!+3Ar>z&|xBQkNg>jL# zBg5qhBk!$ppWGK$B6V)blGzuxBLC8YRfU%oUEU(ISML9${cg#5$(N&FGoRO+<<9GT z;?SbQo4)cl5@pBzXvLZJBiaA$*O!jlZ8PLc5PeH7 z|HGu7d_1Q~J-K|@I+9#oRZ{K0B9%(K%9|)to7eRthKEzf|hU z$LngT7bo&J3Mcz}tJIV0%NdE!>d8tpAo0h`p_X5fF z>CZkWbKfrdNbdJ*cI~3Cni(jT1AwCFXU(o%W*=?x@#!nW?bIttwTljrx*X1CrCl^p zcub;xjBuAkeXj69^1`pBU9_lq7^Y>!X--oU!!MWmK9*+qO;Z1HV)&g>KOr&vA*tV; z82-G}FG&pNnAWEg!~ZVzpC^WYA@vs$!#S-q^Zh%MX%}&t-}9VbvuVHYp7fQWA`k&apa<_oY=i^&4~QcjeUWGkJ1*iyf-M*>iG)2X~x9r@$d78N1=QtDYhui%?#zhQlKIWwP2$ZII^BKw=qjA5V-j|!_AQrUW zGZm?qGkLkUu{aWils9HW%X5xw$*Ge59~^PxN5ABZ&7>0t!{i)oLq8Kka}LcJN{96z z0Xe%br{SS2g64sAGSSd58g3rQqmdlQGH)K3GtJ>lrg>ma?}z71W;iXgL>YS{@|SDJtU{SAvygUlrwx#PJagFOm9%m<2NXGdO70{&dCqX znf{QRq7?LypLvs6*)BmA4^E)(W`a^T3KQw24hUQFvXm0yC{TZ6m z|6w`#VL8(umNUI!IsF}$)4yRk{TY@s|HJm%ZVT$1nX=(%QvIAUvaM(|rzKC>ZbQ1% zayCz^$!v+$_q+pc;N4GokYeV1s1fEni*r9fxceR&g57g$Ll5(?`{Baf_mY27VD}@0 zdzgpaj}`8?M*c~G-A@(nzAsk3|H#cf-|c#shuzN-?s%j8lLEWvyJp9mu=>5zeS_3} zIl%503j1<^-JdD!%K>(Oj<7EW*!^OluKd}2X z!rmX){aRt~5A6OH;qEE5Ykg&H8 zyMGjako=PZyXUJxyf;?9gUc=EL6*`{Zt+M+kBiHk93srR7mvoucXYYMw*K?5Bgq`9`I+zpSKMDG!BtV5N+P>y_CS6wg;a z7CuFJHr$}x0P_MMRm0yH^p!`?( z4CN1CRyrx4!DlMV7yBqaOSuKSSh*v7w({=qIm-NQbG$^EBgNvS%A??A%4}nemn*Y9 zBR*HT20l-D0lY%_Y}m%-_mJb2>aT*&S6&PAN{C-rc!%-8tN>S6yqZMI4J z?`gxqGHvi(H4ppmX|qi(wX1sAe@~kOz5IL;*ndxZ5BzSLhyC}od*OLwkplbgY43~g zp&s_%(;kfPsUG&<(;klBM?LJnr`=6d+($j5`8hEq!s*@B!=){h|Eueh?QrEU`Kr=< zq=;XIO17uzMX9)QS@Q-NzhKk1UgAlUnQe0af4!cQJdBw#SpLh?y16(H7b9;M&F6kl zzo$8+`$ee^k{jcUlpE##68XF@>wXvELb)-Fr}RX*(O$XSC?Cnq-o`R@hH>LMNP-xs%ypysad2)v|ytq!BAVjJK}j zbX$ffdQ$}R%gdEdm$wDR86Y>xzvMaaCtv7NXBanLqLaDjrIG!`dGXw}B497A>~+%X zKI{$=&I}`WV9s>$x5+IzAMeTYxWJYlFMmECj|eB*J9HQQ?k+l0$Wb1UTe7{s_tkl4 zx$yGn?L99n-I*_UnX*{go8%R__i1r2-Dxh*NN#|8@5n=P@45a%_bW-3|8#wdA#$yQ^2`YT`P`2wZ)hKQ&T)N;eo^0O zFqVYE=#m}IwK!*WJZ{a^Wh<79T~?4k@$!OuWu_}vkBtk*Rd#Nb zx8~|4>sm!WF1WnlsvX7*%gZ}om_20b=5UNxjkR5Aqi?8&vO`_=IQF2A6(Q>_uv9fn_%*bm~ zZ-=*{ZuhJxUs1MF&UdNywuY^{>Z(p{)?GDhU3%oIHmk2XcKI92eVE@rxAM4~*3WvP z%IiDJl&-xs@4UI+nOG-@k$s0ucxBY^|$7==+!zd zz3tY#{9di2CA}s_>054<)Qaf2rN`aAc2@ef4cl7udNO+A%@(~{#pk`9UpOItV(o?F zrZ=B~Q+oT_Z5NI^Hd|k__UjABh35K81vi(J-n91X7Hc(y|r9#`XNL zQ_=6rhYjg|@T#I-b=k4*l{KWr&4tkqj~&!&ee_b7Wox!wH}ArBf61&lrG?RFkLEtY zVfje8xIRdnq+=T0k(KAzU)@-?f*c8R7fyDU2gD`gJu{^Z3@MUUMu zta^&f!SD9YE*JVe?!tEOF#UY#afjz~dpuowoOcC1PA_d$;6vwDGq;yKeBwJyzvS9Y zS4Z7=7O-CTS(#34`ufmO`SLNcY(-&VI<;QTjOrStOV-P+;Olf*!M1c?x%Da7)~Rsp zSC@=iRWP=BU604DDqI;2TD~@FIcw1Jo1?a~rY*QT>QLD7tu{SAE6xm!I~7gHyQ^qj zbl$AHByoWy&Lh#*mz%65d3P1uJ<{u^b?GF}s!r9tqRK66qkLJ1+Dt8cA|BUaP2spD zH_J0JjQzTD)nn1xt9^{4ufOTjsKdSTdcEW)ZKHJR(`~zCes{;*{y-QTI`=6?>m{5)C4r0hNEfEn0s;<>Iz&&mOyK<%+ycZ8mM~bm94{S6$eqAHOHJ zs!iMIuEO>4prT*JtBMLf&z=F7FJBQ>$y6sd&ozCJXJGRyiq@0Qz5Jr3Urt~4TJso; zKcl(U?#Wfs&uqPuOm9`u(#?|-OSW*_kE2_o{AFzl(sIA7prZ9(FS&N}0Q~JA@BS7@`a~tg{;qeZ`zhl$r@WCx3Yq*o*Xn} zO_VNJU$Cmx%IK1D*?G$!x3XZjCodV-sc6%e7mm;R4!7*+R<+smrMGvk^oKR`?6Iu# zrKz>srZshWVc6Z%y02=zti!OICyngX_OTQ0YI}8b?#&m(gD$*A){b`3OP?+4R(jk0 zk+(8^`CH9P)m>@H&!S5TN^iNX;QWg}ZJX)EmSoRb^cuVM++It!wg{WH=8s=lP}+O# z*3v#3wwCslN4T)y%T_i7_cZ|Szm&UZ&ct2SKc)6sX6iEl>ThOU&e zCYNTPBYn>I49_0tmV0%0%z5O37pC0R`stBvo@`y1S*zvsXt$?x*XY;e)#&Vr=QU0H zqWcRkHSOIYeN$Ebv;~((=Y6_qi?=jwL9Y(y$veWt=4CQ$-SIbdYSVS#uy-#xcvYL( zpYH5^%Ex}DY0PJ9kAC9Q#ODdwWl83v$M%*YY1LD2ShY zV$m~axY=ioQ>SH1qld>moOtGmiSHP9N5XtiJbBr=WfPb4OnGH_UX8x~`@8$dtD=?{ z?6rQWw|Mc$^y0MzyFd2n$U%j#jBImEVYM&W4m&K_yera+3kpiE`gmi>RmWey+bK7F z6?M-%Q{>feXy!Ff9#MJKOQ+s$ekRDe(fm%;N!AgcZe}X-?pB#!xW|&4SLCH-U0QPU zlX>ah8@9H%xmA9;@7m^PQU2qt3(~B2>n7&OGi__SWbM{;YD4pIZ!=xCc1ybNhArE@ zMy!+10%6mZbRQYkd&8C%H?PcV&hITQm2vsau0&kfhRrQ*o|tug*KU^niCdA`;KC=a zbZ>EC!{+AkQfp=SQ`xplWcc1=KQCL^;^x-PE%iD7_VXpxT+i>jB3jb#$tb^Ht9Z#i z6XHIy{95$NE-`uExS&O^#8NBz_@VMg?|kF-*Ve!K?knqFe(pt<{|7I8^xRv|yzP1(P0Z(gUKR6spI7pGE&aUD%i=%p^P>1I zeO?g1rO$KXxAb{N{FXjX32*N6gbe+n&*L)mi$0t39v1gSA8C8j7kzeopLt#09lu-> z3ck!QE!euGbnMpr-kY{A>AiI8lD(IHdCq0Y*V4MCRuvT(#^|7Zd;*wn@y{dMW;k=rLiurOq@VYT` zxh!;5NmIju>ekV?%!x^prA;~KSx#;#scvYfZ|G}hK{uB4n%z2ce$aO(4wngk>*!M} zPSxg;P0z2-9O_?E(^xY3s7aHu=UI;$J^6^KhmV?c!ZbPKsJ6O1{|^`Ru+WnbU^)N~3*C zDi<^~$o1N$vDnq{2u!N3o6|H`>a*of7E#UY*@=Xm%ODpg*NIlu$eCMpmDS|?mduwk zA{I7}I)7o4*7}xI$iilli!^syHhx;gsala!$7V9?Qmd_%DCcV>#q63|IVD4`dRMD? ztIyTbq}0)usvS+{%qJ49qa*9?JA4b>Hm)m*o(q&_nraz=*@Jdl&% zo94=cr(t<0y$ROxZDI`%d_VUG?p$<9$$^*+c&=ZJm%!Rqh0LoOoh^eaFNTU7Y33=C+j=4QO60 zxx*5RB6m<;RNg$=cf{i8JCz;|X%X(7;GO#1 z@#D;Hxe(U`O%{H zeAnj=ZyrU__07*AmR?@8Xymso#oVkkeE(VB9bWv<|8#iHl}`Q#SK7^938XM_0TKC< zT$H^AZwtMANK3zbNUQ8MLs}=VqteE&qtaG3B6CTT9j?!-7f+EZnVS0|a!Nv}`RX(veJ zvWtB2jP8?tvbuhK=Ve$}NruTSzeiy{oG%-LGbL|q!SQ+Jv=nuc?eBSmGJA}a2Nz^~ zFZ_^}89o>u+AW(Ows(dH;)nOn@_v1@y#IhKA22w}BZg=B|6=b=;H#>x_Th7LlaLUC z85k45a04fZ5J(7?1rqYc|k~&xm zHc6$B66=VcE5%aB<4F=fPYPlNr?5wcc%0y+(`I~C~rkTI#L8tf~TBtKjKIyUe zBdVNhlr-K~1)1^}V&c8g8l52^#CxAeSB4IS6_d$?cz@6w{yI$bVGbv`cu#-{<{5eV z0C>`P;~;sB&Rr>9xf>Pe?|^dgB@u+&Z34RBs{tn9*;3HqbkwEW_4tFv?`Ej!hVHOu ze9wGj7MYLq{me(l-Yk~*MZxRNImE{=Nvg6(CnQ@ZJW9^F2bl5Q9_Yc}3CfYL37L{- zm0)Oen?aGfnV+fkoK3I*qI}sQ>WxLoy|E~{Hx@ldnHQ#9FbgG*H)77%zFCf;Z0RY< zbOmTHsj}m?WHiP_WH1l&qmmr3Dq%upP4|XFzkn~ zPx+Nxa}SBO{nz|8sr}c$-?1WHhh9w2S1mnz895imFL>V^8siuJ3Jny$fRB{%OJ5~w zo8*eUw7~}Gc3AUxjz($(exU<&x>*URUAD;g9dhqeuuH+QIzm2HWgDJWBbc_!?Axu5 zlIfO5W;2|Fo{NYVG|`{bxt(~C>qULjX+K^pOMwUS0*UVFv_E$5r#;}P?41U6vUqTg z!5B!LO1l_r;tuI*eTMSlYT}mRZ77mXd6C7#c+ou!c~x+Eu!eLR&I{_(z_f``TsIYs z{gf1%rWtYlDQ0X#e1g$vcwfuLlsJCdh0tl=)SONQCOb5Lr$T#7=+ujk38r|xxyq(G zw24vtQi-3vD78m6nvj0FN>cWGj&JY+j)VBw3vF{`(E`9 ztc#su^mB?qPb_+Nr+!PFkwUj3DPT;dgdEf0681KD02cr$rtD|iJ!PP6_musMOgiS^ zGKkyV;K6)QGq{uwUih78%8)5R{8|}UvGYw;(lU5X9>_xqeZb?2<%1jR?Q4aKENc&j<9jNdMFJ<~fjk+YqX z_n|P}^0R}NpF7Rrlcw1N3Vy5LT?LuuUJChiQ7~M<9_8O{%fCB$#o3))ozJk!TIbJD zJ6qs?V6;t4e5xLD3J~PZG{<>LPLGiG zaH@+`ms;`R^*3V-#(^0DSp%HK+9;jN>>+6n+u(L>W>L==i#l-<106T>tqnfDq05a! zx;U5thB@4A4pmEz7{?Jz%}7s}u@7Ty9_XK4erV(k?&BVncap4@m6v`NGsrjcM-h0CI8uD za6M_q%ah5Y=}8Qq+$SVaJufhg)3J|Dc8?TavMIilJX~K&&fulw;rcR4YU93~JX~La z)sEgjB-7WE>7PJz2heOl$Q`X98ls1ak|STJHVxKsU(?SxGvE#KI~G~NbYohGHZDS< z2y${*7(=~!jwGdL8=-=e=}&yMWRX39mU|v4SXHx~k&-QIGfJD?-yR9GLtc5YVrJ8> zggt+S1hH@2gJE~Xq z5aTkIwCtfl0=mJpC8H(Sk}*C_qYdu6Ff)6giFP8Q?a$HBOWD|xu>)#tt|DrKo~M#W z{A`JuGBq_NWs-@B_Dq?~W8UB?v?~d!Zz9I|Z_pEGKmW1tFTdR6zqK2l?wIu7+Y8V9 zC=a``VShF3kc-!^?y>uu+4;;q0trrPt8SG|?AqIxjvi@Lwk@W;?dSnZpifGI<-rQx zi;e#t(Oe(Mlb8wh^y(bEhX;?V+M26tR+#tG@YZ_mJogEb9*QNiac%RXM_PwhFAwOA zrU89Bm#Y|6%)Aw6#>5FnRL!1#*z_ZgnjRQ()YxfpJqe38ottWQ#`7QY1&e8Gy}H(_ z7F2L-Yb$ScY<@3^KQroTn-~~FrYI^N ze9`l;8B5J8gXU1@G&SQHVQ?gMJiV+3acQUgCHf*>4b!xu_%l zKe*T6VtUv{TNWnmu_zsEc2=Zu&t^RRV?&*h&?b)N6Bc^xYKA#JNtX|da@tLj z2f|o#6F3=rK(a~?bJ0;V-N(vP8`%~hdD;;1Sg2Vt6QRY z7#8K@=QRe=ARF7bprOtgY2GZZ4VKi^>Q0a5oeTN^7RfuquYopq#5!X3x|AoJMxfyt zRLiv15yz8!TK!^rRaC7h!K|j4cpmN#bbMFe3|HD8+>CtQijuOX8NrHEIDOkRnR&KQ z%bHcn%)5pKX4+6hYzk>!?@Y~5-P|fEIE{d5n!E#N)Ls*4qSj!xHP$uL6eCYl8P2aI zI211wQ<3+qn@5_Wa|0~V0_A+`HbnoUPB^vvF& zc0)_7uP8{gJ85u|v)v_G=hK3-NLO}V7|?;U7B$2J;o5x%;J5D&`Y&vx%I_Sc;a#hSp z9d+l^(O^hJ{XE)u_rJAyYinzLE4|FGs%;5P`MUpb8#bHo3sucGM}YruUh}G3>T9a1 z8x}M**S9WQ{2$Iuw{-p1A@MJa!Q{<+-Hl)AVy>NyUz4SpfbK|(L{qb>rESR)+A>-; zk)?|OT6|a7H))bi*W~QK=a45WEsr!jX+5tYLbp=bl}`HIaYQD%g0{JuvtknIemCY) z(l{WQZhEsXoh2`nsPd3Pvjc}tB z@p!Mj&2Q6ahg@TeawkVR@YoWLj-_Sk#=NraE|+i5zkbw*sZycFjmjNLjrz%FsGIlx z8y@{Njo#WigH-AF&nQt@`e>|ynohAQWa3ST2TH$1mOXu=az*LwtLa50-BTfFGXm0j zX`a+e$zvp~Z_?-(DQ!tZsGYGB^>JTKPc~L=*SknZMAUNar&^|diTG(|>~)F9%_k*b zMy`&~G!nQzF|LI_PX0pUq^FLP9^%_mT3LCP=t*NRt&gaMnkO|G_fBEtZ@7%|B2lB( zkNkTl`=|Am7{f#_(Hy8XxSmm-x=l4D$`%?3$t^&WISp;&*Zk}lO?#<1d!%*Jxb&lG z)12+LetP^A7{ymSv(n=oO%$zVmW-PH8RU($Nxq$ZTP@s#l= z-qYn%t!dd}kGxH)l4h}Z50TG=mV%n}BvXuNoYQwPj6fC32cZ8+i_tCAUeRi_uaq(B z%dT1*surh1t7h`NksgYlZnEhrZJx&^(^yeI=17TqORFgFCGiWS1Zg}2WYh7U9LxQi zHcC?JE}q;z-1ah}(~{o%YZu_psLs9p*`XVq7igJv40h8th{o$MZG%YB5yfSa6r{yy ztuP}st-sVUTHT`7)fw4U>Qo?~(Ws|w08H~nYw$QNXk+t3H+0uW3_(KC@PXP zsMEQx^QAn|=%kACyd0(Fh}OU4aX=G@%M;Z#QmCPmddnY~Pf{;U)Lx2Kd)m0v)Q^h7 zWg9Fd>8m->R;cih)J2t8v;cFSF^N?YUtyAq#m#p3ei>eNW=C>qnZ>g>E0ZJVAvsb0 zX65ixyfP)0mL|1goB4e+z6Gf7qb{N;ivMm%+5=zSOO4+}yYaxWSA!ee_gMS>L&-7v z8lps+g!f+Cz4kB7xGZyP$Dd}I9E;q934fO|ZKN|<UMi4$+O+ITNgK0JWFxfTHfnt3pB3tttopgk5jL9 z^N{@iZ+fQzerIn(s(Fv3&-L3vbarm+=8Fo(iMc#=BZawnI_TJC`;^FT`;-0cxMGgI zD>yJeSgE8x!Q)drKF#CPJwDIl^F6-E;|(5P@9~R0e!0UVNC00OOm6S?xovN@o2Ses zA?9I}DDzT}kMOu{KlZonWqT4)+Iu&9a(Oeo@-xSJ#DV!hrL>wNzAX=PTOQ`NKbhP9 zVjg|lThg=r$9CI)%$IoipX%{d9$)Km+rONi?O*1$f0LEMf7;`_JpO{mU-bB!9{-ESKk@kI9`8uU1P)x^&K}S6c)7>1 z&zl>6hR5wY3poAbJ^KkB*RPJyH%ZL+#WBlGf0f7Ac>Fw%pYL(~7Kx^xLic~%^wT}w z+2c7L4?RB6CP_`vx!d-mlXKhxuO{o(j)Jo`BwztH2CdVGV& zuk-j;kKgF=TRncK$A9T@yFTc*)Yt*<#7XY|_POnUwkM+WncL$7^G46!>haS(ZrhLJ z+x3^ZtuJ$1U*>jwWB$IE{%()k^^5)O`o-L?U(9<%>jCo-9>*S*9N0e1<92;xyIsGS zH+ued{bIXaznI(giTO2Ne4P8c<+<784|#m2$L)H@=|AP!pZ54JkN?Hv?mJ_&Wcb88 zn3Bg|`@CBeiS2g$F)#J(Li+MMXCp;c{e1OLXdVG+_?eT!~JJ_?2^Y{#p+w)zH zKhLw*dfXl#l4nbtzRjGhw9iwc_G5d7$L;)LyIp^o_wf7+Jl@CScD?5K13mj7kK6gi z{&u})Zs!|wyM8mb^Dp`_g~=gKUyM#}pZ0lCR35hX^Y{Rd+x3I}$9Q&I9=1>O>?cS4 z%k~3O)PeaFhpPpj@u0g`pZ2-!Z?<=i66tRCdjv%m@(S?C8mCu+d*EzhB@XzSK=65{do%A31B0r?{ z9{oQ+IMznYSG6xEKAm`9`Vapzi8oQ^L&zalxmieZrJSAp-dOP1!gNrFG^c9EH;3@)kKBoqo zh|d=*?oZxCc%H+z5nk!=`w6di_+y08*BnxV-zYSn8NmzmnHp&sW{=X=sJxlMpUE~R zYOl=TL*hFe`{%@WIy{ANspFqT+`XPh+t}lOR?v&MJ$`2e{fOJ+XI6k?3+lunE2toD z+dC^bhqK$31g0O*vIU{k2$IQO0sWMO6QM1A&xq6*eCcI;Z91aK6etg>wm7@B8Vn$A%aa-mB|bAsFx9-HGu`2bkiE#^SStoO{BYv# z`ZAmNfsXzA#OFD@j<^k(K@0JmNXQIMA-==mXAyVr*PTl|L2bezGq{NOqYl54xH~_7 zg81}b{q6fEp=1R=C!0Or$O;}L?yi4N61V3US;4c!r%7sv|9j%@{Cb1x$NzZZHslA3h-XAXe$YaEio@~FhjfRpPKw`^c2aW3N7vvg;&Y<>x(1txAM5a& zi68Co?ZoZ<;;z9C;_iC(IC1y<@>$~c`loB~3UPNmd<*udyj_F$iT88(XT&QUo{~oI z{&LEbMSP57=U>XJkO+#&K3XZwG~T{Mh5iA4iHGw;4vAnkaT|&P{4^cE>f?|IT8Zy= z_$uOk98UY@I>(Dda2@ffj{P>`3myI-@g|4=mUx@P|496FhkrnPrNd*?**J!3`ErS` zb$DOm7dX6(_;n5+OMIKdk0k!M!>fru@9>j|zwPidh~pTi`CmYMxWhLRxBZ_8ZXu5I zY4yk6@3S2KYvQ*!{1xK+(3-0L?-B3i@UMu64)07~B8@q`5Ah)mFC}irYa%$9_zcHB zo%jh3KY{p(4sRsB!r`YAU*queh;MQDHN-bK{AS{}IsAU&H#z**#NFfXi^LD1I%@s# zJAWGrgWbg6a_pJ3IFv;Wg+Vvs?>qJq;wL%w3gYo7%|tMfco^AJgK5N1cla#gIOpb& z8XQj?$6OAHpnA}gwr$j<}u!cCs7>7h~8F733Ne`|iZu3tMt|wlq?zFPqLVSe7 zw-dMLL+QZ-#HTp+$B5%S6C4u3^Th2tp%cMd#PMz-wSP){x5M#mBD~W@?cIs@cX$bL z_k3g+@#CHPO(1@SMyKn;BZ+r(+It@H2ON77@iNE0lK2~r{fERyIQDCZ;~IfOVem8J z2RQb7iNC34dY<_(@lPE71o8AJerB+XxSda#!OO()ZW#`V;2q-iPW`?lZjZNxLC21C zei)@!7<4Cov{Rk|#OFACG;w=-(5r8u8-7S#OodZdxDfIeyGED5x>ykFB2c&yjrbdmeGPG( z!*VDLE+*cU<^YF8u$j1>--W>)#NT$}KTP}_hd)caC8}Rx@F(JhPI?~^$2+z-6b31D zv6gV``NTJ=na+=U5r5y|v}sG=K5r`}J}v71>;U`BpWyH@#NFp%Q;FN-XLc}?`1y|i zam252cr9`FdDmj%4>|Uw#G9h}B!V@>agNL(5nM{#z5_iGY$1+!hN=B7;`Ti=i2(aj zz2?}lE5w@)f0Ot-4*!Js#|}@YZ3bd=&ZOygBcA4PymKql;UkFmboeCVhd6u=@p%rP zPy8oNeoKk3cla9OcRKu1;=3Hah4>>5zl-=tC;dl>_i^}h#PL2fttH0G_jBg|qr^)c{ycFz zo(qFFh?hI|Pl#{S>d^h5uZh3r@C>>cG0@?;#K$?jfcUWvFDBmT@Ik~+cKC4OA36MB z;<)F=VV__!al5|c29?CGbK0YpIIbZ%6b8-2$2)u_@p^}!NBl<)zl!)ahu=W_DTm)p z`~atY9w+{eV}G7_2fBvP{NEssb3P7<;1lBZ`aL)Jns`4o)7{(*y1_ft;km@^{h{2T zfcSjJUQB$A!v_)X617)uFr0Y8;Rh41aQI~62RnQQ@fi+3hPXZ7$PMNZciaC&;=Gd( z3Xup-CC>YVG5;a)vZy^0!8ODWa`-L8dAAn!-$DEs$NpR5^Bn#f@lzcBcjD_Eo=P_t zE^~NS;+q|gcN5;>@R7u~JA4Z9dmVlZ@f{9dM0}^iPa*!4!`Bmk!QodEf79VN6Q6>r znvfsdL;N0R{QinKuBkZ`2EQZD+iOB84BjG6Lq#J}&@?$*mh$Pnofo7A2MUKH#_8c6uN6LpY3)0sTF|;}sr1$m26S zevHTGdHfWQuk-k29>3D#*LwU8;XEGmgGW94i)uIHrEBoEXaC&eo$bwf(;hvAV-3lp z=l}YXaNeG%v?eH>HnfQTl+yMj@=;o*pj^Q)1r-X0D;S|*q=HcjMk^>A8lfodG9*53 z+|Vi{iBIH#Po#rS6A1vx7(ru{sVnjxKVxcn71B2V$&VXXE{T;_iEDWkTw&nU$)KK+ z&9EvKhDp?6;yJ7e)fqRA?2<`^$!*-Y3MqMoq+L-}##O11C?s$}32@N~AQ8kZ;{pw@ zV#{#JcDN)u++uj5XTXc+lVUkz_@WEB(o9HOe4iUQtTro!BG-_l;QK+8f&WN z)h(!RM0sc<7?grO&^q*C8V8>!KR!hlXXH#O8iqc~HIi7%pxX>2DzQwW>)9qm)ZZqtU{Y;%F)7=%}1p(4i=s%|qgqnXaLT zW#v+qvT{kPY?#!hY>!_nh2T1vF&CFDXGAkc0Wi1~ejZ|(%i`GbZtwvOFQewTZdGb7x! zd&M_{(6#&d`Q`Jo;_T*AW%oC^N?#x8eMvdL2=LhS$RS z)i>*N)Hq(wWoCVetX?_FOhF^7H$2Kru_LQj#xgx{R!F;7pwQGvrm*xm(kp0%H=4>! z>qf~Vc0{~^R%X(48m!D@7P=m?3*X>a#M-_(cdIZ6h{ zXf!T3lB3VjUUQl^>C;J^`MqpGFa~kACEi;EGYxZNC1D7>>1uHX$Cu{Zw zUzs^zTeCk7M(oji7=zZ|?@M#ow`RXtN5G$&ugomX0K<@;0n)-{X5oQi=ClFoW5%pe zP)h@3eDWYNikGK3dvTi6oJ+afYY}s(cI6sDfq-RcFT<#5s;eLMJ{2Afr=fxlC`THxuNN9vnJ19Zwa(rbTnD(=|L zNw~vDdgUMGw}+SiC_jI%KBK(+M|<@*=bldfqrDk1+RM+Z6t2IQpSe(Q?SB4#{k-vD z)-5-_XD>77(T+peP_M_z%#kjdq~=7%GT+%Bk7Z^+T7R!O%FOt{M2zP8NVEVHGxQ8V znT-!(8=$jaugJ>GIETp$5M4UG&gP39TNw0(Wk}O9l)^G3WEuLvGOq{9%n-L`6h319 zXvD zGZ&jlgTNc6WkbDrQ8v^YsAWU_#vbYo)iP7qq+I;LxW~bJk8283JvWU#j(>YxR+#!H zMe$2&E)SDD{600;pRR{#LLFv)Ma{XO?Q_f#%VZ3fo68S$-5z7Yzi{EBo=qWX*qZZA zYfBoo$>+-E+}L{hRWvKFHTzv-re$O{r}u7qnE7YT{<2_ZB`RyqG6DQkpfYnY?k4G9 zpYd6MX>)Uv043BO@Js8Th4a~go4S8#UA9M+{7afLb9U>d;h!9o`A5?-|L|DmpD*w# z=O*f(5tR9-5M^|OVb86v&5Hx3H7yul-Owu&i~RSQf3_Si=M+qQS7O|+}c z%fP>7Q*m_a|D)T$S5+-;Ye2Jp`+o40x9swcJ+&>vD+g+tXv1yVpuN3~+}qg*o%)%# zN#`BW&ED?qZH~^`cirioQl*}!J%}mL*VuyZ$rs0fhe4!(=LiRi4y-yo<_ik;=Les_ zs^jrPq3FP><2&{RgV`Tg^&-NBq64d5L0HQJtoj7PS{`84rxVul0INQeu$Bi{^*Qh_ zSoP)b7adr2JZsMTgdPS_ z09GB3geM%y>ChwiV9-p)qX>_$WQ^zZIr3%fY4DlN`aJ0JBY{QGk7E6F!h;2$16_V7 zfUlbr$d_n=wG4R7TPQlP>Ud8KW80S^$_|$SO-?U6#5se1FJp)I)0c# z0a*1hg!8^)9awd=Pd+_OMgUeFY39dR_tVc$VckuC68t3{U`+?(O49*W9pgvSamUg^ z=#mbw`eQt3I_}sw)kz0f{a+!R7w2*UtNxy&1FQa(qXVnnjk;gU1FSl}x06r1b0Pq% zj%T$6$Iu@Nz^acSTqruQ>KKALmw{Es@X|R2tUA8$Xw~d?*$d&eM%I7Ri96| zKsJ#ARvo`9DHI)8_2uxFAH@Kxek%M$2UdLzVJ$zf>gN#F@&l`WIbm&2VAVGg)_MV} zj_*rry?|BU3jbmBhXSzbHxe!s9a!}j2y4E;s(%7q`Vm<5bebw!FJRR>64rVFtB!rD zwEV!TcOk6h2UfiY{4sDS0IQDQdlZTetU7*2r0Wc@>gDj4bp}{DI)m_IR|=hh=Q2JJSbfO$J^bL0g1_z^D7w4ujU&Ij4(t!C z<-}T=m%%!)>KmZb{;UYVs^3po(+5`l3Bt66I{oF}{Hk6{d_pyse+{sFf$m1a<7-&I z6T0Ag2oJ7h{ZaVTF-|9}^##`SI}+CN0IQxLtm6$>^)b*paXEoip9@{aA+YLL>vSBt z>mH7SIu6}q;+douV4_n1)^t$!LeYU$zmTwwTVT~Mg}LRC^7 zSaqE4MDxzkv2;fB&e10j&igurQl>HG==k2g`U7kFbKpzEy*dJK+OQF+#+6cg^Z-Fj9_5oJ?9_V@O53Kr&gmwG_tNsdM9sj_p<9F^l zAAwcRqjC(w59cW~121HJI^mpp#+wKa7JRFtKkDdtJ zkVkv5BLJ(8ajt8KJLVsTPP=O(0IR=Q1LfQdSoL=Z=k;WNVAXq3bL17U4y<}V!rG_6 zs^hSveG07lBuaCT{IK&_!h@HPk-{tVf5J(O2hqoP9DFF`;lHf;z?x1k=!H@qM;`#4 z_RvNER{sjZsspP&g|MzUz^YFptZNRi>N5%JbqcWRa|r8o3b5*^W5H;y3$W@Zz+ZG= z)iJiUUcjoKPgwgGSoIsBOaB6^j`c7PKcc7Lu8mmt^jz9q1D}E}=hDEM&dbmxePGpJ zC!9y`8$bY7{T;%ZKCtQmH91se}tf2Ufik;k@zz^ZR_bYRuZJd*kHUFOm2PCCGv&TdBsRy~87 zHBWv}3#>YhUs^9<)p72jIoJ36rHCpbE=>NxCaI>4&0C9M4mtom1kb?gDFoW{Ii=UVQ#g-`5sjtjlm!6kw*o{N9LKESHyLtn`{uca_Z*|3L0@hbKKR-c2QuVx)s^{LRMY{04?4t)*#1FL?FqXVn{eduSiKd|a; zgtcrd;3H`QtIuiBF^DJttG=4Bwga&0>!7b=e_++GCLF^J0}4N;|HTe25xg1tx$Fb1 z`i+hbtop6c*Rwyc>c1eYc|8UnNgr5!eg$3f0#^NLM+a8@Ip{y+ynt2zGhxl^UHC{| z!0Ph>bjb@?b*v$(1FQZ8^z%3`VAb~_N%P7lta$;ePj~2&7qIGm935Eo1oR)#9}2*# z?+5*S)`3;WZR_F-SO->p4B^;?tWThiVh5K9o&xhlR} zUW?!(=>w||*2CgU=nn;8)p5vI9awc7GBqz?)iJy@FEmFnF19EDs}G7;d>QM&s&6H% zac_jr;tSmzk-g<#3%r({*0potNuLntLP5}VAcOZ zSo3-hK9U!(`g{mo`T|&Wyyz}=H3<|l2^TxKL~u6rYuE=^b=)^o9aweTH!HrD{ee~A z*U^DhFNVI6{ee{<2>r*b1FMc>Q}K1I1FJrku-0WFe5Cxq>N6GkPdF~H>ezopbzs$J zL6^D!tA3oL1FK#IeG{h-tonTDQWs#=7eU|5{=llAMp)}|27IJ0!0NLa`WB80tojcf z9a!}Xpi5nVRlmZ~fmOd6`t_VXu+bYRt=f-ZFdR{eQL2Uh(h=u#J8)n9`ybpclWP3Te=VAXLMqjmWbK0oC$1FH`n z&lKOlIbTug{4@3kRvnj=sspQzOE0ZEuR-Ye0mwo|O z9eciM+)Lpjae>um19X{dz^Y&8=)kIPfsRF;0Zu{sbRMA6R|ff-ZRhtNxy&1FQZabjb@?b?nihd0~H!;ybxK z!0M9?eH-h*s`n)vyNmVy@Nsa7;QgR)XCGkIhdMg2>J`xMW`AJSCll7Z4ug-R53D{% zK$pCLRiESNz^We$UGf4}9s6o%Uf6>}^8!|%Ht3QUu%gk-BCK&=fY1N1 z53u^Y4E<_H^;e<7>BjF?I1FH}A_$$UqA_ZX87ZQ#= z%z6WS99$xJ3G_$U2UzuGjt;Ck_JSyWl>LEKKaa5Hbs>BtePH#u6uRUEtoqfC4y^i* zq2nZ%0$~b3G`pG4y-!%mngl*kx%|5{DgZ*)|zkpT8 zz9SmI8$>_c$-yvx?zjjzS*rF2=au8+(><0q}E-6Tr_i#*PxP z7Z~GST1>uIa3JvSSf331BI8Qnml#(8zs&eV;NLS|2K)-+vw;7=_(#C6GQJY{kBqMe zevR=Rz<*+leFI~!GsbWA_&$t@+1I7!0KV;kp{CCEu0e{5!EZ~nBuLJ&s@sEH% zWqb+nZpK#vf5!O7z@Ib5sc`HcjByGT`+_kJOR+B*V@kxnVvMP%_wg`%i@#2C;bsGc9|Lz~ycM_`<6D5cGrkKLm7`#;LwhoQ82UL}-<^bu3s?u% zdt$$aPa*5i0^^H66n+QXoAK+weHgzDjK-tzci+1Cx#my6!2I& z){ikB^~L%#E&&c1mja*9WgZS(!ut1s2QWSk_(JxnBCPj(fc2hF9enm<|0Te2ksaPcUMOGL;1+v@)hU<_UgsdR1`lNXcV zS|)Y{mmwecd+dXK{$luo6@}rz80-|r0AJ1i69^Z}3k!kuIuU#L#SUTr*}!8MV{gFN zSjM%$;}|al#-yRp0z857GT@1f&jg;tcn$Dm#uorjVSEYjRK}ZtrSI+lK9u$Qfe&N+ z5b!j{PXf!e^KS|3^)GOV=+D9DaQ1%@7?Ya<_UMZp!T4{$*K_;e96mOK^%$KC#g1g$ z5qKtJoU6ww8TSIl%{B`CfoC%=1)jrrB=Av;#{eJA82f<5j$wQR@Ue`sXLjs3#w&r3 zXN-N(V&7+cIk0TJya^aL@F-xfuh?A1I4_M=GsYfgv3ZPl0oO2o6}Xo1JHT~}cLUF7 zoJuDLu?38CfEO~x`CAMNAqAYX#c)%Q!Z6?y86OPXz!>LdvBivM05>u|4!DW&0^lW# zTYyhu`~zStv=q(yfepTqbQ;M;hde@rC%NSn+d^zLmfv;eEEAR%!cLCqU?Q;*|;wxDP z)@$<}@VSch$AGV9{3~EtC!YhphV>VLrQO~DzLxbr1It?X5%5OVcLPg%#xn{3n04%{ zt;ei9;OkiL2K*DoeStSI?hh=-tTN!utPcm?!gwO^^^B(jZ)JQG@J|`f1-^mt0^px9 zUIKh0;}yU+F+LOcX2$0N-@^D};9D7A4SXBpEx@-kz6JOW#@m4JWV{1-8{?;e?_&HO z@OH-7M>}>m#Nl|A%n{@V$&z0N=-W74ZFxF9(+Sz6tmN)^7#g!5I5r z#~x(76Zj#<*ylR-3&yVkKg{?8;71tm27Z)reimW5_tKqk@nft5>;0DA@Y%_FKj6n1 z4*-@iHVpWetYhzM9ZQpdf5rOYz)vu)1b&in9kASgs3)w~iNJcD*aV+nv;R`y-!MKI zSjPWq;HOw$2P|d7UfHqVvVJ+RjQ^hiKh65}z%rh12Y!b2yMSdpKM1^w^+$l8W&9NI zbBuQZKhO9Nz%MYy{@StMF@6vDMaCZjzr;937r-&OmhT8G*U{K(JN7dBV4v;S?->^Z z%RP$yfL~$#0N_6`J`DI(#&dxG$oN>o#jjahBKlnT{E77+0Kd-o9N;$?UkWVOzt;iF z_3zEVZ?exlz;7{r3ixftZvg+9@#nyQVZ2W^;lDC21n$ka1bAP@6~KKNPXd02@l4=% z8J__BAmcND-($QU_-~9a2Y#P14qSR&NvB{zOs*?wIgGB|sF*>l6Z_`?%QaCK-~!fr z0LwK+FW`%LJud>5bKri!2ebbGU^ylZ0+weD_+FeI3-Gdg60n0o!_cUalj)5+7 zX9BR?W0?XheL4+T`uc60U(s zPK2Ljd>h&`lj}RYGvPwUX9Evl{4wRL`^N)^QiiXfQyvJwAsU`S8kHwO>y+Y9d^$m= zav%VQ;)8pG2`Uo;a40^7(5ZX~z@hl`gHGi`01m|m_xcjFH#GuqC_Xs1OrY~A0Aqh{ zgwfDx?_kBD_~1Ta0ynWJ0Egm(`+*6335xCQQ#1Rj>7k$ z;`1};3D$u_@wp9pG3&sg_-u!ciA4c86rcZr zK90)?9E#5~&(B?W4jhWlJJ1KS4jhWl$Iwez2M)#OE9gU5 z2M)yt=k^IqdJ4dy_;iL|#yW5)KHZ_0vkn}JPZ9KCtOJMQgKLBY77_};q4*4iKAd&n zP<%#1AHh0sC_dw$k7OM<6raPOV{xJY9E#5@=%ZN&4#nsD&<|i8I251x(7(qza40@a z(6QiA01m|m?-ofM#5!;&K4(Bbn04S#eDLmz#38H$hvIV)^f9ahhvIV;^s%f1hvKst z`Z(5sL-Dx@`gqoXL-Dx_Iu>RMz@hj&0DU6sz@hl;gg%LN;81*i3w<){z@hlyy+a8s z_7s3a@%a<Q5{I)69Ewj4^y#bv zhvL%{`Vp)HhvI`{LShE%z@hjIgnlIJz@hjIg+7yY;81*U-Iu6j9XJ%9vCwC+4jhWl z6zH>A2M)z&I`lcL1Bc>+y~Yzqu?`%H&s^w7vkn}J&qC(~f$2xE*KEH-OpLO6+e4dBCfOX(deEtA^ zA?v`Q`1}d__?R&OhvM@O=!@AOIBZ~yYu-eo#i96QL2qImI250J=u21!4#lSs`bn$< zhvHKVy_t33P<-}--oiR?C_cD$PPDQP9E#5Y(A!uC4#j6Y^rfr=hvIV>^ku9AhvHKS zeL3sEq4*pFeFf{lq4-ooKbdvlP<$3aKZSMRP<&dTpUOILC_bk^KaF+ZP<+mUemd*G zq4=B&{RgZAhvIV)^p&gwhvIV;^fOoo4#j6P^fOrp4#nqY=x4DG9E#6f&{wez9E#5a z&{wk#9E#6Q=xbO94#npw=x4JI9E#8Hps!^eI251XL!ZFo7C022kD>pN{ei>vjQ;`s zJc~o|N$p7bk5~r|#itYW^H~QD#RvB;5*M%z9Ewjb=ohjM9EuOl%@Y@~4jhWle$X#w z9XJ%9q0ld39XJ#p+$Tv~$~tf;K8HZRjCJ5peDL0}#O165hvIVt^eb2g4#npv=o?rE z4#fxeWD-}h4jhWlLg-hq4jhWlNzkum9XJ#p+`~y+!#Z#%K4(C`mUZAzeAYqV$U1N+ zJ{Lm&G3&sg_*?<~I@WL8ZmO+1jb>L8ZPKUmOb>L8Z&W8RV>%gJ-{0RC(tOJMQ za~bqsunruG&$ZAWW*s;bpX;GN!a8s$KDR)Bly%@xe6~Y>jCJ5peC~t3lXc)wd~hEx z@i^2Tz@hm35&Dy?1Bc@C7W7}U4jhWlyU>5b zI&dgHA47kNb>L8ZzJ&f;)`3Iu!M()9Bp%Peq4@NK{v7)QhtD$Z3;lVEL-E0V#l#D& z1Bc>M4*hqm1Bc>+dyk11SqBcqXFT+mSO*TpXBzaESqBcqXEyZTvkn}J&k4|9VI4RW zp9RqWz&da!K6npc;#JmxL-A>a{zuk_gDuG#piA4e`6gu6rcB@zt1{wC_bM-|A2Mi zP<&FdN&k>_;81)zLjODKz@hl$LH~$#;81)DpnuFda40^-&_7`vI24~j&_87zI20e; zb587L9XJ%9gP?!LI&dgH6QO_3I&dgH)1m)^b>L8Zj)MLL>%gJ-%!U3X>%gJ-EQJ0Q z>%gJ-G(rEGb>L8ZmO&4A9RLo+XC?F)>%gJ-tb?AyI&dgH7ebG-4jhWlmC#dJ2M)#O zC(zSa2M)#Odgzl`2M)#O0q7lB2M*tOJMQ^E>F-tOJMQ^GE2N zSqBcq=P%IrVI4RWpAVtuunruG&u7qcSqBcq2OH`o@>mBB#U~wlKI_1t`0N9{3+uq4 z_;iQfm381yeD;OjjdkEqd`h5qXB{{cpZ%dvVI4RWpYhOpu?`%{z51!pd$SH4iqDbI z`>+liiqBEd@x?<5z@hkjA9@k%z@hlmLhs8ua40^DpeI-d4#j5)^kUY5L-APwy&vnq zq4=BzeJbm~q4-<^eLvQLLwO!?1@uE%2M)!j2h}Hb80)=&(^119D5C$xg+Po;M4v%C zhA&rAm<8P1z~E^5DDH1@iRddyiXG1WtAGcv&szE@uD7^E^c&$L{{CIw_-TtvL_Z!rQl7cMyV$1| z{^|6G0&t1w>)|8qb3Ske`{40dF}}n~0k}l;y9vi;uzoLa0plI?QQY6+64Bp>kEH(* za0&b1>!-y7EiMr~C~aA>nBDUeOn?zXCq(cdW5F-@*(tZSz2 zKXn^WE_hOP+S!WKNg#O#QpZ58povobn^09WV;SBwMh#Z#?2^l|qFs)uS?lJtEvTxV zH?O&FsWcu-*w8mg;J5E+3`##Jt!Y}kxUP{pr?IKEu5|MB*@Mjvwn@<%=x;#<3PgD@t;nug6Z_%t;Z9@r_g^5n%-0r-1Ls7 zHDU*8NDpPv^r{FWJ*`I4e?%W}MIOCP#W%VnceH>A#!a!4yfpwoVqC-bTW1dSfo2eflVG zq(`R!QM)`u*iCN)HQIp?Bxrr_Bkrcx>5{;_3m56_BQ})p_w?UQuek&Jk!*sd_X06D zz4ey{0lqGR^m4_9^pKdF-iI_8+ZzWs1$EO~cm?lEi1hNshV*dAchkfD=qXw#vMcOK zPHuV?8-ie?l&`Ck-bgRKGpV!a&>RI#uiQ&-*H!$kW0bEu{YPFXA5I78Ur4=^-p8Klp2a-*cE464bVkfLq_xtLa_7dE6gZQ?z`` zz4QvGF`m;z$WP(9p5Oc3=-t8?coNia4FNabmv0Gzl{7KYE`8{~=6jWw-i`gJ4Ky+O z)buX%(mQ^KokvCFr|I1w=?x_fA(hU1TF{^pkRJYT^Zb?#rgvbgllZ{ze(_V&ZRF<$ z_#iyfj^8!TfKk6+6L8yQ+Jiw*)RWrWiHM|%Euabs# z#u~5beLxy56H5>W;pl_ucQ_2qUouCZPBy_N@}oC72K$rsBQhX8>PE8`QhHJ7auR*_ zyGKN$e#4x1{ieN4+{r-m9Wr`oksIiB9Q5+4QNxB0FDjy!os^lspKCu5>jxk9%&6Y^FA7yaIcr{w z;z6Ij`svl`tDhxBKMi)yT|f7!+KX$S`S_8X$!*UbUD>udD50C-(9f^kW%Ti?_e=JV zbh_2-W?R2$m zPk+@(Syl8pt6JpPkqpb_@}b{Wp@KQ*XK-CR^cqq_3rZ8=)|J=>#0 z|8)V{gyu|=m)|dyZL9Wbcl$+i!o2LT`SIA)2vi?s2lfljA(j7OF>H?M6Cp34)yu@&A>F1OfgB{5huAq%l_~UJZKOzAj_l_Ou}A zKtGQexURBobu=1oSatKcBR}4@F+c0s7e+pE>%sXQ+nU1F$2zOiMT5EqWV!z$V|j&a zcJ!Zi{ILEv2E#tSG06U7hyIU8BS>qkpCubnbE<)tv!746Iyrq!z4yD+C)6^Vi!?=) zyF>p>Z(h8z=UR9ja;CQYhMe>1MeptA+;&5NoYC@b&NO5D?|sH<2}?HpG)So}y84ML zRt6*KEcC4YnZfO=io-j<%1>YQ#TgUNh*tdkH1KeZRpR7(R{w{;s>$CL+<1ki_+RTw zslX6D1mgc8V_##}L+`AK~cMo-Ymr^*Z|0>hF12$+rI1~BtgZRE^2m119 z>DuzMZ#a8>O->CR!84xOyshY&^lcljc=Lh|r}fC~@TV>rU*&Gin1^wBTw=?sUv@n% zvH8_EKHGTt!&lIgoSfTNoi*{%%z^7}day&kOd7qbigvzQ*?(0udq#E}e0zTS{5Q6L z^0z}STJzjzT86AqU1Ru#UWfi^!LQm@&8Yl1?dZz>n>S8DGH}V%M$hrJwfrT1quDc;*tSC-R`&B#&3qCYIN3x}tLR zwy5-%Jm9k5ZQphI%AApOZhuyoLHE~oeN{Xl_4DG8{`X7$yjOK`g3!R!&pQm5Na=rC zboPMNLCK&yKdsx zKfGIT*zy;G!*;*DvU2(EoXX`}b4n7a|2Q}37R&GO$=4TkSoQfu>8W3K*t+KHv$szA zy2Hjtzdn0odQiFi?ws+vcdi`2{Hc}WcfT6NJ?^>=e>|=GgXz`($bFYa-RHNjDLwnR z{u4KLs;O+-7JS+5xWx6ZzVUgye+IR}gs*FQJ{y#-zJ2w@mt!031$5@EJ&aLy*2G6L zGpcjyE0;Zz^V7#W)y=9tzK&WaHtLPaPd~|dW_McdW6R%MTM~9nduI2uIh9Mg<&Iyn zJ17~DmRh+aEw^MKeJ*=DXZ*6emW+D0a_J{Ilb80WuDtBIqGy(VoO8j}BY zv-|m+!#>S8iPF7nTM^VUo1~sS2B=tTYgtg$)K)jl}q2u znfyryO7qjA%1__Op&I5ad3V$Ytse~dSVuT!;MI?=Z7}U^M(gIIb+jJzNM&m9er4B9 z8_S+tKeuGS&x5CG)3)wx*B72;kH9zW@%0Oh@7&66kJ4wfln+Ub>To085U zrmx--9mBTMSc+et7F^V?D~+e_!NecN-bH=$)6xRiE?S)yOkeZMH7S>cs}r?F8zu(h z>Zj=|RyaKfM=794BgF$(weif%o`f_Z!Q za?+~VyVr4hH+{EkzQ6YboDzIPIh}02p`1}#dp5^+t3uSCF?;J~&$RyAwTT5zx&G}s zMy>pB*KyC5`7W*O$4Uu?UiQ=in6o8!H(V->FIaaL*i^2^b9^-z%N=J0Hj|4JJ-fn*-npGDr{*KmeM)1t3`JD-oP7dhm>ZgpyjTn@zb~|%S!fj6{3e@Pa?6ScaxSDI~I2<(_+VE(T91^WMak4E$LVZJ@nuZE5Qktxvv~6`J7U5EPp2I zSoTQeAnSV&d>xvc(m~kd#Ix>^+HC7E+vYqwIi=Z1iOXaxd!&Lb7^G&ksF_2PQ>sla zQ!T8SDHlvZo?E6793=Abktw+#LA45m8# zV%xjYWH-RHpWg+$5Y;xpuH>1zE4kLYkc8um?z8254oU6N$L}Zi@%zd78CrP$uMv|r zLQ74j$LX;X3^VmfiRHXUnb>}e2fa;|$tAwQkxeJZssE{jz3Bqggw&EgTT{F33yf@2 zy9XBcNVT|UhQ$S)EH2EkxK|g(7)yP6SiJ85i;G4XjH#B|cZ$V{27^(P)Z+6EMysUu zyUODJR~!5);)WZ8-hY)k#CZpmvR2k8^nbcgpyU-tmIB(^WMhX8f2{jGXbg{Oy zuDPYYsj;Z6ymV-3Suc&-hO{&< zty<97(lTU8ZS#4&=ZODGe!g}Zs=zA&kt!=e+Rc%Y?>oj$2v1&`(k|j;e zt)(^JUW}%;R=Nt-yt{75X(?sQAGT0R2yA>^%-_TUuYTkl8zPYKTUu0dhE=ZV~?q-oOKZFPuL*W5_WhIcKGZ)&Nm zZ=6xzTC;Fw6TQBB#dvxX_PC~|hG4d7KzNT^F&V`j-?VrheJ5yQTSHy*tR~6@3N=w3 zr*Ta6GKx*=)Rs9^{@SsP3mWQzlTgH(d5!o#t*$X>t8Z)_Rn=1~V6r<8`eE};KV zt7~c+jCDpcB{98eSx_G=3TlQ0)ywN!V5n(X(!2t1heo0ChG_Fi+|&dD15&75;P|L+ zYi)9>kFr%FH`R%jt-&zdjRkzgFR8==D zXlkx+UAXw$b32iSVqL?KhWggJrWX0AT3SAIWGO9CL#DJ&yB|xVZ) znnVxv*k3Hir^kO_8mLe$^kPLL4A-X1l!EqBk0~0bKrF}nZ%?B_>+=7%&|Z4`Khr`n zY4_wIdr&NGWJj5oG|G6mW$F+eD}!lY8C<>9Bh+CxLM(m6Ga8s9wVVIRJEwa|5_@t{PKSI9Ja zWeQv5vsinEmOZu5{zN6rwz->Dhy}8|KE6PtBX&plkH@YxO$SDotjK)S}(v zz+d-T`=~AlYDwr$gvs&ST4B#ReAn7jrMblq&^+}h{@rT*In^dh4{K?h);HDujF@R9 z&NELuqq(K^%$9ohmrvz%?BivzmyG8<4u&)b*rTV+mTZ~7v3LhGCH;4f$>&jNau99v$oxi2vnfeWO*JY3Rh0A5 z66~iXh{~oV*drf0%iy@7SH|e{Bbp0ZdK&XtrX)FW?EDdnFUMc{@3iJ7YE2poyhI-ltR%#xuXL62eWk1VN<&496}71(AqAJEkkzEWCi5i4#N-_J)YH=9 zYdGnn*qAoSbxNBo>U3=}>Z{XCJETeBv!yb6j1w;L21}KW67TPrx_GBW)iq-`O;6*x zJEh^#-d*yOQt|9a?w#%Jj`h;?cqdbzE|Nmj^J8=-6-a4%NlhmU@291p13w>KC@~&a zlQeGR6P=_+3OVygndGN8SuLS>=y}A1_=%>hvo)Uuk{_kTy*N$M`ks2|iW04mbn3xn zr1t`w#O7$+g=*20a`hksr#?|V)Iz5KY>8^Mr*D*VbiP2&rq?*G`!_8X&q1N+zca6P zQP0uwl3Qz_tWC7waQXEZL5nDtg_a1mMC(eldPK^=c$=yGzm!Up6D7wv(bY<4lU}rj zc9qgdnbNrQ$@O}l>eX55r72}fipBD&M{Rn205T9&ytKx#cp8k7I^D&l=ED=oIPJDg z?`P-??tImrSP+amgLb|i*U8-d_x+2=-VaVrF#hY}7p7j6c5(V89WKp~xJ8Z+-~^jFF*aE;vxOZGB59VMb_3%dnw}>ir>piBPyfB`DgRkYkC)@nH0aN4gI)L zJ8b2+ejCiCvVT*0-(>r?yo$VbiOO9F$p@+Cv7 z7UR!+{Hej8<@D>s<%_G!A~?^&8iHPKG!h*pHTd9bhti!E*NQu1=FUpw5+}tCaeClX z;0k-;_GUf%%e{Px$=nQdlMeIfX^YsS$2r2$UmV!qJoGXGbNU&R1m?ECnA<*L-bdXf z{UVPiJZ|S7$H!wA4$KEAmGq)7f(S45?6#LUzW%OE+lPPaf=Fy1;l)3|;|F@2e)c1Q z5cRF1dmVh_!N&H>hWnFpW*SD9-rm$IS!8?fq0PSjkor>9ZzhxFw%U+D2mJ-)%?S9$yzk8kw& zbspd1@f$pTv&V1u_?;fV%j0)@{2q_r@9~E`{;0=)>G2ml{<_EC_jpRQO!D~1@pvzf zV=n{_>_5umV>~{=7DHHQ$4=Y1Lt?Y#~<=I zemCv<+xfupU-RsCez4un59W40Fz+1A59WCu@8)rN)dCfX{rhB0UnoEJ4ES?^Xzu-3ogIBZYT1e?)lI3_$-ef?eXJ1KG);54yR0`V6KQG zhV!?M-g?wNx94wcpBtsYyw>B3JigT9_WXE!c@AUW+9)H>6?|6K-$L)H; zZx8sHFbE8C<+wsEOju+-9d;WGju>DfcZqJX|ew}Bx#}~H0>e=o2 zCEM-!C38DonA`Ef+>RIKcDyjR~4lyKnM%X`iP?k=Sm_!@Qek@8R)Y9xw8EKabn` zar)(+y~5+R{_KCCXFu5E<2*jW~65x^QxPwa@MRV!Q2i<~dQK%x!xzx9!K= z=E;177vI*8?RI@&KHc-5>G7jIeyqn&@c2BB*Lr-R#~VDp#N(|VU+VD-J-)%?H+cMJ zkKgX`yFGr7$M5&}Lmq$BU2XZ>49y+~Zeye51!Vd3>wKZ}j-R9^c{dhdpk` zGndznXXbW1Gq>ZJxgF2UU-r^})#I;w{B4iF z=Re5dQPKqB^wguk752hYBOms+^O1R;XYbT+xg4f&R^zs{xY}om${w4%2=t8$G_s<97Yv`rPQ*Z}s@y9>2%q z_j>$(kMHpKLk^E1fjG^s`-|;14s*MHF;7J0VIF$iu2*cg?aSP*FU)6p@fUi$(c$LzSHx53f6VOO7#XR) zeauhDVC&niU1M{cxbbr1+nPa*d*4)uo77!@J5t$yKhxfGA{TyM>E7Q)+q(Cgz}@>5 z;D<)>`Tm1@y$bu>$j;Z3wte|}>!Zld=ezFl67e63?Ed<~Dr_}j3*sh^#1%?)}A)#NGRUhY)w~&rOcf0>}(z(BE?+t)tnW)1E(cG;L$st7Cw% zG%oV*WHz0&$N$V=1=+5P?4AD)b?*XSRdIHW&&kP2AcPnaE`gvNa>4{+3=r;06~avs zkrG4{G=?NVG$fb{g0&Xqj$pM|FL-Hc0g+N_RkXF%dI5`y){0tdwXa&W)~fXeBBK32 zYd_EInKMM&_x--_{r&!<;jFc0&3*Rlz0bZJbp>IYUzS=+-2MK5UUBQZ6Es`hM7#t2 zap)N2HQrDnQ@NEv?PxvK=ze4yqhrdbK zwx_FlkGLI=t_pMGZO8v5VY|L{rN_;c`lS=!nRs@{JJOqj=&5S@{;u1bj?a^i;*FLctMOn7b>pQrE>2=_W1*ZypObyVjP9~s8?Qq{!m{Oc9Gi*}6@ ze+k9UbNDjiwm*BRb;MUV@f(R3Ivm#$W;lEc@w||CR6i$FN{W?)vcsaoa!XN$)d7$}W_*jn7a$iM#7f z0dZTu3{@P~1?6Wde79c!7=%nUmbjg-nF`<4=a^`UsUTkLaD4YZ)Zw+n?V6IQ8i?DF zr7k0G>zk!k61UrPmb#j_t#6jPAt`;f+LDw$TkRxX5*CoH@bmO`{$#6%iQD#MEBu7} z7{`yFL7(h!{3N+{_?yIS$Wb2?cenR1h^K~z9Fcz1Op@f}Y5kBPhM!*=5C`f(3&8+xfniQD<#OFc#0=GRNT zMBLq8Ung$Ix0iaC_>3^aUg{I#wm*8QBgAiU;_+m*yFO$Q-|ocsAil=oapE@gRs)IK z?V)$@zII#x-fAqx*M|vutI0{}wK|9Rs4!lu1xfJ()MdmUcH*xho)_{$bu;n);rME` zJt=*v`XzDq_+&S6cl~*mIMz%KTD_K(zK?pJcu_d#wfd6yDGu*Um+j2a^+c^sB<`+f6NzJuHs#MGKE+UaGe9-*CWkK~zQN(&B|gci&j#Z6IPsf^yX)Up z;%lAq?j!z;J{X=}FQ{IQf?Rt@^ju5}r$v-pA-TwNhp2UZR@qLsg zj(r}7K58iOD;!=<{5+?;>BQaj@qFT&LcdlG#O?L)KEZF6KN`mO34ZJT0#h9A>8~e0 z_Hi7v+DiPLkoQsd630G-Lm%}haeFD7vd8Qr7h!K;=c&<)9NtsWsbiC zy}81s*D85H(8$+%YUjK5j!@om(w^P5X zh`%4k_faT$l{#(RnIOU&CywTz35dWdW=Mx_ja;+{Q9(VX^;)5N2192M) z)g8ot5ytmX_|4!Zqvk8=1l;;jxppZK`2ezZLi#~RClwkP8Io&47m|A!O5iTETZ z{dVFFCOMs-<87|?{tc~uM?9C-43qy0#AiC`-y%NHiT{N7949_XJDUX#&jmNxQF-{S z+CMw}Q$l=%Q~%M#yE^Ho5MSZM&mq3v;q}C?bNFS%Z*};3;#(bl3-O;hdHuQ|AlEJ~xN%hnz1Q9-L>jdK|wgY69X{ zd;B`#*oWrO`NFMU{8o?uR559;@I?{=tGrBepQ=^y+Mlzialpr(|UmsOU@ z=TP|^PM_nZoi?O$P#_Eu!;nfg45@^nynJY&lW~|Bhlz2R7>9{*xG|0pPVTjgl-!RYE8)A0=6j z65}YzX_VwNc#yP$0J5Si1`n1z2yhn=kn(`IYJ|81NZh4_xOxOa1x-h$WhPS|fO)MA z)s=H==hro$AuS6R$wwLdM2DahYeIHV#Wey&gG0A2G=S6*s0Dov9wcA{dePd@C`1ny z|KOlWfnq8%IP^$;1_y1ld4#elYp4N(lMBP-LDs`e*27Gx!%P{&(AL0Xavc_?N^YPu zd+_iusVQ|hvbWVk9gyRQFnw)9O(>eGj7aWe$*XLT#Fq`0YLo?SqWsDR8&B9}qfDJf znW~JEa>@qDsFe+p>Xr>k?wepzA=@%!64aim8LGh?K=crkeu$~i&=5%RWkXG=W+2Lj zqBm`q1OtfNhM8)aAt@V%wD`rhN?I=H?aAmChoU>^NvYaO`enZQTJlsiwRjd}$v+&& zzY~WfP7WAyTa&QYsj)8h5(Qlx{#Kn|AhL8y2zoFydpVV%|6Fs}GgJdq-H8i&Kg`Is ztGh6F?D)T9g(%HeiNpjvyy2b*%3QBqxyOBj>f zr$JlY63}mE8lnwOT(Bb8e3CjQDBYw(liYO3$EHKQElZ9|>WsneCgJr=uwB|*yxAKp ziZ(W>{bk-X8iLWGjbiZdq&_S2CQz^eI*l6QcMd8T7Fp&^sbH(MvEGCjlAP8X*dboy zylAf;Uf;W2=uM_zA+vQ#8i=x_fe5xNr|rSo>~gJ8zrr0E;X6{k|ez3Ck61%ovnwRMca4$R@f5Ia2BDLZ_KH(iE$1r7B!kfC0q zhI*5Hs5eQ1eUnpOus?ITSN~wA=EMhw3@-P|4|Z)%{BW;6!{NtvKMF$?fZ<2IUJ)<( zE5j@ODl6&NW@*uFo>w!kj967oP0c)d!(rvZ)_Ml?uD*uqnt9C>O$qpwij|ekt#c9G zd~uU~!D3})eJ$rQKlr4V%Qeso3#%H+!uKpv#=#G%R#q>#sB(U5RZ~rpGOwzx-n_5T ze?8;E+J()vRM>z1md48YEvOFaIPd7UHTtiS{2#r&G57)6DUI{T(R=C2tEw;J@6>ZY z;1gpyWmZFQE<*v=W^(_@Iu=#oFM(Wg6pV56T8UGfJuI?lUH zeSnRQYYe#`aeaV|z7M*T3vBdPpi8@ejs6aFDHqu22OU4K(Q$3qyyS0Y;;_wH2DJ?{YA$Q zZ1gvvOa8z{$9Hcge_*2@hA!;_HabqHO}W5E|GIft?D&C=|3v7Y@O%I^I=+`M`2!pM zT*nV=^m&AHKIMFXjot#kv=`XumqC|y0ULcibQv#TqvP6=sVA_}cRGGxqdx>)#uwP= z&p3WyqyGiE^aHTb-z99?1#EO&+cWI~Ho9`g3)tw{(4}3#MlXOaz=rUfwM#nW0(=K46?}RSx0yg@ijvv_Q z&pCczqrc(!fsOvL;|DhSSAX2Sm&>%hj};N$~r^u>g84zVBD=$FGU zV+3sUA3&G62W<4)p-X*$jeZ|=sSmKxpM@^@02}=^M+Y|ghlF!J=XwGgJ=k`np6<4j zN!@Mo2R8oR(50ThMi2G{QcrhZFxklm*!a(NbYP=jNZ8a9*yv60OFe;&j_U#?5pLJx z!1AE>81j_J598ue#!0w|fda5e+kxiFRZ z`^z2wXu{*W9&I>Qw?mhFfQ|kD zbeTWEMt=sn%pYK*<9Np818nqQKFfCZzd4^LVjfDnfK7d7Iy$h?=Mgsj25fY!^QPb2 zHGcuMu>^}Eg}(r&GY;mn+~n}zozKTnKDqzme1J_I1`#&%9N6gP(7$9qu+b+IHuD_V z=(7mt$~*@)I*yIUb>w`~2=~gc*myEX&lero=xAd}C-xTtXEMfim))5$>U@HD${kP8 zUKt~|y~D|qo5B~$fK6FQ+bfIn1UC9a!ug^D8~swkW)1)wJy_c%e}8Q^`QPsNw-Pq_ z1DkwsY@ZwDdIB5$T}KBtdKTf5W4Qh&6CR(p6tS9m_Zy9vqlZxPbmn=))L&-Yagg zDL04oe9?i8exlVw{t}Ea=T9hP zJRN#J#@J?!rwLfIehd6^qttfb{;Z=cGyj229njuh1K8uXy*ugoq5~VhCT#KnHahCr z-gb)qIf>rwhv4>AIq}h=1Dkx%#$IwG39!*;63!PL*y!iN|5qA(3cyA`pK!kDz($`& zxTKidi|rzEJYyV7Bph5MI1{?uI1X&|Tt^2sI)23`aRTQFZ1iHnrmRwUB!6JzDT6L$ z0UI6nHyq%2_LnFC#3=mKnX+;?wuV5856eiD}jY;+u_86DW@I3G!jW|82^byN z==f?NF`oUvM#o{a(SePQ!_CA5_5&LoyL?kO>`G1DfQ<*c%)~_chXSzCF|AEnOa+q` z*m%$#rvAW2$GyHr2R8cY&>>I&Hafl!F*>l(XF@-f{-FSD^g6<(ZVTa&eg-z4i=m%J z|4;xn`U=94$*ixTkA#DZ1mj-11S&`Y*yukZY|{P&9`OSk&mGVuEwIraAZ*e;1dpTz zHl9bJOIl!~zd+ce{S!P>=pPEe#`7xlGgt>U`bUH#Q&~Si9|;E+3H}`Vnd|{JI^8@M z>cB?F^Ad?^><2bFy}URq3(riLvVe_;Ubn9j-{!QyM#oPLntBe0N9qP_JSRfO1fc+I z^s$Z(Y;=0Dby!beqt7B7so;EYpJu|rMS?GYK7&2LMsIe~;vPkl7T9=jFJs~?P77@G zE1_c|QvfzPp4Uj6%{s8rZz62!c`H0pH(=wzvm1$7oEF&Vy9k@Kzk=r+_5d5tZ=j#c zIOTPgdeT}078+|==={I1b|A??D>nHF?S-{3~2XyH-V58pyUHT2!==VdHegii8 zW6-7FfQ|k;=+bY%M&A!z`VH9Ve}pdm25j_y5;kr51Rkj~uEbiFJcd{(T6x`M>uJLjproj^_&*i=;It6*yxj> zV+TtC*yw4*BX7|`3I&`4MjF_Y1Kh~CJMbdLy@0VprceOf#JC8!nK7P6jQzC-BXz9}6t?!DeIHaw6~q_KX8QmGNo7lNsZ%GI5K==GYR4BavHKKNt8m z#@K~Ne#E#AxQ#KE4^wAsijg0)j&6}}hxr^}-;9oGtv938rI+<|dZq|X#vCw#U?qU6O z;CmUL2`u@a3%rZ<^MRK$#`DEyTowbPV<=n-d_Uv0z`taS=Z7P|VtfZMI*h`7z`thv zFt8jq?j~%G>wt?ye*&Hd+5a@KjLV;ZF^MR=N;vTwi;F~m1D=Oif7?lW5O^l*c#b&o zTgJJx&y8R(Df9w&vwWeqtG_;J>&fMq?Y2mT%Fi-7ks{toaHjK2r`B;$3!n3xo<2HwYb6YzzMZzG&| z+G4Zs-VDz(tp6MslbXUkz|S&%2>1_-9|eAnF`h||>}UKc@birS3j6|N9Opz{WZajI z86tmVTmt+O(2wf!T2rUzcPLg_)W%HbO022i*YyLw;7`zk-ssfZcveT z7~{M2$T^II<0aV^@}Re{-WynsdE&swvt9_im~nsLfs9LlFK0XmcnD)$yN|47JQ7&; z*Q0^2Vtowo$&AMX%Rcc`;BwZd0AJ5I`2Kt{V|;%exrOm8U|CD&08eB60$}VYDAWMU z+O+^!wzYa-*#;K@SF*naxQcObY$o$LI5v~{{5$Li>G@m)T&j%Vq5*|n7^5o~<5!O& zPcnW3_-)1+^qgkoea0^V*FrJe}cm+C@XRsCzjsXg&JOp4Zp7){4GkU;UJO`m;5>Wuw;=!>& z0o4xySc@l}y0QQl`X~Tv@nl1%HXs0N@$`gF?Lh$6;^_;$3+upIJjKv);7_9Xd`XC;)5m%z)m5bzm)?^PpqHq5!PLQwzN( z>%dw(4bX9dLIGHd=Mw1otOINDEQ5}Xl>)F950;gJV_65*;=$op!EvkuYw_Svub>a> zz*;U*5dg!^aSg`T0GcA6<|@J0IbD>O{<_E>%dw( zSjr1D>%dw(SZWK3SO?bP!SYwopLJj@o)4f8U>#VC=OFZA)`7Kn4nzM3O=JqdT0FKPhcHbiwECl7EELvSc~Ts=#y9n*5Y{+ z`l+k~Yw^4f{WR8rwRjFdpUgV27SC7EPiGxiizhvmbnH|q0Bi9a1N{uvfwg#gK%dGw zuoh1o`kAZ)Yw`4lK8M#ZwNwf^}dmp2^T>unw%nQvv-f z)`7Kn=0KmxI&^ z`W)7QwRmoXeje+6i)R(|rK|&M@q8cprK|&M@!;I2;5)1XYw@%}zl?QYEuK4} zf0uP&EuNo2$CpwRfVFrYg?=Ubf%O%PpMt*JVl5t=PZg|S9axL!73eEj2iD?w6Z$IF zfwg$vhrXJ1U@e}5(ATgIti|&c^tG%5Yw@I|k-m;~U@e|wpkKv0uoh1q^!2O*Yw`4j zzJYaMEuLcNSF;YR#Zw0T`>X?N@tg?#8rFfec*a4$mUUn)o+;3Oz&fxN&kX1rSqIkQ znFIYg)`7KnYN7v-bzm(Xyr-(*de(upcrJl{1M9$AJj1Au@0=oa}D%O ztOIND+ywn*)`7KnZijvg>%dw(+o9jeI&q{SMZF zwRqCgN#Djguoh1?^gCGx*5bi?yb89n4y?t~7y3_G2iD>l0DTARz*;}9`p;Ph*5a80{VvvlwRp~g{tMQDwRp~hemCpDT0FJT?_nKSi>Cqly{rRk z@mvCZ7wf=UJl}(UAM3zcJZqre&pNOc&$ZBh$vUtW58h8!@GI7VwRnCE{Q=g2wRpBe z|26BtT0Hkae~@)xEuLRP{|)QFT0Fa<89Q zGRAw?3ies7#Zv_RY1Vqo>9<$&pNOc&sgZsvJR}pa~kwNunw%nGadSK ztOIND;Qej|`&kFp;+YHmdDelocrJqe0_(t9Jk8KwWF1(G=R45<$U3kV&vNK5u@0=o za~1SIu@0=oa~<@TSqIkQxf%MOSqIkQ*$n*^)`7Kneg^$j)`7Kn@E*E?zpxIh#q%5J z|HV467SA5&udxoS#q%`u*I5VF;&~DJ8>|Cs@!)-S1t0Ld0@mXB5c=QP53Jv2d=UCO z7Hjc*1^w@=18ec%m+K4u$@v3o@#I1Ofc?Pwea3yD|I=bEo_^3jWF1(Grxf}}tOIND zjDY?z>%dw(r$GONbzm)?NzgxK9axL!Oy~z#2iD@51^poFz*;<&&_81xSc_)?^h2xz zYw=tR{d3lVwRo07Kg>F?7S9#XzhE6$i)StLBdh~!@%#Y#m#hP8@!SOcE7pOvcy5RO zFV=yzczz09@i+o&@!SJF!aA@P&#$4Uunw%n^BD9f>%dw(`=Fr2wqO z^EUL3tOINLzWM{`c({ZDuolm!&^xgXti^K#Ixg~40M_Ec1E>Wbu@0=o(;a#j)`7Kr zH+~#+JX}HnSc|6!dM@k0T08@xcV!(|i)RG%Zma`q@tgv^JL|w&Jd>dJU>#VCXBzZ8 z)`7KnW%dw(zk}YN zbzm)?XQ2;Z9axL!Ptc252iD?w9s2RC18ecT3%!JOU@e|cpr61xuoll3&`Vhd*5ZkF zB7Gq1z*;Mvofwg$< zfL_izuoll<(8sY3ti|&y=;K)j*5Y{t`UKX2wRoO{K9O}`EuQC~PhuTdi{~Zir?L*L z#q$dEPgn=m;`tc*8LR{ADU82>KGk9^p43dz&tx4~i>EX6X{-Zl@pOa!ZPtOcc#efW zopoR>o_^3PSO?bPIRW|%)`7KnhCx4zbzm)?lcCRK9axKJ67;iK2iD@jdprwfu@0=o zb2jvISO?bPIS=}|tOINDR70Q5I#VC=V9n|tOINDJOTYe)`7Kno`Zf7>%dw(FGH_q9axL! z4d@G52iD?w7kUHhz*;;XLvLgqSc~Tn^hK-#Yw@Vgq+iTBuoh1T=uNBxYw=`5Z)P1> zi>EvE7S@5ac#ebK$~v$XPZ9LRtOIND41#_M>%dw(!=W!>9axL!6zEG?2iD@52>nvl zfwg$1LjMlyz*;%dw(`=GC99axL!dFUHh2iD?w75dez18ecT4gLG918ed86Z$o*18eadf_^RQ zz*;_Fbzm)?b;zLRxeEuJr+|D1JTEuPe4NWY79U@e}`(0{=?uoh2u=y$UY zti{tC`aP@zYw_S-q=I`{2iD^04}BNwz*;jxN5 zhyI|&T0FC%|Auv7EuL!V53vrc#ZwRcx2ywe@w7sJm~~(+p39*>!aA@P&uZw8vJR}p za}D&zSO?bPxe@wq)`7KnehhsN>%dw(cS3)hbzm)?yP^M%bzm)?Uqj!^I%dw(na~fi4y?t4d*TXSWF1()z<2=kKU%ECGZ^|ytOINDjDr3r z)`7Kn#zKFYbzm)?)1d#Ebzm)?Goio2IpHI6z{4X*VNeDd`1<$!hMMm-^~+cK`PxuULNT3t)^g6WO)me{4^=!Lzu z0%t9vTGpZ(VSarr z>5b?OboyZYTt;9EU(HONUOTsSer46%xlOf;lVb6v;Ut0Id~H%teyX&(apA(+2I|*_ z#+KUBNmI`{A$ZAeQnGq_%YKqDuc>Mwl)C2X#idm(G_-T6InBH^{%8N@lMORWmL})- z5IH?f!65Xdf8mQVJ<7+kl(u<_r%OQp)>lFvzucLUH$F_clRV!#;@Cz^FtD72RQeku z5!)K*x9}*klz5E(5SK}Rv+2(*7q|J>(4PqgqAqTJgD$4u#-qj~zjTR1eizc8+b@SG z5%vKlAP*G4zR0e~GPM7IBl`J%ru-&ZkLn0cj?f z`t2matzX+x{*6`CFI(bJzbEO>&F>+~Zz5?XnEdvT;N~~uQmP|q$S+6Ykl#D>=jNA6 z*MH>l9>v)Chux){-@}w2_D{&KtHdF{4AR{E4pDw35G0uTVfX0f*ZVT1u+K$)-RTc; z$WMFu71DRAkCJYJ$*-@MU*>oDHy4o~j!R5_&6eL(hbB-F!@z_`Niq@2FC`-58H{!?-I$c%w#~{8zc;-Pn3nftHfub z668A@8@L2`5LOXD-eW*04E-Mc_GA{9+lRO*_j)hCOKFnG*9<{AlOIks4Ms#~8vNd7 z(Ijr-HWP5mowI?)f#w3*TR?xNT%2l|G$gA5)VXT_B$zmy!nygiTu(piL>lrdq(75i zaEwBHkfi?w<+q&HD-)0({`S*9_%yzu$I&}Pj7dC*e?@#Is)2lNfCu5Dc6^Q4a3vTY zj(yyAymEt5mkr={&_~#g6q-0D4YGKR8d_*3llY*2>E$=;5&CUv@}XaF$Zh)N7}BU4 z79kBn>R|UbJ8fAg(MRqX^`OX3~8W!|;Hua#+o=>fP_(p0U)iJ$aEYfx(*t*yV+D>!RRz)6}xa>yX z7oD)DW7~~;Z!Y*?nYy2Lu*8fCHEdl6sI0Z^rt_adSt@{Q_qUjEpda3*X~?9 z;=r!9+>95fukJc|V_IwD=F78&Y}ulQwEk3$pg!yQ{>Iqu zBSThgRvqS6w64q>vTBR!66^5BRrv=pd$uKt3%^8*Hm1ht*B5tFU36GN=hvevcXzD0 zHF5Rk4nLtkKYs8NiEV|Ecf0DapL5r)NX=cfBC=t^wG$_YYIM);jy<2qU6tB#1C5H+ zyKFmJi&76Q@3-R1>aM#~Q_Z%UO>1d;>GkuIm0EVn){IrBD0S+%?>~BA^pGLVr<`#2 zd8Zg`Jcx())LRQa)E_MCa6j#jqFXzuMB(lu!FbV+(WVzpNn2gGJ`H?h$27J4@h3X& zTv5C(ckSBL4HG7>oEr86`e${&n5u~FYOC%U>srxzovLWroOkWM+?5^EX7`)imRVKN zx~s#u*3GlN>^i$(%WDTd&0W_qZNmgR17+5z{VgjyRII$tj`CGI*I|@5rrJ?HccmSJ zjU{%J&t3VV6Z7R+>HVk${nn=iqkUk9syMJY`}nuEj4UeH5tMCPFyN7?;b?4Ju{M$$ zTk*vs6CRmp%i$5T9FA+9xq$jFFN~=>_o7rYD%;nVu1%*JgnV7;x{BC}uys*-xTbi` z&NWC)+q$|RGi_x|l|4Ll)sw4cu6}OymDfeLbi#-qsqVH*eO!~$(*IVIo7visaye~D z7^!rfrgHD=rYibviSO^ewe6#;uXwj&%dP;wdD~f6cX>NH@r91n*Y8np-ujcQT^-tP zOl0k$f5&f9d03gEbcoV|8JZrbiIH%zp8mu*LD z>HT(pxw>EKSEk+{WWSw#xcA4sO{;tL{B|sPl|n73&0kgL?ox%DOu8wzEz280tNn6% zl(cN^&UM?@CJLWFlAAFhB~d^tMV$UhQx7LfQV$2U&Wx$(mMMx>lEbu;97f;fZiuM? zuiIG{-SPyjIcpVqZaMW_BL16o8~`?R90`La{*1KH{QQje_exBH89 zJ^n~V>z3@*Th~X%9oRMPvDU|@6>Wb|RUEvJ=4osejbB^Qj(w^+CDwcOmVJ@v%6%zC z+i4C{UPU{1p!`)kQmU6_q~xy5OnGtT>@DMYD^p)~!xr||=g~d;Qqs3fiLKr;B@L-M zTuXb6%%a)jc}l>5d!k?WJgaJ)9_{zk<}mk*9NG8)%es)5ag(FwyjS&u#6g zxI=2?Yw7(muquABk?Qd0Efd=IAJ~%jWv|%8z6#hw%0CIa$Cj9UEvnr?Kh@& zuG;sv4{xG-M6BbebMQ=&X!2Zt6%^_*K#(a6!JzMsu-21z$KW)fe+cA36 z`+hC1yngwX(<0F=9V0#4fD*Ugn~`YSoI%@fqzmm^o>}RxKe_8xq(FTxS*5)cjt{1; zoE-L7?yB8s$;S*>0cggAd##)rdmPZdy8GsWw^d&BcY8Xnugb34TXo;svbFmU?8)x@ z)NH*n{(NnE(Vlw)ZXt$St_wcV-K*QV<||Jqv%ck!xWZN;l* z>s4_RySH|I?X;@rtMaODse+>dIka*P*>g`v9`QTX>Mb4B{sX%x&n>emTCjz!X#3V4 zw>P%a>O8{R*UWVGC_|2K3y&yfQlB|{1KRrysr{+y_;fn0TsVqAiRn~gfZOg=Wi^|_ zeKkh4>VB-=80*zEq7?_W1Z#i#R^A7!rccuHI=o)dZEM^9ZZEVg+;DvD){$*Dj@eZ3 zrpgZH2<<1Ht-G$Scx}Zc_hpa!bnBvu)~(r-4%|1*%&_e%cCK~XSG;QHD($RL!TzFO znyTo&xeeaF!JJ;+t)I$W)lJ=XZKBH_b=A|f(!@IkwTn`%R!&H$U8?hw{=7@Me$+N- zi7qkKW!qJc#iAo(bUaGEK*vy&-YvJFCcbIR%>}RV@hpz4u3PZZg8c_x=^uFE$BXu^7%%q-aH?~hx3SnB8%$mKq!S}YfCsj#j(=aX zVBZ3a(wcWF4y?@E`%X$tJZYqs-aqHIr56_*(4S2HXzD+wzd!RI=l*?Jml1U48`YiF zej3YC?1}X5!`L@%?3794{#3BvNIyOnd$?LWb+~P+(z18(OOPNCiB9rt~wSgUjF#Lj=5{s2gh7C1}TDkX~nG0iS?&7`*T`p zKcBwx?QjoNofgyS1IB;8dO+&uxv>?WSHuSN-M?~FUo$__3s-!;KVwV0qT5w%IQstf zBk5Z@MWWj?)ahTWn^v^#qDXb;jJ)VsCA62=e5hjOxnar?SXnc8WzFsM_<1u|y&Tq= zW)ijSqR=~Y74o+6?H%t#_3lG@^#`j{HsSb|_IWwWY1>H@-g}7FFqJ5{_fR_RrBMr0 z_e6a2p+xDu2hoe6RcQf@(SG9( z7C#>Cx8h*&?r6W=2aAu|lSFmuXJrpZ^@>Bw_4q^4qSQmni*|n&?Z4u)<^9Khw!Con zp)0RL8~4+AR;;q)IWHXfjVspEG3@TolaFD0KD~TvhWgc$#jE_S_sZ+9Xgm4{clYQ1 z5iXtAsfuo!+d4k6n)-*fnhq7MyRwV6{*>C*SuO9k`*3ysE;ae0moL2V!ozhLOE0_gd~XFILw*jcHJyMEN|Ip|J=MY!6 z|{ z22&HHNo;UC5qj*y>>hDXRd9!N<#Lf-jg%GgI%Z^=lFuFQxP?bx0Y z)U$1SD($t_Y)_?8KSJjN!M6!0c_WP^j!4IUiR1P0U)nPPI$B@3S*@wMXXSSF9?n+j zi2a?{JJELl_Ix}_YtnK$j|t97>^{Ody1VtaN}Z-=kFBn*oY>l2*Vu60v=ig~=9R>! z^T$Q}QB_@CKdzyLNKJ+suV$Y%^|Tq4V`t1budZeZiLE7Za-7jju)dxgZhnh!8IE&l zqKk2imR4QDz{$8IE}3Ph32Ju5gsBy0POltWKK0D$XN;Y4UPaZyMfJ7umb!(t@!F=Q z#-Y2#tzN+1mIYNUaVk1KziLr@LDix~ zwGGWB@r70MAk@sYDy0&c(hj68sEE;Ebpmlj3L>E*1tMqW+^Y{T!$c#U_iR;|Bfc>*M}s>5|%2 z{dKuJ-5gQ1#^pf2su4BEy5<^qv@7h%Z|Kw%^-azGra0Rr)UEi6KL~CYySiVyZ;JbG zcUwD|hvQ5I{fBeV>C_PVIY-nt^tZD~gz)GLoJkzQqg`PQzOlsfOt(kW*G@0D1N?F* zF6<~j&KU(i>YI}No49bI_<1_TeM6J~r;YhHwffplpmbkbV~Q&={qMKto9da=(ytx1 zq*Wo@lG`aKtUHxCz|_aZ?WEx=P-G@wn7$of7#CGbZv38;dALb^QzAc(GP%ypB)qoV zj`14TIK-6f8>#xkz9BAbrk^fp2%Jsr8#dc-i2B;i_?vn+sS01asQjC8{Evp=zh8@Q z*Z|v~mfx_0ad%c-BK@**W6`Ya9{E{aB4_oW`8QNWvrfxBrRRyAPU@6GH%LUgtJ89$ zS)g>0H#gF$6T?{Nzz8yuV$uqUp4_Pu!SqPvv|PFgsV^nOnO{dlb?S67!3?^|R&^?k zbcy7ojmf*AyeDT|)bo^{bXUh(y5DDTZWp><+qpDiVou8)9mHnEC_8$6ADezy-V?rT z>tk1!V**!>4nA^A)lns(ZFGl4Or_*;5y-V0(H@p|*Hq0OLz66dL>)`dPC+B+o)2^w zdI9<5qjnq1^H8_moq`TM)^BZ$TYFqsWDF_$gxLo)-cBm6d0!`HFeNNNJ^%^i08l8M zLIoj7ocf*4{(?#ddDGhlEh!3H8N~HJHi8kzNt@N_oY>ivl3t^gl80Q2V>C9@EhA|N zajl>J4KA!Zm-Yjd|4G5e2>Oc_#G=5_a{NmnQk1$a(w$E9l==d+M{xHU<2?E%!00_Y zSlo-gcQbl^w#B`1lNilesz~IxJd6AEw>UmBz}?{Kd#c3+^#Lw|p13B!Lx2l!vAEx@ z0X`ABZsS{dQd84W?+#fcrYbruC!B7jXb=%qj>73uBGCzy1R(|QFrvHe_%=P<02EE6 z2fdW&8of|VsfpCysmBK8qrBAPY(J&;vHg@9=YB#vQu}g0{S=tqXBxdv@=Dnh6xbmW z3=8hcjTTCQsZqHHT%~LdOzEkC=>Saq#6<6$3`ELyRBB=BKwGOpPOSzzwJNitmpa6b zUg}Ugda1*B^n%t6=g|xBh~75;k#Q~=LlZ6HsT5QN&S-zBAMOKIY8(9<9U#)6=sl*& zCs37X1E7GGr)sClMNXCbJ5?UwRJoX|9CYyUT;-sHOQdRjXyl^BQfx}JI2cG8e1uHgjeTsWuhe_b;zJ?jYDJ>KBJ|X&61O%@3CpNT)vTb*4g+6LzWfLVDNZ0 zrTRIH3UjdFS;_O5Stj$~R-{OA)_cep6DA99Mh}qc@)5xtbafXrADe#=q>9rKhhF%I&O?SOlZTZ6t#U!I0Pp!j$UNJCB?eq4fE$xm zg#2wkvKlGF)U|5X1SINGPXBPv4`qeP@wW4`(0wut$e0a-+BI-oNxN}=Z(V77>q_*N zL(vyKqSyX1IMR!*!m?_6Zv`r0>B^+ewEETDq4mL>q+VNZK-jZkhnl%yd-gUl=SR+= z!eo*}h6Vi^&dQ*_ve2vCCu#kiuHv33wMu}FnlhVht2ZO}t|@$05e?W;_Iqhc1qY?k z`!J=#Ib@st2sb-y?PS~nO(Aoh0lQ2`gqt0*Xc>;r*V3(d{lr8(faI_Axm`(;_dD-||=l6)_FHAvmU>hK9f_ z+L;C%W0s&}!X=0&%n)us*sd%Ttm39*se66|TaT?@egq4F%U@4wPkvB8Hy#Dp`s+wg zOkZ0}cbcOGpa}!;I+O$yoJJf~qftQ)wuFDrlWTBNklxm4w8y^{@cam$S^8r+%^AyS zUQOEPwxk(>UlpQh(SZSp^mB;8sILz6GEU)FVvbXZIgz)M24IdiKy!jDIO{nPOtzxv zwYPjP$o}#O)@@tC%D`)Rt;a9)_(dLHWF3aq__1 z{c5;}z>BdEGACp($dA+j$W9>hF_ANm+HsgICfqZd{fF{9cZ1Wp8@$fk5OkpJplgE$ z+CzeHz4kM`(aH42V8n`2t{sD_M>j>V_R*l+%Y$-Tz-<{fd!2ZT$8QaIxX|*%X$vZ< zGR<>W0G9zfob3x6$nmjKxF(v0m z&JSv04l3!XD#K++Q?r%>Q(g)a6g!E#2 zijaPMJje$fo?cRD@d<-0E*%|Uv@Ct#sVa(x;}KG>2zC@{kthyC1LdkNIBo6n4|3#u zNdH9fKs!Q*KB?IqdIkAlKiVOm&m#id+nz^sIF{>=CAPzHnJUaV7Jj?N`ThUs-|G6R zhWYWuwN1EQ8XsI%I;eDTy#JKCh9&XxD!SxW(KxT=61u>3!WrYviVrRwLh~FO-+3*(hh8?Z5?f&>_$ReRVCZHMNzk!SjtA* z;1Nv-3`n7ioZ$GdS0+_u<=E-d$DUJJaoV{PDrcNCZ9-+Gs%mX%#50_H@iK5%v@TTD za~p!FarmSMPn#NB$U{$%PNWN=stm+$SaD#v7(z2qz z;X^B16vd(`6)jDzXjpZ1Jt?Qp3z~IGFzs+BSxiF~W8!;BV6&U86<2GzRWCP7V*Vn`V!nP1slRgZ!fs*CBt)+Wm0 z^x)rebus#FaaB`YRYP?x#Wgh6HPhp&q?}P()!f=ttD5NIIJxQH^5EZbs-mi%ul#eC z^DF6k_|#gO-Dfq|QduUqGv^`iAlBLyUHqL&&7~R}D9xX*np+oADN_~w<0hzFT6M`3 zTsNOowa7NGc|l_nH*xUrpo!!fXRftVsTd&2Xk7h8)U6BY3UXyLhDKom1WzNATD@o~ zsr2~o%-ZUf#wOGYjGxv`ei-=Zr+jI;lp!s%@}=^Kb^G!R+6J4|Q4cIr*Hnl7I*IO7Pz$T(Pgl5Sfo>fLKGkUr zbuHZSDXs-{fx)xc z;RvF(^dL7HgXWLNZ5A_dmxa_Ih(|2kuBDry{V-27SoOw^?a; z6*r9Hf)T^w&LFr$Mj+PR1+;5Z3+o!_iFE1^x~Hawsz49ZD{6JHFjG-eY8w>Yq=LVO zMp`G(@L({`03c?H$QN0i>EGbtIXaSw{IBlG|NS2O zBHCj&1?wbV8?%SYwnvOyzC>G)#csjXF))Yer_q1ZDk1~$@NPnB{Uv9Ptdeqdcg zbv+$644hln()@q7s73WvE%Ru5qZ-YnAvGoa`$GPYj)Ue_HP=;FR@KjMY^rNnu<-wJ zX;q8r{vVgHu&SYIKCO=`IMlNTbj_`c7SUd_bO9dXtg5eXS-PmUnHYVY?m78@kPiLG z*nU)y2MrOeM%9!BO?mb$tZG?M**K4m3Gf~eilMKeIA#&8leNt#kIn&b_({tG&BCgB z2J@<_Ybg%r6RA-Z3%=rymPTS-GoleX!;Qpp(xSLr6p3|8i$()*ti*Ja&s_P8@F&iT zBN3a~C`xKFGfCr;q?3I1mCu-bcI8iD-IG{;6z?35#ORIF!Dlz&NiK;qRg?T;lD}WY z=P0{OQ^%Mz*f;%=Ouhe|=@l|{|97U>$rN@;52qwsD~yz(Ft>&T;J(v_x3Iem>%Xq3)LCC8}D7;+GQjB6k)SL)MIa*;U^y*wy0 z!etXqngLfvBC#GBoNMeJy0*tD-qTGQFY z^f&E{NH6t^E|DJXfKNaFdnx}MlfT($zIkkplbmTHaBtI9$)E_DT3pYbvVEJ4@@ux| zC%A0h_{1yi=_omMlKCK9Vuyq-PTNOjZ1T*H<(m3PkH`8-uHiNij`eYpql|TIw2XFd z(?(jexU9)iRv*dh#IS}O-^+_nNV;Aor*M1gB{60x%QH^N(br8Yip5uCatvEhBr&EH zJ!PZ@NS(;YBXz84O@4CE#d=7qjuBn9Xdch7rMxAX`VKd_hAoo?lva*lWs%v?Pim*- zbD)$_DqPBnburxJOI^o(J4!}niitTz+N0%@Huqo#vY-DIFFV9XTO03zdPUD`Z>w0I z5{YTERg5;J4U*JZras~7LNkrmt>k$+P)Z5=omQcsB}e}o`^Ig~-)e8B`sJFPLs*NU zvI51XNzcwUH6LJVJV9d0Obl%b+_&>3ri+Q8sn1(;IM3);)PwE3pL|YAi(VQCVQyU{ zhSGAb-!{3?uX6@g(}(nHpaBn8vU8>UekR34anP*dyhiZ)8XIFAL&eckKB*(v*;(c* zvk13?ic8v;{G9qQ+w|cOlV@D=%HmJc2PGz+MlhH;er~^_+$v0NgN%EU{Gk{?W$~8D<*`Q_<$Z>)~+IhCCU; za6aZqTeGAkVOpEN#29Dto=ozixfhfq<*>^CCLd{qYl-w?Fe*u@a6IJnb1aKlEUZ~i zGje@RtIWuK-I25x&14U#RizqBrS^kTI9 z^Ol?=@k3?CbdFvYG`>K3f3n0EnBF;0>SbmWeKQdxprbtAdZvXXI{UrY*Q|KEsBb#T zHf%~rnAzLSC^Q8)FL$oVY>;|}$1&DAx zxbhE|)=oERd-;z4dq-KFq@LzjxJWpiW{koF#Y-t+d2lN`e~<8ni3}+;6y*|4IOXHxT({&%sV>= zd3;lw{QL(|eqYy*^DXb;zEQ|8TFr#Pi?LsI*neG+ zTlclmAlC2GcE@>Jr#mwxuee{I}>Z5--l)fQzWAQz4@D*2RiQ+pnCq(I+v+%Zo zKyRO$8w98&fnTn+Qwru?!#tUXPryig_(+NH;hz6QkB@eE2nj^#tGnd-w$E*SIo{4a z=KaG=nUD1NM2}DPINzcKk<-uf;_E$5Uz18;{}Mwb{iPmX;qi4IzsBP~@c4BeztQ8H zJigiCAtVr`x8NrCcl%uK?V}VNZ~LFQoiEmja-#G$*yQ}%=czCUf#Yp{%!4~0C0>ld zN0e5R(AVlXJb%6RAqVjx6keN!SV5+cKC;RsmJYn;dpx8tpw(FelWN5 zgZb6QF8SN}!SQx}FsIjXCgp#Np_0DMhntl6jPl*hp%kSzW+u3h4N<1@+x;7-pX|j?ad-#`MCnHLdN2Mmk1zB1CXa7+cnAqZRS&N}+UMQFL>%ACe1>ey_*x^Z0`vf5_txdwjRY?f!!6v(Jlv*5l86-0ojE z{VQJlYaV~o2}ww|ji6$G3TW zhsW)D&-HuUi#I<>L{HWP>w)|{3Uvwd7d`*W9)H8*Z+rY5kALj(gC0NZ@vl72&pTqo zxPJVwqvd(wX(PwSJ#OD+&hcZs`1?HmOOLsNAb zMpeGozwPsIc*LI<=Ffh+|6+ce7a#X{p~vn1j?))=@ueQOV-DGfEHrB+tn9x!t}wJ~PaPdEDc6esR2=U(D@%Vm{PM zZ|76^R8HWC(lc7g^=+SLh52!Ow#U1A+-^_o@9o9MJ#O2_{y|>+7?0ce%6>avncMlv z+|EDdc0Mt0@$z5daXY`*Z|4{DHJ-oC<6Awx)8qGg{Fffz?eV=14g$bX``nHv z$J_B_o)c!uyt~KkcyfH)i?`#+@%_E{5|0n{_(+d0^SIrfIsf%u{M8=6&f}XrzQf@m zBoL*?MU%IW_PL#}96vtHg!!o+pW^Wu9=Gc$r*H7$FZH-x57}?$C-Yl8f1AfQd)&@H zPXC}6|FFmH{AB-2Ui>Q_f6e3Xc>G9YRU* zlO1ki@EKM8yzQfXo*5?Mc)R{Ex9bgayWTKA&PyNnc!9_5{*lucd-0_nx9bi2CwlRA z`{nq_UcB9&`-L$8QTnC5? zd0oT#%Dk7y?e}*aZ|6UAyMJbGw+H6sUVhUY9#)M&lzvt2I1y6lGveJ*5+#lm8gZo( zk59~Z4{^VL!~XY8lbmV`Zr5WzpC2B^^ZB#ge)#-uM;OoN8}9KC z^0W1k%B6@D8|4C*s96qrBkal1d__&H(z%&+nI8cfb0oT#?Y=Pkl;efVdD zS2%nZ;Wmf=hVaV{-$U4bf1ahDCT_RyEcF8M(P8;n%B~&ABwPKB{!Il8LU!;ws+&W9 z7j=mAOC>h=MMjFNad-#f?)A%T;&??I2bvFrI~YpkVJ)%anX8J4j|t;*6~61Y$9K8G zyFVs}@!b^GnmGsp-Ts!}x49oA{cL_fXZu?{fG>#NF?Qac+S+aOk1FOW3ZD zJ=99#+r#nep{^#r#PQ!ic)i2h2;b#!{08c64!@i5#}5BBVSB#OL+vL1xKrNK#4#qO zelHN8VJOYkzYw40aI9U=IQ&E6wmwS%~Oe!7ded%pP)arb->=a%J8dYn6! zIQe5OwA*iydW-n9Fuq8AK>Q7de@6V|aD0le6L9t#*(!s$&2NChx#hWG`T>gW8dq04 zTob?2;RA`g`*V8sFZf+%whU0?h@TjiKR}&9e7BQ+CUF}wR1NX8P{;^=|2w3#-d#%Z zcD`h(D~WFl4Owa(al4nyQa>PW%g<7qh`a0C?Zn;v(@x?xbWsly9~uf>)NbPLdbW=^ zjxRWLQO^@U-%z^0<`v@Z`uHaCsZKmzlV};0%o+>@&&hMTIZ<~6?@%JSDvcu_J%g*}I zQ_+uyIqPjtHI(=a$Nw$j?s`3uxZOYYRA&;u#_`W0ZbQDBPuv_+(~+!NMBH89mlAIY z6XdHaiC^dNtBBKqs)T%nw*_LK&LLmn^~PNdrTn)NcaP8RA)e#JKS=y5hwmY7!?Egl z;&y*=ta_DracDSJy-j?m!~aR#_Q$d62yq+ws7|!F#6zKv>PpWi5EJ2GV$FGuORN`cL8x5`l?3a{X?OzT0-1zuYDEXE*5v< z>BpLq_Fo%`+x=xi5Lm{nJat z-Q(xCh);3Se?Z)>hY9r=@k^a}MK3e8{gY4~iNE5+=MZ=Ir}@Nf`x2^x^1H6N?|bI#fXVxN|G)SB{70APdtK+6GiT29dCIs^&>MpB zM?>Eq=-r^-3iK4{OXKyo(CrT$9-j||4)6EQfe!EI)-01l^N-K_}buaCZQ7a{L_bj)YEz3bzn?Ol(xR6WWwlxpSa@7nENP-9Of4?nY?- z?w<@5?mpEJ^`%3C@&VAZ0zDjhexS!duL$&1 z=<@@82=p%kT?c(dppS#*HH6L2O6Xq)`XcDx2l^W5X9ImV^q4?D2Hh0sm!WwLV)efd z{b8WLhE9&(6|PekB;)O&!u5yd{SX^}7l)p!^KzzXy69^uGdq zHFR;jzprq2L2ni4$Dp?k^vlrO2Ks$yUL)B2ehr-*Kd}6}V*L-w`$H$kj|w*odUjA= z1$|7Qr$8q|dv_r8*w|?AW3I?cH(ECk6Gbgg!mc7eOaO2X_^8ay;qa zZiT)rsQ*Fe{CI>8?g{A0fqn-1@Ib!|9oF|}=re=qe*&Eho!s}($@yj{*SVW>4+qm9 z0G*tFc5!$hr+YaluYmqAJ_o9BlcAHL*v)|cEGVA~9oAP5y*6my32nyj>Q+G~?d$3; zfaW>03>9u8^ml>213LMXO|g3r`ukw|&qIF`=)XemZq?z+?jO+YI+#&`$BwkU|Fso# za(>X=^@i>mp4-|y~bLMO+! z?(T5tUj+SE4}D#rPk??P(5s<&4Jku~yA=A3Kwl62exUD#zAtW1FZUQUo@*12|1xx) zN%Y@ep?S_LLxuYi`sXH5o`YXr<~gvH_kr#n=%LWO$0$RwD}}xySia+-pRr=pw=Xmv zHmyU2n+2Vm|MhYUpg*!=E1z1;cGyhkWQFZT=R zQLdnf$kjFU+g;I z;-x&8|9;Rr1$r3t1{)pUS15-b7t}WqdT3DJ{?H{s{!r*Cft~}M>~H$Idg!x*@>b~K z!TcPlPUxr`ONz4ZSJW#qKcZWGHh-Ll2IRf5q-N z=y!wZuYx{2C|?KtK~R1T^i6U7{oF0k$@xvOyB~UbJi&hMap*Gw{Venifqo5oaZukT z=+%M#2>Ovge+iwOFZFXjLMPXA{ahzpY$xXr{ai2TU4!MlJ@f&A&O&dB+cUuJ3Ozem zANPS?67R1t3Cj0} z<~=x@|7z&TLHQ!+i>(-+XFU%3`dDx8RzRN<%-;pj?*;X3fX<1_i`^~I+Xec5=$!-o z6tq1Tg!{WUq1VRsRk)9#FADSz(3i*KSGewd!~JEk8w|~R2r^W-QP3yG`C_*-^sfRv z75dm9e<<{iLHPpcnUmNZ&h5lnOyO6;q#tP55S8Qe9;&Z~?uAda6b2u7V1A@( zTt=Y2PHrE)c;rhSelLMf#RuSzf9?lI=?(e%|j36tL8j&en+SDof8n!o<4c~3YGSN0=SkB;)&xLs90 z7HPa+pBjHgO3zZwV}2gK|InzK_lWXv{8_46`e&%ypqlr*^RWN?Lf2>BbIrs4=@u=A z#L^k%?uX{#h=0^iLG$p=Kk7H2xqCGI0d&_ue+$j!YUP~=%lk!miN+rQC;<;qJsg_* zchf)d+tG7e@wAeB{8QZA(xflNS%Xr8GJ|r13WL!Gl?GJ?V+^t-F~xOfS$Xx|wRoDu z+&$_WXV=s>!x%rlqM8%qD+7GxH2KOY@s-u`mDAyCmUT|pZ|dl3P9_36Qkji0 zGL7-$$7o|vBCSJ79FbXs!%k#2D>Dm_xy4x05`cvzk}c7;0i-^FWV2Z-%34vjTBd*^ z9X%Vh7_*Wswf+NXmuAa!{s1yrfL30nGXzKLEVoR#O|Cqys3NW$3rrSMRu(ZQZ3`Ws zodVJZ+Ja`8^c;ze;Fz}L0GhXD2uE958MTz@Dx00E>S+BNKOUCOSe4CBmCX-AS_6pd zRus?1c`llHtqpUkXV=cJYhdTMEL;?|F>zS|T{aG{WvqspD=%Kl)h}lkMq|}B%;h*q z4VtLn=72FqYYi3b3+M{1smgL}9{sq+sC86u$8hYVZXGvUq9bQZ+K$CJ#8}y=vk1{z zO|a%?EcJ=&_SWH=btl9f7cS=^ap%qi1K z%Ayv>Ga8Q>S8cNxt(xq8TXLngbjxflEUmIe$7_kLH>FipkF5%2wz`zrc3c+i)G>*& zXfZ`#t+WMPR+?H}EMT2lW{aY%Jhjkl&dWKE@eG@58&FxLE~c_*<6t9fODY?!^H5f) zOR%gmUV_mMBAyfLtnw1At-OTmLp)XO-LfjHDB9xc8s;@t;~b){VLtspax(b!zS`=R zn%VWW$ka5oq#~Tq+}hc#^Q-a5r1`bY93`lMlMiHc01Px2Tp-!2fn+BIlC2LUdnJ(3 zUL@41mP9LhSe}}8w62Ebsm4URfv`N)oYHj1q^8fsACAtB3w3ICqP=xcUYg2B>uOLQ z?Lh(^?W01S>da_`4$D*1k9JK#d9?2jb!zsajWH}wbzfO({-felG^mDCzf1E*H01sd(TY>KJQi+2A(TeBr>lI*7H8|S2EIBR>$^e$pF zTbwi|R%lFW=|l&fV1m)9NIbn%e`KR`m>`{v_R?`YHKW-Q?XhU*i7rcTy2&Y^9aT6% z1nmGBA9S_cj#cSxAUfg%?TU{0p-!!1(TPAo}zyRl#;~UDYK}X|Gyd$+Z{db|M`eSA!0T zj?^!tNTf)sC0-eivMU(Ci zYL8CzLY?a3=#(sO>*hyd#*^ao=1|HOCB>;e%BGJ*+4N?bjV|kw3T$@lG+k=ooJI$g zB*^tjl$^V;Lz2?;no`!L7dJZ{h%b(!J#|uzt}jL1eua<;~{=d4{xW}|}&i=rz) zf}MtE?W8*!om_{@BGt~Q+*XA2qKM9dleTd^NmP2PicTrw;`I5ATm&Y?>7^PS@RQ=r zma1+-*)eQCXVtC|vSV}&EwweYG(8*9b{F(Pba|Idiz`4-np*7XbI@#bYLSfHW@U}m zp`?tBPE?!jYr7VwSK8=`HXbutmBJQAXERB0y0fAkc2dmwOH_LA7+ruQ#i>m-8=VLx z#i_L?8yyp{I7*{^U%VcrCK4^Qq>?t>(smu(dHL{ZXIRODi$xG)N+h&Z^TndpKNBMv&*Eo%?g!1^UOx4vYd4K z96H)ilUmYiTH76A`UF0qFVYu}a;RxD3cI_Fky?SW(Me;NNMGT|VJl3eui>)kizYe1g`?ORRyNvep}(`Z zT4?(S<@mwVn>|Z8dD40Gl;;Vv8@BX#J|J8>pSMy%SoTIDfEI7J)errwBTvjZP zijJQATU}kdqy?7&&GY8YE5&2d>uco|Z-_w0&rbgT^7QMl3G-^|>i^9HpBoqAx$$`3 zc=L?t3GR4YbHi-McK(OwWY4e014O4a&Yys%n2yKny8qipN87`-+dODHc%Jl@AFllq zkK&eRZdX??Y^|R=uM7`%Z)%wrK9PE}r*X&KoO(nx9!e~2h@Q}mnF}9UjfXuqaEal8 z@(pw5&TGcvl8XOdKF2!!F!$qvXRpgs?Bi$6w|U0;=8t{Hn3#dO*-bTgJhP07Cv5LE zFM9CvW>1Aro>0&C8VB~~JC^dkV_8JR_dH!p8);UQ1uztS9YW0&XKN4*1B%9CoL#>@;^LGVXJ!JFwercY5NRe#*S}@zs zfo%Sz;Jlrr{bci_`9j{_ucc3p=1YB>FZ%pg$3V<4=ZVZbxeNZ-560%>qk}GQcbP6Z zobJxZvn|%2WKL_W`ZitqoYu}0r5>9utZ2Gp)n^;5{sM5`B*~M_F9!FXEI!%%edzBY zKH2;Q^rwhVHh(>s{lH;8{>X(8p08gxJhkxaBh@+~6 z?}8pVM)+m&PQvX`&q)4A0S0~#V3hjh;0a^J=d!ltYs;N^ey+gUNw)U%0o!&&HorgE zwj;9nLzvg)MK*sJ^Xik$kG8x0q#wfVZgNzQw3%%AJ)?TWC!2p7I8Q%3N;ZELc;K#* zC!2pZc#!&J^DhS5dP_F{H}rMAC7b^|eO+(K=JR_QwjPqr?@C|SH?sNsT$^pbWb;eu z>v~8we?0x^(r;w*`F(<&`9*mQWb^j{k5!*+{=s0IU$XfN0-tRDlE5dMe+GDnGWK{$7i1M`ZJ-WBz;YCiNc)9yv~U33+$n zPRNfOFFc*B`Rlf>?^*P**dNQwH@*`WG+s+{M!|lk!A2~^;RZgBP zyc2lB9!VQ)n@zXD`Xp=vw?}JpxNQ!GZ*3-9+qga2wnH|59Q^}jT_T%5lm0>Clg*z? zf2R0k^IO2S4{<{GQ;v3DSpT^A82vc1<>)>$Yvz zWb>mw?f_9b0F}<}ahK>kQd^ z?h^*?CDRS}59h%jq(0g5(PtYEmFbereeX{xd{*G;fWb^L@_vR0>U?7{%-)FIHlWhL8L7r^>WQ;#j zzl42M!1seE@&}eMe2%}K`v~V@S@+ymcqDk_e!^406ZRLLMSr?5zt1#khA@viBe@VT zaG&4v0O5D(A1M4O`5@tZy!6yMZvjs@Sp0|ZGU^cFSIIhV7u0LpKH286JJ_~;viSqS zw(gP5-xh4^9@+dV@Id~^6$Y~TW5I*eC!0SGJg}?e$>vW44^p3Oegin~NLi+2^Opra z+5C0%^;(H+{vMSi)*qRXN656IW6F`j=h3egew)mV7(-XoGpa_IJ;`GS z&#%dx7P%AtcE}?!Otp_jBHQ~THl4m<@UIv2)sZTb)1K8G2viV$B zZT$?_+ad6+Z^@P~4}7xu6Tx}2Ij7im@n`-t@W8p!PO|y?fd{EiHlN2eJLZPRxY^93 z-&hlwd2&7e?A`*|{3T%9zQ|Vp31Hj4$mX90wrhN{`DcJ_A4@iWHQ4sCWb@Bqz8hO6 zzlUW0TIfOQlg+;rytB?1nLfu}kH1~iC!2pSxc40CXR_6EICx~OOm`7@;ymFM^ydp- z3?8MtA>fV7FObYFf&YKI&Wy#lw$6~lw%PW`cACGKdEFk#=3ho%k1u5NqkV$@C2i;SX$(_K+>V4m?PG zviUcG^QvWiBb)y;{TlJf=5GSqc1Je$w)$ z{Lw+4Z2mZ~wTEmzzqeuakj>|{p>6ME^A7~u_D(kcQ0BW!f0E5Vl6m#X=GTL*AIRpf z2HX6S&0in*WbV|lXW zN6^>llFcs#+xA5^pXblEyvXLy0^4#So6kdtEf=!++?@^VfqyWN&F3aMNPV*T>%n<* zWql@_e=U8zheJ01e)@V3mTdkLU|YUq^PdIV`5W2%7r}P^MmC@4mIHaQf`M%Qo8Up} zlg zZzo&ZI)QE7Bb&c9*zRwW&EJ*&&a!Th&F8pwtO@Js3g7yQZ21DPwTEoJ2U~l{=8tE- zRpy0k{$%FWC!0TydE95H$19mW`6&GH*kNowmry&D+qz9Q|1z*` z`(*QP2z;{n_Xa-M{KvopJIVZ#&Hn>t;b?t3RhaJuj5kXb&@Ufd-~^!Pd5Jru#Ni)Gv`T$Y?(Lc zuMwYY{%2qt_X}opx@60ILtooWHoqIz)y!I{vlqB9;3DO|^v{_(U zMe6gnGz-^>Pd0xN$Gu4Wsmugiq`Wu%izP!ge`es5%|Dp_C6Xtb&)@X7X*DvV^^+~r zOkbx(Hvjm*C!2o~{Yzz9Wb^qvfWlvhPd0xg{maBBo6p~-wYKrP!`eo+%m(_}HnREG z1wPsQ8|hyz(;}Py0NAGW2s1nZ$3V6W@ADU4AwJpsXXxvEk!&SZQLQuY`{Ml$d(yK|4Q-6=9dIM z+5B?)8}SbYviV~JpKSg(`d8r}3}o}C(7#%IviZ~KUn4%*{8?a|m$}UF!UzM|G7ISI zypYX50i3xG|6n+UnShIwm(jmoGGz0)%Ql~EK6jCYzs5fp$mVm=+O*hBHZ8Jc*!031 z@DB#E`M(9*xW8vc+eWs`!}M>&KN!g7|1t2%=08LKCj5heZ2l|sZx)|y{u}gf5ua@S zXJBjF7tGu$8M0-*p?{nBWb^T3EUxf&@yX`5r+Gokj>wn{ypN8&7Va7Uh&E19}Ko>9nOr_Pqxe~`dqLW$mY+d zf1mhd^N*(gJMqcp^LJcrTBk9i(;{1D1^xSFT(bFR1wPsQbLn&C!az2E1K6f@H8VOb zvSqHP|A353HviVZC!2pKeVrEB{3pORt*4mLz9L)ZS^5vkw8-Ya3(hEyviba-KO47|8J!l{GRM*XgN#cy|CGQd zo4<@ccQzQv=3fZ5XKY?&VPUyyOh<`;r( zT>iGIjZ3x+pOaDeqKr#6e>bp=JAs*(Bty2$9`s)ppKShN;LI!HS2GiEk@6h+uS$k& z{!xKXHot-XYmz6M&);aYX)R|)>nB@gC4HS1*?j)~q4{L<`7DmY*JWB{^REKiw60@D zr$x5Rjr4U|Wb^L~e6soX(C5Jr1KIos>AxvH+5AW8|5<#p`LBVkZGUFwEy<8A^A7#L zh)*{E?}1M?{}cLeOP*|gPKRV#9l=&7*)n`Sh>c4&zc>ANq)xK={pfEJpKN}9;FHZC zLjSLlC!5dbh*&?2W#(PUkS#Ng{(It+&7TRjaSvwZeaVn5b2$CKiBC4aHt@;j*U{H@ zlFdI6Y|}cG8J!l{GRx^}Uy;o}JMhWopGRM(MK*sU*rs(YGapF%$(Ff+zK%;a{{gU# z%ir@W{JV@xw#*asKNO#A{+nPM_ibiAk__20@6!KRe6sl;1wPsQ&**<5d9wLm)BjX_ zviaZ9=LseTviUvm+klyWh~FDr7;uqtKl=Za4B7ko;AX1^--yFNHXoay%WN&ng7;uE9VL@T?j+3jsxqC02a@^59fkt(R>DQ( zuEM+zo#6>D2HsoFbQ6CMa(CewU};1BKrq^P&^OC*;Ax-;w#SKny)_uO_1p1>t?~ z3@=78@Hsh|d|}>i&ulNudv}=vVLlrt(_8v^F1b*A-iyl&5&ju@sPO4zFT93aBz!q} znD9;H;lg*4M+o0X-a(l6vTVA%PnF>tm>6Csj}m@|TrB)akpGs<2O(m}Mbk4S!oA2@ z;cdvg5XUf_TqayWE*IXNTp_$SnHTFA4k1?x*OIG*o5+0NB8HR5+HXtAyokrZ`!MET zK;BvW=$?$`e@$N>(!$#ZnO!8q%f-yD!o1|L{^u#C^*;~)ncXDALqcYpFgGphf3DV< z-NolBW$oeO%#0VGiy^~@MPgt#WhM%9@|Nd)h7A9~uz%q5c`}*F;va#R!aWi$QhyFJ zQ^ao|PZe$OPFK2o>|Tv(lOk@`!RnI-;G@^We0>CB&*u)V)?7Be-H=WnfN zW(%()b3tL)NS-TvGr3mycJe&o`^mgfgyA7@;ev#V)PJ0rI`Lm2A0_-Y`Do$jI=5c< zbNUN~zbA8L!O#KM5t&Be9^^&BeaXiN??7%6-izEU%x5rWxT0a;^A$6#!snA03*Ss$ zEq!%6xbRr<$@X3hud^~s#D9Q%obV&$>KOXPcmzb0QN?f(v3 zc(3?mdw-!Fp7EFYt@wPtVdg&J?qppz29kd#{`_lNgm=4Htr zPJTsr7Wq}-dh%<+i^#7FpFn;?_!P1pgI1H@6#pFZpM@_aza_k${1@Tt$!`naM1Dv3 zKJq5vhse*#vg7j`3;!xUxk&w|n0Z(H7s>Alze?7&y-R*y{13=Fk6)7iCjPf%oyQJ% z_F?7&@wB4~0v}9|?~o>vX4*Uy=6j4YvEJWV@F23@)7}nj_j}1j z>Q^xHo#ZEw^}g{m^7rB&K-T-NN0NUKzn1)?a6MV?CAN}zB9GxDaz^-cvffKPo2>T( zFC_ELHw^2^Il>#sdQb0KaAAA#$#!q;CT4QQzl+QZ1q}C+I|@HW?j-yNvMy6Ti!#$$ z{MX5RLl47;QAXCcFUVVo|1YxMulo^f_ut5NZz{JNGF>I#joeMR7g^WCd~$d3OUT;J zvE&}&k0bXKo<`2ztFMJPK`{7aY0P&wB>-P8( zd7${Ok$EwP;RCYv)tBVK;(rS++$P~7^?zhW=dovZ@V1iaN8V02pPVl|oV>koDY>1@ zWL{iim`moHx)>Iby)d6|nJE%JgFH-lEm#KGbO@Z$ywq4)r zK2kWkPgpHHj=o-NPbBNL_7t*SOHLynEBXD%dL1;Ae75)pll5BWaPk`QXOZ=~U@rM` znfC=`JtwRu-z#~3me|gb`1#???&QC`U&8BXb|i-An)F2Bk9ZBZN|^6)WO!2+Lk`awJ{A5IxdUz}Vu+4| z#lq2XN*~1Cm)kYJ{DdLe&+r3`7%I6A>%+kL9McRx+=tzrUNb+V-&K6F*UVD-Xg3G4*UXvpvE6bYd(Hfu z{$N=j$X+wN%q!?Ed9v4K#6v@~y7iGqIOlf7o1 zqTgS9veyhxoeKttPxhMOsZ0Ui1i(P{n&ByF!65O;UNbyREEp_4*=vTUWd+-aPxhMO z=}y76;*-5*cp6c_4~AnPd(H6BUXUNzj_ftVLu|qJ;*-5*cnB;g5TEQd!$U|xq4;F4 z8Sd^2hKNu0n&GawV5sPyPxiXq&7i-7_++n{gXnK7^^m=0 z8tIovp6qp-<-N*+toUTFnG@)5C-soMW_W+HV6^1PUbpvO(61Dq>@{-*{d}p1>@{;Y z{jriKd)-(3p8hW4lf7nm-?Cs=@yT8@Pt)H`e6rWfi}c5dPxhMmGyUDgCwtAjPk+4l zWUrY|=}!=!>^1WZ{fXj}y=F4l*A+|>pX@c$nf_$)$zC(P=@_o={&exlUNepK`KBKRve(QK`ZL8Rd(E6o{{ZpHUNih0QNe-Y zlf7onqJNP1WUrZX>2ELVE!k`48u~{_p6m}7zJ>mg346`(9(6&r_++n{hv?4|pX@dB zNBTA5lf7nMq(57Hveyhh7gR7ue6rWfd-UguPxhMmlzy%FWUra8>CY3N>^0+Xj4qfj zKG|!gGyMhPlf7nm54@mGe6rWf0QyIXPxhMGj{ec&lf7n&=+}!+_L?cCzfgR#*9@Nt zThJgr*=uGe`inFHuIi%<5NIgEab_++n{ z8v3o`lf7o@=r0zZ>@~B9{;}edy=E5E=ZPc+ve(SX^p6vt>@~BLeu1pdWUrY^=$|Bc zvOiIH1O1Z|_L})M{Zqszd(GTV|5WkGUNd~wZoz5dlf7p6o7OG$*=uGv{d2`9d(H5(Mg`}IPxhMGiT)b#$zC%P=&u!@>@~yp zI10`epX@a=gZ>5Llf7p6Y}SGc#V32sRMQ_K{Ymzk;j@|xE|oml>pA?%^nW2f*=uGw z{maBBd(H6ul!D8}CwtADPk+7mWUrZD(7!@_ve(S7=>JlDve(RY^nWEj*=y!j`WwV2 zd(GTK|4Q-6UNaBU-zYxWYvu|1SBX#dnt6`?)#8)AW?rLzjre4*nRn=4D?Zt4=0p0| ziBI;L`GWrS;*-5*zNi0d@yT8@{A^Oe4dRo%X1dY8QGBx3%+~a85})ifvmO1L#V32s z@N-H9w}?;nn%R;5t>TltW-965CO+9~hVLI0+%7)ZYi1AncZg5+n%S5Bo#Kr2t$zC&i(SK2Vve(QE`Y(x3_L@0_{>$Q%y=H3Yzal=_ zYo?C=tKyTrW{#o%n)qa|nd9icEGhk*lULOx(fa&KG|z#2l}6jPxhKAr~ifcWUrZB=zl3b z*=uGJ{jbC)d(G@c|7-EdUNbZ3ee-NMSHFGlkAH^qo&746WcU3u%y=Hz+KO;WbYvz3V?ZhX0&0Iv^%W@=p z&D>1CqvXk6?~(q7ekbwCUNaBU?<_vqYvxJ%{2?n0WUra$>2D=I*=yzv`d!5*d(Hfn zemC*SUNaxl?=C*sYvwEZ{9r5wve(Ry^m~d=_L}Lm75rY}lf7no(dQ3vVjz3X45Z&% ze6rUJ@6i_Y5ufZeGlD+9tdD{0HB&~PKgxoE>@~ypqYL_pPxhLbNWZ`MWUm>%H(fA5 ze6rWff%FH8PxhKQlKvp^$zC(_=nod3>^0Lse;e`1UNgti=MQgSAbZX5eeHtn#3y^r zoIyWde6rWfIrO&|pX@br5&Z)3$zC&8&@U99>@{;O{UPF$y=HEqKU93O*UWF|d-2I$ zGY`@)5})if!}rq*hKW!1nt6u)aPi4rGq2DeAwJn_<_-EqvfYurX1<`mqvXk6-;el# zeu?;GubB>A;b+Asd(CvGUn)M?Yo;&#GV#e?GuzVVhsQCHy=IE&SBOvcn%RN=Flj&8 zYliRX7wjZ?ve)-e`2K#u&f=53W@geKD?Zt4=5YGEh)?#K;b#B}b`_uOHPb+!A9%+= z_L@1C{y6c;UNfiA-(7sN*UTC8$BR$)nmL#L1o6pUGZ)dHC_dS1<_h|g#3y^rTtk1d z_++n{o9XW%KG|#LZu(QiCwtBOp8izv$zC&$)8A8kve(Qr^!E~<>@~yBBos^&pX@dB z7yA6700y$x%-`tmBR<({<}>>Hicj{M`HKF2;*-5*_!)+R{lzDH&2;Prf4cZ&ubHjr z^Mm{t$X+vr^be9e+3Wjs!|C%!M=+4RX0r4T5ufZevlIP8#V32sOrU?5_++mcenz6; zaPi4rGY8N=LVU8<%#rku6rb!hGmn0?_++n{M*6eFCwt8tOTR{Zve(Q>^k<7t_L@1J z{v7eiUNijMMZsM0$zC&S=+}x*_L{kf{yg!?UNcwFpD#YyYlffMC>SBji|jS?Tl)2q zC;Ov?AECc6VXv8|=r@Q@_L|{mHVPWWCwtAjMSqd_WUraO(LY9fve(RK^qa&dd(H4O z9tF+flf7ngy2Eb~pX@c$m42)EWUraN^cRay_L|w2{;}edy=IE&FA<;YHB&7OD# z*=wei{;A@Vy=G3Nf13DYubJiamx@pJnmLR9GV#e?GyHr@!E*7*UNaZdUm-r(Yvxz< zPZyu;HFGWfGsGu*&D=zPrTAp8nLFsO5})if^IQ67icj{Md652U@yT8@Ptre2e6rWf zbM(&^pX@dB3jLppPxhL5i~c#{lf7o%rGKvYWUrY|=$|J(*=yzt`fJ1|d(C`Lf35gr zubB=#;GZu(*=wc;{R_k=d(H53K?N6zPxhM0r@u~ove(RT`WJ~$_L><*e+SvmkiBLm z(Z5XcWd94{z3E?`u-D81^w*0|_L@0@{uSbry=H3Z|5ALi*GvQbUx`olnpsSLgZN~x znUm;WDL&b2W(EC?;*-5*&Zd8r_++n{3+Z1iKG|#La{AYZPxhL*ivG3Ylf7ncq<@|G zWUrZ9>5r6tCVS01N&hCvll_gt&(Xg*VXv9j=-(nf*=yz<`nQTt_L})S{oBMRd(C`K z|90`oUNhg(ze9Yo*Gz6t_;-p=_L}KN|1R;#UNe2^-z`4bYi1Dr--u84nkl4zkN9M- znH}igD?Zt4ri}h?#V32s>`ebY@yT8@6X^d=e6rWfUi9x5pX@a=o&N8|Cwt8tM*jiv z$zC&a=szev*=y!#`VWau_L^y?|FHOEubH3Ge?)w;*UVD-kBU$BnpsW%G4aV>Gi&KT zE@`zJ{|)iUUNa-5NWi%<5N*^mA^;*-5*4x+zFe6rU}HT}PePxhKwK>uCw$zC(Z z(0@;Sve(S<^xqes>@{;5{lAG%_L^Bm{{!*KUNdXx|6P2t*UTmKKNO$rHM4>KN8*#c zX0E6IvG`=KncL}qB0kw`=C|}e6`$-i^9cRV#3y^r{E7ZQ#3y^ryhQ(>;*-5*{!IUK z@yT8@@6rE4e6rWfC-lD*pX@dB75%ToCwtBONdIf`$zC%Z^Wc9YKG|!g2mNowCwtBG zqyI1Q$zC)0^uH6I>@_o-{`caOy=JoXe-NMSH8Y0(kK&WPW_F|RWdA_+n%RSXMtri@ z%)a#7iBI;LnL)o;e6rU}e_Z!wb`*awxdX3+oy*5xA&!e2^6|&dzHpd^zf6hb_amcE zIn2agp^q@)BJ~%+vie)d!z8l=FNGr$E>eFrGuobW$i8IxbXOdi`1XUjJ9VA z`2@*KWB&Ani_~vnrcCNzLS8AE6PRC@aFO~~GgB`4>&X{O<|gJpO1MbXkc-skYHID_DwWBVOnY$Q4ha{j&yQl*{PH$mW|U-j3RpNg;Ue|NF{AC7 zNUoC16y|3nT%`WoAiscofMn{KUyyK-`j;}pA8)|0o_v&KHZXs2!bR%8#f&bmP2@`@ z^FH(JU<~9U_4)HLwm$Hq>X{oP(;i&-Ou|L#k7P!dZwdK1$&@pngUT?Fi_~|;&BrZl zshN$}mL_>!VAO)=VY}kFc)GGHp55H+ikoWdYl`U>w|$y-P_Wtayn`}4+nEn!uB&OD z+8_^e4y)vIr)!%U>KYqD7vpUC`QAajYz!WtT-VY%w|4w-yU&?}nUPi}4VLFYPbiDZ z_pYsJZf&YvSlfX4OEN$Cr0gIwy|%fw1(T?sTwBwEI>xuon^)Tu))G7_I~Y$NUVU6s zW0>92)2@S&_?YXq557(nPOPnOshPQ;mP;s^kJPiTH!Df{3YCW=a(a8zHp1nD#&>U+ z8_lgWJ$g8GP?fld?$^|a4o{{Y7ep&fF`jST(xM|ba;b1d%NA#)w0K(e-nC75!ulTd zjk9a&Z5^9iJG&JR(PqVhHM3_o)h^b_h{Y$)w=tS(8s^uc1}Vl=T=AU7g|d(v8e3|M z_t@uvQPCsd+l*FU*HGKWnAcRZkWO9moW;dxd{fyWlu=;A?g!Ns2vvVcz zSRebr>RSd5>nng52+szq?_?NZeXpawDezby-fE5O;~^}pZ!E-?+IPN=GY+pDhTM|0 zkNsxtyAK@Jwj8gqBV1>g{7c!gSw2CY)~hZI};K>@W%BI@^N>|Ht#&l#B1$SS3Myd!*`{h>kxT(`J4B zg8F8s>f>)WY(lvWR`n67`qux}Ii6p!z5)0{)zNkooo9h*GGf>bnp*j&Ajh!%95bD#NSQcV4Q#n^505C}(}!;Lqy2EmhxQ)b|+5ZLs=o zOw~8;e)*kq*0&x0tiGpG_3euHg|D~D@M`t(77520r)4b1Fphog16dfDTcyAqxaYy$s|Pt|vSALo`>2(O$E4(DrqqMT!HmQ4(% z%@X%xVZZG66xxRkoc&UaKkJwEsrvG_k@e5&xB6~P#;~X^VE`knL_PbPloABAKuTjYQ%J66P@$0P|hsQJyQ+9OjhK|Dg zmu39p&+3M`FR_vD#DET#<4?qrZ78WUl2gt>#UjBT(oepNPH9j9`g5gE`JZ_c7?MODr0@vWL#(bp}u$+w-)Qm;8@0O=dmu#JvJ=kb_fic?vB~= zG5Nuett`!!msgclROIJpOG>iQzbFTfE-%l|FDn~UUKQnMbvb#`w8@!_)x>`LXFPqj zXw!+(hVrO+!`u#TgnMXR!3X~RJ>T7Dlj}L7^CS7st-L*dM*A!CpKH0J(~RY7^Djj9 zy;Jag-;Ebt)VssRi|*Wb_ik%eTyT;3a}LOLGjf;Z?{YQ&eJ&US-&p%J_u(0RSFX=I zJY(gU?YCb)qi^{Y$GkG5bx7wKt>^cj(Kq-08Lhcb@Abuoalfo9t$SeZ^tl_>-M`Lt z>h|arxgD=u{$tmgjvF8Tac0fBn!&X*7QfhYLhJ3bCbWLF-(kPp_|}R2Zq7aC$MsP@ z_tBe?pM?B5H8X2ouH91l+}z_d&31Ku;*QT3Al_xt{v z8AH*Jt+@x!xbk-P!SdVl*RMNeT|X@K`B)box&)tf?SI3v5i6}P+3&{Jt}I?v`Ni$) z*K~Q|<;sU|+I3Bb*2aC7AGpHGd+*TK!M{)ZXM>XO4=B6xN>|o;og47CbN|qBXlFO0 zb$S2q`y5tq&08ORJ$!v-?kT$!=3nDV=We*fxz~D39rs#~$9LQGa4zN&n#a3`^S!4{`O{dh}U-9NoUnP%sP);@pfFN)fDy@TNzIG%(4nsIcfUL-W_re zs2nl72h0FgIhRW3)7x`*#jV#${?L>bU)WE>CMa=6PkCo?TVEl3Ssb zSKcvWVDAnqdfmBk+PF0<9y!AN5og?R25an{o9phx>zd`cZaS9Pfu}!l`e|!fL%X^8 zzZiGfDejRo$FD9N^7(g#1)ILRVbzE;E3Z8Kmuour%~t;P+}+l6t^K@o`5nvmS@CYX zWJatiKFg+Z?ODYuXD@%VP5HIUZaCA*N36JEMZ@wZ;w3U-W%26i%Rfjo>hc&r%!lRI zE-PMjD3)lBpZMKUzwA59h3zqq)AGxoZBy5tSOcvbb*;R!!>7AtCY!^p`OM0`8Mwdm zXk}6|=b&82-s^}pJO474**KN&4(ZUl!$0g&Nn|~R5_}XPN zchA}3;Y`lR<(W>qm#(~F)g8-c2iw-t>mG7TuV3cQnezM;?i1#vdSst)uCP92CZ8J5 z!-%t{FMkRxPnI-BoQf=R>rJ=e(4Z%6?(CK8m9f1RVegZ3UHi<^>n3J$@S|Ewuiw+1G42oJY#Nrs+JYtg zCi){-!=fd*`F3pMY;k({GFb12x53hy=nk8(?*Y?iOgdtx`~z!u${#v!Wd4B-@;axn zwW&Gsy0}ShVNFYZUBlx1+NP%BF78JR(Lq!HY3I%vVH!Nlcndk4)5w4vPtc+PY$w1t z%Sik!j6d=x#)-$@!Z`ocw($f$8n#f!Pu8DthyK)P8K>_UxXpSjA6bsn&OJm+=%b9M=Baq2&A8g1t}9-ZgMQ2O z$_(w^J2$6$&whit_sSg54;M{ayQ#f%y6?2r&RgLaGsNX|-*v04fbDs4oLh`B@;Z#` zf8qE6k|`Q6wfAngk%iwpZr4w&skl7uSl&i(Z)4X3`nGh1yXbGmgmxKn#mRH4M(ilrh8rhRll*3~+;&1*Z}0^p!OE1b)>+%RJM z_BbrdkU5yI?Yi@#*lx!Cmt=gg->xUeO=PdOa!^|tz2V*IF;0{NuWwz>=r{3i7Y3t$ zc+jr{8AHDAt%{y!OpBU!U+@rI_CDpZy8|zzJP}hzN>*mg_ujRNqHrF;SuA5Waykm3I;_CSg&CNS5 zn%lHvGtTSh)Do-bwQ}-1E~ukVV|Gn*-JI&0`uUAbbu9}PN=Y@&{TEa>&f{xS-IC%t z|G5#3tu2dMThPp!hPlV>STm;)tr0OQYQlf5VXh9J6~JFvX?2U6SKnCE;-)qqSW{m& zclU<*^|h{gd}Cw1n^w25uBBG2nT^x=hO|4dc1}xUQ}iJQ%;5Or_KsTq6ZTBBve`{+ zY{9$gb2SqoJ}Dp-@tt|ce=zOiYsGUD@W%a&MYXkaCqx%Yk)BwG_qrSA)J6hJvo?AY z9!)}P7uGf4Dr$*qYHo3nBTYq@*SeP4g^S$csL|uyoY@Vox_bBN(|13lddAd4Csofp zWWPz()%2&;Hn`S?=DPU}wR7|5EU0O6t>~XBbdQX@kE@w8r+%N-h3+U>EF&>GDjPJ$M*)7_+o)(MS`O>>=G z8oK(%hOC?0*g6|?S6|bTrBO;Mbu~?M<}^0*s&RMzGoJq(?B>?u(z+J$>1a|liR054$tN?FrwEE zIk}YPc2k|(*&K`@HS{zG537pC$=$)6K3eC14my>1Y*ZYL%@fE>CTZD-Om1!$4R5Wl zMONJytq$+JMomSdr19HYVoHaclcS*9Ar&BZC zTc?uQ^2+^p)ZL|vlv$nV(GFZrxp}(r*iwu)$Zp#AFl6c_In5kHYtYgOx)$fgn7;4?eXOxXG|RCU~A*z6>McUYrjrM~W_ucP!8 z?|MqPt<^nsE>M+}V8u_(7rH|FaIh|qftDSi+0LeCTj6$^u&r>oYTF8TO=(+0`rC91tVU~* zwGf}Xjrzg*#cH&rVA^U#e+9c~c~6^nh;r~L?@YIL-Se^g=3hAMd1~g2c30-e#Z+sUEMiq zZF~z}^PA-^?7XhaMO$6n^(Xpb9L7u65%onlEve(;u9tM%;xzwLe)qjFk?7;3c>Eo( zeb3yc#bu>+rHe|c7xJHZ{AUjTS%OcaE?HQUjd6B@bATAT?SPY&cxdlFYx7PB)|0r5 zkkjT<6V%aFYn;i!iAvjLzh#|dq&)dZh3KldM$zL^de4-O-(t||&q|fgP3iiSUX;=} zozp?4zu2VKe|$=xl+vfA^oo=|C(tnha&RXi=^K`8S@U#I1}Tp=(#Q~<+>aE^&w$Dx zI?trmAKj#gJSmUvBLq5WlawdROLTs!zGT~z@?oj+WP6cvenv|M(aBmG-~+NqG20mC`$<^w>bh2*|}1|qvSpq0zmzBaFFIMDL?`_( zI_ZDWN&kyZ`df6ee-WL`Z+!nfnvERXtZm!=E$gJcQl3m-^r2C0{73ZMl%AK;4Jo}S zrB6udQ&M_apkoB&M4zfpoE(>zn!hdUWcf&W(q7RE;wnY2P3fCb`red&ETvyh=`T}y zaC}-J)6=irAtid(RQWzB&Cl@5Ao==~K0c*arSt_UeOXGcPwCfFTEB`Kx3>%K>sWh? z_{!V=ZP&jo>tubF@??7zJu$9S^uZ~etdCOOk}6NuCn-;sujmb_{9P&iP)a|Y(r=~o zrzzbo?mw9xzYijV=>91^B&B^yk56fSFD9(-;FO+~(z63?WAZfz@2s?4UR&15@kh#& z?MrmexKh!{{zUYURC%(0m-3QSd9r_#@`s0x7DJ}29)0BMIc=?L%nbOJnCgsWcCVFBjKQpD1 z^-1#jwcdF8$^J;nn}YGT(YAA!kx8v>InZ1;SjKY%mXE^gF!iWMgL!_yW9sJP;}a3V zkQ06DCoyu|;6#9OTymzu0=yBymw3p*H~GUM2j7C>_Hj;Z%JosQzNXLT<$N`ns+Yh z!S#VY2pnE7Rzpt=%IAZV^R*7H5jxplba2N)C)EPJ&K`_HG7r|JZ2n4uw8D&|DXf3iMIX;rhXKGh9D7 zZ%KRGyHlaV^=l<`vc0r-=RmIx>R$&P-fvhBoeUiuzs8>|j}Gn*=wx|yX!AWzCjZbT z-^o4SCf~^==RTZD7xw|m!}aeUZSq~*x6tAGnk*}h-_7;J&Mg@q+dFj9zHZT5q2c;G z4CO;OYBY3n{3(VJCQ)A%bTagClcAIPd$@g|!}a+<=y3f%68e<5f*x)jbTa)Ot^xYA zpnNg(+(4fM-4f^((8-YJ_?X0GdE~iEq3=f@$&eR)Kkg=zIRE`M%ERsFcIa?>xsUbX z&&Gc=W;%V`3($SEl=LQaxW9Z4I_bYY?o;TILH?UmJ{Pz64i3t@Lnrgw$MG94$*{G< zdk46yWW&}Dcir*3FNwxG2SNXC?Z!ce$KR>YN&B~U)1kxt`(e<@knfIy9uph+?zlGP zh3+iq`-1XI+mvtXu7@5Gw=dt_1D)(I^4$~Ar9t^C(Bbj#uh4r1<)1?*!vL4T%KcGL z&d1LVivt53pMCewpq$UPOZJBY+|JNn1?77|UmA>mFtq-J58QmW0Q#YzycJr1f+s3p z4*gb8ejapke9d>ig#IolzY)3z)(IK%-S422>*4n95$LL*eJ?;K`_O#12|7GK_!PQ2 z$o~l4C#b&%KB3hwE+60qLk|whM?&k*$)HL3ZY*@Nd*PLw zejzC5GsTkQK^NB^8`pVpdA{odtv^|X{utm2pyvebErsqH>j7>YbZxBj-G0zTu^!-# zgq|PkeAfUyKGp-=3DBp;I^V5^PWEqI+*)YvGi4ayehIxi*7@!h=w#^X?uQ;58(rNW zpf3*Q?{(yq zdM5P!fu0S`?ukxKp5)SuxJ9Rzu$!Oz%=?e40Ur0q$DpNrAo#dU2p1 zfxbAH-iy%Z1?8Kdll!wh9G`KNY|nY_Yv>1q>371y`b{uCpG~wOsGrYkeJdz0hvqRy zhI}^>Iyt82xxJyE3+g`tx)Zi(83wqcp&t&${~7eKpq$V0c_t|5vwHaaO&k9z=of?X zJE4yY${&V)Ehv8h`mI3!6*@eAe8%#iy?m>8V^CiYXdWYF$amX8{~;(J1^r=Az6eKhn1Ry~e{EztQv`7-FKfnE!}bD%dsF9|fC$x;{ShoE`RVC{b% zn&%XzH$mSR=+B{_2(%^nn&Y+)CG^mgE^_VlWQ)hdJeMvU>%#`t|8h$IC8htC(%+_Zj(z}}=V*C2^XVCX zAY1xt+m!B;(%Yo8JxiJEd>+=X9aH7}mV*s!|86P$Qy*O`o>r3Yil_0%m-K}{!4&D@ zQiC$U`0*vxH27MnuNC?_T30tG-mpE2l}9jo~XhG^tv{rCLWRr;(KE z6w55dI+9YYxy&Y{(=TsZ2NxWsTh8h7Rdt2dS)tRYU~Ng=T33a>j@D_7)>=mE+*Iha zE45EXYi*-BUQ(NmRjH-f5*@uts~ux~R$_e_b#79DP9~ex)@N-tvQdAsU$e|aW7Iax zwS3f{EG^}TNqx33%60y-HbdER8`WkhYdx2(WD$RItQuQTUBi6Nb09en_~=G$HGV>` zz80C9rj}HM^DjS5hR=B8hssjLocW+acFzA{@6F?@s_ymSb#ih-AjlMuSq}->VF-aR zh&VAN5fBgwQp6#IBtSF}%s|nr7J)z*Y*oU8Qpru|FvDPYDu;`_>l~%pI?X9-f zTCZ)@I#8#+&$GX4?X}KIK;QfR`u_2L-t{5u=Xut5eb>D9+WYK%jzgmwpnhIL7EJu& z`_jC)uw9}^7Siz;&K#d9LVfgVMAr5Q<2QKVP$u-T(X7Tk49Pf;X0z>U-cz-wyH zDw;!R3a>`&S=S#kk1}IAH_~%EGNm28B7~DL^5kVRN{{T3%po!=^15OaYi@?9*Vv)0 zO_|cVMRwevf6clxicMuxkQv`zUxf>!we#cRP)w6>o8CezbwRBEeu zZ8w^&WT&QE4`Qdk!gg@@Xs_?XmCud$+F`Wo+iQieRim1u4*k@z9u96dmy{M7>GrYL zmf@Mg=E2ffmg>bz8Lm^-mhFjEZ48g5&%K@rS4x}0>zQy(v$0-}m~%ss-{9dXE=o4a z8{Xlm#KwA^GbW|F;e>G-aZF0}!-?X?dd-niaj)><3Bi`a8$#g;%f@+T7M>+PRJ%2ctxAhiMc{#qe6)R@L zqN+tB@k&o^BabPsFwOlJyr|T0b$#QaRIxhRG_E3kU-T<+7^Z(CayfN7}37aZ#U5IltX z$AWR0tP1$y3_>sb6?_`P@Lp9mzo3sA{!BST`_Do-ynkEpx!@ey{ZlY6eY*Wr(h{4r zyx(rxirDC9Q2)8u6B~UNb^YDN#718TT%g20Y!m%`S&h`wL|*|sOzSLz$=59p>t*tF z>&W&u`4XFac|X+nAvQYO-}oUm`daF`{KQ7T8@QXknL=#z9kk~MGYG^+e-PN@OKkLm z)b$u6Hu|g7_02_MqrXXA`zJO!yU>)M*y!C*6jOd;qw_v`_DfPuVxyN**X1EL`fT7n z{J;-^*ywYC`)Zxo=vBbRKe5r51NTYCe+a}zZv^hEbz-Bh1~%m(Hu~3r`y}um0G&VxxaZ{UvE1VxxC~Waa{~(fa}SIYsP=jh+PVt94?dbG~=`E&fAr z=l&!}rX7fl{VYc(Hu^m3zr=qC#70j8F770HFC4mb7TgbZ#y_#KKhx2PjXs6CZhvB< z&!hf3@kwm-E2+OKIaR)r5F7m+ z>e>&n(b;#VoWw>iaCBm$pF>@jli29R)U|(Nqfe)<_g%zB=U6i3BsTg2>e>&n(Ya6P z!U=(}8h-`+CK-g=@i$E4bl_Mw(KCT_9h|RmN9x&PLu~Z!j!ta!UevpbJ+aXXfK6T_ zXruiT8=KM8bza0qKgZFDjXr^T56O$z=u;e>*yz)#pDOmmMxW#8#75^l%GDp{5*xi1 z*wke?ZFF6TjZGtUT^C}bU+3t=Mqfo;*M->VE!1_HiH*LQx-J{B(YFJevT+{ea*!er z8=Kw0rfkGUf6&p1js6Jr-r|SY=tqD}UPo!uM{J0V&CjX#6`k1VuLGO3Z_-BBh1l4< zO97U*ytAlo3t0xMyDk`4Stw7TBa+P8${+f!NqIQrBsTjotzrOX5F- z&9rfFzQ#9GA0RfwM*j}5N&8*eXnSH~b3b*Rme}Y|0-LnY&_<^vHa1-5Oj=^2|0l3X z`&-)N;6DUnW5Xreq$M``2f#6Q8p1zl17{XS+;VKGR{+5*r&n?`6^w z8=XIOY0~oNZA@BXW5e%BH))BD&S$<%+G(`Old=&T8$JhS(h?hezM~Tx{R--V_#rlW zJ+R4(&w`n}h>Z=u1$F3EwQorcj`JV zvC$6!n|zPZX0Z4tHa178>$Jp1f5p*>js6?z+~^??8~t_aLq#Vx`kT}XL?<@-r@*Fc z_<%Vo8?mtof2&BBjo9eDfX(kW^<&y$;-A?3ep8Zqq3Fa$$Gh&4PHc33Z+Gr+u_reA zNa`a*CpJ3X%~rWZq7xgP&#{@Z&7h4g8?mvuh`KHtvC-!_Ijo9ed0-LhkK%0?Leqv*@n))cwiH&|cut|F-ZAOa?v9Y;_x-KWN(RWcFBlg5b z-%DMWpV;V60>^mLKzN2W4$jy3S?XiOhS=yob#!8*|AP9NVoz-J*MUu5Z_;L**bp0= zx2f}Fg+Od{KJ%A*w&=u0KTe&SRs>?Bcf`gqcCP6B#94irhA8j0*ukl0FOT~uR=s$3DVx#|v z`uSo{Z1kT4o4kHW8||Oi*t|l0ilikr`tKZ_*yw+tK2_|Ajs799$?Id<=)8!H&F9po zNm^o~sb8Poe=PUGCGMJLYJI;TObUUUwfSc70TeT*3* zuvv4tan{)EC)rG~Cec}3Q=S#X{14$;VqKT@#JVoG5`R@}ZYS35a4+#n(RUK-x;#jn zBl;saN&n z7Qy3yb2nI=ul4b?*(mxH;!T1tCf+P~A@NOu>xjQD_}_^01%C}V_Zt?Qy&0eRjomEz z&BV6|-b$?7>f6NZWQ6Y!>o(a(yhZefh_?#<5%Fz;pC;CQ_fulMzv8o`xg0DA#AYw? zGHt#oI^T(iZ4>-^VqKoU5Z@vCyTrOY;U4u)(YY^;-6c4S_-?`Y?wzPSrxAZk^nt`@ z2p$BSdymCtKfre+V&4`W-;$J)`J@FpFeC{~5S8%uwykGFW)E^MMllXgrA0*x<_zB_? z!3TkJzi+WQ2XX%v<0MAl-YoX-f`3K)klkKqZ#db|}A>+v>)SoigGV%^ugmXG0ibcW}M z`wE`JKH`h62)`p9FL(&sYMS8piK_%pO8_qyyo;DO+7YhACMLE`@C4)&dsr}^pUz>U zA`l0<43nwj`DX@VKKsrvoq7k018p;hx_(}k*gV^ODRp)f0&$>ixPIp7ucROjv<-hJ zEvJ*%69?L+k$Pv*i34qOJ#}_I0&$>i_^w$Fe|!poIM6oVpw5jO0&$>iwo%U(ojA}o z+o^LvArJ@JhW8wD_(O>Z#DTWqnw-PUAOdlqZGK3-r|86iwt0&B>!K3}+U6zd9Iyz) zfgTTBpL6t!(!_zb;dA*pr-?mrpl$v}{dCcZ18wsW^`z*;fwtiqo-;sn;y~N9r=BA^ zaiDFwQO^~fIM6nIsSgyLIM6n^)bm6q4zvyLC*%a869?L6H1&MZi34rJ^*@J`6@fU= zHl@@Di%uM9n`zYlC^~VVZ7Qhimz;iHc{6fs1OI*W-E0rFbKqfw)qzIF`^R(+GZE^Gejp2w9P*1V?`$p zw9TW`xo9B}2ioQ->iT6t;y~LRp?;Rw69?Lc=b)UkMJEol4bMmTeXlSO2ik`B1ac;b zP8{fU?0xDJMJEol&1cjniB247n~ZemlSL;Ev`r`K#iA1j+U8X1C884t+NK}%QqhS6 zZIh(_C((%mZF44dUU(r82YT(DNSzBg0&$>i_|5h?Gejp2w9Q4-XNpc7Xq!u@Unn|p zplvFs&k~(D&^9&HFA|+N&^GndXNyi8Xq$hdUM4zmpl#MrpCdYPplvo$zgTqQK-=(F zH*)5RP8?{PyQqIfbmBnUe24lx(TM|X^8ocrL?;fk&3@{ew1f;y~N{l=|hO69?MnSJbZ%ojA}ozolL-I&q+F-k`ofbmBnUyhZ&@(TM|Xla_#9 zEjn>fB^bZep>h^k9B7+v)EA3R9B7+9)R%}(9B7*y>NTPh2ij%`^(#du4z$fE>Q{+Q z9B3Q98=6xqI&q+FCQ$#g=){4xnMeI<(TRiQf)`M)w>Z!?i>Wt=P8?{P<xtk@}q$2ij%>^}9qT z4z$fJ)bAFZIM6nCQ2& zw9SvH-zPe8pl$wx`gcSp4z$fN>N`Xy4zvy5QO?;ZI&q+FUZ=iGbmBnU{Dt~=MJEol z&4<)?i%uM9n}1T@BRX-QZ8FHqX=){4x`3ChTL?;fk%{J;k5}i2E zHuqA0Qgq@#+w7+Pl<35Pw)sBwgQ61$+GaoXr$r|Yw9S*$pAnrn&^AAz{$tUJ18ws& z>W4%p4z$h7)DMeJ9B7;0QGZr+;y~N{iTY1OCl0jD->4rEojA}oA5ni!bmBnU{FD0g zq7w(&rd=lV{}7!x&^BGD9~GTA&^EoP|5SA1K-&zU{(|Vlfwmb;{b!;R2im5H`p-ot z4z$fU>c0@3IM6l|slO;XaiDFcQa>g-aiDE3qW(+Ki34qO3H4uzP8?{Ph16dXojA}o zi>UuabmBnU^nw)otLXiRu|_Z?@t4a;ge3lWPGXpazu4bGsOAv&5j+ov+#wd{YrU2> z+I~54f!H+Skb92B`C4zGjke!Re4g0cj6?4E7Uyf7%cZg3O*~a>9>5{D!s2|bAB1G= zIb>s%VsiwC+@%)hYyBPC@IQq2@fWKLp*oI3?zI-@YrR*@+V>;AUTl)Uxwl!Iul37l z^RDO%h`%YgiuMm$oUe7>UN`o3GrK@$R4eVo@P}2?@=^wkzU0>!Ii9JuS3d^}?pb zp4ciRDXDDT2IrYf`|UDy*zqy0jX<093fFuCcoC{FxUI!>hY^nJ6U}lq5x1 zR9~@_N=-xMibDJpOnuG5rpD?9>G&`4e_z;Os3<+1o$oi1#A({c0Bsl7e6&8A1AQ>$ z;}6RTZ-s^7M0Q1p_4DPNHo@e}Wgs1Y6LiFbn76bWgg@&1>xjQu_;dYnE|0*U3C7(NceG2d)BbN%u2nS~T|F#bA0bNyvri1Hzl{<`Cjar8IT^Y>uF{jM0>AA#qu z*F{QQr~RGk_+x+KU-;Yu4k`zGn==V?U>yHuYdfRQhg~n^Z31l=W&pVL*jk3~qCvq~ zkKXt*^|;*gR}Y&$#tG~UT<+Oz#vnOBCps9rs{q`57c9VMg(xHQ<@h)G^5blihAt+f zv*r=#VB)Ux{QYvVQt!Zq{!YW6@yCy$n8vIDcfntp8D!8I$3K1)>)L&*hf-%jH^JEP zBT`}$UWT0;OdLNFG??+UY>W>{mm$YLz zhpMI6efn=Ie6P&68(uVaY|;ruV@DQ^9)0GhF=LX+q7fsC!v7Hu ze8%X}I2Mf@JMIi7SkU2XCDTjgH}Ax2O#MBjFMfm1n^{&_{{~@veMPlg_FuRH8~tPa zO;&3AMEp&_iUIs8j>(BXJ$m$9BpI*ND*PQmJoV9&7$>$StvMb+oWTkz97X~@QX8-wN-nuB#OM5P$AZr?g;CXG2#A6vcfrR+rFi34NiP2AEv=KCgY_PUp% z^hV=12<0d5S8e5IY(k$G!&jnu8fr1Y=&nDOxh%0ZY2r>)zI@!uh@-XEpw+T7vecAk zJ3brFdk%bqI)Kyvn(t<)j?Yhd{s%u{JGINp!ZpnMpBk@w*A}MaG8QSaGcv-ITh?W$ zA?x?8AKCmUTI%_AYjTP|yRT|w)!MsOujX;bT?ejmwtwj@;lEg7nRtaQ~jev{^6jCJOcIdStuQ_`V{UFn$> zLlcjtcdRID+8>sHqk<)A7bIGZuCX8P-=3ZE(klm^eek?3>sHi7Ezz7Pshs?vy8hzr z+a}zR^Qy{Zdzo0)a?9F;+B`k++@^aIiTAo6osxB5B5_;E(Id=>r8TyjaPxg=^A42i z$lIrEAKLs#x_Yf;`p>6qN%T;gk7g%MRY#6wJ@`T5`lsIO{#N(2s^lF}%jK2m_QymRl` z>~+n3vlGRi{i5U-(QILTwqztwr{d3UE9n~P>+^~~V;oyGR#KKw?`%n|{p{Gf{mD`5 zcB)5bJ$2ROw za@90B?A=(n@&4BnHzaWHb<0sA&K%~(KApSn#dR~+KfiwU)_BRKeW|h)vd8oY+u-$Y&A2J{m+Zs^ zeX}z*^}Vg6ta)ox(?rR4I^5r9=k8;uX<3F{H8H|r&mOa-|5i9-Spw$Y4x{bfgQj(c ztoO?_6D!~9t>bowws|<)pf^}DmUk$AHJj1MfDonKhffbjrIO zKWHw=&DfuYKdgOIzLoP%@YiW?ugWaj@KQ4DwY8~ZX6Re&o$eD}bXuG_X5-6NH;u-8 z&g+Bn|vUBm{YDjC|7dAfsDcl_rI|-XJ)gT{>GBrWXJTZ+(ay%cQnqGD7Wy5 zv;*r(C#2eC4NSync}huc;R9*5*2i{k#k}3Wz3XAqQZ>I_Q@lC8>D%d{$4!?d;s-JY zdfr&-um>>$j^(XQ9)kz=VsmlVKW`{5+RmD6nv}?DF3#<;7^`VqR@(xAOvJ z+CpZ}ucNd^NByuGPgge=|FYPfmnpuuH`$q$;;XHFNLhRAa-0#5)(GeE*xPzp#FG%S$b*?+Thn);v=+yK2YX^X|Ft{ax>= zu48c>7|-vh_O8uMzW!-EuldwXr}a4P(TxvnD%^+?Hm7&yIgaPHjthA<+pn_vf3VWD zC|CDz9mO27Ys)6IDN7p9$2sz6etU5(N&BX0^T28I8>h)wN&mF6_x=%cn{RIn8qd6^ z-Ojb0RxO~HaG%@MoLQEKQGi)A?5DZgvsBB1_4vZh0ccItdDOZcs>{N%6}vKj-1O|c z0g3$WkE=hNx<5R}a;EvFUZ zLGecqXWg#W@3=tiy{Yh~vZk#mImh$XezYd9_;^(J&AB;`98Z~5C|^7;{rH-^LmwHd z?2J{NDmNd(`*~|W$}N24!`$SKgI-Wb^(DB@Y9cZUVj^_sH$8!g!AJ0ytf4n7;{*Ua8wNZ)o zZse%^Lx;qFkHxLAH3K_@=csJFigMGDc6rv0v%g*5p(q{q>Fl*FIOj}jo*&Lj*WT1+ z?4xCUvNP6oJ+N!~!7b~az1-*r*3ETBF;lLG_ca3#eR%VNSSePB&T9(NKU$Mt{L!fO zKT+K)=T-iA#joZaTk&${z-$I4$!U z6OUd_S;>d!F(;*;jnZGS{?{07`P(cG7rhRMOxl;JjkYA2XAlDbuem>-dw4>9WpM7M=vuTHd zR;9S|U_4m+$r{X$xhTn^mfvGN&fjrUT6Rfa_1-lZHMdsh$C zrJrLZVgGN$6=Hgc%33$N`@^SP9Ba4p6t#Zm3|vX<&pd`RWm$$j|CyHKYA3tj(aw0! z8l6Du=VHfh+p|4r{?)HIcGlorbIR1pwOQTQ?AVYN-}zh`+pXQs_R-48_AA`XT#fg= zn+tDhhZ02mrhQmjpNsB06h1%X$lPa_9lEkr3oSYrtXqRNisu)9^85AkTV8B=cl-Js z&&Trb+n8oblfUE6w8YfhbwlF#>tDG(t3!O}hOks&>B8Q0N;hc7$GO2HDDhM~ZrG#l z9)dmUjBc!%DDQ@-yt2=6%Kze!pU;0`?$O}+E04@ZJx zpW}@Ad3Hwe=UXz;Kc9xRAQ~^Q_`%cdaAmwc4;Ia9qn=BI`+TlCxq}jYvJ)lggSUq{ z1DXAV-G#(T)?l7v&V63F<*-WLY5X6=RqnpELpE^Nb#wKcrAE){kVwnwrFSm4x^FHn zdS1NS{Z!iRH-XbMC#JJ~MC0nv_V-UEe;9 z^W@g599)4@|LIc`?pD2~5B}ik%%~N|o-t}vcE%Z_4xI7#@mtoNG0N1A<>$SlHHXvV zycXWFzXz^^XZ-O-`dSZ*`;&UFK)W& zHI|qC+E=3sneR1cOAM*^*X@a(sw(k$Jai(VaSHuLVJgE$i}R0)fio? zp2GV5X*TXynRY2UjD5~$a?gqPed31?rHy-TW;7e)hkuz?^c>HSn;W_NZ~Kl=%lnCG z{qJLoa8|Z47pD!lZ(8JY$i~0y#yJG%sSUV~W>?ny-FvWavv;2p(`x?g@~dCt-8fV7 z7{+yRcrT8l#;7IR4cgSTM=WzuWkpj%wWNVf^2(;A z%khu{Jb+0C!m8@Oz*$k`3}2O+TvAtCRjA!c(t_kw)z!;OYbzGRQB?9nS*#nokv z^%XUXmo%0&Ry3k`noVBDyqgM=jZO8-B7%n{8mpPOz?Qd^r7B3yo+C%EtoRn!u&q`m z>*|x&BE%&1%bIkb%)D?; zvTV-miBr#?G6&8LET3L>(dA8zmB@3%$SV08Q#cakUs7FBh3|RSg-NkrTG2RYqhHBmROo$;;T~W(!*Y15Eh)J53 zPu4Uf7gf|J7uDA-O)hF`sHs~vMam|lLL5qjVC}a6E}9meAcr>V%xo9cG@806zgky+ zRUrn^qPlwaGRj@CsIfX6cGkJ>3W*onl6q|unnw(-HAWBc*`LyyWfir$GM95K4oJ3H zuCQ|@1E*UG!V+Cwx7<|G_ZWT){|Q_!Ue?f{a~`y;?yH000|t=O6vxxtgByEUEgLD$JN5>q*%zz*3+adM|Jfz z9BWaxRxaTW5G0p0Eykd9Jr$nB3D>ExvbqJ5cw#E4J$-da^)d{$ipHACLKy+*8W}5L zAIanlXLYM?uWRB^50fUBVmUy|wb@k5>gtzP)D|M!B$6y|YHYJ%xB#$V;mB=sEUmzb zT!l=qWQA*9s{-M1Fsw@TUs)IuXW&`*%2ZsuqCVQ_I9 zc6^4w*hSd4a|+Np>QdvOb=3S5N1ZSg$~)vl$=o>LFH_!=7X4pPzM)^H>?dg{r@S$B z$%&nf`1Xn7GSofh!I99!Z8Se)#0@uofKOQXm^xv9#lo)`51q93ZcBL*4_{Eg6Bf!X z@E7!RCH2)k%DwP6>P4|bzWK5f{wSq9(E?>ymrJVgTX7-_Jd7I7z= zIc_;mR-Z3bPUJPrl;dP&N*T^eObWl`&fqxtsutA`d7iBAPFBAYwqHtFqp9c2LI=jx z%J*;hQq`$4Rx#BUgrhf4;^;D)8V|!sh~e=M9gzB+lcc`f*u_-!$sruQeL_bk8(98; zb#2>-iw2E91kzN|30JfCYm^dXgBsmi?84l%*%2;e_Hs0GAfW*8}-hLpg&&$dJ>_C{6 zbsk_A++~Toj_F8X$SH$h(ho0nbmEI0ojbz`-jOIoal2(q==IG>y`?<)y~p=fs%t`} z^%Q|--A1R-Y}SWaFs}QC)iJeYQm@-4_3j!|st0a5M{%bXs#fmV4*0=uWYEhR_M(%b zZ0)0WVN9a(dr!?iCoB-YEP|Q!ZKJ&6u%CEf5&9SEBG}}o^*~GHBj3{lR6dF7IGGQ~ z3L61$Z|JJf3BIM*ltD@`(9b$S_pA%B9c8qU?)%&da(a@fFbFj&CWC^kw*^PwC;1PDjP$ zMVOGL{Fg>H7Jsp&2|SmKK{|>5BgC#s|9LF-6^uaq@G<#372=NY7Q3Xo#q;Hrmd|N( zX}?ep@nuPiufXS@2%%m+D8#4HPZge$LkMy8un^}_UsM?4vBZlOS+`>$c*E04xhJG#$Izz!ei&@4T@0}q+);yocUq-_c#66xU~EfybPBJK>8%vgMq zR$^yoWya35#TzHp536uix{6@G~dE*6^>8g7RcyFd(|C7zB?V-P|-BQwOWP@maR z#r2o!so2DhEJZAKF5l&nH@Z|T#Az!23q&!b?Fb9lEjjY31yf#bZ- z8>mAcj+;Iq4M$L4#xv;RZfBHjpzT@cPLJ9Kx{qya>334;4wkLoN?B`kNfJqleNz8x zRsKCT$2~N)SsY*%{rH_m4EKfyUg>QaT5+6 zHfpObd$(sS+?U4Q&BT1O^>~*nM9)~b<&3?{N=0M$-PBtAotACX;)7Gd3GC0}f7(3$ zNk<-y#+{uC16dsgJ=8N|Z1TKN$%xTMK+F(pn;YBHQJ7vA;f2UBgk!ILKArhlbn@JO zIWF0BiZPpfor#Kd34P_nE}_z|)O6}U3@}r^pDCC&4c{gVy~O5C$HrhV){cvDY*pB^ z!mpjRZE%)X_%Fx99dhiP7*8tEM9qoSgeCCXr#kEcn`L#33$n`_(626MH`z8>92U{? zB_WRnk(8w|EQ{)A8c4TGPHb_TWm@f(X>}~M46DO_v1M8v_^Vz!?!=0S2xCfrS7!z^RdjJt4oNetz@=(83k@*f*Zb>0A8z;miUB7W$#{tv_2+1CAG z?Cz8iA@R0)PkXKPBac7h@fSUQEacJZq3h!C#cTpIc7~C}3S%*uvV~#dR(1M)?BSGA z{rk|&*6H`&On*I$Z=;9)D7{+9X&mPKw^#zxc~Cf={W7ZIVic`+AIEH#AIEm3G~>sq z)sB2cpjD+hr?F$L$IfY7u3XL>WCjilZEYtFN=u!_gFQYpw3oC)Lfr4VOsP%3F5z|; zqwwn(LJZMxY*oaOUJ*xnMI4#NBHCh&PUAkkUwfTZj-0jhp_TWNu+X-`C80N$r>@`U zhxX2rDEC_YUb-yJy0|PXa2o@mBJ^c9S9&~lkClf_;!mpDwA2Au>or7e+D9p)p*D@H zM^yjnlQ;AAp7-lL@7H_YZwS5HTHfF_+zn}5BW$;<3jJHY&KoW3z0tMPi{CE|{|C8N zQ2o|nGKMw!vz|uLAdiMpzlA31vUb{-Z!LtWer>?|gjV(SxLtX>_e!@_Vy?XXC$ zq(Zz{uAVsEIxOLCSFWi$)O1&!x!;QS()+5kZ_8z5TIYdK3I^l9_-GxMH8yKOmRy{_ z1}ST>WWe-ULnH(4(Xxhi2s2=2Sp^*}9%eJnDwG=pVcOxiJA@G0kFb}5Sw;3{LDtBm zwHYNh3;xc$MoW3v5Lsj7YJ3#NaMl^KRQzpS?zBBpr_A{0TFE*+t4kKYX;dz~v-(O+ zxL3*QCl{SzY5Gg8*gILL;gbA3xMs)-kbZzIQI4b!)8sno2RiBThFoV}+qYwfgqPLn z4t6iG(^Thskx>CF*!g~-_@g@C_^DalBg(5+)YUdM!q@PnHC0u$)l56Qp}KxWO=We%@P_&o<$Nq`I37(J-cZ+6Us+99 zE)VPtUs6Ne5kxQ7&$$&=esQkyI26iNv8?Kv;rNYvWG`e`nCF)(iCV0Sq@V9ncw)@J zMYVMmjjFtS;_TTIFDWmZI=`fR&Ly)-%FETVrlqO|-=BrQQ6tN7tXiq$sk!s*19l1z zpt*E8o`{^)R9`(SdYlev?2~}1p?Xu6lbCk^6b`Be*ITXLkS<}s;*MuV_l{~rQu_gW#MCIp`CdUPZK=V zs%Bp}vAF!=nHS8w@GCQgn1?`x;hD{uCA0Agmh-r*(oe_Qg0XQ}uCR4XE-X487@kqR zR4r^;v`Cp}WG5;-fTz%D7vNb)8qErg>Xa$3WEB=t(yVCI)tp?ntg&WUQ(aSo_O_yN z5?oi;t784=aA+7l{ifaN#t8Mr<$Q`6*{S-as(zWOMSoY-H7%^IR<(7@)KrNKO^auj zm(96wmMSZmS$5&<@?tcBpqUqzUwHAHSr^YyQ)f<{Q(ii8>U6cVdMO?pEN@V4eVH8| zf|f1_yLCo&RZYdR((sW>rmI|j4bolRP*>lmrZ(8IGPCaD<&BDu?L}V^$Ksi;Me7;J zhpemW#iP;6s?lOnQ$Rfm!~ALOj51L7@l-|bK72cu&k<7P$ZnMf#S80eOs>o_C3V=6 zv!WR`dFgUxnQj9XD6$Z3CZ-!~wcCjem6$1EQ=mC&7KS}-vMj4uQJvEDp^00iN!OV8 zl=hv5=gnC!#QkZp)YLG<4H|kQeAnK?#p^T$_D=5h$dOY)o6)4d95n&yk||3su?M> z4eOq&C{hcHqRFQ!RxDOE3J;?zKI_fNytHB^51jFsmeJDHu!JL=Yedl*SiCCH=2hX8 zt*TdedRQ&SP@3Ib%|5|>)p(M;Ra6}-!6k246#o-or3>k+%)1Z_W#C4=Zp6> zS5@Qr_uApLHI3DE4f;^NV&sUih1hispVCzE)#{q^>4?3sYSg76ceS*sp>}x9 zvdY?~Dr|&m8XNx4X0;sWM!XQQ6eU`S$zXE&;!OS@?G6`KG}Kg`d^qIrULS5XsT^2UnD30FC2dVCq~Ah1L3B43NUY;rOQq`@bXydx5gFVp+vvoVorL^{}~AEXQXJi^83ja}k79 zsiL;F@tWn;4TVeiv9xEggzFY&BQ|iAFu=#Bp~rGG{gU#!MLgEmtVB#YerAksxs^A_ zJ10wc(cEeX!Vouw8XBuG$ANJZN!+#WRm9?cBOT!UTV21XqOuwiZd^nXE^JcbaNkp$ zEw8WR2@K}p-Ks=*lPLa6lZEM`JNgdl+vlM`(*eeN1NPyt*5UZaSt%Mm#Mn#c&fdOven+$FuYiKZ}@B z596V~DTOJ2B2p5jW;%DxO-?bL5^izoQo8j%Lt70ntrrsysTQkau|z*(kuLMx#f#ZZimT0QD-4Gtdb#;tAR%`fEqMb@#V74x`TN7LSLP?X~4#oig88B1v6nG0rIc zQVJ=Zu2Z+y`Sg#sXBw@>;(Xl4EA>H?`U|@EFig6nw%n;vM$&?vO`-5Ja$zYk+QO=X zI8F2mcnY+qMAQhd?H4A>ir0ikGm^XNMo8!p-Bss`NiDhb*GJP|iQXpW6dltyBYs2Z zQ~Qcvr*n|ipszHLO@~5BjWAUu4^yL#8Pa^V++B=q2V;xr5vJB$JRn1-3Eo8$WJgV) zGfV1YU>uoDTUV^WEH0-R+n%Nv?R7JCj<*Xd+2#cKC-ToR`480jX6a*&_Mmxc$=9XX zsg+W}#1P$7=*Vz{CC-;-PEG%Hr0>)ro*9-c>ineXD19`(%<_A_*87-Rj!n%Qj>0@s z)gfk~HP(r!B}eI*)`|26kW*Gh68J?$5%jUh)cBP6zolB{Wau8o2$VF#Onv*s#p^jHW~7NJ)FtbnCj^!cNqe?F zo~Ms!37H&$o*YqMp;cu)n`F}BROb%(ggJe|Qp${Gmt4@2;aa4*RtM`=Pqckv`6C*t zml>>sjH`Y+u{n2+(R`FX;-`tj_UdICFiMGKN~+dRHwM~GY)|B)lkpKXLRXz4&_{FD zAFO$iKAI_vJY_}EOM7YqbTtiN{2S|NDZo6}=}lQp&PXCLQT?#tFnP&7BS*MalTv%l z%;d*tk~TnRUY|P9aAFKQT&Flg9}_aTQ)`0BALa=U&T_Xp9!qpJJ!tC4-j;#XOMC3A z`=v*egY;7;b6PZI^d^a}Z)!=R7LUb;g!SnZzcf5zMoCSFdwo>m@ouIaJL~fF)YCbd zG{ytIxHWVg?fH7@6nZgkYf-`0O%}oEon%v+DZ7y|4(G;cJR;tiMHxF!qftrYblr6)tb42mXH%hZ(S2J9tt!c zs!JK|cF_THKF`)ANod|%9}{{3?5*pmxhVk}w2e{vLyXc~oe-s#!bWF|PCBb-`1a5i zdWxGB)>I;Oq9+EJ_(J2^cCSCYwP)XdI2cT7bYVw!q2ZXn(ulFPs`h(S&76$PBAbW` zP-L8#@f^i;(=8t@;JtOB%+=1hnorb6z2nk-uKnsbtRw#+-Db{~iTKkp!gJz34r6q7 zQBmWMr&JoX4L3EYxU;%^jLHo$tIJGNmveNkW(yH*9dJUBuEnx1xwlGV)|Y5wjt!)j zW`a>pY>Ne1*56pX1G_4<)Za+Q^{FX!G^jALy$wO0&Uvyv!a_lc{xW~DS!;LMEpGS(1ZL)@cvO&>x{&oMQf zWqh1t^1je0Xk;nB&R25PvAT}f_{t@cSz)7|F?)SX1l>N;3aRNag4)>19YzTYObNY- zi<=4JueUc%O-XX2Qipb?HrSO(Iuu#P&QyKGGA1$Dvr7zYP0eKzpTH+BY-B`5cR0-c zA}VD}N|`#=euMf&mmAU5k=a4%>s?(IGtRJFOH0o;rNqi5)Aw9m3Ui(|<0V=pqAN1- zsq3r#=zPvMb-^xCS^=XmtX--ddaRAL`fYdi;ItcgaQi^3*bhmoni*qq4x(0fQzfu- zF!MG{m)e$}Bj>)}Siu=lb~1gVu_ry8t#ihLDka1!q%ZM}677O|o3thdS1sZt+67`o z@f4J`KAd@7^jseu&kFezh>R_Q=O(;akR9NR?X#TN6n+Lk7ZkCO|*AKl=NJrpmn9a+dM5kov;_Px|ii4 zf45Z|Lv<>lF@x^dkGj3~ld*<%;dpb<&7(PSEr>@-e zs|nXLtJl!#etY!*-K)4?X|iZo3WfFrD8=NtB;|ZqRjL zAMei4_3+b8K!WHSMs(t7{@D0t``sP(WIfdJ;Zwe_%)b9w@Hs;JHHRs!{cr1VN7n9+ zdro<%lP;%UrZ&^;&f3%QAt{reFCPi^^KCWezuBJo-r4c4Q+9XS)49!dT?Ie#8%Cz| zO105GuAhgxJlr+(^}kJ*v{{8Hs{3wyb^Sx_Lf>CBu1*-Q+t<&-X`9^{dnAwOd1PH4 zXY9(F@y+(3H{X|M7utNGFI}#a&4-B>pdjI|FXAOj!1OMO`W2%_){I;}qI@a;Tg3k= z`QOS~Jl40gq9}q3Evy98HL?eEa}?6myZ?*`0M=2Lf`=d3L|UAmJ2@fFPn(<&$7fB^ z>s_JVHrG$a!$RVdkq_Z^P6$88i!b*06pu%5#B2YxUi@;8H+p=f$5(m$R*&E3@kc%W zjK}}m<8OHUJ&*HwSqah}X;C)`@8N_@r52YuMC_1TIR*`_aEKz-Qe+c z9{;+>Z}s>#kH6~iHymzq<}r>BGE>K2+dMq^hY2OVW8_45Cx=H6fcvpj|7~;YU*fHQ z;nqL5GB(8VL20W0wz>5$@z%d^>tDYnptFeMS2t7rx6Q48iMRfRTmR;D0m&e)I(z=x z=GMQ&TmQnXfBgzURQ|4>|F*gHFY(sDaO+<`zaII|_WZZa?W!m7Nu6H5jUBPL>f!lo zn_GVpuiw{zAK|t>!lO5Wb-X+w|{U+eJ}k8k$)*FAo-$G3WXo5%0=_;!!)@c3?zKj86w9)H~9PkQ_rk00{* z3m$*b;~zUbf&g)Kx;Gx$=IK!)iSOd^?jE=6vDo+V;_Z4S@pknD7^7r)Tsi#%TI@s$pbAV3`7#*o@xZS!7HB8ea9aogV#Z~IU9IiCGYkK6i) zy{(V%&7S>Uk3Z^hJO3p8K`;K-9)HKJHCY5`7hkgf8n;jh1>Zd{IsZ0(Obfy5?6!0^0m$F z`Xcc;kw4*fJrQo_mvB2jgwONRS9yGi$FKAFDv#UoCjRg7;_vggJzt2u9go5v_w4QX zl=y>Q{1J~o@9`Hr{-VcU^0*!ElHdDYyuJRGcst&OcZtTMaQj>L!gIX%z~lD%TI}n+ zc>Z3!guw=c$G95mjiRfKU+%@P^tc^gV!z6Z zZ}IpxkK6Gi=^ydp4|@FP9{-KU-}3lhJ^s1J?Rb#Udf7P>p-Q#a~{4I~$^+fy~_u@bH_{?a$iM^e#!tHz& z&d+ir2*26m+dXdQhu9zS;(zV&H$489$N%c_k3HTcnlF-H(&HmMZob%2>G?Fpi=XcC zIUc{v<5eE7_4rDUukv_{$M5s_E{{Lz@y9&=rpMp+I9_8&=}){Ylfv;xYYNAc!704h ze&ym-4m zmH3ff{BJz|ro*G60>srQuRq)7b`DGYsgV=mNskZo_!%Cz^H+wmd(?D!CFuZM)&^+32CAHvsq{_S{?_?w;h2m-{_7_YtC=C-{h-mZ_rZTkyP zMwtk=?JseMhBjp2?^%NPGuFwS7mAck*}_ zkN5I;(&M(jCBFhM-mbqAKgEl;{VDPDym;H662HKUU*hpAJ#N=yNpI&Hzfs~^@YA9!gxmHJKGKV~^F`wA{186Lv$yRl@pgR@ZrelnGB5pdk6-8U zRUWtPC;m2j@pgVl{H7ypXKU-$SM z9)Hi{?|WQD`)$dugU9XtXNf=6i|^xce#52&vA5R?!UuWr1s=EetHge`7eCkI^E_VV zaeKc@{Mq|m!dH0q*LvJOk0|!5y?A?nOyckM;_dxtiMRL5gdcS5P0R5ZR};PY**3T9 zlf>KgXQJy4{wCvzD+y^h#FRaAP>qA1h9l#+rnQbQ3BR|P{!MzWZA{Zk+mFMM>)8y= zC*imTe^WK*qsd3{SE>0N9EYR+Lp0~NMqdJ6sQDrs*MsxQp5>{-@lkN*OMVTGyr0M? zcgUGn425IO$Zx{21bm_9-^B5|;J0XgFOFy8e$Z^q@5gZ?_%k{$o>lel8*+Yk?X$>kSX0u)!X!trPC*Cs;VDY9zk@%A3i z^7ttp@9goeAx}pBvqN4L@g5;x9`T-D`raWwGm7sU@{c3lKjf1letO8yi?}>rvNGcG zJjm_n0}1jx0mr)p`F#GmC|*8qbwAJP21ECLBl)Y5z1;6|?{_f%W^s=H<@((2Z{+%K zbrdhxAJ0cz_Q!8WT=rAepb_hJS60) zv%u}=%Xx~Q-Egg!kgjHek2Vzf%>%ddJzXsXpB2RqR#$&)4RG+x^%u#m{!!&#!91-Ory^fV-dHtOB19 z`A-ke)x{3qiuh+EK3shZ+^&Da)h=+Z2@-~@?}NYS@E?G?pEo=MKE;@$J&%GagItTQm25=F%d0pOQ8 zd?@$=hmQe&EaGF-dEmPoem?k%4!;Qemkz%a{Gh|R*ZIA}mw{JBJYDgpASOh7thy2W zI)`rrzro>Kz!y0DZg9IEr>kAyc6~}$4}uSj?8m7efIsf=AA?`v@T1@lIQ%7WTmNzD zRq#Vj{9E929sYOl2Oa(y`0|M3rw*_;Yjik%OH{oT@v{|wjp3-nbHR@|ya0Se#Lrb@ z!0&YUdEl!Zem?lhh^H(5PT?wtUkYy9J6-XIGj>PgX}qcfUmMwvS1ZBqbNG$mw!Y)l zMsT}ck5^m4-RrG;z}@S$-QbTo`8@<~Ln7SEc8G+8`U&EBj+2m3KLdBq|1X2P`_JEj z+xeJKZ-CqRl2CsI|GneyLvY()3H2HHHYYxjp~7>Z$^R5^8+xd|;8yCPazQd9gC1%q zcz1`70=MU*9_noHq!T|Ge1gL-0Jov1x&+*|Pft|=zAQ56scOK_bNJQZr4GLa+|Hk# z>PB!oe|oA7;5PJC+rVx4`>O5W)}*i64bm}6&{sVOZtLGyJ!Xwz)nEMtJQ>;dS3d){ z`;-3aW$@8X{O`bDaQK_x3mneh^K|z^$HAX*;$!&kQ9GXds}A5TPJA}_4u|&x-|g@` za2rlnqrp#&gwxfz;GG;^3Z8WMh2XaRPFM55bDa1Ja9jV=)s^5j3{cmAcZ-ApYBhM$ z;hR$IbJd;TwmiA&JK(mwx#|J%E2H$eYCpK`|6KJXxE)Wq>L=hfR?J;2@l-f7@=zk~fEIQPsF zuwMkXVXztxep)09R#U)jdkj_=fv=3x4_5QRuXT7OxV`@~Sk;2tFjV~;xE=pP)mm`( z`tBxh+uuXg?cjF*FjRdTJQ+D0s&<2?rx{_W`gibEhTR`4o%o~R;mwy& z8>)Uq9))4*b#Pn%Vd^j7w>$A4g70hLk(w*QBz^T10Tf9HeS_8X>Vf!p)RFm(xd(($(t{J6uf0=N6QVX6_l(23_a z+?6_f9r#g)e*-+jDbF@=cmH`W_%!U%Bn(q~!QJPZ9tMBOM5F#sfV=zK!{GNs{W(m% z0FJNJiu}C{ex<`-1-D_i`Wv`ypW*5__=?D2xQgLqVaNY))d9RyRG;B08{D?faQs{< z_G?aj9(X^;Um>{Nj}BL3!R`1Tt|oy0x08M<_^S?|3m!QB%E4zkdU@F22ZP)88ly&n zA9CW)2Dj_^7*z~z$Hy2o1KiHXF={UO4kvv%c)i1yfNyj7)!>^Qel55SW7P(5EFn6K zRkwn#HWbeX+yy?w;XA-5IQ)CyH#q!JaC`n4tDXY4>&sYm1iaX>{{^@W*w2I8CLgEx zBY4k82IJI+;GG=)PjEZF$Ei#ZJ6^`AuHg3iYMkl=ZtFKr<$~M(8K(-sA8`DS0k`|< zaq2wqXPo%+!EJwzQ?tO2IPsT&+i2R((VhObI>Sgd#O*Htc;0L4mIbQt*+|Hlz z>O=4;j{QHu*E&2CUm0+p!@Ghf9o`4r_Rn~g3%=cnF96@?@G;=Ff5xlx!0mcIUY!p< z$g!UVUf}Rcz|V8|LhyMGzY6>Thc|+s>G12p?RXxq)`7P;@%%-_HypkV{J6vK1hhGO?@9@pwH#+=oaJxU9p&kIg z*NJ}u+8RW zK100;eytOK9DJR_`Sa+!M{D|*KfuX*zJ?D1AMNln!6!L<3i#Cyp9fy$@Fn2)JA5Vh zO%87Xzt!Q}!0&eWZt(36e+-=WP)+%cfb$-#;je(d>hL$g?ep_9)Nycp5p`sriLV6V zJyZ!ZR4;J+*h9nzfe&=}nc(;`)+l}o_#lVR10V13CE)mu^vIq+zI~CyTfliwRl*Fl z4czXJ5^4wdXHNVh;5L-1r@^~L3;qoCB6v|`P^x|h9ysyufM4Roe+E9xiSLAy74L~i zn4wO$Cof3t)G%;NAsyPOap0NhhR;w_!N)r3=clA^ua=~wZ?77`d5=`W47E1JK1*s3%hFPfom6^*=WyeYUy)JQ=ynR$l>caMCaK;_JY9k6pqH^)>J+L-Bnuo4_|X>F)x+ zF^Vr$yTOZ{^85h&ZYTa(@KPuKW$*(|{OjOTocIsGUv%QrusN~!#Ac{$@V_|mN${CY z`XcZqr#=(Gmq+$J)eP`&I`z36ynVF(m8vVjiyZz{@HvkE7I53eJ=M+N8=U;MgMZWE z4}#m!TRjDC`?t3`3clMZ&u_r(exR@VGx$?Z{6E0I;*_sl5BGdms(OImP zXz)Ew{3P)CPJ9{oVJE%<{Ntzs{naw?pF8Eb0o7`T?-;CDIv2>6d3{u22AIQ(_+Cft*hFhhL+{%b>VfAVv1yI;;z?XY>xiRMF|>H>a- z!+V3zc6bi>l@1>YZbQC03*27cPWxAZ=STfts_JR)lz$EQWGDU> z@D?ZjKJcrY_y@uH8JmPs^(6RK$Np#FM@%%nPvRBuWls5C19$It{uO+pQ{Kw5{Z9N>!8bYzKhrSnHy8YH#Am3*;QUOaNeEaEfN zI`F_mNvRF&ks{EJc#E$KhOc(eO@3N{BX1$%uu=Dmq-0GLyZD& zbn>4Fez(If1Roah8EOIePa|HcmVtlZ@aw?;E8;WMP2l}AO@&I;UEu%Y#6JLjt`q+_ zc(ucifPduJ|0j5}6aOdhSj2HX0$yse!&8$n+}yp#;T^yqb$B-Tgs6RSe;E7)hv$L6 z=(OJ$@c(vr3AlT|bvAgD)4mJAcShwaRm;IUM0|$25&Zw6>^?1(2IY5L8N}35sGDg+KyCAz%^^U2Le>P+3LA?%I3TwXJL0wY%8M+IvCQzOHS5 z?=$cF-g`2-|NrkdA3~n<%y-V5IaBZ4xi?Se%cC==OL@KgJ@C<)3#HsM-=19NN-2L6 zB?@9TrsJ-7vd7EhdS$XiYUw(cQGeuI~ zEgD}c!kemsQ$51ekPiJ zFDZW;l^dm8EcbMEkn^XMo1^7DR?2dTWW$imGAZxlMY+>;mXufL%R@7lO8M1j{wPJ29Ob{0a=)nDbu&3WM&%8qyfi9r zDdjoQ`Duuh3(tg1%#4?E;d)_WW`8NKj;5a@Zsk-=$2}cU0a$$~#5*3Mp4c_YtyhBvp zPs%f*^1)I*ASy4G^3lQXU>{&o@aqMCAvhyiHVoR?1aT`CTawjmqCh z`SPgTxm@laMCJ9RyfP{WDfi8Kdvcj=rCb`7>!ds|DtnUOYeet-YI*l~w2a>)GeV|k z;2vd>eBb&6E92zWYG%(=dEZodW~zKps=O#wJ|(| zDUu7_yRE!R+TTk)_3?Oz@oQyX=}=xf^Kpmrx|v@)l-JAj-drk{LF@08*}}@D;)*i8 zGefORhW@Fya$_=n{mkyE@iSB97AwzB@*8H3N{v4?RX)$k+Ma%yTdZ7{Oka|D$jUz^ z<&871q^AEgRsJSb{!gmheG92bhLQ49B;U7MV&xr@@@ARAR$i2p%QIuGEXAZhCZ)>z zq{;_bnR^aJ^7_Bs%9|whRb-B~^5SItR+%$X)1Pl;UK1C|^Ey|j#@}LPUPBhi>z4;o zd}?K`sf*;!`_ES9nzcwi53+7xN%b0|NUqm5vGNjeMe=_804qO{ zl!s)7TX}U-9-0|%WzKO$a(>_2$`2&-+c7iS$}&3X&&5{e98#1S@tZ#^J|i=5!k|+5 zZ(v({tNj|7bEtHva;SEwaj10|>`>=0#345*Px-oY`O0(o+H?8pbNTvn`5EN$bI9dq zk;~7cGCz;X{5&f2^Qg?vqcT5_O6D7z_-&DbG8pLm!!*6ODIWm{?Dsz=yr;t`EKvN_oMq3b%)0)LtRaFI`M`W_9WbV?; zTy?(k8e5iJP0~b0)<$FtD2^HGSZhtKEt`z9X4Ou$8P!hBJEkKq$-@ik=`XTuy4)GcJ%8)c`P1;xKYg#~8 zq=3#^z}A6~E;i%xWUV2VpFr0+szCV(l8tcWNGi!s;2T_J&bwbodsaY~Qb4yY0c)dV zbn_6!_QjIqHzy(MeIc7ur7wYRVHT3+RN59QK%=RuD&Lr@d{y}ksS4;NhqK4=7`gcN5aDI6Q`wRwqdj@;Y4fYA^e09|MV(XSnO+)fE=?1CJnj>4J^^+eZByXFCA4kM^ z>xJ?oz4hW)-!m7q%$Pd8X;yO!-Q7M{{;W^(tBTbv#VRJ`H(~ir7g6-zG(*a)Z?sQM zxlpx@t+9z}=r>8%Slu-~-YTo<*f5)Ot+i;dl?Qv-Y8`A-5AHbcqz`DJ&8&_shq5)I zj>!v6P1dB09%8i*vG@?1OD^d@0#@G;YfdiNBxOWykaa?C5Nj(jwt%@o9hWRWNpjvG zne5LA*wW;ZlS^W}k}8@Mwb)x$<&#vUdcc-6S8dCbtG0#8RePP)z7#byKC0Z7GFRi1 z)cMjS{Y=B^d@*bD;MERxGuZ3#wUkR%V>Bb5#Me{KS5T$*Nu_s1WpezBrnSabCdWW& zQe|!4Sf5nZTKg-L!)}tXIaVh9nHUfI#$H)VvkNmyE(1sowoa(5^BE0sWR9-)@)U+*XH|Um3MVjo%euuPF22DzB5SXDX88x*uCTp6$tF^XP)q17ANmcoVST%(1h?;0iUhQ2_?Q6Q)4`0=TtWT>4 z*#=sj^l4Oy2Ym0U_8zJBLt}L{eGyG!JyMTu~hLG@stqxX8XA3CdjGpY8&T(xhK)!v)c$$>IjD(|3VW63X7 z-sZtpRE>9Sjc?L5$@x{5ye7G(Nx*iW8sD>O{76{ii&2y8uu(g#YicTeT0d3QBx^NF zTDR7CkJotL)p+04_;If$+0$uK>HwIZOS0YN7u)CUtFFfPz#2bn)%ZqV;|HUfY``l1xKudn&@t*Vr_D z!K|sR4K1^p+L$D&f!!)9REsX@mzjB7PR%XZ5aaQ5L|jhKk1Z)0 zpB$Cqa%%eI5D|^9X6J~?sd#EE+g21#%{#f0i$*8wE-EKibx}Flq2h9?Z<3R0G(I_) zMdf7oi^^5$70FR19-mscd)jtD;}R(-sBt+k56qq$*ChA zPyhOHE7e!YWsL5mbLP!RjnvE6{Mb}8bIDO8KQ`6KTykiMT9Hf6uZ3eXwRxjbH75tY z4wJG53zIS{pENbwSLBB>fRJNncAACQYxIyM4o-LG8 zC*fT3nl)a8kGR{yMeFuT`r2 z^=?)2>Ncu8Ia4oPGNM1)t0}F((x=1ZJ7EZ)pnF>zjs%i z+*`;uD7ED#FWU2SOg7_aS@ghH7|q18K~*O&KoX#dK>8(2a)+fbVTTCp8ZUt{=PjcVU5tCO`F zH6ppMp06vpqA!%_!$K*&S?6zWs*9q=E)F_~ z^vN)}jTtA>_ha;(l{oR6_Wb7JB)QSqVUpAinM>aV$^GWKB7Gl3uV3Rz(}yL!u2hME`5_FSCc-SCMT(QF2A|$kQ{nC zBvOZey`YT~$qR=LBE32IhFV^dFsE^5Ri>@E zMGEb$@;+_j%(j`8nHkC0rbX>?NNbzfC}!%^hQ`Judq``$lp32CQkpfj*(#egb$(;( zgn6?@HO!eavSG%-%xKbr)}~2~t)u5O%#!5H1#QjqTE;dtG|J81%$Sa&r8v5|rD0Aq zdUTxMt6@%aBNL5jX=@wZJg2>>)uS>aLG8Xqh#qX^(lkb0b-nZ&o`?T}bLIX~5+6hW6$e$udoBYHV(3DU3?T zcUdquBeSrXjcA)8-Ie zJuc6r@%UixkGjbJ%2f&JcXSketiHcE_tnC^KT!|6pMbY|VE20n7k#RE*!>jpRuAmH zQMkCPJp3mE?0&XziFw#P&oTD?OzVf;FU7A`54%4*%ERuj#asJf_xD5|cK?uY(dSw} z?EX#ie2JnAu=`Jiy*;pdo^|(rfZg*vXz{WcGvlK7cTl$Gq7ihgnijz_k5PimmPLLko=EY5A42@ zym{Dtt#HwQH4nRIefQ@}vt`&se(LRysq$EK{krORfO{y97ap*l@^pMp<(YV!mTiFT zvyc4t?Ez+;vVA(!26!F$@&1IpZLB-*&v-quE_(LT`6lyPqpO(0yx?SB=3%e1r?B@k z?4EXbKf~_Jgojx@u>0Y{MV)oNu=}yX#r6Ru*!=|I67#V8eT0knl3p2L_l?5EMY@cz z``N-J=3)1@lJBi~*!`X4&BN{=5%%LY?EW!fKW@YBpA+_V1iODzxcEUmuEOr$6)rIk zyZ?~54-Hm z`)cM(;Q_|ogh%yL&$cnDSh-lZ-k5!DREhe|!oDrR-Ztv-Z3%YIc2&HQP8)AyeaV}L zJzpy9#~;{zvM<~5Gv1ebNXFL@?0MSUySw%w?0zhMZS}DGNy5b&Ydc~0dkB}9huzN? zE?P(Hf!))#di%1dM&bU(ETgwGUf%wZhrOPWc)Nyy-S3XK<1OrdKVe@lu=@jreZ9c$ zX|vZ8xBtAz!=7h9@_h$(e~+;5JFxo)g#B6tcF%t2*DA34$ApU?)_nwa{}g%iu=`{m z+*H@sZ}vg+??(Afa;;Fbrmip8>nX;sr5<+A^{1b&<7?46@!k)x=Z6VGeRAHPu={<4y+2|1Q^-G}{Rz9DM&3N^ehzv2QZv~7eDdaD z_lwAv>2ksD7n3&+yPq!WqP|@7w+r_-z8|(PPvcnEe+$j@lxYV9|`!oK~(?l%zj{SkJb95;IE_7ER8Y9-_K!=B$x*z1SgPa4<#yT4Vq#60Z&0b#!egWbO`?DK`)uNE%eTI+}1e<@sI z9(K>Z*XhjBI3-_;7 z?k+r_N||lG-h7#G&ua5Bjlb^hDeTMMN7!Fi!tOU0?rmTA2fH7Rw{r^Yeu6Odbe7*R z9%j4sbp(5U8s6%G-Ot9`>ucEk(RgbQ?0y;E>Ve&_6!ztU-Csc7Uhl*1ug60Hb z)*jgXBY3L^cF+03_XXHJ$0g6h?pcqXhuyQC`?(|D=7V_OM_|uyE$sUU?7mvq=L@?} z&MEeK|2O9p^YJ-_V`lN+bzgwJo(aMw=3)2u341$X_YVkrJ7M?F341$X_pb~4J`1~l zTiEwm*!}zDAJulk?)ltoiFw#P*Ua@bx{ve_Utg=t`MUpLW%m66#s`wAQ@<2HMEQFB zcFKPj?rC|>7ejyN_0&4z{q+&-?co^W{Q$e)18>)Cu={Dk-p{c6Mq%$~*!@Am-k-4h z7GdvC*nKPc$Fx6T_Y29Jhutp|_U#sS&w0m}7j}QMa4~-@N(R_H`&x|>U|cQzIjUa$c;Ny3u{jwo z74B)7JB9m?R==108Z}1wAobQ}yXV@~>xbQ+ zDD3+k?4D!3?|1R>e>wRlWhKY}dwzv*iFw%ljl#aXu=_iOy*;q|Rd`!o*!}yFhuyCh z_T`1$cZ!aOu=}FO!|pd1_I`lfZz=5k0K4x`o&$^wu=_#e&BN}w_VDG6UxUn!JnZ>J zk%!%%7C93{!a4dVfS2P)bFg@`9hX?f-?JZ{Y2%T z@w+GwmuUwWj}-2|tNL{$Q#`4_UVl&VCFWuGeaPDvpu_I_k~a^#--!I~T0iW*RJg=E z?7qLSA0J@%gM|I~0K4Bq*tcic{S;wezp(pOylv00`;&!z|ApP3ChXfY?EY$DuOD`Q zPvl|uPedMe|61f>_v|~q{lo6R6!z^OcKm2JS67k0mqurDv{ zezdSJFYJE5$iwariahN8@W{jNPmVn7{=CS;?r#_N{R?(~m$2_&uzRlAivOYg1H0$7 zQi*xkeVz1G{bb#44~O?q=9t`nPvsTDJvr&g&_kvju($F+VfWo-oNv#t*WW|fw`bUW zAis~+1H0dvym{FDK=S+Ad?TNn@67+-obNc7`F<3i*I0Jk-&J z$Asejw4JbfjtM2^>a8Aje*u02^|1RZg?+xT`)h@LzOehdEMG6bVLW`F{E&Bc|Acsd-3NO;F9>@- z!|vY|_UlI2eIMceQ?x&~gbz?27V#wE`UBO^!B17@xaWMi@Bs5%Ck&XTnb(C!H7NHK zE?Q6f3idXX3i~k!cE7o>A9G;$$u?l`+5Ki4FduIN)iQ1Is!sC1{!J;br%uWx=3)24 zg@;O?<6u0@I^a19XZI7t7xN-O2H5MN-%8BG?xzX+^1|*Lg?)Kp_Xi34F%5R#BJ9UB z*gfa3;%9Yv<8v9;1108R&-WFspP}vF2yRr~TDX6cGW*T|<9+Zm)z5}4-$U5%SHoU^ zu`vBPP=3RBcoX@dKb_sPu6^Huy&kqt-*;g5tY7a>*gfmX`xACQTG-E_u>0}Ceh!7* z??V1L?N8YK?&QtG?hhnCOZx|QKb^dJ*nKup|-;f=cs`!xyd?WApfjR(8mTG+QY*ge~&Z*Q>s zWPd+I+whzH-F&>i??L^onuoofeW>3&?4JJdb1UqgV}dUi?EY}Pz5fNfUn2Z_+sVn| zeLI0Yze3pShuvQqdD#7p!hT$W-Lqc&xCFbull%*v2u=`SB??c!<$HU^6bXj2c$+6LVd~B?hjJF5&{C2|L9@za3!oDxS z?nesyz5u&tyY+1*-iGIh_vL~;KVR6F3wGa5{$*V**!?2%=3)2Ch5h;mcHcv||3Y0y z#qgoZ1BC||S4V!laL+}W=`8&Ja_zc- z{wnIG^}z1C^#P^`MkL3G8d{1eZct2jjUe9o0KVHG^>&bKT zTL#$uSn}p!_fv$6N_4qk_p^nI|DgQ?yPqRmVjgyXB6-_>VE4<&n}^-={)lf^@p~ng z;5X9tz@EQa*k7B#?s+}#uTA3D=A|tEVr_q&aQ`EeC%{K4Pl1n8ULrie@|Q$>W5h2B z_qWXZ5q}LIt@U)1_IN$qd#pc3J?{(mH{MdX=Mwcd3y(ThxwF*6KE*KrW*Omb^20vm z?4EOh?^Ce%3Dahev-Sv=M_ggN4*qz}!0vlT9(FH(VkuL;RP(U=P4FkEhuxRqPgD=P zuMzgP4Iy)qW?;{3k3U&G?0zS_%?oxv4u6W~VfP0J`@9;+EYl3^nI`S6bD@is5m z{UP|%G!MH!UO0QY`jf~+Tw#1Fez|5~_m>F!w3m~yJnWgP@qg55VfXh6`?P;0WA($H zc^H3&P7Awdd-iF$w(TU9eZN+4+(hTgGP4HK%huv2S`?R%WY+Bee z+u?0m*!}3p!|r*XwEP;K7wrB(VV~D@GS_Mb_RLKDb?RaFE%@uz!|q%0H>ii*FBQ(- zsQzR!5my+WhQCQOu=_tn(_TU5X3fB!xdwlWde}Yh`}=$!Aako`V9)S)Yx!;JVfVa6 z=N@*?ZM*W@H4nRgPdIyr`j5y&Tw(kf{!Y!n?*AK2yM~PRX<^T-iT|@s3%f57&fcYd zQ~6aMafNX?{%*~{?zf3N?0#GPJ@TInu=`QMKCdxktbW)tJL7F$uzTLRa1XoR8-K6- zCj;!BTe{`W4jZ72f6ryJr)354&d*EPqh`lL2=BsIbrLNisGs*famY+q_`+FGn7B|4;lw z@}CT_`+o`hyuKmxux4P-{2Tv>df5FMa^YD1H}$alHSvE}54-P;XW?Xk-SfAb%O6t@ zyWd7Q`?&gT$wXXXT!nu^GqC$H(X=~9)54zF6;G$i0K4Bi^052;@lRk0e3V9)UPam!!OX<_#zk%!%Hihoh_u=^@uU#`JqUeXNgnW1=gRvBRT zy9)cXlgYfI8Q3#><6l(|yFXYs`{2S_F z_b1`sR1dpfj(0rm?`s}*&)*gFWry9rf&W1Bu>1ET54-1U4t&{R_rD1Hvh&eO zUv}6te6+IsL!B4wo{y`!huw3#-_)ptsZuNiLg(5IT>3n*fUq-Ki6qt_qRtLcF*7U zEB`|Cu=@w_)(^1zNAUmBJnViI{!8_+`xo$EsfXQvEbPm&nvAs>_RN>~uXS43J%2OM zr|l-}?SwtE4xWo08DRIN!anWhWWLo5?3pd`w(el}!-aj?dNSYXw6JH!;;nyR_fv#@ z+G%9I*J)wTG~#W(u=_>ASuW6ISWG733ge^kKWGMae`4fe_sj7A(LC(_5@Da$gH;{?A!uS^aTAG2~-yM0_{a^6iH4nRg zR@mqDA{nb6_ROnzn-}c*%zw``+?*qJ7#8 zh0E8~4D6W_d=K@o`)!4@>#46I6LE#{V0=%_!0va5JnViXzL(}<_j?Nay!Ity^~0Vy z0AHlj!tR?Q54&&1_tre@{s`f0AN9wOiMYb}c>MaBf!!~QJnVisegnW4jZ9ezWd7IuFtzOQ=N{hj!J>S6bf3;VpDCR3~#*fY=KOVq>e--tZy{vG^Anupzg z5_#DD=lG2^54+EHFSM8Z-KYA!S06$ zd%tZ@rc~>MJu?Dt)57le6wYp@`F+VmTw#0wzDzT)`^Lz_?q}o6H4nT0gRsx*C^A+* z?3rWnHZR!y$&rWMpN8LD=LNez3%`YW*!{WqpdNOAy|B0KW-=9;fjx6OeoOVR`+M;= zFWCKG@mpygcK@7kc5C%7k%_p%_%-}Cnt|QF6M5ME2l)P)hu!}m?DP7WjMWc&CL@1) zy?lU93%g%4^0520@is5m{U*XbuQD-R9$%?>*!}L2hu!am=SH0ju=@ie54)d^uhu;5{-DUi?pyFRnupyl#Mi2a z-5-u0tR8m1B=WHPrFdI+u>13bvvpd}MPwqbFuoK&L^H7aJECdtCbOMpV9)#oKU6*J z{#oJdF!e8ziMYb}Rs8mvf!)82-$6a>{(bz8>S6c)7WR4lM8@ieJ@a4uaGe%*-&GzO za1Xohjvt|U*!{-BKCjKl*t}rRY=IxC)57lSgtMd64S6bv z347cAMP|HaV9$Jm-&sBE{ztsc3wHl2euCy<_g&T%Z*73xuZ5qedDwkV{4VNY_kHlY zs)yZI2>Y^ZLuQg@V9#ue-%UO2erV)j_dDWu*F5ZgOyptrJL4y79(F$&Z+!*3-y3gz z0=u6YdD#67{2p3A?EX+;U-mzc*;6yHXO6<}r5<*F3f|fVyFVSjx8`B@R|)&Pt|POL zW?;|Ugx^;^?EcS@huzP|TFI4UeAF8}5yhwR#_%P)he7G{tRc8O7JO*B@JQ+Shxe-26 zc|LrU@?!XCy0A8y6Bz%JMbMT4EZ@?!h^UO^4 zWaaPRQaXAr@_}KH!|(D1+FlE5Si=LFMzLCK8*Yg1+FlE6qy^Z+i z3tVA-1({paUku->d>Q%M3S43S8Zx)5za73qna4-U?<{bIc^+}d{#iYb0%Y$}egVE) znYTa7?e6VE6i_1=0)`t@P%6EHsq;T2H2nR%aM6m{V@0y<>9dP|IYBM>XY}! zt^fDKzoz~`_@Bzn@axKR;Wv~Q!EY)rhOPfkgzb64Wy0leX$JOZ+s+{Kw)zWUI!1;+ z!S5>H1izi2`cRBnR5Qf`L7R$d5y zqkJ4}eR4Ydt@<Y}G6>YpQR9 zyD1+ETicF>*HV81Y;8Le?ymkE*xGg(Y;EIxz3keW;k~@ncA1_fUQwUQhXT zxTiAjwPkxLuZB7B$nZ7XTlst8@;(KwFyCF?2k~d6dI*=VuNl~%aq2^c1DFh@@P^8p z!+n(p!Tpr0;bP_CaEWp~Z2dC{-bno(u=US0cw_bR;Z2keg?VU5h9h8m_URbm@>2D% zKihKxna$Ln3709K1D7jb25+u>6}&{ZvD@G+)c+Z_Ha`pp^^d|Fuw{52-ctExcq`@i z;H{NE5-#UJE(2U)el;1}H-CZqYo@cjFOVIeyf!>gxfg8Dc&sm6zO8!L-{a=}sq7&2 z6)-0a8Mc9K8F?QnTd961Y}@1*xJv!bFegA6_J*s~?+@1~9}L@h=MV71nm+}u)yz3C z4|B$HD{w^M&F%mZICJPHp}eiGhZ`DJ(q<$ns7?^xgp^KX-} ze&#)wtUV*~75U+shbzo~PiBPrA7PtzP40Dnq{of5xz{~XGjN6Zo@7R;?*rSko5A(! zllNJ6DsYAQt;vj5KQNk>_gS)I)Q^VkIjf2ASoM3s-c$KIcrWGuz>n*8(nao_W_h4bhPB{*l-Gy%Rqh9K;UmLV@czn!;3>*O z-~*J0!v`vlfu|}@gr_NUPd?kAJOl2g?U^N9K3zTR?-9=>GeiAhaHH}OaFg;$@J!`X zVcQ?ig=eY15VmE%23||&dxLQKY|X$G=5Hm_to}~;6U{#gAEf>b_+Vx3V`t|me+u)0 zK!z`b%jc?x{XODu$+W2d8J?%ijg{ zZ%|-=Z*e4<1)ARlUZ}h~Y<+kje5iWvIeXh$;6>^WhYwRe61HvoWcYCPr@^)jp9lXz z{YCI%eq*l(s^wGS19*~mujX8K0$d1ytQVw7xwpeV1IvS6qyq> zzbkx_GWSBg4O8Kh)z5&f&GX<>)VIOQl#hi^RX!O$O?f$7r|nrGTzYswIQ+@@$Uio#{Udwz8-=KaqY}?+?FgGe> z=(3(LHz#E10Z&%m5WZ2TEroAV-U{ABGnMeo>W9L&DA&WcDo=!OQ{D^SPp6#<->!Zp ze24Np_)g_T@Sl~Bfv4!SC%|{9UkTr>e1UNJJq4~Xe<_)J)!zu;r+gRu7v-nn`;}jT z&(e9l51+04CHz;-{0z6LFX}1$fck#$gUSQphm?oF4=e8kKcc)F{5RzT;J+(3!;dO2 zfFDyn27X-mRQL(ybKy?PSHMpy-vU3S{1A2+6*o+zWnFd1Lr3W%hxrU2m{vvu~@HmoIXkM_EosvVSS}h3!7` zM(_o?J(R+BUw3o(O7&a9*C_Xg?OyI6*zV0%!*?;`Mfv&s7}c5ik#-tM*5!?$Uj zW8piLC%|_qPlE4OPTsGv`>6ZiPuFYyDX`raod%z+z7e+jjkDqBwVpY!-S?Xh+x@+E z_$AFOg6)3VV%YAd9Sz&PrsH6{*K{ImpPgI=f3Ni{hwUEA3fS(ktc2}e#|3a#T`!lw zy_GMA`zT)x+h?Y(hu2qsGix)O=PTJ1LV7q313ZAa{ zRj^%iz5v@b=PR&X2fhw(p!K{B+x61>@G)A?$FNn&Ai7&e1=^ zc8-=8{`vD`XLu*AryFd?%ynQpmU6j}?Isn-z;pZALCRmlwaV*rPiB~M9XwKbe|W6& zk?=0c$us18DDzx*c3a`K$*(aPWAmn!p2Y4(rGJdc;XRrx{qVdbA-R)P#e zxrXNp3}ooCj__B?JHbCGw{T5TDhn;cAdc<(D!;@rgfHHZ;TDb+d|+LM)8q>;vY#r~ z_YvmJG#Li2FTAPpD!4}ZW_j~9ySwrd`BIE5Z<@*QGklctWBr8hR_3y%OqP=Y4%Yu% z7L>`dF~GqxoO;V-IT_$!8CGGLEGGjTEW>H3OqQ7e4wm6`QYP023~;avhxIb)7X~<3 zhQo1LPxWxH42Q@v={p8ESmral^dkctEb|SXFA-7>(zGJHjQ8DB;s0~{>F*D96uRSyTtY=M{c!2k!#48-&1xeRcy%wT+pdN^2y z&nuN}q#h2I8H?XoJsd2-%E7ZfmGMD4GR1XKsT#w&M zJsd2<=aR~{Ru2cu+>75vJsd3a2)@61I9TQ}JZ~Dy00+ywiO*>s4tA{j5MQYt4wm^8 z|BluJ2g_vE6hBz=aHv&Y3tv~@V3~FC?`l18uuM6gFSd~Z4t9*?J%X|w)Wg9tykAhp zmlMbU2g{7ckJ3CGMk?=$uP<=0%w+ugS`Qp7(~KXdc{q$!ZpDu;aInlm{0CYO94xa8 zzpLiqVCRJu_(|&FV40Qp549dRSms9jo|=b)ol|bb^TiA@z`-();rG)#9PGUF41Rz0 zaInlv_$lh)V41h@2dIaGWj?|ms2&cM`4T@>Jsd3aJ${;cI9TSt_y+ZGu*{lr9w?ix z9uAgS4?jaa94ylt|FQN194xaHezxY}FiV;DJIb0194s>!e~@}OSY}83!Rp~)nKAe| z>fvA+-XAHOs~!%P*%#lU9uAgiz|T_;2g@|$=c|WQD_RQ3n;aInnZ@Qc;M!7`8IKhf<04wiWfe~jkgaJ2Hr_$37nmf`)KvQM=hI9R6B zTH;U8JRFuPcf+4p;9!}a_>}FG7ItNsE31P zj>NB24+qOE#h(s-+GF#%WR}Tlv zY>U4^Jsd1kgTGNd94s>gzgo9vI9O&^{B4?t!>!7D<8Lo;u*_8a9qQp=89s|tcBgtc zSY|%{&+6e|nZxjRsfUAQmf-JJ4+qPfg1<*S94xZ}f3JEtSmr|fed^(08Q#k)`-^%w zSmp-&{p#UhnLF@*RSyTt+>QTS`x6e9`3L?H&BNhg<(Kh)D{!#PTll}Lhl6E4!au4W z4wm^B{xS7%u*^63FSI>yung}HmOZU`I6S4?6aP$sgJm|r|3f_-EVBuIm3lZ>rUL)0 zdN^2STl{nC;b566{J*rFaInlc{L7k$!%ND1KB(-K0td_NhksQ)94s>(|C)L@SccC5 zmHksa94ym{e_cHsEW_u0%HB{92g@9be^WgiEVB&%mU=i?<_!GX>fvCS^YQPfhl6D< z#lNc_4wktZ|DJj{SmqY|`|9CfnS1absE31P9>#yD9uAgy6918UI9TR+{Kx9yV42tO zpQwj}W!}SosvZuO;eFMz&(y=gGGF3XtA~SS{)7KqJsd3a3;s*pe&Ar4-s_0}TJv!D zO1T98O@V`D%JJW-hl6E!Pqyqk^>DCE4*$J+I9O%~{@?21V43alUuiqxV42DIpEVDM zpOmNIe<^UVOe6kR^>DDv9Q=RP!@)8O@Z7+Y0S=bob3DDvQapd~N(MMs=5+iT z>fvA+K0{Q-O+gvpV3|MRyQqhQWv;>VaJ>w0u*|LaHPyqxGWX)S(I^8PEb}maE%k7) z%#(P&I9UcbSccCBm94EF4wiWx&&^92;9!~e@$0IGgJnL)^T%^!fP-at-??l(^>DBZ zp9w1KsU8lNS#w?Se6T|MzB0hUGX3zq)x*IurT9MT;b569@$0LHgJp7f z{?MfiaInmF_zl&=!7{v;UB-tVWPpQZ#^d{`hl6D%;fvM7!7}^eOVq=`GSl%JsfUAQ zX5x7;Uj{f>W-)#<&BMX&!5)t<}o}UB9Q?OmRW`0Mm-!X^D4f-dN^3-9sB_G zaInlLc>d6n3~;c_SNLt!!@)AV|6VpoJsd2vMi23Pz(oc)SY~Z}rFuA6rZ>JyJsd1k zg0EH&2g{V>Yt+NRGTY#5)x*Iuyr*9_SUnspGYns+9uAhN#}82t2g~e?-%dRoEVCPa zsCqb9WDBZ&lr^Lq#h2IxfwrNJsd2DDv5BOcx!@)AY z;wPzxgJrs|Cw@2eaIg%|LX_>U9uAgSA3s?=94u3U-$OkdEVDU&PxWxH%$E3X^mqsd z%j|&PPxEltS9uJ6{{jcgOu|o54+qQagFiq$94s>pf1r9eSY|eUs(LtBWJP4+qO!fuE%w4wm70 zkFwe7;b56N@y+VtV43^z2dRgHWgf*JtR4=Q`3HWEdN^3-W&B+AaInl<_!jkWu*^sJ zdFtU{nJ@A4)x*IuKj05h4+qO+dWvsV4+qPvg>O?22g~%rx2uPPWq6LIY=L?>Scdod z$`-1JgJrhHAF3V>mZ`)qQV$2q)Zq_P4+qQah(BCC94x~#Gi85J4+qQaf?up24wl&) ze}sBCSY|5zNcC{A%q;v->fvCS`S_#N!@)9#;g3-d2g@9dU!ookmRX8FRy`ana~l3Q z^>DDv+4$qt!@)8a;g_n1gJrJ5pP(KNmbnRkqIx)3<}Un6>fvCS2k|GXhl6FFz@MTX z4wiWizf3(GEb|)vRP}JM%)9v0)Wg9tALCC~4+qP9fnTm34wm^A|3~$3u*{G6Gt|Su zGMQfD&r}Zw%XGu9P!9*o^u(W~9uAi2i$7aE94u3cKSwk9Wh>Rg!7>Bz=c~dhl6GI!C#~v4wjjQzgRsSEHfK_iF!C# zWfvCSMfgkA!@)Ag;4f1T2g{s{zg#^WEOQ3_3iWWX%z5}L)x*Ium*THd4+qO! zi@#bu94vDy{u=dgu*^O9Yt_TSG7sXfQx6BrJb}MnJsd3a4E|d^zr(>Y@8NIJJRELT zUX8!Cz`-)#;crt92h03|zg;~XEW>kdWp}8DgJpW)?^F*5%WQ!EvwApKhUenS?otm2 z%WQ$aTRj{sGXQ^&dN^378h@{PI9O(T{C(=-V42bQzo>_UWp>5iuO1GT*&F{?^>DDv zH2eeV;b58B_y^U)!7?rQht$KtG7Iq!tA~SSj=(>n9uAf{4*xgxaInm&_`j=%gJo9W zA5{+r%UpDDvHTdszdxL{z?#Dl)c{n_+{3!k(1rC;3gnNRW0tA~SSzQ(_x9uAiI3IC#cI9O(l-r`?U4+qPvjel7^94ylt z|B8AzSf&L3s(LtBrX2s8dN^2SYy3ae!@)8+{OjuBV41=AH`K$yG9&PBs)vJR#^K*m z4+qQaj(=M{94xax{vGvjuuKE~UG;FVOf&vH^>DCEEB<};aInl__z%>>!7@wmAF79g zWtQUkLIoM%V3`Z>pJ^TrpDJI0UtQo}nH%t*tA~SS?!bSc9uAhdAOA1)aInmy_%GGN z!7{7xU#W+KWnRU9tsV}Rc?bWEdN^3-6a2U8;b57s@!zS3gJpigf3F@6mg(F_{J+)1 z!7}UOe^3tx%dC(8k9s&*W)u96>fvCS3j9y%;b56T_@C9o!7_FDU)00FGQ;ry*7XYq z%j}Ntq#h1g<^Az%6gXI>5#L!o94s>z-$gwfEVBULRXrRma|C`(^>DDvQhYb{aInnj z__fr-!7}IIyQ_zTWiG+5tsV}Rxf;KYdN^3-X8gM9;b57&@IBPS!7>lx*HaG%%RG+n zsU8lNc@E!8Jsd3a8oo$994zxTzPEZfSmtAVAN6ps%$NA})x*IuKj1e|4+qO+*B8H` zdN^2SEqq_~aIj1-d_VPYuuL(&SUnsp!?T=aCF#94zw({FdtB zV436aTd9YGWtQQ$Ru2cuoQ2;;Jsd1^A-=zQI9TRN`~dZEu*{A4f$HI4nLF^?s)vJR z?!^yM4+qOUg3qakgJmAW|3^I>Eb}J5Ry`c-dFc=FgVn>qGN0q?)Wg9t-{Xg}*w^t7b%WQ(@3zKAkgJrhB@2DOQmKlg2t{x7S z8H^vH9uAh-5kFEr94s>yKT16uEVCQFUOgNvvmbsZ^>DDvbo^-baInll_%Z6?V3}6@ zSoLtQ%whO(>fvCSCHV2`;b56l@H?xAgJsUdPf!mB%Upn;s2&cMxg5WXdN^3-YW$Dt z;b58j@sriV!Jf%~6u*ahI9TQ%_&wFb!7?x7_fiiB%e;Z#TRj{s^8tPz^>DDv7x;bE z!@)BD#_y*d4wlJmD1LwSaIj1_{1o+YuuM<<0qWsknZ9`bD4Yy%u*_!osp{cinXT~C z)Wg9tIede9I9R3*KV3Z>EVCnihI%+yW+!~3dN^2S7kra?I9O(H{7m(5u*@|4EcI}( z%q;wD^>DDvTzs>7I9O&O{vh>mu*~83pVY&_GRyJv)We}g`CR<`0td@nia$g>94vDU zzEwROEOQgSO+6eea~Hl{Jsd3aAbx>*I9TQ}{6h6`u*@p_q3YpanOE?O)Wg9tZ{ZJ9 z4+qP9j6YmG94zxC{txQmV3}|6KdXm>WxDqjf3$iy9Hm@@Kc>LJGR62M>fvA+KHE`t zta>fvCSO8oKa;b57e_@(OMV3~US3F_fsnThxl)x*Iud*M$~4+qN}h(B39 z94s>ne~NlISY|$cnR+-_<}m!J>fvCSCHT|S!@)AA;7?Z%2g|I$FINu-%Upo}qk1@4 z=5qWQ>fvCS8}MhUhl6GAz^_mb2h02gf0lYUSmtl|v(>}FGSA@8Q4a^pyog_^9uAgy z9e=KRI9TRA{CVo(V3|+x=c|WDDvj`%Cp!@)9R z@mHybgJmY+uT~ES%j|={Mm-!XGYx;OdN^2SHvT&GaIj1Z{(ALru*^dI4eH@wnIrKx zs)vJRPQc%!9uAgSj=xzw94vD#{ucFcu*{|STh+tCGS}g6Qx6Br+>XCpJsd1^AN~&Y zaInk+_+Qk+!7?x5?@e1w2$UE9F=Djs>nTe?1w? z-wcn?%D6`&j|A0%cf9{-y#~n7^5ft*_hRTQqYQ`3DMIVg9Ko zzY2axGcS;TyucOae#CvW`>dfqQDjA8_8Jv zXTx7=W)Aru3S42H(^Ym2t)Ej%_D9Wd8Ytgb8Y=@_Vg4~P)}E)}O*ONM{9XmFFu#se zo$ajk_k>yDGV~EHzoEbt=Jz1eMf3Z>H)&=H`6mioVSZVZUkwmnaRchd}CaZ-M8fh)|nld<|2!E-gUnEc`bSD0T( z#_H$mA+kqm<`VLE7P!Lv17vJ_dj!5qGmnwKx4;$VGXvWWo7>(nU4FN>>hIZ3?M;i? zGXonN+8Z(hr?<69M7gzTPQyS(4xHT7KCY#?ebPJ`*}+a)(AqSqv32yEhFS5LF-`6N zd(7zOmWDZFn;IIMThbGaUeMM&uf@jg)i9^IF;(lBmbSLh&2!qDT7RbkX(i)#ZEgOY zk+i=<_2XJ*&WmfGw6NVK8#Qzn4ZH~dbcCpRo?O2)}d((O$qjQeurVIGa=Kdw#Ik5xT>LB}Q2){mOk)L{bY zsNZSI_yvu#nkKimHZ;$g-9EX!p}oUIBN`iJ;}|`!bwb-Aab=^M+uLO|PiSswN{tyc zueG&lM#oi>iu`7k#WmA+|Et^LW!|}|sl(dzMHtc6*4!qWePMH!?S{?gfArO^3zDU7 zo)J$nYIf6%gKbOi;H7c#s)@(3RFj)p+UB*^x9U2TeQw~asm=KvY#zHG`)O`qF4-ex z?96!2u<9C{rZ1Q^b8(u*JB)2EY~`A1ZD^U*B)hSeWG0z`Gv>{m+tea` z(K4^SY2cV$_8idG-Z10f4)x5DHP}JSY;Bl}X>Oaba9~4wdu#Lb1?^Jt|HDusS&sZ& zZJO%Tw0acFWHz&$9Qu(a9kfRVScZ^88*#u`OVPh--Y_tlCsygL^!UGmjb_6AD5GH`|6|m$2H9F)weQLUwc%aJc6FD@BUPMFa3}D?oQQrc~qY~0-3Lmk7mWo`~Lr^@6}X& zFGTgpBQ^Q@_y|v2-`7%KsW=~`m<+NylWB%)G1FPD5623#etXN0uaAwSvba9}&OoD0 z!!NIILkY#}V}jK8zKo~7_2tLwt4Y z*6)N=eSPGb*0<+=QGIQx`o5L=>b!CC+uPTYs;^$^8z$pfUXCf=zSC3nah+$E(~>IG zcXFz}qa`#!W=4G*%a7NmuTcues~|h~NGh_y+sC6_Of%g4Q$H7$cT;g*pT34E)W=tf z?O@aJ%j@Hjp18iBrM~4dp7w1fKVBb?8pyx=@szI^TqI>5ygnXf1toyuQs-_1!K9vrW7*`R(;>nyPO_ zHk;pGIL3Q@LsRuVC-w1q)CaGxHdWsvQXj`k+P9Vbczye(>f1#Qj$OSH$vN&J5HIh1 zc|pI(mUo+|zC%*=?I8z8`+71-73!Ols_)}9vl+g&koIw_#oNcN+jxDfBL}m$e`k5Q zwH&wal6A8gUZYVTw_m(IZehjst?rr0eEd80af>akZ&0sne*Na6`kqYH_kuj1#dhk0 zj82BXr|MhYC!2Xi#?U@LmvX-RC{$X0M;k@Dh>wYUIb4mzUe| z^6t_nlUb6~r2lz+zozOtP7bj2GxZIQ>f1O~-zur^iQlQOujJzXYwVZJoM`PE64f^} zRo{8*XENMR^1<6zo2qYhNjAevO4`TmFJInCsrr`6`-2yGW%AqW+c{O=>`k(n`)ql) zkLsJ9s&8{S89eYi+slkpeVdnNGxgFa+Q+RrZy(o4@%nhbZzi*mjQ7FY$KRoe`){_~ z1oQLd2nl^8@1;uC@7AYB7_M9N#hK18w5x?o@rNm&IiwN|0JI8qVcjmWSN<-Uu&|z@%4m04RxG9Li#Tfj=!YpyKhD|!!}NR zJIjwR2lrl>hI2i`Z6h<8r+p9Z+IJ5#iw1HGLw+asmMpIi zo~xFe{L2it5iiWlW}X_N%P~nDZQJ(^20T})R!MtJ(bCv z8uG<_eO#-?x%pRSGtE?DgU@%{+>jxq(U2QlnX9g@tE#CfEzJ!YluQ1X@xry$)up9_ z2i4YTd|LOTcA79coAsJlmT&U&XEu+>F^D$kYq%{lo5~fy11mG#`1;=7OS@#=+3B6p zTc1#Q{B}!^Ub&$JXGxmzgBjnYOXiZ5UaIJSMO0dIi{rDGtdzgyCW9?b@++I!&x_g2 zfd!nB$6nbjdi3tHMvtBwmh|YA-BXTfovP&{uH$;|*l)YFhpyd8jv#AnkQvu|jUE)G z*L!EzUR$xtx=D~ios8+axfFL;n?KjP=D=*PY*E+Yea{)$PbaMC$J=4ux@0s;DNzaw`l80_Ke_Bt((1c(=8GO>-E>~J zNXGDKO&zTIzSPO<>trywanDZ6w?=f@n09B<6D8jfwC;47vKRgGe?82YBllrS7dEwW z!?QG3IdIUxTCVYTC~*T(bi-AJXULutsdKBt+fia{XfsVGizoKLEE18e82BMzhtlHdFP#X?z3jC zHET`B`sVt^&dHq}>ucBG-qz&yhK|XdZQUL9jfCc|(&V+xlzRfX+f>`p*xB9ERbK!8 zk+yYrwRd+RS#_-q8z4H-~HIx3#sXr7d*}+S)oARA+l*V}p{ryeo9t)w;%Y_3ayLJ5@7oaCNtK zHm_-IY$zhZ-D1(ijZ0WixEY$lBmWw0HS!kP(o%^~J9q zHOc=GRa{;^8Gp^K^)1~EjqhKde}_i&{*heX*wNb9GP$L>tFf)q9BS8BOqo@V7Cm`U zciokZ&9zJ6dtS}tcC>`1wvKgBTiw}MALT@`)uK8ZJDTe18_U=7WD~YtjA{siCl&SZ z=gB8MO(pbD7tfC+ae%+Q`MG+;`$zcA1e>3NBc_0uYvE83^j zuH#P=f9msnjS>H%D1h^!D2{VMs=eO13nl*UzLq|RMAqZD;z+gEJC9CXM&F%(Mc>(Xnv&k^ zz<%%Cg%W>fU%0cc&y`;KouQs7aUq27r~y3D@^!27sp~$ zmRC_EllpS$3(Gq!pD_PJgBa4)7}$2HN>>xWT`JO51$Ytu#igg*bHm+nbuK(`8DLz2 zisp)1GFVUC@3G#{|73&-2C7ftcTm*K3-mSjhds`)B_975@bf+XBXHg`6<47C1EAF7 zuYp&1ocEn)dORC=uE&P~Pw@D7;L|-`3B1tbi-0jNHLgIJB?5-`RgLgF?D=;C7g=@m zSKfnL>-p~nzQW_T0yB)b0(EzUDalaZ1ozv+BjDFZItA+K2va{x{USv_OT7+$d!&Q* zm@>pN8{n!>YGTM9>i4Nqw0OQ#g6@}*7Pt@X958`m_qP66v$hoM*>@X%2F@VJ>G zJ_D@9lRi9%4JbAFWUm%00$LiOQ`gZIs8m43e{vXjPfN8wb$Tif=+sc1*1hD-NTst< zX=N&%8YE?As`uTuCJ64}Ih-rtIag9K{7F+py=`)?Z>Bq*w7#wYuc(~MHo*hfZ zQ$wzqtvnyx%89KUw+~c_zF<^*?IM!nmS7|&w)(}C^8^J)Y~`F~#70so@x~?!=6NkP zNiff8v2ww~h$joCotT-H@p(yXs>oSRF;ic2hsaEr;(= zhc}_&9>IU?ObzvY_Sjj1e@gjW!9OFOC-~3A^9AFP3idJ)jK>Ywhf*-_Z`$>s#HB`# zTj1FHN_2R>wCh19QGb!hiS2sOY1COP@-v7{87?MXBJy*A?OIaeQX{XS&Qj6guPqa{ z=a^|5S;Qu7Y?HBS{J`;iV$;T%SInf1ZQaJpd+IUH_u;N)T$zG-9*)r%+=Ije1V2m6 z#tU~Ha4{n{IBCN2d|X^2a^j@Xxr=f$g(SB7g?yRvF``dw_X{~fIU6+`vEAo`&qj;$ zMNXVFI=ugG_mdz_8l7KK&P>A*+x7vMT~I%2y&$D5QVMNVw@=g{R=Dso+J?1*qh z_%GolB3u#vOO2e>95edt2C*Fcz_EYvJ9c!${3b5la{OEUmBg$-xC`)K!U}{VE;aHN zV5{FwY$mc@z$NVTaKxo{g8SF3^K)yTqEmo5C3wrC!n1|v6@`*}BA!na$oR+-Cz;3S zn>(T#oqz3mr2nT@Fbzk!qv>DKAK>!py<9*19>k5_>iW(xl4#=+hX ztPyZR{{P+_t=@mbfSD4&$LaC5y%$`K*N+CYivF>F`2ZHvgL>w37AboDpycOcKk`uo z8S}x@n$5?Uz}}cltlQI;i}n@2nS5hY9-k8SV5idhYx`!^Y`(wfsq{OFdd6=_TY7#;(S7e` zZTu{9`^!yu!oRb8r+#ACC!sROJ{pVUyUKUfY`LMx^0M9c?9Lq9CoSUF-m|$Tu{rXO zFI=2fajg8YvZKjIE<4inJ^K`r>DaR+p;jMWwzVgj{_d)6Pj36j_GhWZN+aT-`te<>Ct7ouK3>esde9_ojvIZ6@PeTTH~WO_PHC6wD_?f z+EKn^)=!Qd%g^}9u~|QP_pCh`4Shw*!uKVt6`5U)jrkCNeQ*- z^?YbOc5l7vn-w3wE3Iez57RQo=EQ9}Sc@s;f!ecvi=w(_9d2*8^7tcFsIgfYuYafF zv9zP*kCgRVYfH91zSY)Q+HFkV-M86%up~!+*DuFeGp9|<&zL#w!I@8;wP)+hX*MpF z=&Z)3ru>Y?rdf?IqkbBjSi0xmpQwKHemxerQXgx_-gE>f`6{zj^Lnc>>Nhvwi7=EeF!G zUi|dZzSUP(*H=A^{xe8Dv1s?P8zXk?D09O)vetH$B$N(Ucl5QQy>Aq}T2QoivHI}B z^J^BLx2(2id3ANwCEZ>1rx%T#Qqds)Gs-KPCKk1??}Ct^p+kVo;skegb+0z4gMk~e z{}P*A>OT6fxBMQ@_Cv2UB~NYH5rNGG{K?A$;5UIfbimPBF|?PmjG#&MIk5HyPY(NG z7oay72FOtRa0=MOOJD6me?OrUo(v*(*x$$zB(oDuFR|%1}s0*{OoP zm!FqLAO0N|Z^U9;X^}Y^>m_F4VlB%p=IBG1lXE7d+3C=-%Rh3)K|TVL>XhXfr(BuQ z{}gLN@=_Lo3^;ia$Us>HlApSEq=3Qp%pWoUr}x6?Da%R*aRCcgr7%Z>#XQx9lpA^J zP`kinXfKJ9g(SlYk=0VnZ-ysPVI#~s5-!o;`~<&xTEXjwlbxR3%z`|2TCk2JHY$Bw zY!C(~EH9(~U|AocZv_pJ{dYAUIz;Pyi8{kZI6S;a;~!8yVvNRb5|13KGN_z+4}KDQ zdXI%9oI$Cq%=lp*;nH^LxqTu%{-g+0JU{!_fU$Ug)GnO;Wzqs#5W8F}hgRk|y*a5?=5V{#LK6kPNly|i zf2qbgZ3~vGxUNzdN;}}1Xu8*2y=O|MsdOHOx~q{+u8<6Wsa9R{XKD+)FUOC6SAW+%$z7|&6u{#NwQXqb&**vV}uSnS@z}D zI#b+ukvY|k7nv1B&gL{}8yHSi=5$HV3gQ`3?|X@7qQ1;F<0|bg-SacE;v6FA(mof* ziaddz7tgf#NF&KSEj=%Dm?ms0nZqTU8jp~stCKoXvaGW+Dp$oXG2yeYbS|q=lk4%D zWtPrqY?jV3e3n@{$M9KLI;WG7o)te}%w#5!jM19t=!zv78kcy<7~>^lY_96djqXRh zgrE3tjHSfl^t8l6O&D3?Y_X&L0OC>QrmtI=Kq$|H4u@xq*sVxByxG zR$Du7#fo_s*48Y(sJeFLh0CjJYgH@WJLbAJ{7#j#<7YSOPt^Q~4Bny+39?Chv_ z>*4Cx)^#X-5m39lYK29sRvIK%2}%d7K{$W$-9r6hs`gsUcTMq>v9qxY3+_@D+u?rj z@`et1ZMajv{JMba@oZY#JKC^Jv6HeZy0N;iuD-qo+3D zzfM*L-q%%F)zyJlSF4)&E-_X=GGup0UHwM=MmnB(*R?maUD>)|E#G=w*^D<ROLpdT zw1WCJtc}C#{S;KPRkU_@Hu4qqNWF7yTZi~hoe71t4Q=fTb*P&0qWuQ^veNL@^O}yf z?$!oLDQa{t^D|*;EtZ$6b%>{{k<0Gd@XGu7UG=)`+hwI?FN-=;mvC0M zcB@9!s=5`BEbU|)mQ|r>MtVUeFFgg}%2d7;(9Cz;J&1Rf=()xa0<(PjPz3py(?Gmb01Q~AHLpfen&{=UmC+u9pjYt2I8b={pUcD?1~)y-X< zf8VH1wX*XcJGj@iH@|;2{zt1|W$|>a48i~4xYpIR)~#vm_=m)jx^mdAMd~!CLreqe zT3Wg`wl{WSaV@6r(!XlOUoXc^S$nISZLJya5dw2SbYHX5+!PkXm~>E#K?`ey>snG) z_@bXherC~cCZ{51N$==bV%RBG-WrYM`)W)GmjzqnQ{Fe|47Y69Ec=zkzlm5zJdW#8 zy9(H(Wlk(nkR8vYN8&USATh}V>0^#VGUB;fqmR`Xlo8L-lCf4YCL^9EIBlydaJx@~jUeVmD#Jj)-&r>R6($)tH%KtR<}kiDVXHiHdl(iBD%MQ5^rc=EIGD zAF*k}A^Rh>|Im21KH5~6JkGav2T6G7U?8>Sj+clM15K?O`}yWL#l}!>EFtld!hGwK zYkY7of>EcMJ^|BZVS`CbHbGF(Vyurj4w70-SU%7cs^w$j37x$X8#yvA7KX<^N*}{w z63(PWKkwlkw*Q-J!uia}Ps63)Q}FM*g z@9cM1f4yS;FAj5O-@E$#t!vzO#C6F3m)5bfe4R_zbslnkHK&E*@9wV&k8TN>yKpu< z*R`kG@0~mQ;_vJWclI&NdXDSdQ|(J9p_7f0th2F1>uh z?_3-!8&cETJ2$td5K#PG7~y=zD^BfiwkhhJyYz^^%dc>k zU*XQCaI+*Rvd^`K;>5qmQWO8UfJZmyjsL{Je`&zER!N-L#|%1!ueH?JI}-4t0e>do z&jtKf0e>UlZwH)f0mPZ|3OLvN`Tkt@=X0(b@Hy8E_p9uJC0e{Qm zHfA25PuF5ndbpC9mr0eAV6_?89!%LBe5;41^Z z%Ht6P;Cl)7rY*;enD>SY_4wWm>yCc3N&m4p(jK4Novc3?Qs=yT(pnf-Ze*b#uC4p} zZln?aBIgMdSEF_Py7~&wXL9~=q2&DG^kuxiH?k_@vEM(~eq8xWd-cmNwSAT7^lXmo zm8f!He|(=A`4RNf->z`|rJr6)=lWMa^+9Mo5ryfmup~zLN*_vd-{CV|Axo+gWrIEasBl-ejczC<1x$9@1GBW7f1g2>M-yW zj~@kI?s1n_3Uk%-_;vcZ>Sb^@e&nj(fcxe97P#w=x#~~g&h=Nh$cyXm{T0`3XL$J= z0qmDA$L6J;|3qNFe5Zr^?PV^w>+k&)?`gX{^;gTmpNkUIU%v-c37NS5>Qdk`OHrO& zqc_px?cn!$d_xqL!U1Y4xIZ3W2kzR}0R63{f++j|wGaL-y#sXKiadXJ?x8SWf5T;d ze;1z+WHu7$hEt?me?nir+i>s^|Z0aJCU~ zqtuVUD?I)j_%e_G7dSqh66qfYztiK{xc9fsKovEj3#cd zdIWqf{>6<_PXj+=DfIcUbDih^JK(oHf8OOPipp!S>I=Ry;{6pLZ|?UvA2hxc@lgs( z=yad7@t*;n=9SmE;C(&L2aW8bR(~D%P>+8coZnuv{?~$!^Z0Gx_FYGo&zHd`dj9_c zUg7Z{f%6+}*4}@BFZKAZ!THTK>;Fe^^EqUQMyb9S96##$j|AWC@k!wPcD4T4@_eN^6q)gJJVdj4Mo|AgoNRq&5{{@(@P z>-qmH_$JT)XW;jF{=WwA@%;Y?&hILTLwVpfr@LMltcHWX=7k>*zQYSY8~j$Ud=`WA z8%oyRh2T>>`_16|-naGN2;SoH9pKk`d@nf17^{C5_)Q-F2KcQWe-!)s~&#^ z{C3>vyD@Z>>Vunw{3fQ2 zZz#B4d7%ZP)Oheh&;D%i!5&`>&N0`9zYzRVk2ixa_V`9{e&5{cTf}1=UvBbUTz@&z zN#eNL*n#kL9P{~J^k)qp2R;B-FL$K)XQ;0lUZnN2)We2@>bd&kDf-#!CBu2n7>JqT zn}L2Jn<2&J;gD}Q=YRt-Un>s$%L6_$;AaJVQNYhPoMX;Fdv1(qn0l^^Qd3GCg5Al zTEN$rH4tl1p%pE$fu}~w){G6rcb(_YpQ%$YfBvlK$XC9}spsBXrW7w!Pi0Iz(ms#0 z!ei=N&Ww~&z9o(03=?Vw-*^U}No^jfXWxc4VJa9e{H7Z|-NZ11>4&_+@Cw7H)3!^e z2|dfiG|QxWma#U=gr1d}J0q<$T9uYF4x2v8y!X$U1&^{kTK=AI;^S@bln8=1@q^Ta z@6w<2wmeJ8Pj2w;xvnYCp9SGjmX=3@SMym)p09p0-{*m`Uf;U+^@FSiZ_r0A?c}c` zOlL^f7FdF|_QKL+nw)0ThE9Hef4XT=K_>JU2E0U9ut1%`h{0e`)Ve|2WCdBB&Z3N7 zstlT#?nRMjkfBN@Gx7{-TeoK~vC~3R9{h2{qm>I+uwpD$S^1}!5%?$EB zGmJl|1$|2L>{SMBV@A;SW&~|>Mi^fhK8!EO->g7?R#4Nkg7TRa+6&UBPpMvhW(E1z zr&`ayGRRM55PxM5e`S#V*`a=rzS&dsrvTkLKl>3CSu^&2tNx<(kAK z%>t~Vna@o(YHP7v52Jo(Q$tflxH^zF?J~;R+LkV=)Yh)+ZfR(m22j_~AfT%Qp9X4Z z>V&slM92k&wY6(>5Gyka3scrOVs6SQ|FD@cRb=oq9Eou`qJ|qev6WN*1CWowk(hE~ z>dY~6t8aB^pU&zNTl*H%4ju0i51cLf#8%F*jFF|F|<=+GzZsf#P{sgcsPhu4I zuq}ULD`(YOIkA;51-9*k*veOV`ovb=;K_-td=s$k3&d8w8QAs(Vk_TH{Z$MkrP|_L%=q_#8& znn`^lC${p_fd`%~`ovZ~40yq(@dGyw{|i2&p_-3F)%Ajzp4cA2Ohbu>OATf@lyLBX zBerthDYIcqfNfY}t5Zt(jrf5hw(`lqR!(f?Onb>q_<unNDemfT7y?oH$0%2^F1w^1t3z^$CgD%q#SirC8k3E1Z4E7URR zC$>6Yr~LEyfg`r^ZvvO>#}6E_m46$!7~wrP6- z*p?fy)%gYGCSSx>{w}Z$tI+gIz6b#wu+>SYe7~0Jw|cESmvU2v#8#e1xrvL|%EtiP zxW-ZEfY>CqIuj|sL*&F(KAmzC7qOM|dAp5^*vgjz#}0~}<<#+Tslh8L|B~nsTlpF< z?B!lqVyn|e`JED$*vk1DtBrRnb&P#ttFx2xyCf{JmEQ(z!+wD}#y+vtxr6dU5|-G? zdG4@bzeOE3SU6&>>#^q--Qhf589j`A;y4zZQFE$#owq5! zN5T?Y`JX9g2ZAHE@^~8L_llg@$}=E}wTqnNr`-dX^UT=SL_Ua^oez%VcI-Y4^}3Z9 zUtNXc_!)aZLp?Ue%sgriN#yXJS7P z{Cmoe3Qj}W#yDWWWdN5v=5VQzv;W#Xj|USoayV=qq)L9|aH)}xrVb|*aO|hCe-%81 z`cF7qYUC{9*uROK)0)_mf_b`)JtbK8J5FZdS}FgD;11xDryaI?DsQ09zl*$wc#q(1 z)PKfddp^3BIzJWp4aCn1zL}T>4EIH14ybTnBK{A-oD0RC7yJP6&jf#;*qmn{B{t^; zu6wZK60seZo}$hR5>|gl@kPPUQ*P4m3h~cH{%hiw1henNIC#UoOKj4Ri9QnhPm%Na zee7kygNRM~xz;Ae#sW8%*tBhKUmW|q$j>0YMesu6UkN^!_!Yr5#IFioL;PQYJBeQt z{7K?p3)Xv*{YLO-DgST5UnG8A@K=a`E0|jo$KDY91LEHaev0@_!9OEr1Bc_9o7h`| z|3Lf)!Fn&Rw*~i)L;jB7;l#%Ub8SfMgy2eIo($nWM0`;2hk;A}=&&6#>!|Z5k@FdN z?9YPRiFxvb`zUct@F$7c5#e?c#|2+U%o8l!UgCt{+lbj&;qD~P6nr;vmf(ko@75}M zZH^r?xlYH9nct&MAJONt@mRLt9}%0f<+`0%j>w-Q=3oH#U&Ln2*Lz9z6*>37j`b7# z0pk9G&nD&xAFhU&-xPtXB_1gFa$NC@5HpLvK1Do8-MQB;H4nr#N#QB0>AZ7yL^j>D81W#ofC>4AG%VeqGuM=M=_|ph$zjI4$ zzjMnzTii!>MIK1JljNu$FxhQ(7wPMkD4H&R|9a^j@XxsCE^A}3B7or9FKqred-jm}pnpCNMM zq|teZ@|hwhP8yxVl+O}5ank4;-t~xcwRhLJOoH%K8swh8O z`6s`S~IzP8ywmqWohb zCr%n2p8JX~5;<}5Lcxzw{$YocM(0V&FBUm*(&+pj$}bT)ank7U!#Bkr5jkMu zwIU}@8XcZzi!T*9ank6VpuA4x#7UzQ&wzZj$cd9iCx`NSkrOA4P66c&A}3B79j<{b zZWK9j(&&t(yh-H5Nux7?@--qSP8ywQl&=*zank7UYn8&J7M1oVki*EEeWZ3V_&jBvUqc)x!;J-9iL;W6twa=yy8z}M%a40EsxYWp7sAKH6 z6Au=hE*wgRJ6vkyw^HYmBHvFuQt$yBN=h6qHS#B@WAuMaoD`jBa41>qaH)}Vif_}y z>3i%P(cx6PWR=6EM$T!d)#ns5#*D&o%2?9uaH)~2zwNv3cwp>(u_pBc?fQ8(Kj-6# zd;5-!=iTcwZO{LtuiKP&Hq_z6DxL}+bl3NuB>PmFPpZ8DR%{+tm;0ZRmq+sD9c_$- z3nZs-QMY6qM;^Cw((MO`3=rjU)BqhEF#~d!Qd(DgLwY|9*O$ zhJ^9o+3NX6^<@{&YUV?w$-hA-h>{UbV+Z%y-gSE#pu=eT# zd&|L#@Nb<>-^CF4_LjmPPn}F3%fZ^)1nj4;9lW>n@f7UayTMBzhd*m?Kd^6)L)5+a zx6Y>T76^QMM_{iC0hvCQo3-~KFzwlT z*Pt`r{>G2?{{#QNy$a|oh0Ho@kK>_l@9neX9Y@+5VEkzBP5k@zJ^_1XScH$fr^@4h zLMj8jXb+%l1dw}s)7!T_C^+7-Wvs`(!j&peTu8i~J zCAyzJH4pC)B&7U!s-Yj#$4BVCy_+(y-J&P3knfjS%(%0VDcPo$%=s;bk{@rwLac+x zlz4|h&&FFD*egI|UZgF_kBy7(&H45YW1e^zDlF#___y}f8GBP8qq`XPcpYOM?eSmV ztHsgk{R-!4H0j7$y{nBq>tXkJv7CBzH}#@72W4oT)#Lkhem*uWQ)-hbm(ftR`Ox=z zZD1TP9g64B)`-!g_w9i_HquRyv0O@w9_#l$$k3G90kyjsm9W$j9Ia^{ZC|1HFQB)n zK*r-4@MQY(@ZSgjuot<8$x3Z8^C}9hJ@zSIZ_|gcFOv22^e%5QoBNj6m$$9HZ1Vek z>%X#c=8Ty|bnpMI|7XsN=`_f>W*pwBn;(7apWhsRFtO>Zr9XNwadiIDe|s=dG%pvw zix%YmWPh}GcYb1v`a<;=7RGw{;(tj|!rRxo1UKYdxcFGIBYTTqR(Z3~>m)YZ9l|9< z)+<+pA6;28@xXDH`jWB($4kcDcRXdsgx%%W`a2oKkL`>dy7r!(N26RG+Ke4B z65~hPT*nt?tBNPeA1^z0(PPP@tB|i@%4l=Q23y<4ytl5J7I}mft z*4a_)Y=br>p`R{ogsYGD8OQceQdV_h+0LFro73X| zhlpjpr_bjuIC z1?z8R;&r-6#_)k{@`;jKl}4%9{ch0k3W0t z>BoL^^vOr!V>kc)(2@AqBfmfNz4+Mlw+mla zC-Hlt>>-YGlG zy0vE$_U^PFqm>^=D?c7DtvcRQntnV!?#Mem<2Jw3Gba7SH8*^FD)c(k6hA(^Ru4BbGIxm z={NmE{pPgvp3)zxcqy%%qZq^LCqME8+Q;$a<2_@ljwg?;dThnfCD=L0oISR?vq#zC z`CD4Izr6jL>+=(vqp>3)=MvngJF z%k3{D|Ac*#cvk*Wwwk%~Ync0#?I@Y}i+A%A>F@qq^}k^TW3@3u`3}z{dot4B&Cfh? zV#$_+TUL1GOKx@ZGd7>tlTihoC$}uyW~G^9HlH|@vSU)L`mSR+gR-L?m9j?ndAMX^ z`f)rjetp}RBPWoG<9m>j4@Rljlh}MBAC{4d<4d;qy<{8uvtPqK7=7Z&&3~-F@nQ8w zS4P8>TWmTGf3EoFDvxci0zK={=KSm}(dbgP^~LHJ7p{nMQgU!itmMG-$bb8uji52lwvH&p5dE!Go`0 zcc7d0TKTc6#KK(_iP*Y}}KKd17_cO2Rg ztG1!y4=;{wsXF5oUHcgc%;b6=-htWGZwvQecC%;Z9qQNDE&ASPUQR5WHshc=_uAMi ziRvv?HuR)B^SA7XTZU0S%4PiEV%38)MCKif)0RYKVKuL=Dp7k?a!b+Y=H9A?u*JC6 z$N77G|32v~haTLL=e!=0t8+4J=$=Q@Rs696j``6U!OaoNPCC0L4=>qz5#~9|wm*q^ z!{|F{nLABAb>kiTcRaki=%+v3J>}7#7TtQ}w&ItQzgY6~O_;$~tz(MxPFHWitXEc_?F>$j0vgYG#yKjVS3AKbbbwK3?PGjxxNcF0P@4q2Gv+LXJx`$kILS^u8# zkH+I=JK{ZMi_?21^hwvH(iijLF<*{acznXcDm|*do^jPGJ}#j?f^lR8#>eEgXQSQ{ zuU;J6c1NztpHZmu${FfYH{Pdbs%N~yIZfu+Ya_ewmo}!QXN;s}%dwOh4)zW6`w_2h zbjlNM{8_g3v8~tKkckif*K{AqV}1rU-`;>Lo|JvCSXM8MO8h1&dzAZtXvZ(v3Cxyl z?BPu0ZML3cTba`xy5Gjteg6gfZh!OO8)|@_D#ysRfw>Vv z*u2`gqu*)|;T-1IZ%^rCI13?#$t4&cvsL-iWj}6ua`h8Q%!1O7mmOR3SnJWt9=Yhq zM^5UAs}9>)%{6;jrZ(0-)jeaYj&J`0>z&u!`g~J(zq+X_*;VPzHn^@-u|t~|jmL~& zVEK-NJ3f36edW%FWAQt;#Gd=$%^&R1qt2r$?#(x6@!T{a8!L$JD5_87WaDb4_`tik zn!#+zyPCmy3A5Uis~KM5+_T%wDtmsoS;e0_pjf*{8*JM3Roq(3SQe|ET=4{BUH$k+ zjVgB|_irMSi^-FzZGuIj|g+tY4|dO+cp{j(o- zyYRUg@)L7+&pq0H^4MB}dpkX)+3Mum3&*m^^Od=8C8DkT;6A_&OoOYNxrb^c?<{IN44^y^x|6gyVw;4;UdjH-ecEq#k zJG3QM{l}kJwsd@=`aggB*T;13(_wlq{7%)rO<6o6#J`lwS-BxJvt7L(ZQtGX z6y)$5a`ZJDYUqD*|3AxmKj+eN&m>$$Ue`C>wPo&g=xP~r*hi?%v*It)6@* zg7*$^y^1TC{0(-}X-Oq8uBj?unn?B;jt^Y2$I2M@lvboBeJ{$`)$;BT~f6|Hnrf6 z5~ItDdfl0@cl+3Yus3U0Hg{oTimoEreB`gPII(DbT}v}_(lD_ITVF^n^o|h%n>)EX zMHRP4R!v7JAN#Z${g3)cIEiUy6=G7M-p!QVJt>6T^p>0R0*mgRZt`QRZ594%{8Wxip1;6(^&h# zOZ=8?vjlCgKd?_=dmii%gTTl(wiN; zM$?g?cYZsb-Z$#}BWLXXMJ-WYv9%5Knd`b1vk|G;^XI*lShw$`!SY2f!fr>kRf}tS z??Ff_79U6(VzIC9lHNny&=KKiNHBZtNI}?*c7$5?caq!~qz zB@Emnm8IxwA=V-pGKw178as6BZ+~jjLw_&R<55xEyhU$+W>v&`O`@A7MIjmVY#z$}wJXwqD4UDb&_l75jy~G7r z{oe58upe;&JlNo*y}{5-P>|7cbYI>}nDI6i==F+w2~*~UvCrgLkr58Vq*R_+^oOPG zaMlu!u;5#cauDiybr@4#MR}#vXziXH)~n!>(;(epFv<5L!4P&kooU*1bRetMz;eXlUycF4V$i;~)lUu3=)zf*=wX&F(+ z2`!}5_$k{@On+2DS4~R0i2BsYX1!h;H3rX27$Dr#8SUmB47(Ru z175A2Y%4MlQ>Sbv8R{yP7aR6@YcK<^pZh$t8ss#}b*R^S`}0mdCkOB{6(#pQQjU~F zjmO8KVZT0n+>2h68|a;KSV?ISO}5-ZYhM1*?hZul?qt2F7oF_ol}Oa|-m?h*vKoKy zZPvpc8z$?$$}pvDq9lhFys~+Z`c1JFowNQ{Ti!YBJ<`?N;1B;gk$^VC*u9`1`qEyAa?#>oX)v{IkzF_Cgy2FFk}tFw(PQ}Io3?&$LtpD ziN0EqYLz)yEjtGE%$yv+On;~LEW1;CAFgrC_O@uBibaJv-X7@WxhWg6_dR(-_I|P< zdwcNkpEVRKx;%^4hw=fbTeuH2Te#mie<)w2%y-+fpEa}yc_GJN(cbUB<&qU`qiO4?wjHa>|OE$c;B@;)I-l{TtoVga3;b+}?bbuBHqxHKMS<3F}MGfrGG zB3{KKTx@=NUhE9q9K*-LNzYUcpOx-T2}luP`cQ%^sLx9+8RUQrALjqa5i>s zx{8|@b5(qoo|GmeY5HCNnuN}De3mXE^u7aHCDT(`Y2r)Iky>WoU`Xft z&D1gr>3t|OF5gCj`Zg0~@W0TA!QUcwg?2QRK1Nz-%b>8AQdtcJV07`~X5%2JfVHfp;EF88+VGz~CwK zj5a#$Gjm}ApZH)8a3%65R|J3N;4_v=bof38y&O-|JgNQC^;dQT_t)4Bjhp0bqzbp2 zb4B5Kc8vU-m0;zSc7@yQpwfxPp`9KR(kFcoY3_FiO!XTCT{$0}LB#H@MjnDs$ye}` zerc|>@r%(6a>q-Fw-T3`5+|OJtxKF4%AJ_&@FZ6gx#fKOSt%WMGIy4dK9oB}`j!qm zb%c{w6gfOi`rIzYHC@ufW|=!f`qR_IGncFQ8UVWZT{^p&S#kTyOZ;>3&DQht;+Yn| z$w+cfOV7(4rlVsQ%pES-)Odsp2|9TrCCh9pxubGboK2E0=d$>V)>IOvM!S?3izywv z#4|O~FSuOYsXT+EkV*|&d`tiE{?DeIu`0Evi& z)puY~RET}^rOp^v--2;biS#X$aWW6nk-mebsQ5+%q)QAd6@b2R0TI69GA@$j$DT*; z@i`l$&lyoPsub=rvz@}PS`eKc>^ay>&GrRTvwuPWJxNm|?*$w$15rNBmqp2u1dh^O z(A>)^Hi>V&T80C#@=@snt(vC+GhVA$nulAk^%I2A1EP6)w z9M_Yc(ci;zwfnp-KgWM2<$0xf&9`tXnlN4ACARPVs|A}mp3tkobb&%U0t|~?u04Kg zJx*ORg?6wo#VYwupYQ`17M%suO@eQc1)eTx}$b&b4BH>skNOAmrpI9Qroz`t);sQwkEG@ZfIy} zWZ21_jUDTo>l-^KcXq6=<(h=ac!oc@v#q?Q#+7Fvd#CN*mSP+S$COwXp%K6S`D4esnC) z<$23hP4%*x^RV_~g+m5Mrz4leQKqpV7?*0v2R&@qrOoS_yBZtjwXSJtT-mk)eY27FkSkPw zSEG_ebga-`%9vZ0u-ThUR>3-3C?H)#XZKd0QtIcPT7tQVnh0t6LfsRy8TC zXHqrzJc}+cqY`}_#g+=!KO+C@+RyD|pf$28GHTMc+0UGg{$iFN>3&cNZdV|=9?-eA z4V{nuWa>;Pa8Z)NdL-41y4ZkUmUMHyTGP?i-P)ilU14z({?{vxT`RDn&`+4cipmbP z4)N&vLHrHs{H}UkR#-B`JmY^sTU$qi6nk}Rw`x?as#^hx980VkI;5Rwc%ELzq@&Y6 ztf}_yjz(yqHoI3VbZxAk3pYlI3Q|&yhEs#8U)tEZe0`T{K|N+@m({m#tnGA_CkA1ExuinZy|&M?iWrv>@>@Er!7AI{5Q+^Qd9cNXKdRm>jjxr9q47PooyY+s~$+~ znnq>TcH(IBuUA3Z=9VI~qzYZ2tIjeuNNKx7zEoO`S%RygrMGN~3$S3b5e*R#MZI3> zNH37Xg-Wjg6@oRM24LW5x4pzPLy6Y(44W}qb}&&rrHBuqu;9x}veO8)bwZ zAFVeuNFUI}FcRqT2pix2t<$4B2Vx4U9>$%oSnNc87pI9BS8BOqo@VY24&R-E~(sHrFnN?|C(o+u9pjYt3|RU3X{8z0KMC zNAfpk3aznrbzNt3eQjOKnzjzC$Y1vlj;*e}`5zKPdHH1gnYQo`iNReEtgCCSThrL_ z500h1v7v2UV;AC4{-ptfjuC8lsZCewM9nBlygUeU(G1ESXaR1oYGE1Fxv}|2C zeKmG8)zvpb3s?1#2rm?*_~BC97`53(09@o=*4==0@11%Y1c|<}pU}7Z;!oq#-Gj5^ zF=*l0LHL_6GF~WSxHDm%N0=NFCe`O9_!JtS-oyS18u{<3@oQ+{GbTDMi9|-686fcz z@CH;8+3|GxB!Xp5&A&3tnlY>pFb$nhq`02_zZ7!d!YwlLg; zD6=7oO<5-@tYnN0n+#&<6VId#qi55Y5x?wYDU?R(_>!hn`$!H_!a~6-;%}mePs@(? z)xr7)Q4cUYA;%Oml8_8(VktgsNV&9^8q@O1Xv5a!itv4~z97kEZqE}?}Mwx;f zV|cy|*T)vyi1;UT9ty0_hzt`Zk_^s}qD+jkI%OtSeB@3ChK9s@lE!H!r-`!o$FypR z>0GvPl!URBSX)v2up!nH($NwH(lL#6P~@w%Od4&xed6tm*GNrzK?hQbf3Hs8k&dam zjj?IV(bQyOkV(C*he0Ow*57unai;S{O?{4uxsN$UO@4&YwBu2t)Hd-#TiQr%F9Xb; zv{+)49nC7OZjP}(%$Augov1XU4n4?*$+o&^6jGm2=vZ$t??cRXWKTq4kjesG!v*m+ zeY8HdCQyxH-IhV$43qahrc{%r)JL0RETxyER@MVZ1V(CU7zL(b*eDaooA}r<+g6n2 z3l` zWbO9LFr5`ctfaNW14BJSa~?Cj`la~zf7WSf55*z;_xkY2;-U|S+)Qj%I`JL0iKfz^l_5$dZy^w3vL6CZ3Q zRfe0?N`6hQags{tFxHAqcd@B*E9Wdg8o^?lYcsZ3xgGsdJCcc~_i^=ZnqN2C)?MIs4K(~>?bu`OkmP4DR@Ep|-&3v8S^*KXMBHNUVeUB#v*aZ>vJ zX4@#sVqHFk@eU~`lXE+nj)tuNg`6S*-f8_AsnFDlNZ_O=vwYJ;Ooc}?O>_mB7}?HJ zW-=6wKqy7AnTY4;ERQ!fR@lm&YbtkwIobgOamzSwE5ceTH}Yz00qcrs+B6#@wKB0W zCcah*+=lrpD%Hd*`AD(uno>+o>!wWgLQKBc5LdB}#rmf8F$l=ay@H)rq7`CRTTeedjdSO2f&8C!gc?xkJt`)bq70bs=Td~zixoUuft@?E?&_n%7I`{^QMt1m?#$FWy_Wrsxb{0`+3%5h z3-ieQg=vfG%awhv`I?KcVfmc0-tO#sSHG|I@72!!zpmI$+orZM?;L1%GS}HYdE;svG;ReTlzba%93sssMbCBQ-s}bF*>=A;jOskGpoBi>s`_UhfAm33v4&e3Z!#R`Kch#sz$Bz*{^XL4Y{Uq^arcox5C$ze|s6$+R0+ z0|R@#a~DedUHca9@*})FO0;lyZWBH;@IN!)3j@9^;1>rxdV$>J=Tgr<}bz+VXXuLAyB$fNv<{kJ_HsRG3D z@>=S6**hN*1rq;cz}G(Z43}-x~0n0)8;yZwB18U$LJTwGZJ% z0XJKw!ixC2JvxMQzZ7x8FAMlp0pA($n*)9z;9OMi+rKy9u761Uu73!3{X@9xAHtsr z>^&Fo7XtpPfWH>-Hv;bV{E_&M2mWV9?NR)f27G0}R|Wj4fbaCUEjb?JSmm7BzI*4c zeT#oZWJI`Y-@;x07VgeJ!rO!Ju78WaJKqR*=L_Mky$jzN*t^8X1&#@7#^2;$IM15bov+!Y2m)(*r&y;AaMWVZav!e0jj# z_$BeL4E!(fcmx6B>a-yLy>mDJ6#s#d5#g>pgbxb*hXj0Bz+L%B__=|r(d z#ox6@;jaA&PezdlcjYhK^=IK93-mVy{F;Ef@lwLO@lyEqK;Mm@;=kMTk03xC?|h|} zNAKMAU-5V4A>5URa919}U3mz1=M&+s{RnsMN4P5w;rpUY2tOF`y90h-z@G^C&jbEO z!23n#bBWJva}O=yW-I!Lmj(J01Kt#HH=h!Ft%3h10=_li*9V;YxQP>chXQ_2z`q^v z?*-h=pQ0DKwD~w*AxmvPy>mC;5P#P`gqPdo8haH1pBZpBK1ulbfxjEi#sA{K-;GD& z@5UeD9fAH;0eAgN^gkE)9}4)_0{+c_e=p!q2HdqziSIXo{~G~+E8uSjTt)RO_T2S? z@Z7-PT|bDwyWSN(EYNq?7vk^Qqi{F>7yiv4{85ibNe76l@j-j*oo7XX#6LUWZayad zu6+qVGthVKOZ*oG{%*Vx|9b=fHv{hKL-daa{;od6KO-s+;ch$;6EhbMFB4k zcv-+F27G$J-TYhPpBwlu3i#51FAw+y0lz5Vs{`H?@U;Q&2>AMdeq7=67XjO{#?Lc3%DCUB|UEi{;ofY|GR;|8$ZQA zD{BA3vjgt>r}(?^Q}~cTzc}Eozly%=pTb@L6h7YzA0-_it|kTjv3KtJkN6iwMufZT z4dLSg|I-8R##7OEhOXDtvknp8Ht)_T~oM zjrS6MMc{u?z%LGXYrx(7R_tx}{0Ewpq~RD-lMRzY9DFDs{ifod{>3;>GcxiCz%%f_ z4FBXD%X{$8FFlc;fnyrtW1Avhh+_lzO2f~?k@p|3#6SJnHYej91)H8aa4hE2>7f5* z;7h>yp$>AkweN$UZ8+OfcDj7Vh5l?i72s@x|?mx1Ph?Dzims)D>m$8n;$^DMqmYVw${`D5^`}1LP*Z*X` z=8yOE_xlgIb7$!C-5&{ryZOCv*I$L-iMB6J`0D}R&CZ~m_#X{;9@@X}f49e9fyY|w zjpyONjW9uhI*wm-2jdD<9C2q^3V&X!nF7OeLb5HmOJkGJtUC$J%4};IQ(c$@9J-D0C7N{2Rg2=x>b%VbamDgbPad7|n zz*cbo`N5~aFN^ets++-GdmXC20Dg_)`u5{w?s=J^nB_$3Af*)#KoU zEJgeMcW{^f)6@&#OFaKqz%Tar8{pSPe6%_NUgdFq-gJe>`-1QE_#p5h5id|h;9U_f zQR7qeOH>6o$2xH(>I2{-EJezz!8vw{D^TZwPq!5Q7lIdgydHdv$Jc?6^Z1qE96QAo zsH?%JSPFZ)z$-m|BRJ17;>N0d;2oCYe$tn~*Q1QA|GnU=J^l^wYpgf)zXyK1=YI_R zNsm7b?%L~E^#VBS)Y^X)e6FQP@0;K^MgFDgkKnF9lq#(7^y;rbv2Xj=gG0ezi|mb8 z#o%tdn}DxQ`Q<%9O$T2Z=}%B+fIsK)v%&2-if644f7a( zekJ$~k^UsL3A~@@zXQD0J+tY7w}*KUAoe)8Es-0DQR(j`%MHFZ2A@ zf^YD6JNPJ1e*^d?k8c9^$M@~vWuE`1!LRZ7&EWezz90M{kKYOYh{x{*cW$uyHh5kn z7_1%vFN?}|u=-bUm)^nZ8F2P7af8*1;I4iLt5?C@_%>Mm4*UtLj`b7of^$r@;jz7_ zH$Gzh1GpPc2CG5f*LnJ92U_!p?*rg&7B^T`fxGc*usRp~4KF{d zz+L+stZKnO;@MjZ-sJHsz*{|j6}W#s+4ccjNg`bqlzw-=XRNctsRosQNPa z=^lRoe7?uO1D^EwQE-2L_Y?4OQTYv3&x5<`?V;+I;BNjjRJ{)FpTFM$Kj_&{%TVeb zkLQ3pH(U(^cljHxO2FTa6o#uQ;Ojj;8{CaI!_|E7cF+GD@G6h2i&#i;p$fKn>_zJ!1sCl9`O4-{vi0{ z9zP8J8;?H<{<_DX1b1$vdJ)|9&yng?@Czb^k?MEgt33X0O8C=M4qj<@;ZIWq;A0~F z)6__C=SHiE;BJ08TFn5zK2jL1&P>rSQRjl^M*byg6?lQiYr%JWd@cBNk6!`q%C|&a z1@7igC8`H}iKo9C+_|yp7H}8;Sakq=PSoDVsxO24^N|O@pYi;^58f{_I9444cjw=+ z>L=iCd>gBt2k-L2{}SAt-^Z%g!Qb%gy#wygf8-1IR-sf4Kw+0#iswhez+HbSRVCmP zJ^zW|N2B;l)ogG#9+ay2;LeR#9|U)z@#-Rwswn(;RS)jZe_Ftoc>dksuKkQxp8$99 zjaS>qJ^fFEJ2ydn9^8p0s5?{iC#d_KCxT5}dYAX2bNKmQfructA ztpq>h`PYLNMSP~}1RogXuTotD?#Aaz^%?MD&woF-n_pC_uYkMzVU_CJ;N_nFkHE)x z{5kNs9)AsdjmO^wKiA{A*-F)Td;~bJ5ye%iiQsh}p9AjZpOtDUIIrof{>9)Q^LPt5 zuMw^P$H4b`d^h-w9={d*K9AoG{%;=t7P!0KtyIUrpY{Bo1AoiouYv!`*{yzb~*{b8N_s_w9=K22) z{M(*C8`E)*_XVFB^}nfV82H;>_zB>=2PJN*ssxW=%okUw7K4A)^Irwt$MatU?%Yhp zFaG|gr@t9I-_ySlJQ)QjRJVb<`Ff$c1H8lY|1$WeJ$^s2x9YfFECPSQ^SgY1rhiaW|)mp1oTZgtMnOo{&-#g|FUJrymr$&V%edlcUz@xP<^ zafv^O;y+9LQ53%;anh|=-{%r<62%+IUs~Tfino%O=RI0#lMxb6h~jTayiXMGE%Cuo ze6Ym7j+Vbf;<9LaJ5l0;3e)q+84{lz#TQG=IjJxIdWnnUl~4FmoaNEyccbY&OXX7^h4$x@%_P1cnqDdKrBPffG2hYQ?VB#~b{@)8w%HQL z_rnjAc+bNAutm}!aq<4s7ReHc>kG@TO-_*bh$uc&;^U+EGKrT*@sA~57RC2SydsJp zmv~q-{x3>gU6`Iv-j;a(DE?I98>9a9k#C|pDVn~8#Kn6|`J_@}&gp$TY9)R-%AYE+ zevJni`DCudljNR*mV7c_;-{kd+a-QJidRTH($nSh17}KnN)%rp@wrj_1BuToEMLx_ zCB8a}@00kcDE_U)#rD=Ff04LLp?$TU&J@gJl30f|3} z;-@6$o}RboWr?{*=J9(H7uQ#9(nUV9H7%N6D)G0YxLjiWJ|JqSO{yh6A(}o};-jK? zp2WvQ@j{7@i{hgsUKPcwB|ayLFOvAOD85eOE28)=iLZ;|$0WWvivKL}?NR&>iSLc# zFC~6Fiu-RS_y41KTZ#W3#Z?mjBZ?59EAdBB+$iyvQGBGtJ)-l)(mlx*GC$~uaYPA16DDgj|>A#cs(`fo%CH_@3{a+Fn&!4wSK9zX5Z4L5Q z|C6rr%~iWZabJmx=cijG10|jnP2XDLfl+@(NxXFwPmuV~LjE?%-pn8M?+}Um74q{* zv&6;yecR+1iR+{M(u?xcy$!NAn}O8@@kWJBtD}sy(0Nk;=`l%_K}+*Cl~Vb$rcj-G>R)F{$mu6 zk$75E->wqRj^aHeZj0hs67N!&zc#6tc+V(qllb_kJ*P_CyAbD-b0pq5ihm&Sf++s6 z#A~DYE{Q*nwy(z|zNXL~x!)%7tx^1<#7{=?8xrpuweMqz&n(nmoAi=5)Z9{t^U3BC z|1pZUmzaA*T56NA5*M!z^2ub0C-`K!AGf!}bE9})i7zOe-&H1c5*MFeRwj!j?sWf5 z;>!xluT54-yk%kea=j{X@%%QQTp@9LH2o%txksg?HhDnebe5Q#%HeLIP7i2651;@?KgpCmE& z;I!nEeIy{9C$K-H{%RH3lr5zIQ5XC1*Toc8sBrYCrc1*r2@w90Ag%a-< z#g|JwKZ>uDxVS&;nA{@q_oL}|OMGn$XZ$Y%Z50rRW6bFe{Me#U^&yV7165kNT`%C;lw7w3L zct~M=pO4~uB`z!Ue?;;tiFbW=lz3@0{S}EJf-CN>kqwzgN;=f06tHfgp`$KKAT;kiK z_#BDfjp8dLKB&;Yfys3eUsY(&z~p9$i`NTsG7^=p(Vb~@*Yw?j#e}ZOZpoc8KPAXd zY0@ou#A1GxCf$=4EGCEj^fim+wt`IWnS9hK?w$15icGx+SSmLU2U*-Ku2gR31dGX` zzHym&ip9G8{>fa650%_f`EOw+|M*ONw#AG|sXULrA~XG_OniSPel`=ok%>Rc#QnFH zhDqTWbgA4w*veuY{TpU6&tyyG`mZW8eR3wAn~4w3#PylDF%!3C;$t)MDVca}CO$6{ zUzLe(v-o4_Td7=cJ)D{TTqb@!6MvA2yKcisX<@v2Tg)-LRL&>MGSi1;;#!LjP4l-& zre~(_WAVA^^lg&^Gt&>Vm~*gFdH>>ZndxgX@%a|>46#(+zjRGz`Yjeel1{Hoewms6 zn8h4pO6B$Vd5d|5Rw}P|?`HD5lu5&^Fg^pyJksr}JQI)4#4{~koz_1hIUqB=$zm?? zHj#G%9V0R9@o5rsIO2!t=SxgG`dWO2#O$j$rbmDJeL*sE#^^HnXQX^Fj{O>$cc^lx zcBpX}<1p4?oI|a{c!&Jx0u}1c7b?#eYR?y{&ll>?7Z#8&EFoW5M82?$Dwa{VcVpY4 z#)dtbTj$p|w~LrKaZDWxnlx*AZ5#`R&6W4$sO_m|ak4f7sHIDJ5F+SUvv==0e^^OU#D%8<#B^zIvY9k>; zKXoddP@;uO)_I*lmOj>7Hr7W$my}Mjj*YELx1m&}+lG>jkxcaljq^T@^HCa?R?nh! ztB^Tsy_>!fsdhO6G$sv zxU6MC-TcNyO)d1ZW69EVTjV!+>D0!S2A{^TGL7nsbFxyzRoXuNfb&sXB%TKEwdIYmWsI?U z##p^$n7`OF%N}o2^EFmoezZf456x&+j4Uaiu8tIZE+3fjR$V?_iKJB9OydiSmBIFf zS{L%8t*!adHc)vV+5G6j(tTN@3v>Cx(jh8#sj%!C&m7||_rc2h=;X)v3a_CyUl)Zc z#`&D%d^pD1_~&aK#ug^gji?>&)4?rNZC1WVM~Ab@J6+{{t@4qsDy)Qb_!v(g;VR#X ztJ2L_CRL5Lu2iLm^VHawRi!TpnDiAPg~B9nMwK_LD$@;HIaO7*a;kiDuBv8{fgi&qY+;qb!^cY)AN?+@xyEWf|^Eg~Tb8FTpyqK$PO_3~Y5 ze5p)ZM<#`p(9k%4*`hl6=FUZp?aUI@z^aKtS{sF#rPI!6DkB<&jC~X`mQk1<7UDQN zJ=3uC^(W5Hv^3ot%{_|K%{q=VW0P*=@$^jpsxr&3 z$_!UkX6Vy{e_UUtf7O}ss%Aw;`RVZ`jx+78&a^K*?!@_-_Eu-wo4!^?`88~J#oeM1 z$=+Jv^h|8kD{&8-V) zZ6PQ$Hm#La;I+aW>C1zGgK3yX;fhzg!O(K!l z4n2Mvk!~^K(=CPRYytevtl9KP6*nm}J)f@n!VqP)J3T!pOwDvZKZeE@rgjQwPGJgt ziQ14)Pr(XPvqLckQJ9)-Z+hCMQ}r0wX%%PoyZjg*HmZ@~NjGeM+pzjsPudglwG4p# z9-m#anTpdBsi;fo>v$Yz1~OevJUvr?K5bZ`)9LZG7-fzQ`ShiwIGJS?BUVx|$}T58 zM~fPgPfwRSi4A7yv@X-rtxox@-QohX>)KEC^L|#A_t*QppIqd9qtB(6Y|>B(|DJ+nQfr`OT+ z^mH(eGwn;a>u9=Ot`yfor(G!f>X=VkQ%ugZC7+&e6((=+TAH@CI61pV+H$ShLt19ZyB ztcLvP4aOm})O>oO7T2-C*?V@|$Zv4Io?bV1sv~ni%y00zkX}r7nkC!04US9M)AalX z$DR!?1hQxH`Scvl&$2e?M|!n| zm7b1~v%#V^IB2A`6dIn{8}vR&X-x79 z)+&GPuFAfA<4tMQx4HQCd*eD;Qh-k$C>2-$;9 z_7py!J?G2&p~Y{}rTd=rSxzmcw={Lg_ucQca8`X=eH!W4+Rx!8T!L~W z&Day`7aX3{)ioa7A-7iA7d9-cN^6U>Syfd1XG<7sK?B24dxp8jm zY;I2`v*a#k$E>!-hNcDSsK^M*fOa${liMa9GpD0*sdQa#b1pc%Zo%Ti>lQ7mZ)-@~ zl(u13Yx|7mddXO_thr%fb<*C{k}PO#7tzrsPqG>ow##7E)ipOVXmxe+bT<9n&~zl( zb#?U(4SSPf|>wTkKOg}iiwqdOgRhhd)AvasoBx-m<>`kcJx z`bEj^4TmjjXN%Qp_Mt|GwrN2+nTV}mPTPWP>gOm319IkWF+H`2XY-|H~=19^jl z6yEnxosz!iVTgI&|KOe+@^PN;?~x$inS6Lt`6)e|Oy#(qoxf(e-};*6l21*(Tz<0* z@|~&QbH1+rUB04z-p1zR0DC*-Be4nnqQLHX57^H9K@%yk`%>Xu%){=73JnDr^m?R zH`x85!oKan?iUJse_{8B36~zL^~3JlguNcv{c7^9zp(rB@W*LAu>1AGgY6Fx!S1gT z9%3GLf35J~ZFC!h-QPgIdD#6;!lm|sF4+B@!h_4S9@zc8!b8l%?jIw6Tg`{vKS{oM z*!>^yw*A2Fd&}I_?~CUT`AIo6@{hqgsOK}>BaF9} zyumxFhrP|^!b8l%?gRP5H6M1r1Nr7*_d5yuF$8u$6>rBh*!{jyKJ5MwVc(Wu_w$8) zTY}x6DD2w??Eb9C!|uNydDuP2L$3#Rf2XjY55Vs4754K1*!?fae_d9B6xjX4!b8l% z?q3r2{=)8G754tZ?!OTBcEaxYds^;c_Z$y>{9*S)qkPzXE%_&QlbYp|l9A`V!d^e@ z`D};oVfPD#{WT7D|8>W-Q=)oc&%ZeGu=^V$54-<1D)IKi?m7PWIK;=I z&!T+T^SgDC^=PkUu=}3Eh4bFXmkRrGVbAAf)jjNfbmU?8cMJP54R(LOupiT4_Yac) zhBRCX?EVq*&BN{&N?!jFBBZ<-aZll$m+N){dwyTxUChJodB1k)$(j$l=NRJs%^pwO z$HxeE#606xi#T z9eLP&y8qg8VfQDJZ{q;FKO1lL!|pk+@b<^&7&qb9XnSDKe=_p0`DvDITw;cJZzt^a%o6r? z!tVJ#!@+Ora$)xe2oEt2yFY|{{*bT~*!_I+&BN{w6ZZWVcHbiG`!DSN6yX7DwO_D% z&RhDA6d~n9S$zLd%6rPM5e$r!x$q=VE41} zXQ_wXFUB9K9(I2${=4d7_ow5}Ru8*R&l%29AD=U@zn7k%KHm4A#oHgQfW4j$P%{binb>T^4G-p#`KlZ|2&vy8A+D_Pg4c`7>1?+xT zyj{1#?x*4H`WkjWOL+KLZ39d3Yi-zbdJ6kBAncyk2tS_0uNSmuzy;doxNW84hmX@` z4T5WxCkRg-uRImrNtw1e_ZBX_Q0s)f4TFWf&9M8eg}u$N`*a+vo_HMgl^j1Nz@9%J zZ`&K}{%HKU+8)^ba(ugb*nQex{%E(9TKO5ii}FPHTgvoz1Q$J07-#QSJm$P!d%xn> zZu;)WuIxDYu`3>j;gav`4)%6V5H7t~+Yh_n6Mu<%*!^5#KUTx;_Y?MGHSGQ%^54>9 zAng87;UVT>_Z`B6?GH=A?vEB8VjgzCnQ;FJI)+2x-IY177-76zc)0Njc%tU4j(B6? z!IRX(UO(IL5c9Bm#&+;z&5y^q9M2zTmjZkK*Ns2h|6nd;rNExgm=7@@kN*MUeLcdS zPk;Tj8+Lyz-p*BE_vZ@x_6EDZK-jl8*!}l~{dfhtzajFl`$zDX>GlJ=e_D8mjT`L# zLt*b1?0#d}bi7}%`_1syFWCLo!oFX??#qRJzkuD37WU=B?k7YZc0WVdw}06EEMedN zVfS;%e_Q^M0=wT&c!+t}{d~M_Kd}2Fg$M7U+X?LcSn|!o?zz`Ac$((N_npon-#qO3 z7m`0+^I`X#2M#eGpA%jY<-?wTO_UG2zX@;a9d`dS;lZ4kNP*qoNxpg5{e$H1rTMV? zN60r1yMF?2;|aSDvb^D(^hud4KO^>5o-N#ert;gu!}($bDLcr#&Z~s`b7Cmv0{lM8 z>xDg*}g{5%l$Hun|wa}wD7roz52!|n$O`@Rgj zPmf*mv<=x~*AVmNQGTtk@B6UVGXrnW6kzxBg?*ob-JgR0fgTfJ_g{D2$8pB5JK|%` zqftGu*Yhmiu7hCrujB3d1$NK1n;$D+_dSLESOL4=PT2beyRVHr?0#D0VfXB(ehi8C zS+3Fi7!qHvokIRQ@{bhQ>tQ<_VjgyXv9O=p!0xXT_U#IG&$jB@73}_gVL#V}-47P- z&jpYa_Ss3_Q64F=AM;_)A1mzR47=Y+*vA=mKUdht8Fs%o^051(BM-Yzw=28;h238o z<-_i85cYP$?tdZd>kD@Ou&}Q$*gf0i;D5-#NQt-4CnO$X9`^jVg$M7aV+gzF`eKNA z*!^e1zJ6i%-DQz}?h3o#3~%SIuzOw~{oFNvt>jqe>jn1w(ZW6su=^Te9|zby`@-OV z%0E)#{bCpL&BLDGTk`tvuj4Qg=3-jP$MQ4W{7A`n=Ga(zz8+8F z`{lyEUSRhtgnhlh?pF&B{+F&7*!>ygn}^+BAng5u-LJ=6zhL(_;jLe=`@4m`U$Fc8 zg}q;}d-f^sS9bsMer5Ns!S8Cn;{EG)QqK_cu-E^RaOwASJ;Lt)fw%jju=_-+_HlsS z_r}{e!0tIt`Z&PugRqYS?EZgszvBkElnwSf^YMPyU-E_@sQcQc@IlJE2v0s(c^b@3 zEGZ|-&+t0svxP?-s{CN&--heee;RSR|JuA0q=`N+Yr$WeU>_6qYkzHm-KYEb<+|?T zeY{F?O3zRadp_+iy+}RmewMJGJHhUG-SKlL*!^PR(o3}-*ga!X%9rd&f!(tom407+ zyiZ+$w|xZm{Og2$+koBQDD3+P?EVg6f31Ywv%k2H_noIB4}1PAk%!&09(^B#-M=gB z`ylN8ee&PeZ4Y+;G5O|U_ob3rx?aZzc3+0Kd$zFq;dtBEVD}U8HlDEiJ@Iyb26jJN z*vA=mzpt>5Gwl8#VIK$B{h`7>4zT+M^8YRWNP*oi79L_AcHbuK+d1rhxv-yu!S2hX z-u~P?mNFk+pu9?Wc!ToI_(o-pKO-#v0O8?0h?a7!@T5h`tcBcS<(|S75my@b#W!gV z?0!=`H?5_>?gt519IhUAKU~x2ZzXso-9(I4Ju=iy>Io5vIbFRW$Utssw9Sz=zYz9iam?{$!JfnG zbp;O`q`>Z<5_S)}e+JK&6H0;IzaU(3w0hY6OZa2d!|va}+ql8*-@+fO`LO#hguO3a zWFPUqz@Ec7wznB}zft62_nY94(`CW#2jQ(Ru=_3X$7??9z5;K3f!$Z)tuL_qorJwF zyOLwu0PHy&GkqI?-Sa)6z74?c_r{-~ZG+v#3-BjtKJ5N5 zy!9P+--5Tk!|qQO_P(zqXSvo1d(IlXZRfE2bMPl?KJ5N{JP+KY!0s=@Tiamwm*cH% zu>0GDy=^}y=Txl|_MCh0);8GvL--Y%54-<0-r5Gce+qAHgWW%ax3;69v&eD zcK<_R@5}Y%*m{9I=O_4c}`9I z9BUiwIj`X9kQCVc-y;vZ{|Ekj`9})uzFXJgvU&*^I`Yr347ZvB*)qVd(NeJYa8tT zs>s9cuf<=f%YxnC6nWVFt@x`nA9nwUu($0oa<0}K*mIu5U!xv&|5st3_YHE`DW$-k z^A`SE^|1Rdg?-+xa$!*MBh7(5rw9Hz^|1RP!anadvS9Z-c6ATC=XOcO&6*Fpzg5`Vb_Y2& z4zTCkjkj@t-TyN3u=`)(Z_#DJ?w^P}?EZK7TQwhc|C+G3?Qi7Vra7?Zyo2Y3LJI7j z?=Nu=yZ;=2yXM30yUX`mxQE^M#^0g&u=}lry=~>>{9JQj&*3{=DtNJy0=pj-dDuPQ zTkOk%-R~jn%i4<^TNdm&e7{P?UAipT{eF>$-5-R%Tk~P}4Uvc4^PR^P_h>%sz5{=+ zdf5HZ`1{nu?oW<9?0zNwe$9v7pNZ#%T?*`;?|1S28g_rRaPAkH|08lDt~BQRlq-Iz zIk5X%BM-a31OK4r!|s10?92KsIaWXHIlsr-vS9bmM;>^c9zTRUO*1G>w+4{M#93s*#3X*>k~E6su3mq#9UAMlT8KJ1?Fa?br){kO=8xYBrc z{G*x!yPp<$*!>LrZ!{lvUnlI#;`>jIai#Hn_?I;YcK>kXVfT;X zU(tNn{hx(>Suc}g^~0X?8vd_3FYNy9$iwdWp6`lRH6M0g(zCcMzE`y3HO+xNXCu7L z3%f59&b_Yr+mRD-r7_=?S@DME!0tyy9(G@ie^c{e_dDVLrXF^`E1nBnDX@FKN8H;s zj~r_c>^XcdXT@7OFYNx%$iwa%@YXii{ZYcctmDYBI$_T_32*I(-G5Km=e>j+n-}&R zzLVVNh28T#EI#jD<l;@{I8*!{@J z!|to_|JHoi{S;we)^u{Le%N#N#@n)B_k7Q~d)WPccv}|i{%~PmRx3HSEZB4SZg#H| zc7JT-VfQEE-`9S@?)eUPU)K5L*s@^Hxd?Clg5C3d@9tsuSK&Xa`X?tc||*!^$tA8S7B{x8D5tiO_D?SVb#4g4oMFYNx`_)pct?mxo+M?LIb zP7RXW$GP;l#Pi48XPQ$Af3Cb4{Dtyh_)Fz-IFTD0QYzt`GS5_VA84Js!d=u)hr24z zgSnX}r5-L(UIKSl=J{Q&hw{mAPvtXVtN%i{m-;K=-pV{j%h?xf-v#$o{|LO1@^9gd zm7j;L&e!37>i-4zSNEx`C{0U{fL1|KH>NI4E3r#UAHSJW1{()?NEj8}giypuAw zn{zuWUj^@?d;|O~N2*q@`p{v7Q9a`u*gq%^`am7CyiD|f(D zCgo^&ALUcw*~+KEw#}Ri&ryE?Y{#_AVHPgsYIvUVP4K?Tx5D31z7O6{`Iqqi%1^*F zT*~j^1C^hH4^n;uZq>fO3m>fh6ZjD2E^^;5$A&DW4_v2yQ}|Hjt>Aj)0I$;g5%7HV zHShxEo!|!LDKLX7Wfr_p`9OG)@_cx)@)DSVm%>ML{W%VAW%K7sus=`XK5*_Z&F5`x zxxt|5e7152`~w}gqlGK3DY8FvIgy-mG@tugId)89(P z;PuK|!W?*{RKQm#^F8;uE0rh0S1HegIXFo<0KP_fA>3EF9sZ&6vGBFZr@{8zgzq`_ z`_i!Amp+G_A8G!j@O8@TVLRSl4_~kTC-4o*cfvnbz8ALR=da-#)jtmZMEQBx_S4s4 z4zyDE4pKi3d;r_=oDZPpeyTa$U|YZa;hWWO3fr+Fy+?72`r&vE-cojfZ&RL}#yx>UTS~z#V@}}?u%4P5`l!wE-C`qY>A5@+UKcqYheptC4{+04#_z`8U zC3C-4<~lL=sPanqH_B(jk11aQKd$^km={ASx4^$u<~q)|)hFR6)$?7vxu=w0hkvL1 z9?T1=lrP|?m3#LVwrzfU_!;$i_*vyW;OCU*z<*G#ga4>}IQ%E&qu}S2*T63*UjqMG z`C9lz<-1{P!z1ut)ISZsr2G>6vhv$-ALWnXSCqT;5&o<4K=@VVEn$0JQzl&TntIru zn*?%RS3eSdL%9lmQ+ZeTZ^{$lzbns#-%_3p+cq;Fep~(F@H@&K@IRDKfd8qy3Vv7l z4ESHlH^c8K-ve{{2%4f@Mp^7;m?&P!e1!w1%Ii$51hz} zhLl5KduB0TxFV+>_U8zT$>F3=%2K$iatCb3(&cbB^($c8_s@n))Sn06pl!Gc?ymmF za1Z5M;hxHO!o8Fqf_p1J3ET6Fr-l7KJnZ+z|3nTar&3;l`zpT<+c>`mZ>0W1*xKA> zBjJtJcZa)cn@iz->NkV?D+hQJ9hB$8J1QRz4_9u3?LPU@u-%J3UfA#V z!hXN^6mq!Gk#ZJ1Qu$oi`u=@*l=>@R+sAK&N2|XV&MW^4u2Oyyu2%jd%!QPcSKu+q zZ^2`g--mf~kd)8iTIKHjgvTrQgSiNkG6?1kL{heecTpY+e@i(J@2b2L%$td%OoAsU z&wzJVo(E4RsI89uly#=1-g`f!*(qC61H>BKAQ;l)-l{1 zwsVgP*v1BYTRULCZiVeS>v;Gln!g;jbGa3;oy)C; z?Y!s=*v^a2hV4A(JlM{2();svE^#T|&L!5v_IiC4Y|qWFh3&QP2KZHN&rPtszT67i z>&qRm9eeMF?OEIXupJW~gzZ_?@45-gbsB~Dq~-c6m%#&-C&ELNdB0X}TjkT>O68|u zJ`gG8EqI*r-dsoTp?nk9gUgf$_Y_{Kyn^e3Ta>FfuYOed2KZ0PdCvXbR{j@UA~(XN zEa@xEht8#(#cL%WMv?Lhj^Xvnr*mvMUim=w9d6!Bc}ek99o56Za&E&9 zR}Tlvxf?%1Jsd3OA^b@7aIl>lbep29I`^8`J-83H#mh%ao1E&-? z*uImKeW!f9dN^245ByH*;b1u%;dfRK2g~8TdF8vPhlAzt9=!5zsfUB*Y>VeXr4%?= z&M^FL>fvBHdHe+RaIl>5_}$gR!E$!TPgD;F%b9{N(eZ(UfvBHx8UcfhlAzZjps#D3LGrwK|BwZrNF^*9>ede9uAiC4E{Un z;b1wuf3JK$^>DBp-ltc-zj`=W&O7)6)WgAYKExlW9uAiC1^yuQaIl;nay%|SSUnsp zryu?h^>DD9&GB{W;b1x2;15*~2g~6-c;)r#;b1v={CxFru$-On3)I8Gawg#$)WgAY z_QE%+hlAzJ!7o$~2g^ASzeqhCEN4D`v3fXI&SHF%dN^3l5%|N@!@+Wn#viU84wiEw zzF9pSEQfo}g>I&N^V z9NxcIzDo1quu^$6{!E*M)pP?QO zmczaJ@-x-L!EzSk&r%Nu%Q*u7UG;FVoMZ84tA~T-oPs|`Jsd1&E&g2faIl>7@axpW z!E!Fcb5bt_4wiEb{(SXtu$-UZFHjE$%i(>1<=;~e2g~98e&rXchlAxjg1<;T94zN4 z{Ke|wU^#!pU!ookmh%e!QuT1KoWJ8QQx6Brc@O`6^>DD9Pw_uc4+qQX(o6h$^>DD9 zKKRSk!@+WR4pM%FdN^3lR`@H`!@+Vm?=HVeJsd2D_x_b%tsV}RGZuf1dN^3lF8Cj+ zhlAztoTdC)^>DD98TcQmhlAzJ!C$8y4wiEO{(ALru$=k$8`Q(Wa+>fzRu2cu;k|<8 zH>!t&DD9`|)?GhlAxjg1<{W94v?DP33p1hlAz(0e_ErI9Sfh_fvBHTj3v4 z4+qQPI^>DD99q_$${ldX=Cg6Xg`EYntc{={FA_vRa2miQwI9SdB_$SoE!E)x~ zf2$r2mcui+@+Z~9!E!qAPpOB4<(z>3oq9M}&MN%x)x*JZzKefaJsd3OLi{u8;b1xI z@z1J@2%qo2g|t=|GehI;ZMrH#J^DFU^$QB|EwMkmh&|JMfGs7oIm6Lq8<*G z^D6!&^>DD9cknN(hlAyOfPY0j94zMx{9o0>!E(Cy5&x=sI9Sfc_}A3K!E!dkzpfq* zma{ef4fSxaobB;%s)vK+48!-)afXBC?1q0w^WpHe@*enq6ggPVEc`#!!@+X)$G@u{ z4wh4o|Cf3=SWXlEJ@s&~oFnl6Ru2cuITruEdN^3lsrV1n!@+Xa;y+Xm2g^AJ|B-q) zSk6WGkJZD$axTYzq8<*Ga~=Lu^>DD9Tk!u;4+qP+8~>SlI9Sd@_|MhD!E&C!f1w@@ zmh&wBOZ9NDoIm4}Tsi>`mh&1urydTL^EZ57-5%gzIbY)W!!}ajVE6QT^cCMjJsd2j zAHJu0I9Sf+_+IMaU^(01d#i_o<#4~PypMV~Sk5SXU-fXXoLc-w>fvBH6Y#w8SqdC1 zXBxhrdN^3lEPQ|UaIl>H@tdfJgXPrYOVz`{avJd)>3G7ya*o4quK94V`=Y1f2dRgH z<*dbTp&kyF!!zje!Rp~)IhWywsE32)T#e_A-csOTIXB|BQV$2qxgF0R1eF2@%efD~ zje0m(&ad!g>fvBHzr}B>9uAiC9KKvV94zNA_zLxKu$(vW+o^|x<-CjEUOgNv=M#KT z4+qOhHWFW{9uAh%3(uS1rNF^*Ho*^54+qQH0>6WLI9N^@en<6iu$*Cd{#cz9I9N^< zeuR2BSkBJ)k?P@KIg{|C)WgAYX5dGwhlAzJ!}CUdDR8iyL-1AV;b1w7@YU+!U^z?i zHR|DDImh6~sE32)oPr;#9uAhX3cs=L7jUqgOYu8vJ{;^B!PWR()WgAYevJQ?dN^3l zZFv5ul@vHw&OLZOxF7`%mh&)vf_gYu&J+0E)x*JZp2bg84+qQn3x1M%I9Sdb_{r+w zU^)N9Pf-sC%lQaDRXrRm=S%z^>fvBHJvJ6UO+6eeryqX0dN^3l=J-9;!@+WRA42(F z>fvBH!|*fI!@+X$_`TJ`!E(mqXR3#TfvBHbMX79hlAxDgrBV* z4wlo1pQ9cQmeYdgkB~`$gXJ8FpQj!UmUAM0U-fXXoYU~%Q4a^pIUB#9dN^3lh4}r| z!@+WXfImPz94zM={DJD>U^%>xqWmEBaIl=8;SW|12g|t=-%s~1I9LwvwJ4vj`EaOL z=6x6C3yK^phxcHVH>ih$<@_Drs2&cM^B#VodN^3lr}#zc;b1wre&QFahlAzxz&ELf zgXL_5KTJIwEN3(P;p*XFIosfy)x*JZ0)B~lI9Sd|e2aQGSk5?nt9m$C&IJ5Y^>DD9 z>G&hm!@+X)!MCZ0gXQdpZ&wco%Q+O^p&kyF!~0Cim#K$?<+S3DR1XKs;k_v3N2!N{ z<(!B=T0I;rhxe>>e2g`X0zfwIMEaz|dRqEkjIq%|6Qx6Br z`2@dOJsd2DXY%E1)WgAYdf`u34+qOB#jjNl2g@0PKSMnnEN46Xnd;$SIV13AsfUB* zjKzOfJsd1&H~iV^;b1v?;LlMH2g{j-KUX~*EN4IbI`wd{oI3n@>fvBHjrjA`!@+V| z@E53ugXJ8B|DJj{Sk7|%h3es8IcxA2sfUB*oQuC$Jsd3O68t6V;b1ve;xAPX2g|tu zf0=qXSkA5Z@2iJ{<=ln;fqFPt&I9=M>fvBHkK!*^4+qQn9sUaSaIl;|;jdH=2g`W{ zf0cSTSk7DctJTB7a(G`;`8Dd{U^$=Rf2bY~mQ%8c_-oa}!E!dn|42O?EQj|*m0zbG z4wh4fzg|5YEN2-02K8{ToIL)=>fvBHJK=9s4+qPci2sRtI9Sef{7vfNU^(B$|5QC3 zEN2dW6FnZn!E&1LKhu0T+@{=yzrD!8a*o5_p&kyFb1MGl>fvBHYw&lfhlAyui@!@f z94zM&{N3u|U^!Rf?@Jsd12DHZ>SdN^245B#sy z!@+X;;U85G2g@0R|BZS$SWX%KG4*h;oJ#!T>fvBHBk@nDhlAzR;D4(g4wkbs{z>(4 zu$)Qwr_{s2a%SLvrydTLGY|iJ^>DD9L-0?lhlAxT!at)P4wkbN|EzjASkBS-=hVZ& za!$hkK|LHSXC?lR>fvBHXW;*&9uAgsF8+D-aIl<9@Gq!`gXLU_|Fe2HSk4derMh3k z!Ey%4bwX}{`Yqw^Tsb63nfz49br+>fek#q^2z!1lEawE2UF4@i>ZQPy=4T0e{#9XWrNEWun}t1pDLh#Ik?$a<=?bY?ornm1W9z z$gkX{+TXk3p#FaORWYi_mFE8-%Ikjt&TGy~@~fhz$d%^b7v=dM!(%n)Gx=39smPV) zhsvtT4b=7who@@JXyJ;sB3GJUO3r4Q-vKi)QjRA7lpgl|b9hT}#UVwmG=C5|wtf$V57nFo@{cKUrTMeTvGL*KAGzZ+ zhmVg|++5^J^Lz|1x23k{5%^Zkd5ruQi(F|w8QFf!l8*ZM^1Gu=e=m0GXgsu5YHgX*QQy|_Rg)*T&1{|1 z*wWtGHmODG?>z6UBRgicPHj3mGii^;j<20TK=W z&thxRMb25;*w`?wvA&_HWl>!9thT0>j#+Ju4NVI=bzySb#AD`kG%oFw>kImd{N3Bz z8<)&)ZY(rrc6)QD3a7UhCZz)!SG-3{d;7eWg-u7ta`%SAmbJ5Pv~&A>!?fA)w89+o zmdZ#pW+&CRO>Jvk!V=>tlNL8FI9wMrskNn{sYBL#JiSoqUJFIHGQ@0W`H}f_iyAp{ zM%~_xZHpQk_GoUMU*GI?H#E*)wy3VTb%AVsDb~-Q-`04f)vT(ixUyBW)we8alo~XW zr6eO4v@TiF$Trr}+R-?2kD2pEw0G1mIJ{Fm%}p)dS)FrXTm2GDQ~QD=N7i?Av^C9N z)*%)D_hpErvZr;oS?pz@P=W59^1fBelU*|{**x7_~ig8E3My` zJ6xh}@-rc|@_x(*yewS>d?9eI@v+_3@O=GeLe+ z?ti$rKKe`S^}Q<`*T=cXq2j!F`*iAkJMcms zlua#NCdmJVnk+yEs!{Z+Xsrs7&|b z^_`!o?*^%lePM$9Y$HEjAD8^{f1!PcNqy`~UcA1aX6l>P~Y}Z zeSEw^QVab(RCd}&5LUdtFEaH_miN-!ArmJ^9>;iZ-`1J>hRRO6=U3FnX>Hu!&t8_# zbz6PIqWWqx^>L48;#bsHovE++Rr!8i*_mnIj!}L4W$L?C4g&1!USx7w=49%teN(nS zt8av4cz^jbTFhRhvn9K1nj}O0;2@4^{2U{B9RH{IWInq zkM2?T1e@-z~o&eFD^cfKW*sDbnV}j)EEI-~4K4R+gP{rGG<+$M+h2`P-xPM&V-P3Yu-UONUE&1{K21%a$ zzf@FOUXX+73=ibDFN@#O#6lUmzkEJVPLg&P(3LO>+*~Hoir2@c z5$D}7BbV4mSJO<-8&y>^x-2UBaaH-6n%e3yW6H|%qeth{e`UJx*qWNMvT@a;$5f^H zhxR^c%8aSGoYzEO{$1z~3%OzAT-pXb_Z*rWk{m3y=9ls_DM^;^CO`K*-*5T^`Ms-5 zkoaur?rQn*-=15xdoH>EqNL~T@(Mj*RY`K{)Ky(dru2Divo1ZZE=gw0pR???p5tWN zY1@}1{O%!N1@Jwo@{Q&4*OTq{bt^`$x&F116L0T6XhLqPTWak3!;++W`}N7XF`Fm9 zK6A}G)G(l=Bw^aRl_m0g>d{qQzL%S_{-XOYOw#3aopOGc^%v5jak4_zb?cQ3SUEZO z@|2gS7Hb}`^1&`yGr3#VJXq4%yx0HJ{w#mxl#1lGq+*j^$)o*W+0$>0H zr9!rY+|=b4ZQeCW7ReaXuChP<`6#La%iz z={|bh>c9SV@^fEE%O$^l>d8}l6x3`~7!{VsSk5{B>hfwWZI%{f9 z$%;b$4y$fl6;?jF(x(sDeqd77aMeY#F1_N_<%4dQqwlHL^iHbQj6D6iH5EHN{aMA( zZl6^I`Poi>%H^j_enxitv|@O-PuKN%@IPLU_hL@RZT$yyU-8+QQ`dD{@!8Ckzbh=M zQ!CbvJl*H?-}LH$DBpc;Dme9(75$%_A+ zQy6)T26UhN$(e=GUsp2ulZ~csw8zYqkFN3>yI$QpId%KVpD)<-HhEvb=u6#CzNGxk z@Om<6hc!JL-Hp5Epexq(+AKfr^>cPx*KOhZGgn<782w{(9fd1T@0SE^5YDCxOilkShazIMomeRZG6P0g3wvg)B^^?b56>Aw1vwObaa zZ7^k!9u-Eexo#z+w60r8dSvjWa!h!1W#|3&E83- zYcKtYD=bNlDC;j|i)DK)_Ta%1 z&tQL|{e`&Ws-E}18gFCQoj!8SxMkG-%n{>C-o0;K_uIbMx3GmS_)bZ3^7P!E@5wQ9 zi)&Xm%vp9-vieo8?K(L^u+&p4OOo?{%f4MP^8L?zs;`CHWo@im)jiqav>Q*WTKTh; zGgtj?)xN7AU43f#gP%`q=yu5|r?BNrxH#$0-+=D=?65>ecEuJ?P;(FI;Q;ybV)E+I z<(fjPdOaQ=y}F)1EGa3eIOj)6uWLK`XNDz1&sjU5qzg5zNss?!7e9D$GALcnHN9jx zJDgro{@@pKJo`e9XP?RO>@#wGD_gg+TNgQweSUIbTX-~mElFEdvf}gNaV_`j+0pTI z+iT;98qZ9Z-u3EU9CN-{FyOZ2s*8P`SkvV23VG_lDap!`;pfi0eC?#}QM+{;^*K7X z@te2RQ_r8AzJd>&T9G`I*8Rl#K2kSJTQjBa2{QB5`!)VHd$Ej0$CZBJ%_QlOg#>pLl0rGL*>h8}a z{mXBcXq|lc^ycrKa@z6>{q>%9bRPdc6E>4E>Y0wwz-x<{MPeSd{EL3$bKfq8^PA-t zo^smy3*|IPim%+|KpzN^)H$~5hPJL!da!fjHfShYokG(%xIrWy?ewG|@ z=H6$@{(Tv*NXwJk(<2k z`e|3MNzPtO+fE%`lKftd1ascMy62o_tCH1kE;yraw^M)JC*h33w<t&fI@9lEHWu-*_mKu#%Xt#N<8w~;bAt5Z{D;;*@~RwzFO|=(47za*<8mq=KWOC4 zW!;M2$<2e-URIK;Sl%n?A+Pex%X+H3;zvozlq*+U)#bHc;aK0d%Wry8+OYi6Q%*~5 zpOU2OyuFf=J^PdnEWDZze7s`$^c>T>%2+Pw)wc^dvOdQTEWBD@w<=rfo~ycCy2X0h zK{joy9($b}&z|{m-PnOib>p+iz=ynrU9E+iY_K(T`QDW)CU+fpZIA8O%GmVD$uU^g z;%zew|mueouBug9?R ziNcYT<7INO?*)^S1Lt(K)h}&mJ*uT_(qit>Hym8n(AeBjzf;-v3(J~Yj~ZSkx97_i z=(OI+fpY8K@+G^u@!$o^+S=qUepwnZ)9|u}riBZY7VX_w-*RBp!9=~2DRRCe4=>7= z)Gt^p_w~z~+RK_+yy`N!`7e(FWC?ApX_hWh>rIzZx3IZ>k<`>MyliP(V-#5vY&pZr zmdHZ)uRp4DW2E9K?Hx@^WFhk0V|HWv!7OlDd)f4v)913-%+x*QIgO2oE^~LfJ6XCm zqh6kg;J#w6S^NaKP71ifj14nC%HOfE@^}c-bpcR&sOBVPX8}_g;w7I0=>$3_Y zn@i?@T~^$(>~i91F@HtgH*5w`kN&5v_-|_8uu;X0EITciM2#wp<%U^>Nznj)!y1pO z&DQl_Zm{22`Tt&PzM-Mfq^Q%`?tJ514_DX+<)^S8*h@Ex4GOdu1UIXJbl1!TkOTBXh;scG-d%OG~5`a*jJP`I?$H{fcEW<3L@+`4hLG=FOt4ywtaONz!Ey zAb&Ql%jUoqebTlk$zYm_k#9$c+blyvOSTH>FZl}EVt2NYSq2ruGRB{QA%ELqpR`Bi zEV?*d-oMAfwkxLXwndo?sGK0n8zi^NF-oP~_v^ENpYMpR+$tTmq8M77kCA51VK$=H z^&O(2V@W%XwANM10FytQI_GWfix?3NRocuF64O7VXTwoKzeYtZDWPejqviN~y7Kdd zm7mU8^%V=y#A<7rEYUkt6OBN+m@y^Emi_2Q`d1CRrMrQ?jZPk@enm;2os5?WxvhH0 zO>ucB+cW*uty^)*);2{yip|kHw@ry=wK9v8E@dSb$gf7${fr~dt;Ga=Ogki1e?1KJNlCi6 zk`q_SJf#mvb){!QX$WawO1kM9m7{B6VUI}nH_sjLr2LXYaFRSPu!T<^47`yJP_}*h z4DqDgKKIG?U6`jhFmsMfH@58X?Zo|bqetW0w7Sd7O9$CtK`cJyW zZn;F_t(cNs-~z_CxP%3r7nlvx1?GH#*={c`*0Z>CJ(;kHK}p|)ooo6;8nsQAbEe5J z`2)Eh$%JjXo^!`ZY1lkfnk(UX8ZMnJVX^y5XiYI}?HslcZb3DaGXBXeO9#E5cc9;u zvNTG+2OXYu=qmSD(y}f8b_>yn()iMJ|J{;hXu{CaqE1cs9ds5FOZm&GHVZv0?nqs2 z_H8w}kQddKU1KM((Bep+z&yoKIEksna5>=y`_GE*bf0KSx9n&Z{vM+2M*R6hnW2~5^(@R#F;Jon z8+dWCe;0S&lG3o>B3nBH9g^+R=AMz$t?CT=Wyt*7m!*@>(%y7q*Qaz{o85%h7Z<#q z8GUThAkcR&xhqPfPn~*Sp*`=Mc4bMivpU_{y3X3VuDCO-i`shr1|xrnJdy~ErI*~b z#k$jx*TJmplp|l_p6%of#ZKPPd34k8D@He4!_CDSZjOg34LbM#*8gspZYy@hhB1k@ zps{inJ>BRg3MA?MmfRib%aX3-J7~lP{k*5x%6mu%RO2OgfA3pe)fGk$yY34 zVY&}VYT@!Ix8Fk9SawWjzb2=@U-OU5NR?XgJH-aPLj!ay-}yvl3v6s&a_^S>kG8wv zG=h@*cS%3K#3(J3T?U#M_YZoF_Y9-YQXVKeTZYs$9huCHj(x6=CkeRMuJ6H{9_drPXRDp#J` zoCdWT=+Sq&9nq#2k7(05HMXPgUhszfo)-0cTBhIAat-qGSM1)NneOhD#-kWyFS&WS zUY*5vM9^t3xr1}PYB;s?l55QM8q>Se$z6q>*x3s0ca~)rpnq;LbNdNxc3m!s`m`j| zr)=Dk4qIX)SC;UAB|s%>Q5hyAfE>ERU7Sj%;k>BTHrZs*$5d=F5i8XlgmSY+`+T zW7(Y6g&jxLw>6H~d(ynJ{K#sVK5_Kual?{P%i7!Wqvp5OEpDo+9ha|bZ#Xvpi1|!mz{CDk3 z7S-8yLWW7dqd0wj*UXAjZvbu?_td+xBXe74*UJOeMB3Qi z*iqM>$WRoAhhTE6d}^(=A=y_RA-1-qIJ32FNquwEv5o4IeU{aCR85-SVmaxE$o4n! zn7!-evrtDTvm2K-*Dq+?y{)bOn7Q>$&53-@Z&71M($aX;WIig`#8RuPWVqtY_Cz=L zWP1Bt`2Zmwr?YLTFeW_7^?7F7IJbYNsbjG}7J*%P3KKeJab>33?Bcoc#v!}T- zG|8l9nl2w0oZiwQM-mxZvAStZZ!h$3j;yI>+2kdUuG(;0Bu|s2k?o6hSX$WY-jrx4$ii+qsL|8fAZNZb&*m6)*1TX|2&9r|%g^78Q29dU;~{ z{}J~l@KqGq_jo;C!VZQ+5E9goN9wVLtn4aFSk$-%8B{ccBy5JjBmr>;Swu!11s7Zg z6%Y}Xab?tT90lAR$8B_U)N$XpK?fa`-#vZr?W)&Co%zoH`~TJ_FMZCb)3>Uts;m3; zd#}5xrkYw5!+1eWvuW0tT%m>G7)RzWX;_;Y8rJyiUfRC8rl$Vz1#``;>iQYHPR+cg zi6Lp4-QWoQ60pfs;}iO^^8{4RZZNu|hrJw(;_5}Sn-Exrc(98L<|YfK71RX%j&C!V zCY|9N(r$6nL8NtPEH2P85U4Sj*@D>Se|%uOqBE|f{hr=h$728L+=>3j=mY~_8jt<| zea!p$1KUY;jSY46gX(DtoYy3as)facLkj3%JZR#A>XYkcS5;8%5tW1H&97^yl7sHt z1x@vXW;fK-FQ}y>;cV*K|J`kyUfndirmDJr=DbFl(B}SpY5&QF(R|!IgJyBs{^>ON z=yv^lA^+7W3hfZHo2mJ#7Vr;-%}<=5(BS#e+*ue})%Eqwr_8TwDwu^|Sg@DANHeQy z-i#_*(s74!=&dbn-h#%u8X|O#%eJr{O$+AFrxO6m3oZhr2N#FpHkQ6m`*@7r*~QY^ z(Jw**kkvXK4?wXh^n3k4=+s)goulh?Wrz6M$ueCd#p1Y)Jj$Ux#z^6%vGi;$oSZ=s zsg7Z>^bX?S0{#E#`${FUWx0J16LwFKYmuQH62(_E%H%niFB=1A6c`f zHiT?ux^AFtEwQr2p$(KSdW@SgwTwSg8Qt1TZCY%a7s-*Mwb1PfJ7~YwvTlaftGhNd z^&NLrM_JNiJ%jE|t-+fVzoW)a>N?uZ^i;T@f#^dNEK^r~pH@xnlyt3NI9{kX=@%tr z++P|nM~m27LX*IwZg0)$rizt~>#aH3=(G-ZTvu6F8kw7zHOYzbGPUO4QHAn!qep1; z{iH?{WjRfj<+2qtE`QbOyLC1q$QYKJIqv169SV(Hy=R8ebk zHECpUL+8ZL4C>uYnm1i|jJqnesm`NV;a<>PB7`x+j_4*iKRMdhP^_+6uW)>ZF|z)h z7*}}pVSj3U*YURF;u!5XGEAbi)9v`N{8+pj)=!PRks@cckK?HgctUPa0D--K=-l!% zb-a!1I5i0IV|DoXI`;Wt$=fJ$xHtFJTDCYyeoxk(x(^IfD?O$$s8zO(yVmj30wD}W zb5H9)=_SX8-qLNo;%5YUI&&UO64y0X3$y=YRFigE6P-S3PUo7)1gnErr}B0@cx4E8 z)%xpnOoNICdyA9mU#LW#xzeS+>5<41QQ}BBIX@NkZHh_*gv)Iw%b#51V_GBJxw7In z1e01=@SnK>_KD*GD-=4uAXxq|a*$7X-VybymbOsZEG$5$gOnPl^qaP#ZiPfhZ?RQZ zwTh*8((Tv7csiXa1bt5RKeomCcZvrCS?2EGXdyLpqoys^Ox?oksI+jXQ+IP?wK&vo zAnV>*F*;DQm7ZD})ThN&w$Li!m<-4MfwD?CPwT{@`+)XM57`&`%P5HCYZdbKVBO+T zYTLiRg}?W$bW-pWTlOGX3$-!A)0yymu8*!vJ0c%rW&cQR{YSWc_}JcEwl-UOT3aDs zw!T-mPw+_CUk*6?g?caowd9Vi<9PH=EIk=73YPseNB3@Ox0Erf`LyO?!5ZOspxLS< zQ1WHA>KLDv>d0*!PXvmqCCA=hwqLeJ%b?cf{Df?+p7Zn)zs@6i#?v$YUNA9Aww|Nv zkuoQKCASK70e4$if}a1hxVL>mJ)m<3*NFeqw$MC~LI3d;yf~hg+Nl*D!<=#t6ryI# z5_+2Mx$)I$V>$+(>;#_=B12M;FM0HH|CIEftou`Oe=0A!4Y^cY_w7InHW$iY#m+g$MUr6f)pZ0h$#;2~osqKyJg0+8YTmGkc z(e3@O+x^^lP}l#@<4XHQ+bYu5o7#%+N6TNs{g~^uH(Y@-%cd&*anjC%_b~!Y4-fi4i^{!skTz*%7|X;~^vvH*F&A(J~JX9Knj5@7jksT_lyHUrAt! zL!E02Xf1Q>Gn_a-PpSAzBYb>>Pm1u#5k4itr$@MJPcDB}B;U0!=bswMKQqEtc|3#! z;`F(6YJ0TI-Kgb!H~yHr@yFc7WS$!q%Di`k+X#1a1N-|$^25*VrT%U_>!FNTlW$w0*^IiWlciSr;@JoH-X0J&6mbr`1`L4Z~2j2+_VlsEz&)m(|%-#OVe3aCO zzQGXGXJUlA@yPkddHEqE5T~!VrnXnhynVP5=ez!4J~)!^_7Bc?`vY@VpWy4Y;o5Qf zrgCb1TITNf#QAP~F?a37+_ew$im*iHZhvIn7|D108|SZxsV;;)bJ(<6Lwgr67TYa@JpguC|U^6!h}KN8{3MffWb{(6Le6ye`SINgFw5|`g6 z!g2p;PMkk9!VmPgIE5 zxakq8Z_C`(m-E|(F_^phGI#Skb60=nuKvukBk^4Q!*34;jyQdV+~q-PnY;ROzH49R z?s&x9)t9-eFLT$v%w2uMuYpSa_Kno9W$xm0er~Wf{xKim@emS-)14<%x4&iX`h)Xb z{h7P^Gj}nWyYn;Vu0G5Q!b&lB^AGdVNd91thmZh%NZ`swPRrc27w6kB2y<6H^I|VQ zgaqPrXUx>{TIQ}i&d&{lFn8^d2y+19CO;CtW$yZi^IiWicm2cM)tR~LALgz;%w7L5 zckRR6^$&B`KlzdENk+D(Wu6wU#rdwj%=<+0-T6&2%mIj-zLD};=B|G@-yIK`yY^u2 zwx78hAIy&qYr%YKgx5y+j0m3-;f)dQ-al~s6_Nav5&mF=@AP;G3B>8!@~*9s(=vDS zHRor9L72Po#N4$Xb2pxt509)rKEhplvVU?Ue@cYA_GZ6pU*@wse+UW0>HFxZ+ut&G z}%Y3yLKZFG0W>92%TILGTFW$yNO&UfoDcjJZm(6A8ZBO~06AI`6cqjro8uD08>}Fn9Y8^NNVywHN14i{!icl=I#G#JoA;cl#IT zuk!LkNFZ*8_>}mtNPD!*+lFg#zH1NWnUQ=qp70X|m*RA1-_-HgGI#CI`7R#wK4D1a zu0NQ&{cl9*1c=j}fK$tFnY-=d{O(~C=5GFA?)DevZhvR)_IKuPyfAnBKXbRgF+V&~ z{-g+Z^8x#}MDn*r_+1_kA%QsE@;9}8TIOy%aDL}72y-_cn7jTvD0BkE>2AuY<+aS+ zc;I~3Kg?Zu%w2h-Bjt^al-DwM@i~9LFbZ=wzL*zB@&`w_8xQPv=MQ5;CqSI;X_nd^ zEpylYoSzX!VeXE9%w0_8xeX|cs++Xo;AXWIo&oqg=a>1w+PRU@Z1Q`i*W04EeXrGnGo3@TITJ; zl{nwc2h836%Y1<64`EQ=!SoKCQ!84;f~Vq$K#MqW>>J3#K7oAv&Jp`R#ymLo1&mi+ zAA9(GdSM?!eg!Qrrq{8;@r&h;>4iEX|3q5i7Btw$z-Q8OG;!1!9I=p^=@m2hpwgxI z4>(G5DQ*sTgizcZ5#dKgcx8n1@2gdeo5?}{EK@-~FYFxhHbMTXkhcps+Ky9)fV=+c z6mU0R>=of%0`6Z=#@yy#j|6x9&DRH^aq1DQpRH7`pSkg{Z; z5OO|0x+~;-zTo`P<24^oF{U~3@yp*|v3;&Rc>hv2o>YVU?V-Tj%~#Cb^=0OG_8q4w zW{JXJnP#x9X`z;8))02{d%C%jxZBmF zh`an8gSoeJ=-=Pu5YO{?@09#}GcYAT-wY-`C-nC<2N6HhaqEV=m=1 z$lOePic*@5@jN1zpJpB)jyaoCn!zJ%UHlS*N55{BCuW3(GSi;8YmYL6$2(5*@_Q0@{ZVG}i4XSj3y8b=9AJhJcjcv-(Zt<+ znr03qUK*~SW{x3#bjZh<6N&rBUp$Lzlb8QX;;y`L=2YUJdHKtTf8g;8h^K{ZGR~|e zp6l`Jh`W?-wjw_i=nl%nM|m92w{fY1d4jmV|2{|D?f)Hu=hwLL*ulJ&vVJG?1#!1O zcQSZBja$EyX%)^jD0MHBLEPmf;c=?-%Z}<3C;x2VHxW$RvzOH5`@sC17SMwC{#U6iw_{ea4bTzLLf8EP} zm-u@g|CG2(JzDOpkb8xcOt^rY-&6t~e~P zFFge#Bn0}KT;gtj>u>rJpA}mAn_}Xw{QhP{%K8J%A;jJBbfBpuzB*igpqZB9FEaCp zcMS83%p&5}<4aQfCFVlnE`Eu*ocL3rzr<`z@t2u9iM#!^%-m1hpU)pA-Vm-|W}YVQ z+N;dGM0~NA{|0fF4lth+cl~*Q`G)w^&~SjkT@Ky;e}L&oe2bUgmH1sA-;ekq9>=r0 z5BGQ>ahJxKgNVEG$C-)5j}8sv%u&SM_Kq{h5qINboT(vxr01_E?w=nnAfD;vpGn-+ zXPh~Qc<*pN7-udd?&hO$=5pfx@#;F_E=@4MCGO%+F!vC5^U(zJ5b@sO3KPr|#NB*8 z!8}jg?Vl6OtHj;@Ho?40+_ldHvx~S(l_uWC&{b4Tl_rz8OOuTyz9SSWO&M|5pGTQ- z#Bq+ssnSd$KF;Gc#1Hj&Bk^e-Uqbu_k6%Q5vB%dD*V{%KQ)zA`eu0<&2jZ7`{7=Mx zP!bA4r^kK#LZrG`Qsy&Ve{pniGi+ z^mqetobzb@nZ$99qx=HmwI08Q_#%(rLi`+$-%lLR^3(O7B7TX-UnPF6$3G#y!Q|aN8Ifn?aUvE7kd6jiI4I4 zpNUWM_)En7_sMi>5#Q>y|9s-7c==}#KRP@IsWj&kKQ7GQ%Un+UP%r+C#4ic+E6iQQ z@A2aAB)-+lf0p=tUjCcJANTSUY$0reg!Yi+qc#{{enK<4Pa;h+A6F=GG7ZShPEWDQX*zZ^<~6VUY~p))`TdCVEqSp86=o>$ zo?iY$;_G4xEfVfNhn32TY{IHLiNF2}2I9;x~EaO(nip=&vwyh|`~> z{Y?{*T&1-B>BQap|NYH!;#0%*E6pXu=XiVr@#1j(UgkF9?)Mm z&k%R>b1(BU@q4}ce@Gnfc{x>>uZiP5tnxN=1AEtA36nwGwMV|$m-u5|yn)28_SPRk zoI*;zY8nkB?f^Y}%?cZTctHP;aT zt5?5Uh(8Qew?j){r#D)hZ3LW z#m^!>$KySTuk?66ahHafQsQoY8fHeP*1J zz33+sZoC~}x)XQlAd@8S+T$Qonvy@-j7`ZOZH^?4Yb=~9&9oH%STm2fn-9jC(}}xl zE|umy;#OBTW6dSR@ACGy4aA@E_?^UYO;5|)LEO!MmF9Wk^aJlO|83&2aDS*YUlRAP zC$yrCJ=?2)Ch@()_Np+s#D{ylfcUu~uQUe{KPluD<}l(9hMeAS5?>SY3R6#feaI`# z8N}UuGR~|ZK257n-{1H(@iRTXmbe?w&8|q{#Zm3&)tuq|YzrNAed% z_!$wtDrNmH=ITiP#t6SfI6i~Or1wYnMe?7D@KYlEr3n99gnu02UqyH)?J`wL1u%DM;;$V=8uy9RFGd{T6ZTv3CH|Q`hIM-aGDl~4>N;>KbZQlSpL}p-gHuM9Lo`|^nb0ThO z*d{^m7D@9Lm4-kXs>rn|wO-)!%9BVv zP<0N|vW8+~T+Cu^%VA*`QAGpQGf6WR2jiP+Rvg)qVrjYJ00b){N@_D|9~A5OD-Ie5 z;dC4omr6B@BTZ5)?O8ln4MSwhiU&*Y6c3S&E*`3Tn>J5zFdp6Z=x$Q11FU$MG;Q&) zFo>2IGz?X;q(loEsvd3Bl3>8VqdRd)um^f2N(+{hNc~Gnr2ZwPQrnUeDY2wPDpTTi zUuw-D;_QYQ^Ki$1x|KUt^C(6n-2G*gQ@gGSt9TL6 zTOP&MdKA_5C^o~R!NBl1w!oukFpmcNtX6V7Cm5i0+g_BV7>8v(BB;uE7rL@*=Gl%(7l* z1&4Ew2lJ`Nhed|zu+*|5%^#dSxUwT{JPh3BM%qRv@SvM$*y+)w3SMy-z_Ibn~%=Ow&(e_QPX{3jPqmbK<$hyJd%jHH&4UTC+slnL_au;Dxqor{ArNf!(C zb4)80oj`-rHGi|v)M1&C(Hiu%izy?Zs91(Tk)B%@MLRz@ckxR}X&Q~Ahx?+SZCyF2 z61F^OVlPTCe9~@l${K#en zZvp*$zaOIK%)uPtS}1i4VMQ-cQDJH}8ph8~J&XlYo1a|>KaI2!-RVp8dPPZaGz_xT zqn9E|^o+MecbO7BqLk>tv?REUfz^W=1Ryf+4o#Wgf-xU%bTFYi2B%-`;6UrLQ|3E8 z&nbx>DT{(C`C)Vui-TF7>R23Ju%c=0M;_}nQy-ysFui{@Ej>N0s)`;^M$>!KjM^E+ z^nACO%~;Yi;%XZ!=FJ>SkE$6{U31cZ@_exHd2HSz^6+>pdK%sjA56v%6XR7{ex{f{ z#EqWghv(1HL!cUJYG*W2C0lsfSXI^B1@*NvO2}AWhYd-6{8$yG?dP6^=s$Py$DXf9PbI6KUpwz)c>l*mvHtj zeDcKKAyd6K@f^{CRqsPM`%Cr%tB%i;azqDKJ@`!bUalvw>O%=<-N!nx>W4%BJ?p@# zPbNG9KfIy@tU5m98!0-l>iB+5_PtzBVAUH4=ZFrhdL#V5XFss&3*i?XSoKW8)`2xnXTsTE^SZ#QqknTm z2Ub0oaP~Ls2Ufi|;T+L{RWBf%{V(^%jIH!9Pl0E!Gs5j-kxwKe!NHtSl7k&>b~i3JK8zxarOhNALB~>{unz1`V;I2 zRzKQ*1b!q*$?uEy#7Bw_tbVkK))QFuQG~O<=j{Sky_|54=)kHUM>z9OTrRNcGYD(_ zfmLsW|7rFEt9~l{(&oUbuY&*2><3nTwdV&`{XY2Ri(|m5KMh^JPz$X3ThO25_`s@v zL|EGmSoLoSXFbn;VAXFUT)v0fZ5QFO!5+)sA<%Z{==u8))_w=pIKkX5?c>kwqu`gh z9a#Mp&}IApt3HXawllEmwebIi>kq7YJ#=Y*VAY!mXU8!6@V!D*Uqn1dbYRt&5!QMF zt9~JLsVA`NYYA)r0;|3We%W4N)$f2Vae!41`d!9}-|tVrFWU>O{^y{}_5!Q^I&>)) zSoP059awdI;VSb*Zckv<@!dO(53G6ybcqkFdLQVrUBIg29?BXASoQ8yhw@h3FF0nE z#~JSpoW{5$)8Y=g4sZSaqzM`4Vpnu5=k>jSLiPJ%A=0ahLJx%z=sKa;SYX9BB!Heo%_ z1Xle*!Wsuyb<7WX{^`#ZSCOvgpTO#02mk%F(@ zRy~98fKI3ZE%EBixSa67y%S`im;xa0INQk@PJI-u3EwaaRV7j%jh+BZ`bD9hH0ehx;nPu_uCxf zQ|s)H)m+lG&cGT6y|=b3U-@g`N(q`bfgr z@}3J=^)ZBdiVm#$k%V(Z2Ufj;aCtYkE&mr|^+2ja_C8z(V67YKpCh`zEvU1ORbcfW z2VKS_u17SU909L)3aP}YgSP!iFBEmVM1FIg4$p_dEtoma3MF&>BGvV_6xjiR( z7-L|d=os?@1QRs9q@98D1*61Xxf};rbtt`hv5x<$qh)&Ku@0;{#!N5yfi|$OkD&7h zXn3LiSYj-V6kW%adUW4WKUvw|!Z_?mc^V&B<7W`o_`s^8EFC{uE=j?6>vjBS9OzhA zb&UhPkY1T`jtZ>(f_YEJNpud>aWcm9W9(^se;iIDUC%jzHU4~02UdNtrvs~w`AW}G zfmOeNu%4p=tB$!M`;R;hfmOd0e$jzd-$Gcg=>ea>L>X}#{)dtzfr%ov&Kgp>_^#hV-{eoKjyR?(ScR(2EXO)0#-d6e$jzd z-;Z#nTpI^g-4f1DavWgQ`w`9&9aweLS@#RS{urwxrG5Nyi#qFP2hsYs^cg{K@~aN4 z<@O=0;~7}>0fcot1FMd67#(lGs*fV9;|*B#a>CgU@^}MQeInr;(ScPz8h&{{0<8LE z_(ca+y_Rt1XFQ(+tKLXhw+mSHg@kpxfK^{fSmOYzzM8OZFR<#D64vbnR{aY2*w@F2$RiD!PmV*ps|)(!f{tOKjw8~W$01FN1!I9A9p+Y(L`Ih+(7 z`(UD&bzs$V3CBuUN6dtWlY;v|FJ%v~>bTp#u8TX(C(76Zte&yZWnEy^5A}3l)sKKa znBxGeKAmuE2jJBOIpNrF_FoN;hm(S@ zg+78kz^dQjt-H-z7g#;_L6>!bRsR!VE%#Y?Msj>$_520;0jvY7{vqMmfvkTDkB5_j z{{j6V_5iEiI_B2JeadxRVD(@;>$lv9YWl3y+7Bf=_^6&K_XZYdsxU^;yuzu^(9V(+F!>XTc-! zfz`7Vx|9X1`YKNcRvq_{ON{5TfK|Viu$Hv}9w`f0JvTy^vVc|J>gm9$-vM2=3t07s z32Rx8!!v>F1FW7uL7&Jvul^VD;d#PNIT!VAXMo6FZD`Oz{a1Ck12rP8`l2VAU~gsSd0IkQ09R<&k>;YEKG0-7U0#dOhoCb51lEfOA13O*k? z3Zw+A`Z~h8?s|A8vjd|>r_0A0!gR{e8N2Uh({=*Q7NO2Ddr>*>I%(+v?!;&}E0tDZ$T zHkI{#;PG%$Fz!K?IDtLDsuy706IsW7t`b!aCq*9&eH!b)svm-Nt64uB9uFr49}Rsv zdw^9x*3*GiKLL6T`+-%TPgu)phDYK9s|WW|*0O+AKg-jBRbL9dmdgTGeU+yJt9}9W zI`#vrel6kH4AwWm8==o+53uU^NHR8y^#|bba8mGg=-5Fi0jrLWS7UQne;FPR zCk5lPJDBvVc{u zB^+zyIJ4mKa8htR^d|NItB!jzst&9=?l+xiW;YCC_q|pfSoLq9pUQq<)o~9mEerR+*0O-r(-pdu1+02cPX|^#7rK-M zta=II*lApcA@F!ODH!+BPMppjVAaP!KZA8()yG3WlXYO#k0q>SodA!-2Ubrt^s{(f zVAW?qm$HCWuZO;v{lKc9ML4#E^`-E5I4SrX=x4JBSoI4$9a#0%(3i3wSoIBrwX7TA zk@&#sxf%L0UKd#P-+4N)>c5AMlNUQkZrn*G44 z&m*jLYl7!O_5iErWat;M4y^iF(4{P3)t5qF&3<6jFC(mFT?x+`_5iErH_$I;9a#0- z3CAvB{cdly3cs)0;}f*=$G-jz^ebv(}7k0JM^{e2UZ>TNY{Gq zhDYiKte$V7OIg6Gx21cBsSd1qN9dPxS-`4y_jF*@dqTg0{lKc164ts6g-7ZJte%n3 zrEb8gkM(q5)h9r|lFI^C{cukQR{dz`SFs;h^*X{@x7qMW-GJ3I7rOK>u7<0~X|bz0ekSlWjB)KQ_8Z38z(hYcdi!kPjjS&MzJc+Xz?&E^1HO^*D&WnGF9g1c@nyhU7~|S+>}JNBfu){z z0^hr}#Eb-$SY3#SGzX2@z`@pxc{-vjX4}3f8>C`l_I~aEXmUa69 z-^n_z9mVcqjO#+`DF?or^&>s~7r@(CukrLbz`tXCA+UUJ9M^DS_ppxZGqHOaUkZF5 zcyBxR#RmgTs0~_DOi~=9topz<*?n=Oo1*WQ=Pgv4#9m+zHe0VJV>1$eVI5en{i0g27g>J^82>2!4fwB&-vb`T_#;~A zHDutV=%2&$GJC!ReuZ%>yhj_(xHaJf0#gFkYq=fad6jisD~P?u7}o@1uQRs5e`nke z_zlKoz;7}h2K*M|iNGTm<2pd>ZN^Q&2QogHaN-?@^*ZVq@Vv|VN?Q% z&-#_XQlE{$AF#d|_(R6O13rlHAArX)eu%JM-vicbboe@Q3=K>PUjdJO%otx!*E-<6 zbLt6tW#yEJtjEUQ5KiiDMYBl!gPhVSFHP zTgC?iw_|)5aC^p6fIBdr3XH){3GZcMofrr2WjZ^Y6ul81xludr9~{eI&r0AfjMo5X zGQNy(0vFyW0VhSj3La_O8-XYB_Tv3WVsG{X>ov@6@N{MU5#Y(}$1@xf-B<@sivDMK zu;WsC1-Lt7ya!42a5yRY*YISs{vABn(J28ZMQ=wZA9`)G6VB_7=Q;p~*BIgH$?IkV z@5^{UV41t{oPyYXtPcd1{u&8?}T44?z5W^ z53qXv3eO2#w^!jwavb2K=) zdpkU(tltBS10ALNfu-EXfu*d!0^>qBrB?|jhB%xQ{bSGbx#s~^PmDfXkKyEnQaa(p zP>utf6upz@>Ed~S)w3Twvp7y3JUBR00@iEA1K}CY`Vim|jK>0xWPAkh9F9{-IB@{$ zz?pkk z`vqaWb_%T5PItpo!TvqKhcS+~BP?~mGp1rVQKFOyEOp2QK7#c@z(+D33Vamf(ZEMD zJ_NXu@sYrj7*8UcIL6_m=vDAcW_>2`FBs1QUchaO=T9Z3unw%(W>10VSk@NgcB#R4y@N~Plu5T27APKy3HJd0TW4tNQ-LyVp;l{kfUV7+$QhH&gu*7pKF zjd2$6>5TUWK7(-r_)NxwfX`xFLRhcO0w+Zu3eRHpj09f7cp~uGj4ObbGCl!#8Dl)N zE4G~LKPSMfHxN#&a5%Y~@hR|}!}tt%Ryv#%eJMQWvi@t}RgBlb|0{=+qF)Zrd92?E zd_Ln_fiGZuAMmdkKMH&y<39sm#P}89)r{W*Uc>lH;B#ePBb>OH^{)x*_0m1?T*7)A zx+oUAlyL`O8I$_}U&eY4@LI-6;L92J2fl*w5a25rj{v@k@u9$1Gd_ZF;u?pOqEChA zH>~5iVTpAPCqzIpWdF;+n;E|bEOW(&z&Ek}DX{d* zzks)}z6bbb#vSPSTd`Xh?*%OVl>>Y$>-z)CabytirChh6z*jIH4ZM~84Zy!;d*c_54QC>-TuZ3{mTM_T0?YM{;QH-2 zUUv#~d9OVcIGwj^8gM7ZwZNSj&jObBs`bEovpyfVJL6{H9*l$Qz`x+KPKPe<85aY~ z`?6)gdF)>aEbmRu1MbIqaD7k@eG{;pyKVtK zfc34wa^83c@Hp1D0XK5}?*ndT`~dJI_G|~1^QcFF7-7 zfFEMqjp`eFjPYRLrx{-e{5Qt;0>8z09M19n$@p&IHq-!=I^nzmjYKIpXG6nK!ZSo; z`0^>GPB>-_XM7s)p^P^IAI5FOOtt21`@Cp&o|I%4n+dC;)zrL=21P6 zfUS5sK;MgXU@IO>C3zXF16%R*gig;JLjtzq!IY7Q556b?Tk&AZ$jf3K*op^JL*Cx3 z16%QofG*EZ0k+~f2>MgphQL-llc3{+HA=u%#x@Qcc{!{DTk+s+Kpwu7N(tDC2fJ}z zZXg?AEBnRi(0j2CY{hdn^gPyqt$48O<|SAMw&KBQR$gz`fvtFOD9y`f9oUKorzv@s zbzm!=P0*9916%Rnu$tG0bzm!=ZP5F&4s6Bq0Q7#W16%Pt0=+-$z*am@Lm$98uocg9 z(4Xe^1h(S&0D2Mofo&nf&Iz*ao_LLb69uoX{l=tEftw&EE8eHiP&Ry?@opN9`-DFIvY;QD{wpSc}?t#}TH zjvqr%0=6=*;`)EyD5!KlG3eqs4!S(t8`zEtEM`9RaSq#Z#*3hjci4(&3G@l916%Rn zJ85|nSqHY_Sp)rG)`6{f@Eq2>Ls$p4;@JTGP}YI1cy5MX!8))N&t1?DV;$Iv=N{7iVIA0t=X2!pr61xuoX`p^b=VJw&Ljzy^3{UD;|6gEpHm@z*amX zp;xmGY{gR!eLCyFRy_F3C9j5cU@M-<&}&%-w&JORUdKAH70*oQGgt?<;+YS9ChNdf zJd2>uVjb9uX9@J#tOHx|oC|#p>%dk#7ePOXbzmzVe2$Y>&pNOb&(+Z9vJPy;b3OD1 z)`6{fZh}6Kbzm!=TcJPC;{n);X9x6V_5<4{#!o?C;II|X3(yy`4s6BqD)f_C2e#sQ z2l^t`fvtG(T<*M6SO>P^`3m}}tOHx|d=LFJ)`6{fTDK2bc<|iryfat_w&Ljy z{Y=(@t$1>wpT#<`6;B`Ni&+P@;wgl_gmqvmo}tjsW*yjyXB70MtOHx|OoYCSbzm!= zBcU&69oUNJSm-NQ2e#sw4*eX~fvtGvKwrr^uoX`u^mADUw&FPz`YP6et$5Cc{wvmj zt$0>JKaX`_E1nCWzrf=S*op_AdF5Tieqehch$^8Uj02e#t*4Ej~<2ewx--VOa~hpl*G zZAia{bzmzVe2$j)8`goXcru}{V;$IvCmZ^;tOHx|{(IJet$1F9en0ELRy?mm{{!p5Ry=P(f0?%z z*ox;H=-b&3Y#(Bb_sw}b9JbxdP9Gl{lNAy#{Hl_;jk4? z0rbCd9AGP+a_E0%Kd^n8aRu~e9Jb<_1pQgofvtF^LVu2RU@M+l=+CnbY{gR#{RP&6 zt$3QD|Alp6E1uJ#zsNeU70)v0FR>16#j_IntGvCyRy@}PI{Sg`-x%XF#JtxWwy!e2 z75eKATk+f;_&GkX70;v4-)29seT(rk(BE;`is!G;-(?-xisudJ@39VS#q%Nb_gM$F z;@JiL1J;49c)o-FA?v_aJn8L7|A=*9E1pi!KV}`+il-~|Pgn=G;@KDar>p~8@g$&s z#yYSSPe16Nvkq*%dk#2S9(F+aK79rxN;Z_5<60GM)%dk#tD)lp z9wlHao-3foSO>P^xgL5e)`6{fZh{_X9oUNJR_K3c9oULz2XtH@qy%i`de@WC+p!L8 z#q&J$_N)V2@%#;X2iAeDc;14Ji;k3lt$03!-idW!E1u7xmsfUS7&Ic(lutOHx| z#M+aN3z?LFt$5O*zri}N6;BTIuB-!Fxu%zZjvFda0=DAm4}BljfvtE-pyNU*C15L_ zA<*As9oUNJFzEZT4s7N6;biFhu?}p-a{~1JSqHY_se_)&I`^!}^^Tk+ft zeE{pgRy_AZAILhe70(Xn1*`*G@jMBA5bMBJJkLWfWF6Rw=Vj>lqBkXAE1ox?7qbp* z#q&P&64rsOc<>o?UMcIqRy%dk#MbK+m2e#rF2EC4TU@M+c&}Xm?Y{hdh z^qH&!Tk#wPeHQD$Ry@Z*f1h<=E1r{}&t)Ch)-!H~-r%qm&*{+Tu?}p-vl#jZtOHx| zTnfFJbzs}X_&3lOIBdmp1N4Qg16%Rj1pPzSfvtG{2>mqHfvtS5^ceKhSqHY_!RP*Y zXRr=z#q$dEGg$|=;&~hTS*!zF@q7$@G3&rqJfB1Vh;?8qo;ICGU(PzPUB(#S6UbZP zuocff(9dBV*op_=AIMwDIP^83O%RtOHx|90dJ5)`6{f zCO|)*bzm!=BcNZvI0+FJm3pisw4$Ygq@j;<*X><*Wl+@!Ssm z3f6(GcP^ z`55}OtOHx|?1FwB>%dk#-$B2gbzm!=^v%dk#=R&`WbzplZ<6lF++hHr7 zOQ3IK9oUNJa_FD14s6BKozAObpR(Q)n6C98<Lw*rr4&mFW#9PV&Z^jF~djN9jR;3L_C%OZ(iIGhwcgRHU7*}pgNvFzzi zI5FShr07S&^9B1S0XMQ|3jF6goD_W#JW_ug(qg}6&tmwo(UgFbqGS3~|61TH*n?>$ zalOMy(J>s=e+Tde_H2XyW`~oaKjHbG2ELU&&%uAY!%5LU^8B9x-^rd`@IT;iQuMa1 zTzxtMKgga8!ik3+PKw?e9%-LGz>l(L0Q^rnoD{v>^G^i+6MOKpvBX~;PKrLw^Vb4n zfKbBMxe|YOI4Sz+@JRnI27Z%0%i!PTa8mU3@StHRZ36y^JzL;UV;wjt`gV9E{v*Jx z+4BVaT^vq|{vJHiJ|6*Ru?Ii-OZ0F!DSBGm`P%~Lu%{#8gmpM6dM-RtpWeWI*wY98 zAr2=+FNa6!GZA@jKNKiT1===jct z#_tY%3VVWk5G`>yDS9D1(*F29MrpI17Wj@MYa1ulRoBvk z^$wqR%zO&yGLNons%s7(_cyModG_4u=GpTae9sRbaOnl$XI**%JuLFzhUU7)rn(vg z;wJ)n`7J!)(#uVKwB-*oj;%g9wQ5bXMmIKApE7A)@VH5D1^>yDKb1#~>Y5|+fJ!eX z@@z_frASufv6Ws7jvhQIk@}*A5G`f72U>cOT6(6Xmwj-<>}EVyF?f_^YB}^2&FOWG zzNSyV^w#HxIoA5Fma5j$^D;R~<2;Phf*&`?*bPTsFiiYsYkIW_o|qXvX4A{y@cjJA z7RDJrXEWvDo8HPTKZi47@E?PTr(Pbhu&!~^tj4;gS@Y^snn(7WI@;A}m+~7fbrbzP zjCSaP)MwciNW0PQUsOPk?S`YEqUx}^#+h}s6YA$puddhF;j?#XdZ?SeU}jbI^y!Ut z3#DY1@TA=ofgjDSYfvespl06OxpfURCp64!t}B>u_%Q>U@HE+!)#_(A)TIbB8ms3* zncY;gu%NoRxpDUN17%Tl z^$j3TG~TcvGXJ9~I!Ht5KYUuh2ExmN9R8>EDWi`36Ce9PA}xqr3`Z% zz5ICi$co-Fgh}HaLy8~o!mIdR`-q3P3mWfa!hSrERitUscsRxN<2^v}hD!bDqmnS* zm4y9xtB4e8Fj{K7OJ$u=lDGS6W4aSY{piwR7;hV4Ki)k=GD*{<@o+lp*DvE57q64# zq5W`b>Bqx4GTKy=#@kMUAFmI^+nc4bw<$=Y2q0M-g?Mc!m>&=4rE+RXxvu?Mk;$*$9TZQ;OBVSwUT!2F&aDna0g`lkaf;~2tGL#f zDU^x&b)}ca8yty;@7c@S!yux@D~iNhe?4y>;_c(b!>Jwph5N_r6t8CxiT`Q5ib%Yz zUc4S&yt$Eh-%`Bn7UIo{#JkUnm*d4-5sBB0cE$lM#KY+x+Gv#IJwoxO5ytlJOE2W1 zf7eCgjiGphN!O&?i%U*^yguuVnMfwY+n-(<@7_o}d~dN>gV9ps;Sz)&Z$8DFM)`=> zi(VS3HaN)h~i-$!uDd0*X=Ec#2ZZUc4{zMYP`OYc$+9*GgSof`g-y3lPJG_xOdsC z7UE5e#Orwj`6OO{FCKoP zJ87t&9!s&m-4Tgb-mc~28*T&UZ*MJKPkCMXqm1I{c){(S(0;TC(o+;KT`(5NLwYI_ zul!aw-w&aDjkinU(J%?pa};lH!B}WHxCM}3zxybjj%S>AXuO`@Ka(x-Y$waobom4_TuNte*FgAM!z*D z6Sj9Oy>xs35Q$fS&qYyyB#n1ZBwiYw(2OJv@y5|hs35pM#$G#;*b&@L99@8WYqKOTHY!9AvEsmB)haIDn?h*vhP;K%!nPQIGeL`#iV zM!;L$z=!*=Xwp1fGr>BeBx5CQM>Cz^U^^=4g*>W?85N0FPbV$-O_?T*R~hlmpp(wk zRJJDd;rB0yJxVgZeU$bOiivWMpcnE`F0RGsIz-Lxd}HMD8EBYS6^S?XHR=!P-=oN< z@fszbo-^krXvrqwFmq;-}4 zYZFX7COs{!mZWyG=^thy(>m6kYRV~wRZOc+m(u^R)K;BPiirn#0KYOd_0Y4^MH7=~0 z+0fK9h(^(%rg;k*Yw7^2W-LJQgJ#W!E+b5r1vNik*1QGH^A|KzZK@k;PZ?BQGmi>o zGB7CV-z(qDtRi>CyqROG>+8qhlFn?p%u_R~y3tHT%_wL5f`%G%bluD&12&P0tFMEr zq_~Ql(}V2)d7EBKgCuTn!9EuISLaUjKiFBo|2LYupkNUF&2FfvUr<~3^Nsx9cIeNS za8g}kLtXu#`q|BO^O|H)wXnEwNC6G4K@%5LpIkS)s)BNls2ntJeqBSA457ITn(B2s z22G#c+(h#yjVkJwy2csRHFX8EFwH;;W-iQ|)WglE%&%*rEbMY=txS5b8^$}u(%ZF< z$7tG&rFVrKv z{d`J1*v3$c2iqP}VrjuODW|l|-C=?AgN+PUV%{wbz}#JzaBIR658vJL3i05IUAQvk zqsd*08#+n#Qrt~#ff`S_LWuZ#1>577AI^}$8eM|E%nW0u1^wvPKR3(+NDJO$xV}y^ zc+ccgM^jD&?^8H+G?fa2g4GA-{fS6YmsuTSs#d@ubJs5#P__^mc~6 z(@y__)Y05e%TkX&DLK4oWBy72*O)kU46f^ydt7s{j2rKSG2l2$a4BxG%xUo zwh{|H-39&YcDsU#!dz2OF=k9*Rk18fXgP!C)T-%qGiNsx5^J72A0jTqSJCBm`qT%i zN9iJe1??ntRrJAMeI0qK8=E5*L=U3YHPlA3BC!Xj#x6~zWvO%s(eOirNZetm)}cQ* zNc`Z~LhXb7W<)>wM+vwjKzzVHKy)0uRY#i+pmTF1%sB(yKs5!D$8y*MDJB;yaSb#k@$(2LaM6zvu*RoT`S3e7sC!Jdg-(sb zdz%~!oJ;>G&7oJUR{%{Tu*Ao{q49w={^{_bKuYJ(E0zeL`4w<)##aKjLXNK+xPVd83aei=nY8<V^lx3`q2-%*!h3>sTMs0lp2AWFFX?Pxj#1z z{j6K>2)1|B+WaCxL@u{D)%$eP;Pt4!}bRIAT3cRq%{z!-??pj6|Bly@OC^aJ^$M^!@8Qps2+srB6oAE<99q~TF5EbY~nl8{%}f;^3TZMO%6;eYpHz zrNxDLH*I)3h;mc@?u`ESg^Zgv?8wz^xx4lJ17qWrB?|6ol^C$OReZ;?AmV}?jd+(t z-2R_N%)2LzYM*xej^_PZsD1CvX^Gau)8jiX{vKPfd_OI3=YG5e&wc-MTYz?N(>vWf z+q^vEnRAcdba`!j$KHDoEq#BDHhzDOHfhh#MXNkzc}DWOzOmzXEZhI(9pxszbJw1w zJKx&Vf8)-Kr8}S7v#s#H++~H_FFSJkZ+w?p^OBSntz5V~qjEvtE)RWq@sX8ZrcbHN z->@#Z{!vrYE1(Dd|~dUCp!U=ChmXHVjP;xW~lPXQwC9C@=lS^rho2Pw&5B zLq?+OW`pstE4_twqniXAPqk|yrw^i>l74-AICk}b!=8Km#DfjS(}jgE7A~DI%q$(> z*YwZdA*15GjQ$(H3brAu^{Q4n7UJW`H;#N%mnRD2<4R)u3djcL0Z!`sr0?M$NgbKl}l?@Q^H6+>vYI{&H7 z%Sy`DncD|%HSs=e%!2c8AN+uM|AMTt?&jJzvf9o6V@>z;Go$-xtF`an8mE)9GZtjE zTToupruFGRa9mn*|0t2{m#GT{FT%EIy5{u zN9u6&isR0C?3@!1FSidW4`HmA3z1Q!miM1X%dHKuZ@@ZUc-xc3E+>{pe=|%Hb#^e>pPnbbt`1y>R z)^Es-?>N;ApqXx|P5U~L``oUjw*2cv!E;~q&%XhqljqO@>%VA|zwB$RaiZV)FA{z3 z_yX}a(0-mxW2wD~KYWiFNo8PvPuT5WOkVNw_;(D?pkHRhAO6OSq;hDV$ff#y(SO4` z880k9{*nAxfBO}cvLiQiOP6e2)0W$$owOxQn{A zfUocC`+5JL&;NXqndf=V_pEc~%-l0G=lneH*5KJBa{lIlW8O=LSe{6{skvr;Zi*q7 zG3Enx^=9e#JKtm(UWwg$)2ry;|H53xY#EZJV;_8zVS;#AhJ)hiG6Z|x)H0;v414Q= z53x4mlK=0$j=KIwQGcj9BK-`O%Y z3 zpC0|~Dff)Vk$t#aBDy*4`j=nAw~ zT&?yu;QZLzqkf+pd*_UAkKKDg#d!z9>eexD^oaZGlkQAjF^Olutv9`%$8rKEtDZdR z;YRc`$K6-)#Q6Qo9@Cm=*?01`cu%@AFp}(uWD0>(4md0^#c+^rsK|2dAz*(y%CSbF%f3I$yFixUemYY{w~(zzOFEl z@qvZ}{>zS<9rMFGAm+C)GvhB|e)ewNIe1`#InhvC#^rkT+p;s1#}_2hc{!p>)xGCc zoToTGwkF2ilg#g9{R-U_u@Bi_qpG4^TV>gJ~L+Y8|KH* zc0brsR{g=2(OW;*5`o;>u4gZ8g^jP-lczF`j!dT{;&(NfI4 zZ^`z@(Az(A&a!i3Us|*6uA7nH_X-m`e3a>f7i(Tj-&^9W`pcFvTmQmdp)|M!SMcw6 zWn*u_UCPNBTOK+HJ@9z+z{AXair)9SEk1g-YbnddBQE@c36GeW1$IIF#%vGieON#6 zF8KAUn{};**!QK)S!^Hiui~1U-7jWu=cIYI^6n>onx} z^KUl1i zj&&0PCmZXUu+Bg)zAatN&B?Y_^TYxMORJaFE?+TcMa_xHj?(?dW)0%`_4upt+ zV77ck&C=RMHA`xj9=+nk4Ry^;4F@I1G?XWsQ!N0E<;nV%P5?|*VPc%Wa`}RzmYkUE z>a2%4sj5N#r&d(K)C4b=;B}n<(3)FY1a!2eQizutAK%qBtA#K%bK+PhUr*TJ?ezf2 zMzz*q;65&Ne0R!ed`cpN{b;Y4dTrV;7mFUO-%?;gk- zGF@-J$4Hv@>AR)WYrz|v>(;W8P~1A!mdO)JuCT6|DoSoDA)V{Af0r7rZEx*rX;{vx zk^rZ+ZV=Gk)@i>cu{>4RyaF}gh$s~^&vqyI?lrHcwze^bWPK|hZEZBi7WwK#d3i)p zgtiU%G^MVSxddx!>FTg>U4sNIPo~y)NG=*u&7F13290w(G^ynBmGkD+EMHy`)*51Q z8dgWUO~+Q1v=M}F2I^i>l7?*tBsu1hnHd?d8|Se-pQe3`m+!4n9|!gfz!xcu^SuUz zJ*|#YFW=(`v~f;895wE3eDX{+=^2reTyGGe_kTj@6EtGqys%-jkya7<=}!oq&UrLj zaSTOW7e@WB+I>QOeQXrHS6bxti{`qH}W(1x%vOhJbUJi@gnb2uHZebg?az-*Md{$o);HUj40dK&i+Dj#3!}u%Hp6Uj?+KS_ zmhnV(vdnO4Mg~XIjgxm~`~$Wj%k~Ko5+6kxKA5&fV=jZ5J>C=v4bSH=yq7)I^6Xg( z<|(kBf_mBf5WpCpWPuGVPu?^7vldJxB?`b zVN4~Gf{C@%Nnx~;0!CTTyWjvFBcK2K$DD_FhMH$M{_&hvUCC-gy! zV|Z+$iE#uxW0T}74}&Y$W%H4sXGqnP1zyou6CP$0iq~bw#+zVV4I*}+1Y;e?%2#K5 zBbGxQ$+cM;ydt~&mKPgaFeD}qAx(};!)lA!s$vz!#`H~BZ7j$$_&O$1R^%1!1)$44 z%YaN-dm^ikVTlZ>;uuq-yu*xf_FYO#BQxF%+FQ>ghlAwIky#79VrG&T#IN?0hh zX!IkiLiR^j#GZYDCyuGC}F_je{r2pW*FQkx?@3xjK8R=Z1| zGr1qd*XPywyAosK7w$jv5olvFkfH0IqHm7Bnie^}xlK&7dJ)YoJ7udiN2dJ9@kL%@ zvzy(j;B*C-DM(+JZcybe1@~EClMb(L>5JNr)bu3dh& zzITz$#r%vjm#KJJ|J6vQe~M}4voFs-8E_EK1>DQv(iN=6*4XwL*#CUmQtf${f7Yb?YsSU4Yp!Yo&g4a=|HUxt&+A@)L(LV? z_~+#t!Q_Sc?mvQM&F32@1+h%&f|y3;;nM02KEjtY^T$Y8O1pu5auW|*cK)DAUeRh8(8Y(DLT3$@ z%6Sg{Cg-MjUjB>B#H3iW32ZvH^^ytGi?=u@ZL6HL<^*n&{)HKhojSzU-?fqYn~Otk zYSPO;98i}|!S()FX3XChp4S`kZ~&*p$<)2EW{Zurdz7bV{(0C8`XV+sNT_7Lh^f)# z?#ws+C=Uc(=7Ri7*r2`#+aeZ^F4ms^BSt{+-**2;-?Uy|*HX7OC2w6@{J;9fHHWh> zOt!qMzTT^y+uGXfb+vRft!+s)B+Z-G%WIY_KWbU+f+a`KS+tX;>=z!9|t^Fn^ioJB{5Y~fLdhh*-8BWpr7Z_cuA z#Ei`$riRuoyn^U8Hn-Mwdh<98xI9&lGIZ9o)VFWqIF4t>440cxyak+H0EL~?yq3E0 z#JlEAYYxYVmhrUaGQ?<<<(zDU13dFFPGv&OS#~tuNaw%}Mt;_}Rjur-_b^_ymcw;x zlj+*Sh@rO*uh@t6Nu>)L^RoJS3=VasFdm1oqz2E7@p#Bfy&1onhj1M!FXgp(UEWf> zgxR^=jN4VSNHT=yz~y-1TKtJHaJ9I@$q-Y;|FkK1Lp}_OVsU)0*-9NAM+8lIyp7%_ z?{p8iv#Y~%n*w5)fk?uvEUjy=^J;77EL%2bRqgTx$JNxXShcjKw${VAr(Jsg8^ri2`oTh`XOtfRRTWvVxagd>J1r#4f}Y|$z(Lx*r?pkEmg?H0!Ks$QowY7H4 z!RcYF2$;J?HZ#m18%WAakLP)Ic+g~pHP&P-n(93r9z;PgGPtB`y@wG+k7I)#h6PQ$ zXrA*h!G$R()6v44ieN49Kq0~PZ8*wJ9rK$udd|Qn;@ea6YH*}Ax{sfEd- zv|vYbm|fse=BpDqYdTYHi&8CfH!a=J$z+xbCu>G&J3!3_HeQ|N$(w`Oel|39nyjao zkeu~LHhLIlmAYU)>f1IUACmQ>p2}An6IWem9DwyqX=o>NY1qB z&vZG@G(7tq5Z~FBaxU#^XC(@OYQivVs-p`>rA@r$fc*R4y?h5ZHgPY&{lNdqcQ4^* zM)rdD>0hS&8{fYCZ+%^pYT3}#-rB+`X=>Zio3CwYI{iQMH4m;8wQF#7`;Sytcu?xv zn*Nh1w5Qr|GN(E^{*#HMziImqCW6oGFt^dCei-&Y_fgfSCiQQeCE;OTQ`gZ{Ut8C_ zwza*fbKUy?*@Csr=S8;FmvIM0k6RpJf!# zXQw|O*$)Y{ z@Dml9+!Rd?lN!)6G0^VE+XNGZYEj-pnW@TfwV7)}53~E87V{z&l^Vw|jRTP}!+v6h z-KS$eEE0BxTK*dr$xJyCiDmK6o76^V`U5nTOzShi=A&3G(qZ*r*$|U5?H8DX)iPbW zA*xK!JQu0bvtE0K8mqZIR72splgW0K##d;|Qyf3jcpPAJoo)AH?0%ufFviAEYWHX? z90l_e1LCdR*<7iX1HfZ2SJ8A+)Q__cr zDO>Mx(N2z7x-JH5jCKzT$<-&v6k30Be3|iy%xC;KC$|zdGv22ct(00~gsty{v(HmrZ&X zw{6*Y(6};s+CPd`tM)b~8Di(F2>r-3h^CSLCBK+tGUmf9{5zg;Y#YuV>DYfZe z=I}HGh=-4mjLfsHd;Rpz&HaxFA^z!Ma2viTorw5{^&>nP@t+alvm%_|D~glwVf_d{ zPrYsWVfn>>cf|kZ2!AfZUyks%Bm9F1&$Caw@TAGqUr~e)iSY2-cdC3 zMfmIpua59zBYaJSH%9n15q@oie?P(>j_}7K{Ff2_YJ^WopC3{moa$gopi!lqc*zgx`_AAPc`c z!oM5gcjH&PTYvi^{HX|kKEhv%@HZm--3X6mc26%S!Z`z&o1c*po{aF(5zbL*H$2xt zclqoH=ep;v|Dp(A5#fyy&UMP&@MlIi*CluTxgNR8FN*MRPCYq(Z$$jL?zbEM-3Z^4 zeyK*n-xlFqSK1AKXN2Du;aor3wcj7%Pe(Y{k9O_D+a}3R9>%9!{~;01d0Jinq{H=I zX)_FBc-4aE^DM`oe4)cZ(~fiFbnkC_=jqeK+K2aVVjuR$!p}^nAbhjK(-44j8+A{= zcOIrM{^{aGLdWr<)F_((^W>XZ4Z;-pYWY}D`tcG+|4Qsxhhr?~wP7ay)qfuF!T4t$ zXuk;i!|=~*4*5##`Qj|oB|iy!mcPvMwbY8WY4#EAG(ny zJsu-*!p~KTqelDv4*vmgOPXhTj{r||_>Y0Z-v^oA&%wj^GQHoVZ3(ix*RXZ(cised z?}y%}84tE`9GsB3Gll1xxu;IIzP$eOx51=zfpg8g8FxGWqu@Uq|Kf7J@xbo&e=@jx z|G;a%dp)fIcdy4wz}@RR+opRxTn&D6pD;Zx<>OutxZI9=eK`Z%?Z3BzyZ!M6;5wHP z%X=C4T&KKTZqMyc^tErvL59a=-1=&EaF*T!?zXpm;GxU*p6O(zmu;Mg~TpY8Bd!QK1UP2leR=vm-y``ZETwyz7p z-S&7TxZ9q-4DPnSTfp7>g*#~Pw6E`hhpwOZD7bsQc?vu%Z$Ix>-Ry^Y{H??OT-;Fa zZ{7Tdd;RcRb7hpz+YIi%rF10Uz` z?cm}4^HA?n@J){Yjo>>Rei!)V4u1%IkHdckZkMM*l0&^$z<=QQzX$$PhbM4h`=!GN zf*+c`e;Voq;Grwl}KGfk` z!RI@CC-@SFUj!bu?@aGX@YRn0m%-OL{1)(Y9sUjQ7o76n5B?X2{{%c7PZ;XG2ws?O zLqol{z{fb8pY}|5cs_WI!$*Oyb?T!Eyf~eo0`D;JyK#)f4fT!!53gqh-U;A8K$_~` z4DSB^?*tF$($4li3x1T7{`uf1I{X^&PKVzH&W}tq{(HbLbNGJnFFE`<@a+zN1Dt(^ zhW`-!28Z`W*}v)V;ox^UoNpt4%i*)YzvFQJ7GWQt@t**Gy;EP!;G7p;{XYxN?~8}P$4iEK_ke%s*zX4q$4iEK&w+ED7LET6@Nm3jsP`fG8IFHn^lh6R zJ{-Kw;pO0Xbd`>87C7g_7dO;f1irxGCx9Q|@MiFF4(B}W2Ri(G@CgpT2At~wX#BT< zADn%lhJOzH zV28f}KG)$Ng8#h)4y#@X~^~RmbKfwRya8AVjfD?W= zIQtxNLp@B*;bl9VU%rOp^9A0K;7>dLCxD0d9|c|$__Fl%tH9d;e!9cAfV<;oJHg%i z`%Az#YIbn{c@4NbzPJbc+v)gnz1zUu@wL0a-SM*TgFl(B&s^^jaCf}yNpN?(>=)qf z_}EL}?)carz}@k&cfp6H>m%3u2;BYsk%^m)ZsS|v?)cUaaQFAiC~$W?Ydm;(ymP(D z;O_XH5X}BY2I&ZvtQH@Na>q9KH{{)#1MY-{SDs!7p|A-@&hUcwc;6gNaV88|sY!58KmF zuLAr5$NwD{1*>9sYapsSf`De6uEp@vlt$xZL6R4+g(CeLfU;Tw^_S1H8%L>BEK5hr_@xbHXnL zU*zyQ@LGqrgWu)wE#QwiJWPw@F~eL6J~G0S-X#c6#~tUozTR@)vln=o-q$Us4S(l8 z9N|BY@ZU%HyAf_CLSSTYjBkiDU_%~6_$13&rJULPP|Nunya3M&kBZnIAK?uV-WK6! zM)(&Z{F(^ACBnaEIj;!?=pXNk_&*ilzliXcBm8d>9%rRkM>sgb$3^(G2%i(-3nTpK z2wxlFT@ij(gr67TS6j|DUck{czFHZ+C2HnNH(%c@wQt^6EaHmCm};CmE_W(`^PL-o zvzr^hiOdb)6y^qSrgH;0i@5aoL zUTGUi77BAnn<|ZevWBXXEW;~p!>XY1AyRpzf4vx3-U5cPK3;e zLzw}GvOErDeK|CeH&%}0%aS?NoFOh}9l4x!?ea*@%$ei*N0Kwm#PyG4w$hvo=?UH= z)lfNw$%hAmnbS5F&8TV5INI7cV9H}JJKLmeTea=VlpQvewq5inOQa?%BXw65$*nmd zow8O%>aHqMcU6(YT4~OqbX`OWIE^)%_KZY5)1CrVwrHj$yIF}G7SmI>{*l8nIZ`y! zeK_`}%W=3#*X5C_i{{51b;o{kB!A{$y8hApMdCMIf@5#`5{FNY9J(oy$~AqGV?QNQ z{wa||XWFG>KP_q>DbLhMeoa^Agr6EI-;~HHJ~hfCO=n6pd?Y>7p}FZr@;fzBA5$ac zHC?b9K2ko@^*a8hr*!ztNPbP1?D(6m*yWM-ZLSH9zv;?d95=-J9;wgik@jRRDNcT7MCx-|#6EffF_$VQytyPfd`2YyGa~t)5y|h2NPcHT(w`YQ z{xc)_of)am8Ik&_j9xcpMhs>~GBh)ip_!2kVWmBEZ%&CTCq=SUIVo~XD*Z;E-EKQ>alWCq#`RPMG8_mi81VEVtW;hWS=-o~c8|SjA2cu(L||@{4Ped;V4e+NdIm5p z18h2#<`PN8T>A`A8@*Ai)N53wxyaDQTwM&{0W?64oZW=zk?3(-VD7-X1&Owq%4oYYxAEPAM2~3nW}-5BHz8H(#u2@r zsO)h=VSWd63lhy~RWzs3E4dscH;(ANKxOo1K<=aUl!=~k=F*yOpr#)QZ}527HDHfZ zB-$ZFZyG8mM++0ZtXJZ?+Wo`x?%$mEKIKJ^m9A`{|M@vE*5dQSaQ2WMU%uDYnwdEo zni?80OT_xF=7z?}09Nd1jLe}Co&BP=7E`QZ1+k9ChQ=y{>ukqDWetrTARVW+cQ$%G zzO1k1ca-&~;3LgbYS(tvVMc@h3)2>ua((>#1Q=ULPdt#GZon-GCoT56&l7<03O+U% z_7FC3#FGt@@w#HGb6i7p+7$dv2K!ul42gON^TiN2VzuYc$SkW9t3Dif*rV9M5v!gA zF19+c>Z5^&J%$Y&vFc-ii>*$qdO5I`i&*tZw72CVR-Mn^3;r(oCsv)$;S21`_r$8t zr~Z-H6RW<2`aeV`R-Ny^6#P?kV%1ku_vGO!vFaOuhdqJ~9I@(rPo~)F#HybOJZv8} zaKx&g4P0z>V%5(BKG>IZiB&QFXqjJ?sq_!V#-}EO4>aiB-P} zSmPm9{W(V`R-NA+6l6-dh*f`^dLPk=Rp)yMh4$qMV%7P4T+2nQI=?F@%$9hFRj;C+ zBRa9_Y?^t0l=AYKeEFXQ9|W5Te-_N4@`L+ISYi#E13b&>#H#b%B5fPQst=;QZ5za@ zvpwj!PptZQ+S_xVSoLaPZQI1E9|5dwn^^TlwBL^n9I@(4fs3t9tUAvxO_x~pMqo{s zSoM>EHCTa9g3w_v6uz@31``dww ztxl}^Q^3Qxf#Xi~XMl^XPOSPbf%Ui$tNuK&)(^4jZv$&vC00GgbHTP@V$};Aomh3g z`=#j;t9}CTu%9AgIAYcLK4r1hiB;!2bDB?L)i(lbeuz~+*U^bp=lhguPptZrzyU^I| zuieC|e?UE7?1@$9v-*Mp(TP>>53I+9Sap8eQea=GBUU{Lto2Wa(fadmCca`Rul!NXkpB`bpFWicYM08}&h= z6RUnU^}(VOtIl@~v>u36zliqsLq=lNuXS`{)o%vYc1x`KosK=R>h}R_Jrk?`Ah6am zvFiJ1|Af>tvFiJ2Z*^kTUj{B1D&-|s{S9C(FR|(#-Xqie6RTe2=)|gzcXVRaw*zar zh*duiSj$DM`WI;bV<{K0>KD=8>cpyl8@OPYl#5vP_klJ4#HwdyLAU)IvFiLLNbiM+ zRp-0%1$Rn*h*jr1A$p%ftUBKv*ZUk|)%lKnVX@?sSoM*Jy8KOv{~+SG1kc7Uj~7O` zqwzn%;x)jkZ*=r)fXm;(2JT_}m%nSE_Y!t_?+KoT>&v{q2^XG-$kr-1(S4JC02bjupVn-)vFwxSoPVCPOLiXR@*AE>W#qKR*6;T z{o63!1i?k`<%+G|0zb9y3!KNB8aS5Aj|*m5N;5)SW_8+^CPXJz{Q!o|6up!-4lc8} zjCvojAy&P@(TP=O{gh^jJ+bP1m%lVybYj&Hp`If;vFf}x*1WBtjm;0S+8j%ri&Vf7 zt6mGNI^}t7vJLrd&ta?D*mW5dLgMqay zhtXyzHgLph!v#J{hlx(C`q97|_Bh%wBXGoOa}xF8q7$pW*3pSoKZW`TY~YAhKNDEf zI@_@!R-5hAM`8mV4oEa z_Yiia4lc9!QR<~)L#+Cfj!vxl)6_>}14pcSCb<8skSaz z_p1f7OY&<3v-$e-1@mzFhYRLm@Q)D8>hKo`W)}U0f*GBEq+ss+MS_oxLz>7d-NLwpXuN$iBqEANX$xw`vx&PHn@9<*9m@txJmFYh*{Zi zFA$$1_z%R*g8xdqUT{1P+#)!SxK%LcSMhnE;P`E-f2v@PbNcOq`Av@BA-JBnQ*bMB zmtcN}xr)x+(LYf;M0k1 zy4#6u{1*}1IIktPaqcDll7!{E{F+a`$M0V&`V+)9Z@(nIPV`racME=-_{)O-LCj79 zj=$IZ8w3{Lj2tJ;;SnwKRUIgHph`%Seo!G{+ ziTEDTHxt{mb`akyI>%W2?+d<~_y>adt&D%4;I9(jFZgca2L%6s_=kcycZ>g^;2#q| zB=}k4hXub#{D|P!iT4S9hxk#!9}@F|2A9YJ{*mDR#QOygCVpHn=WOwx5L`z5W5FDg z@t+hto%kn$XA?gqcmeTG1s_HHwBR=4p9wyL_!+^M6aQTB9^z*O-%b1r!S@sYQZT=1 z^nWGzx5Up0j%Ne^T5uWh^MWT6|3>g^;ui!jCVo+H9kD$(*Au@a`X=Jv3f@L+uU{7u z+rIZp#4n4@EyVWR`7ZG*qTf&as^C|Ne<%2DV%zWigZMSkb8>)f{DX*XUsOu`d$CzS zTq1ZeaOvwI)_d~hwE2VR#}U6F_#|T651c|gTJ%$i|0ozM)Ow|V3UQg$&!EkpMc+mI zrr@iI-x7Q)@!Nv$BYsCP+n?SWK65y+ z?K6|awoXP9+d3IbZ1Z1EY|Ay7eH6|Ox<$lH9PWF>BL%<7Hnv7EzfbhPBlsrb`vuR2 zJ;yichyxpEHTCC3Cl0L5D(d}2Ck|}7YpC}Zoj9;Ir%)dtI&ola+NraW;E476q)pWG zMJEod&F87}2N@i3U~RThFBF|Pur@oXv*O{118c);P02vfi34kMId%TXgCh>C&2`l6 zbUeg?wYiBp4<;OOU~RreeW>Wffwkc^tK>JL69?9YWB4Tph)x{XWA_v4NzsV|Yx4{0 zqeLeTtj&wmOGGCQtj+7xOGPIRtj#;r+0fvK18c+Y=u5_kP8?X91lmPOAUbhiZTeF$ z6P?(s{0hozUkMwp#kwfh0o2EdP8?X9GV0?+Cl0L5BP8?X9nbdhgz!3-5W)AfU zq7w(!W&!mI(TM|VvyA#g(TM|V!)t5FB+-cjYtulzQgq_L+B8$I5}i1(HeJ*?7yw5c zSewsLpCUSOU~RThpDH?WU~TwJq-2`t#DTTBoceUpi34kM9rYQa69?AjE7WI-P8?Vp z&dpYGkm$sLwfPS9gGDC}tj+z@XNgW6SewVFb6^;bIIuQPQ9o34;=tPciuz%q69?Aj zx725gP8?Vp&U;WYM|9%A+Pq7BuIR*pwfTtpJkf~*YmuN)@CO4g`yJ&)`riFN{$qrIIuQH zQePxGabRs$P+u%MabRsuq`pLS;=tN8Qa?&`;=tN)^~aK>q7w(!W+U~_h)x_>o3p4d z6P-A)Han;<7o9k;HWyJ}Av$qjZLXreQgq_L+FVclXwiuSYqOX7F`^R(*5(fC$BIrI zSex%sUnM$mU~PU#oda)h#DTTpYLz9&i%uL^o1aoYL3HB4+HjtVk`qNI4y?_~)K3zf zIIuRaQGY>n;=tPcgL=K_#K9WDob$ecQYqN;@deMmkYqOks zi|E9GwK;)$tLVgmwMkKL6P-A)Hm6WORdnLO+H_KH7o9k;He55Iq(gM#z}jr3-YGh9 zU~Mj--X%J5U~Mj?zCm>2z}oQMyW}*{i34kM6ZMUv69?AjYt%Q1P8?VpF2h-Jy6D7# zwfR2vGejp2tj$BzKPx(MU~PUx{d1xd2iE3k>Su~h99WxQQ~$i^#DTSWh5BaEi34l% zN9t#ZP8?X9cd4H(I&olaKA^rubmG9;_&LzGicTC@n?BUHiB23?oBq_di%uL^n}O8N z5uG@&HpSG>6`eS+He6q}WQXX)fwdV={XEf$18Y-7eW&Qefwh@I{e01h18Xyz`URpB z2iAtal}f%KI&olaI6q6t7eyxytj)31cZp6MSR2mYQgWf_#DTS0NBttvi34lXO8sKd zi34l1f%+w)69?AjbJQ;toj9;IoEN6#GSP_xYjYm;%S9&+tPOvcm0Te@abRt(pnj$3 z#DTT>GWDxOCl0L5Ug}qiP8?X9JE&hHI&olazDxZ}q7w(!hQ9$zt`(g)ur^#rw&Xg| zi34l%IQ8A469?9Y^VyVqS#;vS+B`@7deMmkYx5HI8$>4#tj+JK?-89iur`0DexvBb zfwlPy^_xT|4y+C5%PIMa=){4w>5~inX3>cQYcqiQEus?#)@BIxy`mEb)+R~)R?&$A zYcrPmZK4wg)@Bm*uZm6_SeqHtZx@|7ur_n3e@%4az}hUJ{&mrb18egc>faEZIIuRy zQNKfU;=tOhq5e(Li34kMGWEMeCl0Jl3-uR8Cl0L5R_fmsojCZ8V9p0r^1ToT*5*R$ z_lQm$SevV;-zz$CU~R6Y{*vg#fwj4l`U9d92los9Huc|zIIuQDAo(wgKAbpHa1y)H z>=2h(eF`MCpFxax>1N@-beMq#ms!05lK+b6>xf4PZpN;(HpFFCzlJuiioTn;PB5Ew z>D?hNvpTcx|4#JRh`%lP4eUz4AL25r7x}QULS$`o0cN=^=95>9_QhQg%QbgiweTeGG;wV|6YKUeD}$RrCI0`Ykj z^;i@ZOH6tdEv=oYio=(zoM66n>K3fIsU_7-Xl$=rPo=4&enUlFCsu=7gGGls zqdOV@Zo1Ebhja3V>87B&={DemJ|6*@F1rd%cRR2f-w=2#WQAI%H@+#Ip7$~|=C7aiV?DErcH?^qqLaOJJwFONw;gb< zE{0R5_{R{4tE>m@R%)eNKl=aHVr%9dmIqBEar~YKcFQrO3*USsq#Om-kLCE269&+X zliF9qNz-}tk%p6uH>Jq)eu8>dr+yzoaMQi*bbJqoghoLhX#JROK_tG!0eCk6x;l-o zAAlR*lV}*bV8r+ayKU10!}L1J651jjRprrdT`mIu>@W zqYd4HUhM9**Dd<1T{VDPj@9R2&Nm#pQLq_~e=Wyxk@$w7L6mDG)($&wWhB0@<6f6_ zFbaMntsU!SEi^QvHbCR5C(AcV%HeGs_j(Rc*af>M5m^cFU*XC8A-m=rb(*EOdZp*x zLJ#XSzI<@k?#V0MIg`VBnOHTmGU>R==~b0erp%Z;b!sw+*$3caHf2gOSyeT2 z#tdV>I_L8>i{|^jrpP$oN!K^C)399fAbs>$Z=5&QyYC7w>!%6t&E=QfxI6oayg3(V z4)P}7eYe+eZT)ZW_RgALbbr;h-B+y1_iJ`vLEGs#XD&`8yw~&J&M(bNc)L*!xY@TK zp16PZm0niG_KV+pWkBwgi5M-n1PO0j^`j3E7b4WR72uDQ zgtz>?8zmo?-nct)KUJo3ZcQR_;r#LE?3|NG_=iuv>n87thsNz@ETwxA-dWX&SBc{{ zCA^EL4)PklwD^Mj-!rV6R_wB~s)KFGDsRO;jZw>ZVT~NCDXWq~r<=TA3 z+2`Pxpw6c=)cj1ZV#nUCH+au@+a7pq8-MEkZZqC@-Il1i;QnA+sN~-q;{9X4IrZz_ z`U^H+$@zQNqJ`=)-cpnB;xz+3`ZFi%F9?r+9Dcj6Sl}Ih_>$$zYnQK>v!dq2B$u*H zCF|GKwX97gvF2~GzOKE!Db=1_-`bG+^F3E3$28=051|IS{%*3X<&>7z(^`5)B`e)0 zJK9nyMzXYe*?%q7PYMu;d;appT9(H4*7eABva{9XUDh~cV^`;U$Mpia5~9l7|EpHV zYal-|?>$*Z?HS-xa_|Y6iFuRL8F6tmjhMGL71HVZ1*nE(N3EduVPhU?Rg`P?(!5dgfT@!v|n4VEm(JM8pM|vxi(hcW7lH zE*uFjHiRGtU@$>$g_pLFxXXqfHWZih3STMnz!3nveI?QYgzG;5nen^>*}ix2+#&h6zzk-Eu#`-A z2t%$Mtl@_Ck`ESRm<@mF+@Xx3IM>t%uJ+WKwC9ZwXe~zeQXi}UOpY3u5+@6Nt?N84idU95>qxvrU+7rbL$I_c4)XWTfw+ z{bN~{?AWgHdDxqKO}?;{?H?boj4ZZs{;}M}%1oJKgP9+nx9T|D4`OR!6~b7^!g>9< zWkWU2#xaqB(|0qmi6c;2hyDy%aYq{chA;pW{W?ajgzdcV^k4sJvB!S>#vYjLyF*E@uv)ObXv879VP?5cYs%UdAvJ6`OlTu@uwb;Td5z zMo5uOaYpv_;;U@<#L3AaiIlPX0;EKvgg1Dtgn1D0Cf0@3k!UKCGdd$HzFV^qARD8? z9Sq zSj?ZcF*&!cBb8j<+SqwoU3+T6;(05Rl@*iWKX=lk>EpbKT^;R}6W6rYu4}5AF}xorr7V`lg14<`lzD>`1k5XsSxV~;|uENWWc)Hx4>dtEIZO>0|H4ap`FY$jLLcBqdA9F8(B)!BpU zn!Vb&t*yh<&qg!!$UH6!I3o~n>S}!H)8J05tEtj$y?B|oHy+?8|$%6HJEaE4XNhNICH30Fl6c^qk0Rw8rG)NMrON0pk=9a3^H(R zjIB4D$+C{-POr0ReF`4y+ZK0t&8=vxW|OWoJs#7h;CR%xB1;&Z<^h@k-qh07ky_HV zK0JIK>ss5zzj7K3)-|-Yd8zdsUQ@^Xrj6J#3r+Q&{Nykd>Hc z@aj-7$n#oTF%_0+Z8a@jUJ7%fba_Ccv!R$OsFTX|=G1pKZD{J;B$e8pLV>&5+cEYm zLQ{vSe(ZQ)Ony&wtAf&EqHCzW?|B{jl|Y^kn$=KeY=uCDq=NYM$8K z)R}7Su)Ep~RgFyMVRDaipd4e6T+qAAorkBp)D$U_yC(m^zPidQUDf-z`e1{y0Mm5- z3gdjm$*HR;8hW;qlf~U_qB)6I(Z9EnBJ-!wuY37X-^ZI6{kVDQ9=Kb5{~Q@gY7LIi zd}Q0BH8eB+c@sMOUpW{rAg+-b*YI>)nR28PgSACST#4aQXNe)UZUd{A%08OY_gQte zX(ZA)MR9wr`OUtc=&RNVn-_@^HNc+?9KVS3E3|&G{^S@)=;r30<)0gy+t>Wy`!D!Bip+ed^P^X zWt%yR+LWTaHvot2Da*SJ-0k1)1mB*v&-LyFKF{F~1BdmK>pcN}iR1rsV7LGH4Y+%L z{tkS8+J1od=QJkB@IJyeJl`|Sqmv+Qli}s!mTJ7i3%lK7WqYH*3)24CX3c1~J}cor z!||U9p6T#8;9>j8Ht&*r*75%g{KNh}+gkRuGb1aBrW86r-3&*{PW-^ zJNz8*?GFDUxLg01gNOOe^{xXC%aiMU1$?U${%hdw@%a{bSiiYujqCZ2{Uh)X-2jiD zNxS_uKWjcBZ7{%l1w3r?13Z4(I@|Go4?K*2fcFu2wc{_ps#O^2aY{%Ig^L^Mm4b(E zlvyL1ZC2b!Z$A8wRf;q7XmGv@s{SePsSf9w&0`(D1^iHlUj)9);a>)Cbokf7n;rfG z@CzOOWAN)8{u^+8a>7R;e+IwL@&70I;|?DX_q<;@oNE-@Pq9&?k!H=|EspG2%vgxf$-eQG@Y(>-AjrxxT58ZH&bDexH zEe!T*z`y6%uLQ47`)7M6g1h}=3j7Mke|umzBaq_nV{7Y&3!DfwM_KD&Kn>C5U z^K-aa(|L$`qrLtR;rSR;?Vkj1_RnSD?)7alc%u`39ys5B6F1nbiMrY0C&E8$KLgAfscwJ29{&5C^gjn4 z9`6C(HgL{)BW|QwGxa7X{u|)`u*1Ir{wv4+e(ZkgS*%Fzk{Fd)JJY+XpM)=-cazc|10#yfS=>ob4}E1ocz{+U+?&HE*8#x zByOaa0uR?wAL(_0vyV{!ZQvPBe4Jk;%i%YI_jmYR;NiOHBfW>fOCA58f%7S>#{UX< zxbFE#?>+E?9e;i+Ugz+E;9DI&2K*r>zf-|)cX$o>GY($~{uhU*z<=j(eq+7LiGLgT zY=>V8UgPi^!52CFF7V|Je+c{xhyM&b>=Q?NuYh+r{_laG=5Wqg60R#h(&M+o7d!rA zz%Ow4RPZl4yaxP2hpz4&@Vf)SY)`N%bH`nU|pRI=r{lVwJ=Q?~F_%4TE03O~C zrQgpm7IE)@v?W2@{2Byg%T$2hpMSHQ=Ooub?Z?qdIG%$A_&qkva-L%aIN!=GXP1zVT+9Y1R(=dP zyGZ`ipWlWu3FY0N5SV3FW!+OOrz6XsD&U$)M&T+)25@~I1GwH!?c!AX+El~g&8=(d zn(>VY)()Ly*Dsx9)-~<6;3?yni-k|^`lSGjo(h*;;+_lgaL?6_5OlI#E7e*0luI_v zyyr%JJl|$I@M$+Tro%&vO*{<_@wJlQ4MVv6IX+>>sFbimcY&W zNz_>d+}kCl%(_D0x*Vukj4+IirG{^M8B-fdm(%SX;ZV*BF`M=R>MS^uUQ2xog|BxCid($3qbNbi_|OwB+P=2 z=}62fXCaH)k~4=ktr@Hx#>tX#PdzLlMcV}aGkS=D2~)kx#)vA}BNsG45VIqRbfq(&D&?XiGqxdk{%jZrKjC<*$qdI{~Dv4JC2JpeAYIcpxq1lD>WR(%QWZFz}R zUk7|Jbk+?qbz)}a5UUfb-U+PrL#**^1lIZ?R((6L)(^4j=K*W|5Uc(L+ONk3j#%}J zfQzk8ta=V`H6w-_g8%Y!3^cztCRjX)`njSXLA*ooaoANeakxhOPvBrUTs!_X9yTux zTLe7pd~D!|H4jX;*y_Zpj|bLcL9BWO?d`E3R((FO)-AE>3xTz6iB(?)taVGQ`q98z zx5TQmyuO4=&FQzKbEy^zuT!q~Pi~p-- z;W5(VsK<*b|5xLoy?-e-aIC9R2bWpQ_)9ONg|rjZ3&Be-H?nzVt2&>MmR=z`vFfZt z|4Px>=af3Q%wpC_=~ZGwtU8~klwK`5vFe9VzeaRo)t3TmS}SN{<0n>|W2xJLZ(`N? zwTkM*s@GG$78^KX)lUZ2yb-I;?xXZNY~YAhKMPp%#>;2vZfxL))rOac(l1l>JYv-; z`PWm$GX(sXI=IZ@Td3ba3w%S3f7QPZT)Ky<=Mk%ZCvYhvgCkb`d%&ePQN{BI{Hy*0 z;L@*9#kf5FReuUt^Y#p|=8afweo6giY~YAhe-T)9V%1-v&O*QutNsSCmW5dLH>vN% z298+uzXEGnh*keP^;@xlBUZh?AC{#6xb!w-V&)f68%}>+`c=`1RUb*+)(^4jCDd(N z#HvpN)_OaLHa0C{wc+zUO^aCd`P6M%#Huf(Zqp)G{Ul)jcFFS^+Bmq(;zsIU6B}aH z*E>3~>Zej?gMuSgeJil0buMje{KRU*IXX(eAz_JCzu3`3>IX8S!@oPbRk4)M-@nH|ZxQjmg4uVeJ^L&F`=X!X=xxM2S>aB@ zzkeSQzIVsJhP{aReyZ~P(0@QMyFCAgg4uoe4+`dK=07Buhu?o#FpKR!BA8k9_X(z{ z|ES>o#P<5~Byj0tq7&=&;7Vc8Vp192FSJCD@ zvH1$Ijq_I8+kS?)%<6n+!~cue-$`u4{(zVlG`JrU^W=d0De>O~KS%t5;8%!wp@aJq z@rQ!nCH_e8`@p3V>q4iA_0iT<~;a z`;GBDVxFvUeD6c&r$3&!kLYWOvjp?Grk^eN^TauVcM|i(D!9vu`wG5+xS!y!5%(AT zJ>mg^A0g&9&Tu~^W`_ayGI4?6KM)rR{tK~vLC4Pk9w>SiF>eIm3W)~`9!bmz-Qc)h zv99$ojd+;obBXy`H{5b!c2saD5swgjGBIx`;5HB+Aoy%z8}^IDNztz&=F4PoHxl!v z1MVBdrGoDz9xeD$VjItIh{uS|FuLX#WULE8MSd^%yA70UpY4l=K=N-BeK;{YTDTbAE)ar5C_)g3hINzo;VmN zcsKRIAr7p~9_nX^POR%Ke2@AF(TM|ljMzVyj1-+Xur`lTKR|S1U2ow@>PgXw)9Woz zA0;~184IkE4|(VabRr* zP%jgE;vf*rcXmp~hB&Y`d>^o6oan@XwJD=MUUcHX+DxK;pym=~q8C@rVSl3DDqCQpZiFKWX zGpSD#omkgNIEVUl(TM|Vvx_=AKR9AtC*ex!Gesv3tj(9HA0#@lu9NT;>IaKXtm`E3 zT^(H~fjF=>cTzt@?1_U}g1<}s&=3dK=7-b|6P;MsNqCIzCur|M- zK38<&z}mb>eV*vVfwg&s`sYL^4y?^b)Q=FISl2hmL|<33Ky+eV-+;4Ylq?jTIIuQ@ zsUImiabRr@puR|S;=tOBp}tsj;=tNWpuR+OVqM>$lKPpV69?920rlmg6YIJJ%c!pq zomkf;IG*}S(TR0kf_myli%zWT5}ZQ)7}1G!U4jnkyhy?k>$(JIP+uiFabRt>P(My| z;=tPMq<*~U#JVm4?@4rCcH+R=e1-aIu_q4fwTWx)mDGt&99Wz0P+ucDabRtD4^y&P zbmG9;a1t3^Pk=bE*E_D!r|St22WutlOVrN_aj;JC5bXT31+y#nGX*EHE6odWw|R)I zJx@`;Kx}wAl`=9o;xel*1=jd^nEhgG;8@+I6$TnyX7y%BYH#jICW%ca?W;pvX7zI& z`}2wCi_I?VN{Lw>^JlmryFaLQe0t8R;du5o!G`1A zZLSSR?>X&8MSJ&|k}-R7MbEeS{{Q)tr74-MZ!vE{vha_~gK<;rUUzE8TWMl@s+;HD zM!Lh{$#k==AIq^5|89KzIeG;&bsFDx z2yT4W;NFJcWH7#5>&N(R#J?Ng-5`fTQ>XFmhTz8c;0&2Rnep-G0sR=?1Ne92dlzIW zG<6!^y%5~^ZpMAperSx3KQT1E7lGaQsu2ON0qQiq=ODQ8b>e>P2xyEi-}*6sf5X2U z-)cl)f5yNkYzOZGyYbzF_}HB@KK_i+{F$*$aC`geaSZECaCJh6G@>(uYdz1aP(mwLGdc5c1wLgU+vI%GLU z;a|(a=N|Y=yKC?p_x&^zJ5r7v19zbs8VfDc5cnI@q76C;SvnoIGh}(s7?Q z4|L_U=`*X0{in|Z-8M_|fUXj5Eb2MwadzarTjOK4P6<+-n%d%v+*zr5?N ztbMSM-1*2+M*p+(zqxIXw|`T9;{3nu9PwUW;kN3;E9pGk`~p(E+ROXy)@eJd&clqz zJEm>>ZhAK4+}Yz3$8Ec5+p_IiqP<&>+xAr2fA4uU7gRnTZ2M(eIoiSXXXRwX$Lx&t zd;GYxKWB2@f|;D_x5Q#w%68_)kIfxG&7FaI$@a&#FFR-R)n}i*`|4^;Uz}=atxk2O zFyB^d%ZW|vyEv8C;*NuoW15>A%99&he2Hj7e8~2kZ8U7!g!#6s;?KG1#3v*;|FWlj@TvEAGYJRw{O}be}1+oB9LN zRqhWs2slx1jT0AGka>#+$K?buoSAhxc3IoG`8<_uZgYtGWXLWimZxRyfhd+V_p-Sa zzl~Y<0gK;nfV}L7u*v-iHhrJPCMGdvWbo$B%j%Q;GIssx9W6m|Sc2jUaETe=;bA0mq{q zJ2orSSLKEJaYI6Ue9~YRF?Pb(5T96X@O{)znq=^P;@WD1`HgmL^$`YhlG|9_3WH5N zYrbtTD>YVskHLJV7i+lBU_Qr-rCu|brHeJb9pbg`7;M6>dpE>Q?}zy056w?IV{-}~ z39`V3G~?XNWfp83A8bw__{R5yO+Voc{y9wO;#ZlP%<{uPn81ipnFxkDIANpAWveq7 z@tCuY@m!b9g2)l;3XhnazlR~jVEte{wtg_bFQ6Aj2QoP(6 zn&;YSzNGU-WHW)B%OHSR@^)y8{#TjNP>TpQ8Gi=^=`k;W_jwZ_Y1iT1jX3Z-aDW}uTy zrZ$}reyl`5r9iN}Q0V~xb|Pqec4pEi_c>bZ32mc^EW&)LLxiefAAG z{{v&6+LOR=T$y~b8{t_IZqKr;#(sC{#yq^Ppp$&m-!@X-EfdbieM?Tv1Eo^FXN1c~ zjHI%^UnF1eEo=UuNdDjmuZVEm2j|4~yZeL8Cuz2{f11ZbNC2@})91HwE~l?lg7e*c zGk52+%-#Gmck|EO-JfUfmIrftT5UVZ+$|sGZuv0BeQHk34^t}rEsF4@$3sW}v0~Hb zqjB!$gY(^dFn9C8+|37bHy_O1d@y(O!Q9OUb2lH%-Fz^2^TFKB2lJwE(9GR@xSqoj zr+WtJ^U*kWr8wV>kGUHkbJu_7_Il3tiMbmObGQ95FS1_zWA3&;=Dj2NZhLe~0+u*^ zVv|0;#<}Z1=ezl3?&g=dYmYhI)|SM4xKe3y(o~PIGjpoaj3n>o?u~hvO=L_giihFxvh=;}sb!!Ia z7uw}_T37?`|J?e_`vb>$eRs=;*B5`h>FYyBTmRCq{*Lx{i*EU3+Rq7#!u%}zj8eyQ z%m~VJ>rYer++Tmb$A@JBGR@ia-|bH_>Dh<==dGFccW-|C3nd0l-??R_VIK3}GMf4uu`J^HViIY>~~DY~y> zexK%VMo$LyKmTrKz98<;SDY>m{N;tOsJr%?(akg}5T#;VHu>-D@bno!o80Hxf1y_s0CpDYav?Ahf z(o6mQ2$w3Q@f=0GyEmQ_h$qAR9CIr159r0Iox%5uzo(SSUqDf zoZ6Yz#QpUP&rx%+^xBy|#9vW6wSNThd13jMW)yLJw^i$#MEFCcbhW z0g_r8#M&I=)prf?de475;j2CVeZuZ|*Uao7euP#}+t*XX{o~8?#NGa*nR%7Cf4sn* z(v@NRw0;p^@A1D9zs2L(bTWj`wmG#k_;qg<5zvuB8 z#Q($N7ZS&Bq_q5U;_YdfD!-9;{C(p1eUs+@ zmH0Ux&!!KK=6bw<_@y2%A->Av_zV`mRnq#7C4RrhPa%$dgyzp6-pb3rka&j2mlHqP z<2Mq2+~ao>??TH=>)S#6GLJt`e2&M}iT60g8ub%B5y_{N-`TuL<&m(DL@dDfg+s%6 z>|Y{0;SO##KTmklmd`T9X*|c^8Nx`|XSAX7y^2WrvBI&y zp>1z6Y#6SvztPNafl|RpJgfoWVZmr7I-oNY9T#|5Fq(<3hMAaxkVGaxmu@s}*}%vc zY@{{qN@PxL#Ky1zOle4LF>ju1_^>cHGTk=zRhWsfha?hZtkEc4w62B`CQ&oiVXQfL z*HtAldK(z<9X>GR0E{>w2CBWsY2gz44)PX#RW{gM7hWAfQ}d%i!?esn3@J%#7D z(FlDW8UG>C>LUG#?jxen+@jImY=ls+J-f&9d9?k=T6suxyvX((jn+od)EfV!i9hH2 zuFnBE|6ll2%6&YDX5Hsg{)dHv<%6(8LbchaShP8SBOM~DyI40v3AcF{D*wizKSTQ+ z+%^Z9jH5TzajjM{hjlttF}>$9#x8CjC1i;g3l(bI_}x1o=I3^Vqh7i3;+M?t@sJ;17;L^yT{>!;FN z%EKjs@$I#yXlwdALL{-cpyd2Uzv%2y5B(@Q5E+JsY6Qw@H9iZ}4>-blz>YF|D14Y2~>&y zBl;hSYuP^&*0R7__A}^MsVM=g{uN=>fmNpuH%+RZ1WLfFBa}dD8SB8RBV<5oIqSfx z<7f8TH+%rDeFIhxewwa*09L)Prvs~A23`6FtU8|MqJ0Ba{V3?tH(=Gr5!SxpUXb<; zSUr=V%e(=rKH1ZORi6qSI|)j_s$W1@+qxJYsS{W|mqV9v0jqu$beVHt)vtyw;{sM4 zmp!p5whMOu5L?N(4fLxRw*y|q82hUjc3_l}^oq$%m+ru_&*@D#bv6B?1g!gnGQzQI zpz^)9*tLw0qPG|}K1yTg6}#R-WA_7V8Dm!)ll{*$;B~Ao0>%bP3B!xsV4*?tu^Sn0 z1HOsz>%iD>DgBIIv70Tl_hNK^g>58t3+uqTU;2b_Ol|^w0lbktUjyI980)i+r9JQ^ ztRu{X#wY{U{T1#*#v0gz`+KoF8216blkpM2GC%fr9+$Cx9O1<<#$ei86JjF$p0X1s#1#{L2>5gqq9H5SB1VA;ps1$-Zu zeHK{uMb8t~SX;olPQDD!1ML4P@b?+x9;f#IAn=2%zYqKn<39ucfHCfQ#vW!I%OLy+ z;{>pb7xz$N+gZmwP#td<;73`vaUrn7rZfb)>{mwsKgRm;z>hPY2>b-&Gl8*Fr!*b- zM~r6y%XT^+_{XeY4g4hI+kvs;r*tpyP7BQr;HMcs3;YaYJWnY0EaSIk zz&~NU1Q;77rE7rqF~)OHGzJuY7q2m(eggakd)@+mlW}1t;kOv$x8WKCssb1XLrNzC zzs>k$;CC3~zwWz8HnFQ&&jG%OaWmjs7`FnJ?Yb@S?X0&4mTj{W@LjAI0bj|u82En1 z{jh#!GkzPmGvi5EE`1sA2Oh?FFvfcVV;q|_mI$!M62bmKV~GH3ERnI$n{ruTjU|Hp zgT@j8)>tAqPH8L=V2vd*1A23=2Uuf?;PVfSB?7FmM6eIhSR%k0OXN!Em`F;%8cSpq z^wz8c2jW==y$$QYfq1Z=N#X>S5^x}%&Cs!MC;@9s65Ny4m?Xd&lVm$|9Ox(kYfO?S zp%<_YtT9P;L&pNA1gtShUWH!BI&dJKebCQg9XJrr2ha~=9av+Pd%bbTg9#yW5y9_$;F0qekl zc*>xcunruE=Sb+?SqBcpGZK0a)`2xv3GTUTtP)_2RWc6xO!fn7tdbh&hqDeG$aaMN zZL%Nhz=3%1IaIQgb>KieS3oag9av+PEQj8obzqHEat-tWtOIMTk{h89WF1&zm0;hl zu}Xk7R>|Ga%h?aCu}biHm&Pgq)>tKvK_9|?V2xF>6Z#RX18c03J%bag^h(x& z1M#$hUd1|aAfArUk7XS=5D$)D$x*BWYpfE)NlT7q9av+P^n-pL>%bbT1fLxy$FdHr zF-FEhKaq7{jWKdE^l_{M2jV#k`uA7|4#YDZ`gqoX1M$p;K7n;$ja5NpE6E)o4!l47%2ZvY;{ zcoV&)&UCm$^nWuJNA&)t7vAEK+n0yrrG3BN%SEN(SM4LZyQ>)umhnG7EJjBxCwj>$ zWn)wDlH&ig8?&h^{fCcMSDUcz`3ZSQIMm^s^1FOE97WreO^b5)dsTSvO|MLP4W}1U zCu#ueE>0()t|p$OmnIztcAtKIbE&>!(oi4fK54IeIVHWH0gLZkl@$%4%K%C zc`;tho7VRO!l+M92Ml5WoIqR?^6=U%@2dZf#5<88N#WDP{dNb_c@M5r&~8h~L;F9W zmzE)D5PK8%3p6SG4GD^ocR$s2CK`~WdA}kKdAR78(!Pv-z-!xWBY9}|Q+jC`SerI+ zaTdTe?_w3R&67pDR!(~n+AM^JqmbR!^+JiJ;&eEX=doWfA9^A(8C ziuA8}b4C1)x{!J|;(I*OE_@~A^T+Ww8b|MJ9!DYNBM;-ib(Ypm)V$Ejn4JKU;6oZ5 zsjrv@fw{uGV4tG(;rPf@!ufM+Hik&x^oV;b9e!VZTxv2Rw6B6d*UfH`c>#Lqve)^W@ht+4b zI(YQ*gSYJeN3#PP4m97|?7$8hXZGeSGa<`-Jo3}cXRlhGh_z1OTPyO9eX9XIRm9K#{!vN0D;SiZSoan&);HWPHzOJgo$ZQ%30s~Poqc6qnTRugW7 zbI40$W@QJ7R{JQ@!-RrINhy7HNmXTL?u}WoF*WRI{?g*AQSV*UZrsy}$`yCyH%vU{ zqIM5wy)iuZ^{ftyt6Fbuds2N?+x?^78~1d5RVrhD=DIru)w>?;%i7)$tJ?fxvx^x0 z_?a=6F?#5g-qnomd2vjQ?FB`o*w^k+^55}HoO+S}%(&5?=l5T>Yk2PXtPZiNJ`Lke zN@R`OKk5%-_M|crnTe{dTgRPr{x8SO+Sd-PtlS-|8uf?I^T+HdlOABsb9W~)7FR8< z?3KMgbIjEG#C_K{J9zNL-T&y7*p-=cfP0#^;?u8JkuP@a;>vro-^*BXLkT^fxA)o` z?m9R+`|DnbM7+%%>|Bc)pAVf`D`xDSvEm@Sdk-EQ_2xfvru0he&&oM4YRV|78%z7T zJ$;wGeR8)&`#x>=+GXu1u7;WQ_kEw{zecFN%vCk|`Bi@F1eWdu8qZhxz24h3_z#~q znt#LQNPfGnxvwWO2Gw`n`c-~jRyT9{Nx`D22e+6(^KeH};=*j8H!>TU zKOKqjt$X(1ads{et)AvS#i|zX!Kl_gT9x%x{-7H^{k+w6oU?=?nXGy>k-4O@Tg#1m z7FXtF)wjSrJe>8Yxgm*JSed{q@j?Hzy3{qNMNUruCI~HQC;x;ieZhCjS_G zv?ymsF2(rRoNIcnOeG)rGB1(&#rLY#Hp~2CapjG)iNC*ya!*>>VsTYo;+__Lm-o-w zZ`vfMj{L1TV%f^9vgNtAewNeunZ;H8v-g`0si_CwGkuq@%zC08`h*49ukBlqWtT#a zhH~mhcDICyRhIO;r^VVtlV+!Hu5akS>^{>vk@IeD=TF;a7iWGEt6ZB|@x{K(rA3H? zvZ8w5`b`b36ZcNrJ~+42r>$a@qUP6=+Dp_4iKRu_*Pg5Ut}6d@d&AnM``;?x_2AKK zn=F_!rT*k)uY@sC`uAxtl=Ea>Q{?=d@?H<~@~D6PYwoA82NOPB+PqZ?l_JzBj z+b<|~YmH)e|M|2MV-I@R973YjobQ zLPWO8Xipbe98W7#<7p*0h*p-1xRvc9Y~?f(<_ne4wPkvsuciY`MuCgLm8&thn&rk$ zDxfR!^blPw8mShQw)FH;`Vg-b8UbjH@&Ikn4nUqC&uds=5uM_;P0&y=OvDSz_k(}6 z%cV=*0uC+K-jCi@*g003*E-fFYf|p1xu;Ma9R?WG-jSN|LW*@tm`*LBcTU*s!(6Da zE?#UfDqrMLIvX~9=o*~QSTgO^Hf|dnn(W1VIq9+H341>xK9Wc#J|ZYIiBa@sui7&+ z=_Ul-GR)4w8a*bQKlza<3&SpZrn{9Z{Bg&dKSWV6(S5Jads1-4FYu z{a{{N3&EX4n@c#bpc6IiS`Tau(E(JYS5SotT$w6chHh|hl18hYp*nqp)#uZcH_y1X zC;YMMZy4ZIxV#@BO0_dxwKKaC_Nc8kX7^IDnIMf!+j))GdcLdXe0tPS{Bzh724jTF9-h<93NMo}ZS>_i2V30UvB ze*0FrfRwb-E40u$1-BEh-faZJ-dp8SQqoG(o`BmfR8UO7dJiXHw-3vXB$ih4B^rk9 zHGX^totwwxAcF4s(Gos z23Uv{T2pLa+t!&^eh|AID|e?v+L|4%F?L<&wYw18k*3(2-NOwiGej@4y><*fNj#KqIaGre(Mr`lgmU@ct*g z)%U)+RX$Q?#M&>l+Z1gFH`}!@Csu$-Z-0x*n|SlcEV!GL_CF9gKI^cYSp4KJ7~nIs zG~=h(yXxi@;7K`7Ked&`RzI!1!>1QnjJ-(wjP4Gf+1p~QA@Q^NS&RvZPp+`|x6scX zW$~YZt0!7)>zVSH#iOWC@u@$u_#g00+i7ttS|Q^#A6SgzXngvg9iH(Qi*4C+K5=;F z-yA;o%Oa}UhE0!C*u)~jOb|9PjxN|!kqi?@HHTn2?Fv0{&r|5(gqFfKWidrbL}v>i z6kr+)P|5!>>3>orMvbWU-xrE;#^mWXPU6TpHPfe?Zw{zP@d)|1SQNRj+68UoIE@Hy zXu}fDHuEVk-?_$GDIVcy4#sDy5$ch+WK=Ii28-1TL$RuMPIa9@11E&)%-Nnw6}Vq+ z`M=egJYvqA+DPa^??+=*s%P6J zU>BrCSOKw2uy&b$d$;f(bo`E+V!DX@zby=;+dI+V)8jpUQ&h+>4rF00(W9w^{nO}< z60EPgMmN+@gFzSu5YIh`C0a`;!i4CpB?Ms?txxy>$qxescGAd@8XqyiC2-zIKZi=# ztNnQ3gTTPn$vb7(sD_C!h~? z#`z!z&qsePLy>1}kwe0D>I{{}=Uc-+vBY|6-}}oLs5!2k;%l}9g7B(4P@7#`HA)# zJ~kntQ#(iu(s0h&%REyNo);<-&U_;?@dfpaBAaqh+I%UayRy9WxlOc@)>>(ubeHka zg;^hqCGx|CDOG4-*>J&xdpFI|1=z^uckO?9jki#ZZ6kfuLDBkcCrWwPQ=R0j#&!`~ z{>y88h-&wVtc3w~e1_$F4_T>AjBX zkY$UV4sPqk63yes@1O2FEi^wu zHf|2#W3lgypDgi;>C>&W^qn!1|6e)#%tU|E{@FQ;E}L;wNk6|L!c~i7D>D4J(l<7_ zsp*E?o11NIeou@4fib52;l)jYq7?e6aqjN%a=!Zjkh#5mYO7)H)?w!OjxZC+FL{ zxV9qZbR$s`^YHGy)Q|O+6X(16XYS^oc?Y#i`A!j@jBvL+xO@=F?;YW8d9c4Ml0P`Y zkBD%${J8w^NPb0x9~a?cA{^T>C$4XzQW?Kn-kfhg4YeNTXGi?ucSofBv`GFr5ndbN zvm<pdPq0yz4n?++U1nPDN$ck3^6xBfDB>o0S+ z{xWy#FLSs4GI#4QbGQC7ck3_n;zUxgjYm( zRfLau)w-TsXE*^%;YedhdgBl&Lq=KR@_e78Px z{=!K9#S!k-clKW%$#?5NoojlD9%mI?D|m$@4sb2mQbZhXuS z3p>f&ZI8^|_?Wx#F?YxJ^dCLN>6c^a<87R~@p8T!FLO6u=5D;qT^r2Z_?f%$Gk4=> z?#9o&D4Y-GZh13z^TFJWpSjyVF?ahX=5GJQ+#PSjFW1-}AO^h~8>Gg$n=j697WSXH zn=j_BPUdcYn7jF5UKFX%%?IbZ`M|HZT#D0I9$Z_{8|QBMbADD>1@jgW?v6K{@7iGQ zmOpbh9_DU&GcWS$4p$na{xf&|XYTsX+_k~n^`E)xKXccA=0)h5 zP4;UJN~r$@k^VQ%UH>`X^`E)xKXbP}F?aoC?)t~v?N6Ay^@q7zf9PwPUW(H<58d1# zqjB!~&-t$Z%w7MPyZ$qG{b%m_&)oH&x$8f3*MIyn()#xKE)&^1bN`d*FmLTQ}4<-_@|zsy~KnY;cncl~4T=AXHnU*>Lp znY-f&^TFt_h?}mF`DmQGIpchH{A2EpZ_EdUjWBopW$yaR z-1V3Fagp+4BYa|npBCX~Mfj8mpB~}oM)>6ser1F&i}0%=e079h9pTqU_)QVs5aC-Q zd|QOy7vT>^_@fd2qX^#_;m<_)?g)P|!VzPT6E8o+7WDaH5$@s#u)ljGAHSLR%lC`$ z0TJ$=LBjRnx9@)Wp%IRlWPbjb2p<>W<0Jg!2uHjIzrHCEK0U(EiSXJ8pBv$uB7AFv zZ;S8;A{;Tp{Qm9rxaQ!U9{K50;_k@6`9UPVB*J?{c&`YjU=Lo3Q-lrdTh0zOzMto| z55B+Swm-h!bo)!b{^}W)=j)TQkn{Pr>vi<}HhMnD=U2`jJzwGDziXe5kN)unm z;QoAryVTE)AF(_*^|P@Vl+m{q?Gor43JDu;#kH5P@nGEkH(}!mx&2?l#;JDu&xDP` z;`T?`Hoj?XSbw%b7@$i%KAo`JA2u;_h@TVYH!&9yKH1|}5U%q0a>7L+&o$Q&cE`(H zb0hI&nBUw!^U38mx6gcXYau;zC#`%-vx9i2uzYJ9qqv#JpC^1+$n(srgj;z0&9wY{ z^Q*M{eDi)9FEIZ>-1Vox{57q7f%%%aJN_4#Y+AOiy+YH9xGP_13W>Y^724P;u6&{C zMfpWkC#Q}E`#v{69c?@iw@!67*tg}VozBNjB%T@aOmix6w|u%7?5o`Tb+ON5a^*7( zVzG`0%Xc-G6CdR9<;3TD{5s^CSMD+rGQn=kqjp`A<{+qaJ^W zct9^sUCn;Ny*>Ub!v6jp@o)V7^IwSn!1I4a_&JYfXK3AcPndk-ZhfNPWD$4cNtj~d zZa!)IBz|021#O?i{p}U;28+D>5yX=oA5FZw#}QX>xW^Hf)8D?&Chqos2{VIuU(Y{> zct4L{NZh4tQ%~G&&)H@TaesfXp7_;afo!vp_%x4iChnGhw)easn3|X$QvRaQ-^4si z+|5rD^Ad5_eiO5gxZD3UF>e!hDc9hcS#JBuwa?6Q+e5DTobuiJo@-)pf4*}KeTeO) z<_2+QgHUO1pGV~CYi{VfVP1XB4dTxxJ%4#xeJxETako5LniGh-`dXTkh`au^G-ncb zMtN!+zpVEPkx*TV&7C~>!cEijeDi^C2S*q^R7_4p~2?^2eJ5{uP?5h`at3nzh7T{|e2m#9jXi&1T}oVFwD$1H@hb3e67U zE_F1!)BGLHtHfRV9nD+BU6GFF0Fk1wf{x}xmq}`8gP;1i{eNeZLBG6lmd+-ZxPQE% zAHaI4i%Ai8>th$woA}Vs(Zvi*^LI5B#9e(|%?ZT)^QF^>_YKQ;HB*WE$Ddl_uKuoO z0r3%@|8nAPf78`0C*IG?zn1uw9^XKGqQ~zf?jO(YB|gQ=e}wqu9{(}%8$7<7c!S4Z zCBDVuZxMgQ;|GZQ*MlDt|B;uEXO_L_@h^!FkEzhrBxq&xuOC_vf5yu%AnqUUiin@) z<@X@&A3w{8kMZ)4B<^3|R1kNm7h+#|&$R4irljTfHF(C^qhWzwrk?nykoPd_iM#8? zUIssza>w^x=3(M^h61Nv<{9E=E2ZQ0E5u*%@_$L(rDF4Y;tMlW>1Dnk-d!nec{$m} zTf_4r^hrHNyB#v`RPQ|7>aW|j2W&rWOh55Zq1@S9FUTnq_$1#NytuMrJ&d90Q z%q3nM@?K^UaU63v^)lBIN33j4#pX8RJ(beuZQF?Fc=PcD@pnA`3&j8G@i&OK3H`<9 zH^lwx$&ZO6CN(FzzNL>i5s#l!v1vgZvG$h;Q`#zbEd-OV>-p_j~yXI=Fq|@jT+~!UImR=}O!kFMF6$ z;>UXV!-%{33(XkfI7VxKPb0qG1AFej$fN|DmK3$j%O!u>Sg{we3+O21#x%1(AnhBPg-#eq5k&7 zr+a?H#Q&q$-XP+Oz5EK|w|aa$@lQPe6ymfCl+@XrNBmjOe-UwaJm_Us5XUtor(Whp z;(`0nnnvq;m$*Bh>SBIR{8wIoJ}2&$R~M5(CuenD z{cVUZ^*Ej%u*lxs|w#&aj}FTDOg zNc>B0{&y0e9WH=k^9u1^w9n;KY~CS`b7W4v%typqc>GJ^JvE!|=O^eR`L14ldBn$i zyesjsp1&vYm0tc};_i6U)f_|o`(FNu#9#9GnZ*C%@$-ng<9kJoC3So^P^RQ3fUU7nn9_ywDsboZIhcdJ4xepbcG*4Hk}lW*gdH zjuwt8);MP8v7Vl_?-Z3BahVjvxi0Cyul4+YI zj`|^Ml^BU@4~%l{lUwmFZu`t%aQ{iWt`tT@xr3x-``BON1I0ZEGvnOSp>oMBmo^7U zhs#lmbE7QPHCS>7OIzjAv%#pvxn&B5NbV46Ylw_?2x@U|>2GO2X{5BD^rf_4x>34X zs*_o2H!SK_shvk#BR%aoy)V+^(lY5psV;(2yE15@^p;EoAS^q+9kVccuuWTSDjM3Hh2bYVlZm3Iv(B~ zs@lL{on>7wN{47ChJMUCML?D$~uXOjnRHU1iF2<1N!UDzndr zrpYSPHKa@zWSP!*nSJ&(JUWkMx>U+^V=U9HwahM5?}5r#*dE2I@Gm~J9W(CL5TTeW zFV~;+NYi%J51;QH$+T;Bn2BC`mD(u@GqITbOe~TxGt!;(r^-jVZkG?2oL4=2M$LTm zDXhsKNu)n^S%pSyDqer=lgB-7*W}QQ&ia|*j_%M0#h0N6VL_~lA;G$8?tlI9o9dkY9H8yP=_AsG!+9mG_rY(c?jm_J-xKh_h?VPE04--}z-4N1yjw$jM z=b-dlFfZ5c!@>^Q4K-{AJ@BmQQxe_4%F{O6NVSozLr*kH?Rko8J+eASHtEPl8{KRo z1M^o+yXW^ug8pD_uxB`~eQXGj2S+A2THc=ZdG*=jn$IIWw+9?QKeCAI;m6Cj+l$X5 z{jujAuG^8;%G1`I0cneWU}Re_k1iQ30y_n184whnu` z64s>Wr)BBewVt4q*;S5ODofv1?4j6If)xX%0crb;fsskJI}2}8?RlNgqmvw2q3p5U z^V@T2kK5LL9$B01>7Ab+S!{NW{rpJ(?Sl03?R5J*(tkVCetu+8+e!BGBddm;WIsQ$ z{YB?@U}U}qMGs?<{@IgHum12nwag0wmL9&$4+$oipPc3g|N5tbfra7DZ1gA!7{yV@ zm}yKh%|kFV%>n-ANMhd=Gi>tY`E}J(&zn5;obx8nSWrE0nweEIYkp0gnLN2>VI3XN z=TDzDy^L6G4ZqKjcUNqB^~_p(N2o&$-|*{4_dojMMhK+=^y(-&ujRnvPq*I!I{l};vIweD+vfZsg=dI z86~UZVf2)W=r!^}r}tjS828G0U&J_zaK*)pQGf4CJpEEnzs%F|r8Y`f)_vr|NzBhk z`QX6L&tlJirRQJ5*!tyz2kWnA-S&SOV>@1aVU7~|*?R@!w!kYHV;$~rmBYH;4j{dw z=)kJm`d6_Zx9)li#&WD!%{n|szK}uxc|Nr)#yeDWVAaw8JUp0{60quX33reWPk>d& z^6e-(uTcd%)`3;WYN7Q2tB&c`dVp2G3A)q+tUA8; zr{e`y{Wk4P(1KUdwnQ=_B!_M@nbWtKxdbvkCWE%lK;O z>li->yq@uH;2RisqPN~RG9FBC73er6eAm1}KA^&8Um+ik<2&HJZ(+|9^fvNV#@Ls| z@DOTBSneqgmk7qPPTj^HVAb1tIKOpNfy)A`ek@@v zdptZ+7FazeLcfE{0;@iSu$G+;kBkLaJ=p)Gh+dLgu^#`Ee&3<6jpCPPmVO>gLrJw|? zo)-zH?qMBR_1B?qV;xxaH=s-3fK~scrvt10E_7KpfK~sDaO_^L|L^d4xJ2+jpx?(H zVAT^OrS4}PSoJ2*A7C9=b!Kd^d=p?{zLQ36)I7j$V0SoOo9%Ll)}s*fNX zdx-u~s)EPEC4!HGjvWjoVAangtYxd=5kIhcYM?(%|0n^gj%`2n2A&yQTj&-hn$p$O9ZcizJoo$s$-Save<;QEU3;+A3*;Rdw^B{g0PnT8XoZjt0$g8 zIyz1XSoL;T->cBFXLx0S)r0Skr=H=mz^czDtYz_?@zk^I0ani?(4{P}>iB+~>cFZmhyEPb z1FZVZgk!r{zYQJ_mk7QS`fm0BtG?YUOQ-K9^*nok)$?QMQWjWsoZ_estU68wQZH~l zz^dbOeC_9Z@JL(0>iHdXX$x5OuL#GmQd7cr(o-HT5sc@sq+VnXu<8`2F)Z83D+{ci zBIqx1Szy)s6V`U|UG>yn_5iErNa)fou<9og*0K}ek+Q(*IR!d4N=m@0pGP?M3hQ&= z@o|WI)PRH8R6JI)_(zyhf4$>fc{hV0IU81^!=;@tB&u^r`}*4Sak|c z7q%6r6FzMVSUuU$-{i8us&^o){X7hwx7Y)$o+NZ>7g+Tk(0|5$VAcCT|2gZxst@pV zVAb*XnAF?s2Uh)f!rHeJ;gP-pt7iiAcepID>Ze1OIRsXHGISXWui&V?VI!?-AC%{SF@K8?butn4Hva zxh$~ipF)>81XdltKhUuNtBz-n#NOw6=*e6r<>3;+`OtBYrv$8ecdsmdkDz6N)zc69 z@3<_m>LUqjyT`)wA$x$;b3Ak@3#>XlJ2%vURX+v#@3|ge)$t&t*hj3-hR4Gtg6Bd1 z1ABl~ulLHX^vVLOXAN{I3#@trVQqI4Jb&c+fz`7Wx|9W0{XtI$Rvo{KNc{)b1FZV< zgte`g;E}d~)q~$iXj{OlA0!<6nCpBWo$5WJ{bDvtOKh) z%+rBY9|`^M><3o;WWw6F)8N60FePC1oCRI_2CVu#!de!;bH72u<8xaal%dsSatkHMBBnM*;9s2z9<2!=ZDaxpTMfW zN?6P8gD1vifz|US^bFR4RsR)qTqsZiR{bFKOxA%_|0`i_3%^52CD;S3p0A-xTfnO4 z(RW_8Yysg^7MBH9Pe^^`-GA5H+PJ`8#jZVOoTkb6H^3uY=x# zbzs%kLzlLIRlkR@wsk)|Ex9bPdLDuKKncg7zB_h9@L zFfPg|<%e+XCJ9ep*82b-&bSm<+8PSnkM-feQvVp> zN9iA>arBldWe>344>=j0GS<%o?$5XySbjuO3p|kZxxj-MUk+T(cqOphw^>72@4Wz* zh>qLbvBB)W0a%s`ZlUVEk-G_}hOh@%?`hl*&k?NSmR9UY#*YC@KXJPuHk9?}fu*0g zeA0g6^f4y)UT~VL_fLRJM91l1>?p1Wr%>8Y97^^61`b83quB$j_a(3^j}2oTySCVH z#@J10Ke4IAaASrNHUsS^Ru}CjraOiKQNncSJrLj$(b0Tt1pT9gH|^(%z;X{{0^!t1 z_5ka>g|pzPV0|`lC1c#HiB&PS_iE&xhP_uK`XYFaWzQ;LxfgK_VZE*g*6VtEuVxhc z?}C3cJnO)Eo!AZ@Og5!1z!MpF z2R?~$De%dR2LYeL_!!_{@H|u!PT__eC1Aa-83)g)te*;e8sjOzr!%(qQgG9b5`JqD zJCpGxz;f+_-&~}yB2WU>Yl?b!CbPa8_-w}40#`G>1$YYM+ks_UyAOCO>pOtu+UJLa z_4)<4MD(5TOk@9Zz$wP~eW#xDKP4u8S5tjOWCu5rR;gYm$T9nw^;{HK&(mIkXEB%E4}2x#p8?Bq`2ctc>-cScY$@Zv0?WK*&|SJ!|0O(Y z*>7-ezs}(j(G#TW81sR}QwV=E_5+uQ-W8tptoH-Hf$QLue*%0LV|yzYMNICs z4hF^vG9`SEB_{W8M*(kSeGG7W?t{HfyqEQf&;!;d0n2sG8Nhv5KO0!CN2URnvVIQm z54oON;32Hr>&Km}*Fis;^@YH4etRkKNY)nt%em-M;Fr1V3Sc=WTn#Meiq`_~W6wHZ zIhVT$SkA$21(tKL24FdN+5{};PFsO-p+M))1>AFnPF&UI%_Bg`$eBkRD=VG6;g)#2M#eTr}LEtADXJC85 zg)gOv!1&?@r7ghkGHyqGiT#POUFW}K{7dM~dAvu{Taw~4AOQ!`|6`#yWgR#W&k4}! z_xMP_fp~Bonry~8Fk%!SodunKZ>=~G&vfW5SO*ToGaI`6o)$O|&jrw1u^%`P&*ji1 zBsp*(o@LN+bA=LcAfBtC=dlhPi020AZCM8n#B&>T3Aqg%hzFZ)5;trp0SDrF5PAXY zz=3#hottdWI&dH!Y#vDoDGeNm2OpUyC(=Jkz=3#v2K_Lu2RM**47-D57uJCT@!&K) zS;RVUARgQ%f6{@}YNQ9XJrrVbBBC zfdlbi*OM$^9XJrr;n2IY4jhPQF!Ua*0|(+64!tMqz=3#1L+`~pa3CJ+GLpSn2M)x8 zOR{7i)`0`@;P960%Q|o%o?7UKvkn}Hrw)2Q)`0`@;Iued$~tf$o_gqItOEz)Sp!|Z zqzD{{2d56n0qh43#Dha`avmQkvyGs;6Ob1 z?nm+r)`0`@AP!LSOxA$|@%$e8S*!yG;z3-VKie z&7n_W9XJpV;wmMlvJM=G2jBfjPGcQ75Kjs88rFdW@f;3)I_toJc*>#AU>!IR&oJoc zunruEXB70AtOEz)`5yFhSqBcpa~kyXSO*ToGX;7r>%f6{&VxRSb>Kie`0ht?HtWEF zcrJxLhjrjUJoV7$vJM=GXC?HLdHV$p#B)3J1?&e7>KJc@eu2Y*cpid&A?v__c%Fd1 zkagfdJoqk0@*>uO1M%Q~PV!>bfdldEhkgm`z=3#v0sT_efdld2{!j8U)`0`@d<6Y+ z)`0`@;QJfND_92(#Dni|Bv0Y_0S?5|GC}%M_5%k?7`KOB?{FZVuF#jU4jhQ5C-mj4 z0|(;i4}Asez=3#h-zmA0b>KiemC&zZ9XJpVVo@enu?`%F2jAsLu4WxL5YHLV*RT#8 zh^Gen)vN;t;+YA363-8CAf79ruVp`Qa6RJ{(APN}i03-!>sbd5#B($B8(0Sp#B&Gq z8(9Yq#B&eyn^*@9#PbmJ4XgtP;&}r4&8!0l;z9hdhHtTOAI>gYSDJ?_nJ{5Kk%eZL9+a;u!+{UeH#B(Y1?W_X_;z2CWo1M%Dj{c+ZT1MwghXz~fxfdlbug?>7Z3pfzZlhB`HKXC9Q z%f6{xKie_Kie&p^*+9XJrr zi_q}}8A`x`cwUFzgmvIRJczZMtY#fJ5YI=@Td)os$o9EfKr^di=Q1M#ee-j#LWKs@W9Cs_v$#Iq54ign;XJe#2xvkn}H z=YHtjSO*To^CKiePeCtX9XJrr^U%Aq4jhQ*Rp>of2M)yZCiI@H0|(;yHS}Jr z0|(;y9rWI;0|(;y6ZAf;0|(;y9C}~YfdlbmG$s9T)`0`@y6@eG1KkagfdJc!Ah9K^bf&n%u%(92l|4#YDK z`e4?91My6PK7@7PKs?pZk6;}*5YJ5LN3sqah-V)3p{xT3;<*I+QLF<8;#mUyXx4!P z@vMSAjCJ5ZJZqs3XB{{Y&#lmpVI4RS&t~W&SO*Tob3gQvtOEz)*$%yeb>KiePeQL` z9XJrr^U$kU2M)x8Sk%d5SqBcp^A_|`tOEz)IRJe$>%f6{K7@W8>%f6{{s?^v>%f6{ z+SB?Mo6348U^<6DDxz1a0}$g9(FYJ$|6pJgqBN9VsVWOCE)jhkN$Q^nJc>P&=q+`= z!zH5E!Xy2`Et}YU_SDf^YLUYwqOTxH{i}hmWY4wqmb%8_645uoBlT|uzK%Wj(Oc>+ zhf74?Ns{_;Nf6u2o)_pX^?ip+M1Kb!ssGo&53vWQiK!ntTp~J7Q`G+@@Q>MJXpy9z zceq4!9LCg-Lr!cDdvJJ2?Q^(9bnI5tk6l1)KYOsbrhesciRfcI|2W_S?3oDv9~~|c z{Tz5?ytTj|vu7^+pF3P4`cluo0{9E|tcJfS{i6h2BKjlnOk@2q;AV_}L~p6%9WD{w z^qqgvth(wc^js&iruB^fa@$oalFhHJJqyBJ2phGe=IM5*( z)e8|D=n#44?1=0Q!gn8AQ)gQqIcGt7HHX9$@|u`XS2K6yMN?~Q##h(PoI};k!MyiP zkDA2(FkBWbr^XHceUBY` zQXdg9S0g(bUQNICe@Dv28kr?7>?{40 zA*3t4!xtAG_3>Iw+W_U~{1d+38_R0yVkc*$_$shbyQz_!suTvz0el=cN4w*`raYZ zlQd0Q-&zv<{@v%**Ie>Y-*$TW^<_~7Wu$4+`W_^~ukSgpzLt`Q`fw}Aug`woPMRjI zZx0E6eeZbnwU#{8_b$Es`tUWJBGNQzeZL^VukRDDzC6i8eb}Y@^*KR9|E3A5LNY`j&d*#Xd#*cWR`*HnangQ#5k9^%=)%zrI_&`Z{~{&5P96 zo9e^1s!8W>R;0d1s6L#_Vg9<%OZ#_qq`o?;Z!c+@w7!**`f|=Q<|EQjUsrl*eRq*Y zf8lmIoOV9bv@-F5J}ExU+C;vmv15^hI*=YG;Lpn^we&nFT0zlnF}<|iJ(2oqXrsMe zDE0dStK`L&< z_m`%ehyUv9LOy?9F1?nvLt5c6j=uELc^Md~ZvbsXztKv>M{lNIq`npR8uJ=ys1IY) z`bLmOtL9vkL2BQVo}{9&$x9?m!%aS0n^+WIo3$t& zt6FqZ0d;)_^?&CEcCXD$n6-(WIcu|a<^=VzsvD{H_ZLx%l{*IZAGWrBVE_JE>rLxK zvuAP-`*d7+q7T)-KV$1&w8Ui>wW7LP`DJY{nxJ0JJI<@OJh5ol3wu+2?=j^y%ZBA8 zYNn^|+|;Uk|K6jh-o2>?!kagczIj6`c@OZ>d0Cq`=(uzwsiHltXfzwb(a6~2-6|6e zIKa~*pJ*>Q(wIf`zLQ?RrWZ6boc`$bP45Gqr8Q%u&R%x6gq_bZ)#yQXkT4S#Y^T?* zR&IvlmD_WCmY^Ptxh?r+@b^XSd#sPhO_^dA;%t=})r$ zikI`%N&Po(HvJdeYntp@Ji5H;$HRJTwf&}1OjuCgUTfI4vhP(^FRsj>PuD-5kiV&+ z*R;)pX({Z@%i6!Ue7_mKHfz`3vGuRlYndGw|K^10->t#y%dc;E_~Pxf1gB5W%c_}P zUXw-sn(5!R#8%Z3ekSz9*j*z!9n zeZvOTS04BH*7EgVUz?XzIj=nNEVcUHj(OpI9(@MoUe)*7N#RW3O7W=aHPAYjinkPT$vizBZP&!jGTo`C`Tk=RP<6891=* zV@a*8Pnan?Pg`dD5oCUO*76sZk6-b|iYqt5wY)fC3LExiZZ5L55}S~}uA%d;c#m8& zwPlmc3H9sT+PLh2Wzm{5HgwzSd&=q3A-g!sOt^7rL*m(Z2|W||)t-%&yK&L4U$2`| z*ZVeXU)kL%TcWSaX|39qzrCUU>E+$(t%CJz-}=oB8+I-4wyPyjqVl=}u}a>`mQ)UG zx$)&CmEBs_zwFmBq22a|#g+Nb__a*9VKZs57g5gys%LR!>!<50`_?zyH2h}M3gf~) zEPL~FxjL`3ZLGAj(rs6$?a2C@x6X}S_F}j#W^b+t$B?~cDdR0Xo(b*VXrP)~VvCuz z=KMAL^7l8)T2plM|GJiSuZFb*vlyp2#IlQ54Ql!Dzz0qLf#~VO19#GYw?~7!zB1l! zb0U?qJ#$TE?VePpU72eWuVthZtiD2*LhGj& zR|NG98-}Cqc8P@Qg}Xe@0eFfw*iqS0Y{|K-UEZK}<^-B;?w2m%_^tshm+UGIN1Hb= z->lu9PtLUi;cxwP!-l;2r7hN1YD+y=Dr&w5wb(g3sV3+CJ*(D#8mq6II~udGgk~jv zV`j@l)?AvE{h6uG?`5vsdR*FG6We0^jhdWk8!v0uf6z|zy)}vV5|tm1POaFSx#R{d z|M8yGtyF&Fdzq=Vn{!g@Hs>^KNUclI|N6>Q-u9eSTRO_{Sfw}dlk0PKU=61Fm+bD= z5_PYAw4FKW>gMlK@A48k=oOaRlJ$v}^;M}Hs-Kn|FEz|8mi^kyEEC_oiH`rDef{vD z*Jv)LZ9HjB;U5x}OV)2nq*iRoY+m`n3#nTl$;`tN-?%9=v2|6)tPGu<`1*>RL}Kf8 zsp~i8zw=flOe!Zgb4BgC zioF$OE4Qt@D>w5?JJ(I=sGD8))u8&_qb(S!rXXe-B*QAr`qJ^ zj1T8N2+_A|J+E@kB~|z4Y^(2Iv(4nuO!mKUmq}DL`F-B9&%Va&PTTmsHBG7t52O+= zdF{k2a}%X6=hd$a=LBO|LVMN6cP_biWk!74o{a3xP2xIZOSXnXGl@0Bngwm+Di`}Y-fVeghca25KY9J8yv*@5|> zttD9Y#3q1$KrTpQ#0Yy!q+A&*wlVjc;-Q8gIDdipU!5M-M^uH zGo8(3t>56*=WRE2Ug`RTSLx0)_GdE4d8ej)c-c*es8d@;%wlK=lrAk zwlxo|_RmYsec`y>W1s8$3}!KJnLE$uxwEYPv}M0sHh%dV%V)3n?TRbcl?1nDe6ImB z6sL8l^@~8*f1)JjKjQ{n1E$cG!RyneOv}7Y&*b4ne@cS;G7^<3v(2p8t9{*eRo|=p z9yPXX&)s=4Z8c+8yh!~>C7WfS_Tt+r%;~s&J*H;%jJk6w=hw}gg?reu&sAj2Qle21G&G`#zW>39{vPr6*I<* z^O*5Pwbk=cj^<h zqVK5jYf7}U4O52cce|1dQx@W=FXooMIaOh_ zt(ZAOv%Ym<`)kp{Q(TeL6dqb}nB`U6IE>kG2vi|7}|d?yK4qYaQ#>A}nKvy;|uQ*a9C3wd`wJ$J%5KZ-3*6LheXOA$mv;qU}o~kepI# zz4gi~W2Q83{fI(*)2>b5n6nQpM1i~nb&nqW-IrQMgC(REQNQxNid+ueVa~M;&_^qn z7L-8o_5(~tfun_;sm+rLCgq-*dkWRnfjfa7bo6?T{&k|GzE`j_oNGt4hxIVmrO|oZ z*)DLSSdl*v?r>MSnhN_vzgTKo6I+%~(?E z=7DFZtdUlE#Qg)T;JxXC3EU{B|Mo62J{UVRWk4#YSG-dq4jdnW|CC}AGgrq((|Snp zY(S5*9~qmU0Utlk>c0jaGtuHd1D`O-;#SmPY%G4AV+_7_8#{5S!{g}0QT6ZP*EY0j zz(4*fi}5w5*o0Lk>m|y_ex3fcwV$1vOnkePwyo?Oyk*4VzsEbJj7?U_&dfqvwn&DF zH?f1J+}k-fBkR|iODFa6K{dW^-b3d<=&aJ66mi8!_97 zTtv=zXPL-VTI~O0@6F?@s_ymSbvQ{3ggG*ph=v6A0f8hZOhHjX7z9K`0cQ;%14Kg- zGay*C4mew@;?z3Sx!PK*b*Q!4i({=?uT!nH)}nT>)%M!zZPiZi^Q`Z8?X}J(YTMua z-S_?DU7zHf=Xut%ziZfQuRWY|_TDhKFqJyQwvIRVNF6FY$(w1U4lDHf;lnMq`Vst{ z7JlhY&yi&oZ)X*bn&k1(ytl3~chhqW@BM={MclB^V*VO9wPuOMFB3P)n%WLuYVG}2 zf10@IL5ts{r+J&j{6%l7Q4D$5ux`w9N5swXI zOkORn;BWypHgCABptF#jH$qm>cIqSjipVR*843~`n76a66pKg6O8Fs|9bIkG7i$^$ z$L5XAZ?Vff0V%&#%CLByl)>fm*UKPaJ@VV!&@W8CqG1Y3WDFLJEP^9R&YMplU4J@4mBciqI!G z*+Q}r%cUh2R|I`BA?TBd=#x{heEM7sQdFI{q6jBlNCh|wEQ%zE#Ti-9;z`nM1}~cI zn^&}lZ(h+9Y2FCNnJUe*c$ysiT3k8TmNkx^swFtq)A2Uoq5{UY2a0LTN%n{otv=1R zx&X7l|DQg!2b$U&aXlATse5qQyewN&SzVben}jEJZz`*A>}e@m+1c8ALSuK!wEY*X zF3VOE_3X)}s;{RzTeY^kVSQUo?d)trPxEov%Ib!ejh*d%yaZphp{=>Oy@ktG z^|W+vY-?)isp{$8*s!jnr>Cl`xx1>Tv#-0Ug|MNukHuH5Z=+73tEIVfLkqs?FPi6- zO`lzIXJ2nuUoYy`*wMVXspQ!}k(~ucS4-n@tJ*fS%*Uq`D_f4YOYDy;`?#8Ky1H9<<($;$Rr{E;wy1Y^ zudPiSy=i@8w^^}h;eibY9LSFq<{!LDXaM(Hv}lD{f!_Da+s{A5xcY$o4mj}81B4tp zfBAlb4qgoj%gk@;ZQIz^yV(WcxAUbJS2T7vvK4WYEWnR5`dZA!#`gA>&1|Pak-NI= z`vUny!uk*B+n^Srj?V54^?j|a_&EqVV+H!k_H8XXuDhkNoq`RD4;EInZ0Pd+jUQ|n zjc$6{HnH0bKBL*ct;7BdLNPuTV)e4Qw8k`U=xT54?Q3pXwZ6LrE3Caalx)-4+Mwb4 zZtm^`vjc98&?d^@G9b>7vvu`a%L3?M1X>9K`%i9|lbar+(+X|Z|tn2mi zv5OTD!8CTusGPrG)zU+jt~$KIt(RE98eO$?fr+_YS20_5;J!Yqe(8RTJXkpZ zJw0vghTPwIc7uS>Cpxt+%Cle#g4@mQ|exW3se0WJo(d(cZ%ca5r^rMknyowS{P5V@H$q zFo^ z9ZrGVlN{WGErx+HCN^~K-xI9fc;0if?yMP@8c?GBp&4q>)52+FeRF4*!2{Gy8;05@ zymG*{HJNqY_z_jJ{T$dF56khL8>K|dE&4gA>FVsk)@pkAVez7lKGR}4OrHUg4R~Ky zLHQ7NA%0e+6V`^7#vU{q^+n}uz0g<@)?q~mV*3xkBxfjDu%U6CeP_xGL`W~z+-KE$~$9{%u;*VT`bTHG1k*vSJ zGynE+!*_?_Fw*RWt3#>OUxp6BtNl7Oj?_~BONSJneE@M>OLs?0dljbnmd+l1YuH#* zJ-ZTzI8{sf8c%3xYgmrl16NjccC~ag=%LJpzMl4~wvMKD>>aAsw)OUWc2WPvQBq}P z75=oC|0^ZPaac>o#Y zE7u!rSvbJz-Q3mE1BUZe@3MO^98trP6zy{CEX*D)-K~vHEm#;QnvHrK;70^>Y|L1D zeHbJlI8pP#8k+5X7jj$%zM-?ep|iCC@7-;ikb^65aY6X5Mox*i5TwCm7Xv%b?DEnk zpBMCS%{!H!KPa8T=^+0xoA|6Km0$D;SyOygJ{~*9rSo@9f8M@VNVNQX<>hI9M1=*? zX})W&E~TtYV`O4(YlLNvv&&}EqcsL^7P3Q4A3^xBTGjmgf;4}!vV-aSFb#30$!f~a zh&g|uzT-2H{uX}bpDE#am`1r0QtABu0=){)#6jBJnosDm3hAo+eOxW)YVAt(ePDrf zl;*2iR-ns`()c6Ng{(t9?6y_;W7XmKY|(vGyDHPC*rk?fv?H8*zWSQf3UI_>t6 ztm6xa63-~{sKJf=ZIn-1>QyX-o?LBBaZh4|PL;*drS^S%y4Ai9k=er4ahz-62&Y5^ z;?NO3RhdlDk@mwLIeosf%sei_Osz3C7nxyXTbYy-sazvPIguvnnwhNcx_#wOPM@r; zvAY#52~y7H{ZZI~6J2%iq%6DaZd#rE@!B*UIQbKDDz=+etURY;De)vr+%mwfvIA`a z1JgD3y)1p7wD{9U>hSc_QZY9i-F|V1Ha^)I19b!Vgt}aYx|Fz`%|!LicfByEAbpap zUA|7=E_&?Hogt@XyV~56=yQ*TW(jkoI7T4CA%FK3X%?(?3_+f zuKAy_0X%?q4|46!xR`tBQcLyyFnxC$;b@&|@-Zx=7UT7OpM(?bklj>?b7G^h!!UoY zQ}8Vc+qpwrOGfKDjH5@1Qrr@*KG^K+)R!NZf(_pGasIG$n+={ykFoE=(w+8Q$BouO z;uoX`*}M`R6>JU8W%0@wo>hc30nPlj~hGYsAINUwn01A?XBJ3wIaDnDm12U zUT%35AuDr8`gnGo>bi8i?;n!h$#$%px5~6tiD+1R1L>2VMtAdrdVW z&A+tZvYjq3ykg*$gT7Ss<-u1CxpnAm!)(p}r^+uwp`X}CTk~yMpOydb*5wo9e%iV@ zH~pFI|F`1)6J;jXT^;&v0{+8f$7Sxivyng3r{yQhSb^aG&iI(W9~QKCGQyV?0rQ6E zcW<0t(^k_}-LQc#t$b0iY14+rYz)_W*aR3h&tjZu$0^VJ;U6&pz&0CFaC;gZ zYxoQ`#sq1c+v7{FLF%953V(@W` z@g#qbIEHZE&q9)L->bsoFNbBq_pu)%4stsQC|PtmnZqdtCFR-#_>J0Ll0LC*04;!hL@V_x&k6ifbX9^X`KKoMB?*2@g5Qzg z-%9W&68zN!e>1`LcF0hretP@gn3u=XrsV7GSL6JH6ZuCZ_@)HED8X+}@Fx@exdi`x zg8OM)>Nk9VYoPF*6MT7s>tj;m_FRz2*GE~#`FysOB#D1dg5Q_m4%?dzZW_DQ~_X zk4^B71o!i!EPrBBhMU;o^1kCN~EM|fErQMm6P;eLGz_uGT;<%#82CHP?pepJ9?2#_`v ziT3o*eS0L|&o9FL{2|=Wr^5YwBD^fFgm6DzD&ic1w3(QwU;o_KNAi7t3-|RA?&o*m ze!NUfl%GkI-#_=|NxpB7aKC7V=YBl&)N5$?y6@JVqY!uLpUKfWa2AAbn<`)A>E6U)~n_`(GD<58CP z`{&8AlOS!TB--CU_wAQ_-+tkKz83E1YvEJlQic2W3-|36?%ON8F0s6CpX9Gf3ZeD~vK@-U_GW3Jreq5gS6ypZG%O>lpFB>8^)2>0VhxZmD{`|%>& zZ(qWz6Xn$=xZmEyUzf;VlHkh|d_{u${h!41<4<@;!rztP-3fk5f}ft?7bUnKk5b;1 ziTtY*{MrP6Ai*C@@aGczl>~n+!Tn`osZU{iy+OD>3IauHjIWg`FD1ivA{Z%T09J6w{)`&GbQ4&T%E z?$usNn;D+i{Fwr>0CH0HE*;*I2ImMRG-pjZ%=^I_SVf_N}Ktf*!+4KKd~yGFO|hyJ|B8E=JI*S(3s2T6MjAz zl884f!ADqL7F-|X`1P%n>ut;8_;S6;Z{Nx5HF7{L&w9$oY}4j~qX@$9_HD#QKvY#|Pp3%=U%jJ9mCwX#2zOAA}zj#}j@f2a`?0 z{q@;}xc^u1>v?=Wb-Fs`ZLm2XATQPi8}17W1AYzg;DFx(JUrmv1l~E|_vi3pvklzO zr^WW3{Wrw^V#9r76t}0?yaIl8z_){c81T2jZ;IPnZ2ka#YrsDS53gsZvFzAjJaKLe zuSbt!K9-R**z5+rtD|T+?`q>`l~IO|sPpF^xMw(cS>Ue&_v2@<;Y~6Y$N6K-LEwJ; z4K_!DbFPpy*tCFGJBso}m@B59f#1pbnvJl+P^$Js%hW_AT%ju?`r;TfXg{4v-*2f^28u-Oy& zzQ3x>0`P0y;+XaMSxsHQSA#zo@CNWp1HK*{6ThY^(+$pTLQ<9a9QgJ)KWoke_x+VM z7lMcT<14_!{p%ePbVU+30$sc1*0k4bm$C$IhhX?$k z9RGOp6>#4_aV%`If0{#)W zAKz2V08H+Fd`&UD`H)Z3ObPg;SeRxi!2S4|W~#wQ2l;crefiT&Jvfg|Buz8>f&2PQ zGpoQSxNK~nM}xNpycN77;GN(;Rhd)33u2+loDCjsPZxoQ+vAtOUkUs-fQQ@T*TKX6 z@BQF@KCLnjgZuhanWwFBj1MqDD{~LI?eHY*tJLd%3 zFK?L@ZtuKp1CJLaWex8gak`^88r=gtoKL2M`~7X!@YW6Ce6R@IZ(mt+0Qhx5yhFkL z=iyni20T2UXao0Yp4kLGCl=&@2ar@?(AAlbc&mZ&5 zPr%)s<@l(Px554VKF|CaocmBo^GpE-%jW_<8l3w)mmh(DBjB^Z`RpT?zZm@SfFA<> zqky-9R|NIj2+n7*x#iCUuMPO6;Hv}9TORS*QqF%jIQRLEKMKx$w&O2?pBeDCz()n; zzYqS0AV1B!_XPRH;6(wi0Dmj+PX}Kb})w*~xt@LBO3G!Hjv#P%NK7lWS^@Cxv&13n%6`hYJ0zd7J5!M_pkCh&U$ z-UGfh;AeoJ8t|>)=Lh^o@Gl1ZZtyJue-wOD(4H5;9}4o{0)IB(?}NV{@H8ghcLUDn zM{}R(`nLjnry%}x@SOv`0NkfMa}fB@SjaO+gCB)CN76jAA;*vVBZHT@Z0xztPVfuC z=Lh9o3%)GicYq%da6TXT*r2>;!S{&c7n&b|&kFc!^kYttG|&7Fe2Jqt-s2see5y4A ziaay8KEQh*mc>$`*#-QlfR6{?6mUG;Cg*rD3+~e(GY{PN-ypMJPW}*cIQWEkfgy&s zMB_e1(md0b;~!?u0Qd2RnJcMXc@>hb7b=f!`J`%h< z;7#Bc1pZ#;$MboyISG78Jbx6ME#Q9sEH)Q_Zx8Y>1rN`UuLkEanxuK=cJNw9@%^d$ z!5@lwt$7@Lec=BQ_{M<$5`0yW4o9o;4cL64+rEVc zyc7J=fNui#*JGxc)4;zLW1n!S#YjJa993KV!H4=Pyp{vk5QvvRWaFv+~?$4*I%uH}U-&UD@!2R}7 zW%dPs&V|GEsTJUF2mEmGzXyCR_~Ll|SDE9$%YycN4tz$y&j$~$M_&nkc+lS4z<(CB z@7v&Wlm={EmR%1Abq?9|!+lz+VP`BH+IU|6#yC1V1g{197u$ zo)f$AQ3C$sfa9^I!S&EWGadYU&W?$EFYreKz5u)|=3~rq@bZAK2A>h|W5E6S#~8B? zygtb90{8oeF=lhl@)>hF__o-eG3SH(`ee+d;7po^{q1NK#c>_9hl+3Ob2E;Fxvr~ zcGz&0a~#N41J&2pG%)gl6-#F{Pym?ifo9EaV4*gPg<8Nu>+5IRrTOkS>p;$u`Obp* z&T{#lWlReg(*n0h)_Jouqm)`#lUgmNwt?l>*Vo$O;F#kabJQ`Xfo(@lw%TO@X*;sn zSj(zEJ3~VPNE5O%oifuY(*FAT>}(s|0%;EvX%B&PD3G)xTWh-w?l~T?c2pl1W5a99OM5 zGzVp9ntjzRTnraRwsw^nDc_@FRdn>91F#x-vJ z*35Cm&v8NKxFEL1jPC}=bi0bIqOGcN&8wO1mU5js-L7w%ZGW|Ow07b?!`*mBBkLAW zHU~EnXldwe#7%bL!R=xb7FNHxWo_TO2HZG%T}uz^97IUc#L`?jft&3ND0?KJb~uKd zD`WTwC*s#6;w5MzIy*HC#=Z)9qNR453G)*@QkH} z+1VrXC#qkQ=o~xi1peuX_RLI_KRwA4^_iY%kDaZ;_=)=14JFJ^^zZb<%CehL;GdDG zkDV36{6u~1mK^3M>SH(XFh5bB8HxJLO!U8<7sBO}{h8>mnTh(@DKS`nW@0qXOw@N) zqW!ZH@nRkIUKvGZ-N7KzN&;p%Jm#X+fYTn5S^$$qv6Dsjt_8-qLK z%FbXLiNnfl+=;AzVtdY3Q(yshQn!G85v~!p zJ-X48wevHr$%)w>mIpl-Z@DZv*&Wphp*GQ*wTX_YO>BR)IqlkEkWq+NMeh6)AN#u_ z%&grYyqhbT?Q=($*<{&S+vk3PMAftQh{tCqS|TgcXD1q#wfh^Nom^$JIDA+=cMzSO z!vdhx*eS^Z_0+_N!*=tqS*)xDESJFbM~yu#v`V5olgH9_!U(n}d)^Up79a3zVg+#3 z`vxWolVQbb*lx7IRn;DvQE_L8HSUzK#vZjW%O0*+kmxykUKP~J_Mh9Pk_Vw#+beM; z-Dy~jJ(ythS-R!a*xk1`CYx@LR(y7H;aL#J31}b)fw!ls1K8jQ9rbmz4QnGI2&bo~| zi(_~HWEwuHDCe<7iO2iIkN(Mhv`zTjti;owJmmvs++%No2kH32{|_IF)6meesTcd< zp4R5p8a%D5y+z*Fx%Xaj6z3jL)X=b@uf4f-I=qd|%>sJ6ap|wQwFgeryt#XM=Q=## zroFzg={P*=Mjn474>bCBp2EZB~wnm6~FyVMnB9a&WUr{CzPvtSnemqsbhUkmpH^O{zBkV z)rpN*u^1s`W?Woe~6v_EnwH5#7^huo-Pit z(`$eiK7|i}kl5#Yp-)&}VtR<#KXX-gedRnQ|3csLyGy0&Cw6rh30%S-e<2Y&oge3w zs!r^5SI_gIxq1@2dOA$M^RQhj0za|yJ4`<@>*m@O)^j*?SASwxpBcc#=gK-Ib~^j0 z_&m{xo!&uRzsOAN^z(pAo{@eacKU_DrK%G<{c>PeF0s>Z0OnYofOlf*#JAv|W7T1& zKLx$`0;wmli}M0-$q%JI#7=)1xKwpwr+*CW;t)H1078^JD{+XOUI1LGIO<`GJ%Nia6rI@Vyk}#vei5A5>1zT%vC}sNeqyKdw=yn1vD5DibYiDJNnOh&cKXYK zpV;ZY5B$VV|B$-=_>0)-W&pOwi>1B9PR|3Lt2(jM3xRjl?Tgsy6M)?~A$IzVKqq#3 z9kAcmbziGKaz4YAWt zrC)Vor=J7t`i{O+==Ke5xV1$Ol(cKWUK|EJWG*y*>^uR5{Q?*n%0h1ltj0K0x5 zb~=BX;rfBt=`R4gejs-G%k=9F5Qv@rD*dVxJN;L{u3TcL{~oyHIcXQM)BgxusyeaL z`5SQ8E@G$i-kh%f#7-Xs?CMYK^r7^BMam_1`bhd!CwBU77#|Ct7yqfiQ(q8#4)C-W z1&_tsRQ=K_zq`Ire_-`x;A!0WkcOkq!+$LJ2HQ4keK+mg!x6`BeV|son zI=#mH0|7idG zQrf#i|ERu0|LB*2cjzD0|4;gd+rnOG@B4TsWjzhP-Q~%WQ{QtuGT8=u6yc81{5;6OSiT$wf*RmcL2Y40m)VD=vdq-X-%euBh zvi~uRn=(q~U|4HzS{F1~WcK$6v9Ac-R1MH4Th@CzachA;}2E335m`I!OKaDrWK>9NNr@klH_UFGa{<$9Ad>+ov>}NNhhhxC* zv-HQr|7uxvh&l4A9s7JO^=m{Yc74MA=F~q*yY>X0_P*e`zzY?xBL2X)eXr{z4(sOP z*s-TNvC~HayLC9T7X7>&W#LvD2&R$F|Qz>~z+1NiMyVi%ud!|B9MKb`uG;wN_c1%XcN^vkL14|j>3enX%WJN;$q*Ghb1 zr@u}89MOrL{vNP9o+ozt2f*&Ql-TJ!mvqMf;dx~Q-5swIJO3WQ?s%2h>6P?fhZiJb zr`G_Ns!r^5{x)c?jvr#D^Bx1mH%YsQo!*MLQ~w(R()Wn}B=}k4KMQ`7m?wou9|m|a zqy-;|UI5*luMxZW9IH+b$L$2@?%ENt^G^bH*N%vt&avv^gyXg@(21S@5a5!JrEbJd z=a?*2Jsh9M(Ek_l6FdJ}`c)@(I{R(pEz+OFPVWYG>z&x?=TO({EyPa07TEOzvC}zL zT|W>z{Z3$a4UO38PX;=%)1L!&w#pXgVe*y#pVS5IQ6=K;HV5<7i3u)Wbk@_2F=D4z1CP`j{SZ677MRCN ztME=totSNL*JjBg8Haw+k1?Z6ow=#J`I}?BbsX?CMGE;#>*r#sIO? z@1w5Q=!l*EMBpcO`gZE-CwBUK)b-jLvC}`K?yi*u`oB7cM`GQ%`V+hOyoTU(VyAPS zcVjr5^JhVKW0=_a_oV+8ydV)fo%@AS)x&+n5zyT>NbLN_0K09F*y+u{B{$*)iP-7u zflE~Ax8-NW@Nm2DnspVyBOUZ+Kd^_j2H=ys(ON z0R9)Memd}Qd0e@@@6pr(@eD?ssXGZi40u|h;I-5T3g)ymRdpV7rg-x?q(b~x=uLHq zGpY}!K3F`&PTx7uiJd-{`VjFGJAEo}YN+U(PbvbOQ9OhCF!2yOop=1K;Kef}VyDjo zt{5RYvC|h*A1OMq)0a`_&GnFooqja1t6L**#m?d(cAggMdXpkzr*8;!Vy7QZeYC_O zcKVsXuB>zE86zHI=lKHlv7!?@{d!=x?9KG-A|7Jrxs7^>=)_Kc7&uib`s4HjIHULn z)OQsRvD07Uvg1VGPEUX{ihn_UH}McV{m;N|*}u@UyLgD5=O5H{Sz@PiK1`K~e>8AK zfHR6qsE-#9vD2q<*>cgd^aMDgcqa7<@en(G376#u6iCbI32;X73hEQZL+teRTs9KD zot^+^6n9b2h=go70ftszfJtI;V_^YSD?E&QtF6iP-7W1D)9Ev#D#l zh@HL+*p+nvJz7s<=Q)^q4PKCloqj~16FdDF>MR_I*y*i-PVDq!sn5U*60y@y22RZs z{WQE)1URFZ_xP-sB_3j@Ul8cTPQQpcI{=B;=~qy%6`k1WS5coMI`VXk@BRa9ue@K0v=)_Kc12|PD`Y-WT5#WsC z-%y_~9%84z7wE)J|A2ZuUXX~L{uk;CL??FoKd3Jho!II8T&!Y|=)_Lv=VBF$MJIOp zIAGV7@$~E~9%AR2NL|Y!cKTH6S{AX>tEn%MIK)n00PM=zmmV#P*m?G&zEqYacKXUd zCwBUw)U|(zo!$`W#7=Lb&W#d@*y+bn*R~Kly_34Oh1lt50K2xFP0xN3lh}FAr@mZt zVyE-cl`D(b=~qzSU;M;Q|2nWM>znj&@<1YXp1Y}QKM*^;0KU|%m|T%~T$egfmgVth zYK7p@#0LrHxnYWv5K=kuO2HZ8Rf2g8o5Hyv6VCxtt3}_J_z=M>i4PUrKzx|sb#K#FffVf@o(Zm}BHxYLTZX@m# z%wvO8m*A6#^_uOO#K((%F>$xxYlwRU-$vXk_+H{Z!4DH}6wI&Aq)rgbkDpWgvI7!7 zHcM?5%uDB~69w}UM(T5d2jVStlHgIqx*o?9pDg+`;!^~3DtGIbo0A&@9A2rYbi{QtI&lH@(5KNsVcnC2!N+f=!pE_Ig-H7#kFhhKf z=)8|*>RiG55T7S_8S(jo40r~KM+vAMth0s&?i(X9p9l>Mhf5796>f`A7uIQ79hYFrbe~HKL zyt0O#2SuMl{E*O#GbSH;JDY{66tG!Mw+F#S0$0bKbwv^P=d5*h!~e57H=O>~sAbwTwzV!dpg(wF zx#-8yv)$v2>b&=tJFh>Ho;Sop?9Sg$rRPo2&nJFM@E3`HA^2M2Ukc{^M&0@Tt-uw( z5}nwc*Ylo~sb7o!9pbkIKSZoCpCPUg{YS*V5&To)34(tPT=83v-MRm7>3K(VgZovb z-W5EU_;-Sb16TasG?0w#}mINcq09O@HnITG@QK8K7JLeD#fKheRNq3+N1~rk{ITFGi2ow^2I9X8=DopEe-q66g1PGq z4**yEU36l1Jz*O?{}BC2VuKwN(lf*w{}p2H*pXf%*0SCu9w7RAz!hnaGpc_?PoC(- zxVV|h7d!^oT{9uhs6K(7J)}Og=(B<2^Lk)+?z}fWJBfc0vEE2~De*wj zR}=GO3+Zs;BEc=hg9Wz{^WX)kk9ery&BVh5pGmC!b1|{@$@Rp;#q%}d5rXd~=0OnB zgT%#xA1Brud_POf2U;Ngn0U0{?ZjgQ|Ats^u=_`1z4_rs#QGqbe-M|7zic4zu7b0~ zJh?>LhnNRqNc$1bl)gO>*qzH0yYuVS^z1JFM&dHTEyUWl#}khiy^pwD@R`IFf-fYV zAovPmp1dMmM;r;hjd*XV&$ozY3;r%K4;YaiBc3GqY2wL(Um)H?@GHbq1oOV$DV`7` z{e!qpVx|XiEQwC+&d~+}rz%AsL0lzx6tT8{TsvqZ`z z&Zxc@J=4WAk9daQ{fPO15~Kr(X9+%%c(&jM;tM5aCvmOlJ-`)nJkF?o5Sxlkmw3)4o-6n&;=KjmM9hP9q;C+<6MPSGo#5{hFO&F>5ib(_H1T}#JWpIN z_|L=(1n*GeTdEak$+}=yPMD))SFBN<~F;6Ctt{~n|@QuXF z1%H!xf5G1+K0xsIi4PR~BJm2rKPNs&@H@l@3;r|lO2KKI)??{AiGM8mJ;Ztpd_S=s(>_T2Q}Jvg{+Zy%i1nEENn$--eTG<% zW1k}~6aP!ZdhGfNak=QP5$o~ic49ql`~|TdH@;1*$A0e;>oMVb#CqKI0kIyBeMlTh z{J#?GaTE@g;$xCL;%VY3B-Z`uVB)<*A5L5+cxUUEal+>{q;Q-mL!y;-^G^o0uyEX*bT{TnR{gmP3l2gme`#I{+zz_N6KW^M3rP zg@TX3mv~bA;120fw7nelaM;}gnAa}K?+_1hq@Hf-h{Z%4X&>_00p;HmKXIgfyDB@|{H|j?{BAb-gDmaiktzuPEn5TqNR1J@-=AdvFp*>UoIz zSn(4_>fycQ%Xbl-I8qOr?VZ<8%J&wX zI8x7@)cGYEB;rUtPg1WJKXEi)@N?7`cpRzc73vE`Cyvy!o%$lti6iyAO?|QG#F2Xb zKz(1)i6ixVM16_q#F2VZ1<;p@P8_Lc5cOrE6G!S9L47~bi6ixlp}t&n;z&JZ)b|&i zI8x6f>ipsl5^Z?U3j?}~Fij^NCI&q|)4(f-BP8_M{1nP&0P8_M{^VIbLHN=s6&Zd5Z z_=zL+@ETG1k)jhv>ba8oQKAz^>bai!(V`Pa>bZ^jF`^Sk>bZ+LKfFRBj@0u2^)*&D z#F2U)rrszzaipH_Q(r4OaipFfQg0HSI8qOvn^xW|I&q|)pHOcRoj6j@o77uHCyvzf z4)t}S6G!UdbJxn(i%uM==VR(^q7z5z;qgNGv7!@4>fyci%a0SCI8x70>g}QvN9q|v zeS_%4k$QHg-XS`1q#o{v%R5CUj?}|zV&z?;6G!TqPW^b%i6iyQrQR(%aipF)>ip0Q zi8xZvVbo6$KXJ5Ca3l3i9!KhFqrO>m;z&KmQ$JC3;z&K4seev%;z&KGQ9ns^;z&K` zQ9oI9;z&JPsh=V`aikvJ)4%-lq7z5zxrzFzq7z5zxt02T(htOudU(CA{7mr^M_UB{ zfcjY;N9uW=`q`orN9y?r^>aigj@0ue^>alhj@0uG_47n0j@0u$_47q1j@0uP>KBMk z9H}Q=2>lD96G!SPqJE+1#F2V-rv63Ii6ixlqkfU-#F2V;BYeXlG)N=}TexVGBI8x8$)Nc?!adf@luTa0y<48SUrGAs>#F2WwN&RNg zi6iygOZ^tni6iwqME$Fx6G!TKg8HqZ6G!TKin=~9lQ>e(o7BG{e&XnM!S7JN!{bOj zA5j0M=){qFKBWGD^bc{Qp5X(b-y?qF=x)Jdso(2yq#j;JEx%86;z&J{sDE2@;z&J} z)bAIaI8x6n>faHaI8x7^)W0kBB#zW`F!k?=pE!C*@DbGi!{bOjP1LuEP8_M{IO-3J zP8_MHhx#L;6G!U#9Q8*5*6G!T~k~+Weh(sKz z=T7QRi=Q}pO7M56KjU$vo`Uov=bD|SR>Uo{| zLsC!TNIid|{v+`dM=uHHwdL}cJ&x3~(;({dJEc_3T6a=b{rw>RC*EyXeG`dJdrehUmnRdJdufrs%|xdieax^0!1M zj?~ji{THGWN9y4<>hfQTP8_Lc6ZKz-P8_M{6zabgoj6j@S=8Saoj6j@1=N2dI&q|) zOR4`>bmB-oS5tpSbmB-oH&B09bmB-oU!(pz(TOAV+(rHOq7z5z`408}5}i0w&m+{| z6P-9x&y&>uAUbiRp696lQFP)+Jug##Uv%O~J+D*$Ky>0rJ-?#<-=Y&o>Uo#?pF}5) z)bj!LKZ{NrspqfMKNOufQcqqH^p8X*j?^=l`p2RZN9x&``d>sRj?`01{jZ`EN9x&~ z`hUoFK^&=PHuaR~#F1Wis-r$YbmB-oOQ@$sCyvx}5cNFKi6iy!^M&$!(TOAVG*T}R zoj6iY8}*$;Cyvz9Nu3u6k%%MpoIrh`=){qF`1wUSzXXRw9I59_>P4axN9y?kbzXEt zB97E^G4*Yt6G!T~jrs`Di6gy6cNca32mpyVQqKd_i$y1n)bj{+UerV)j?}~Fp_Y#l zoj6j@3)K0;0wm%{J+Dw7BRX-Uo;RqE6`eRz&u^&jB06!Totz=){qF#!-J*bmB-oe12>B1ks73 z3c-6*pXhOii)H5^73B|34Wo-3$Vi%uM==Njr+(TOAV z+(^AfbmB-oU#C7@bmB-ocTt}qI&q{PK9{z9rs%|xdLE|EFPtI~N9y?j_1U5mN9uW= zdadZhk$QeYeU9kFk$U)Ptl@j?{Aq^<|(q}Boj6j@uc#j> zI&q|)|Dt}B=){qFKBRuM=){qFQbVC1BRX-Uo`KXGL?@2aGlKdW(TOAV>_WX!bmB-o z+|D5Q=k$T>xev;_Kk$OI$ezNGqk$V10{S?uOBlYAD zgZ_EZi6iw4rGBdD#F2VNQ$I~~;z&KaQ$JmF;z&Ii>Su^f9I2;@`WDfNBlXOtex~Te zk$UD)KTCAtNIgrapDj9Zq@ESj&k>zCQqN)3&lR0GQcnZ*^F$|()U%%Y`Jxj?>gl3> zf#}4MdQPDJ1<{Ek^_)!oLeYsM^_)fhi=q=p>ba2mMWPc&>bacy#iA2O>baKsC885Y z>bZsbR?&$g^?ZZ+rJ@r@>bZ~lWug;D>Un_rW1KTjuQ0j5fcO@?1p2?Up{8!)_ z1XCIQGpf%3cK%vo9Q!iO#eW6HB@=N*^%cO*zlwM`UXTvMe?_^47H3rNg5>*W7gmfqVE7%|;;*9E#0XzSb#Czfe z=^6Z2>|>$D8Pz|4lzKw?^F!h~@$mGrqQ~Qm>XTq~@uw2^iKiO4;xvylsxJ)uONh@9 z&vN>=dYn<6(_iZQctPS+mAXtkoK`BX^*EzChl}%HNqn7nuBQJsk29*@Lyz|7{ls4v z&x7={Baw(Rsy`R_Un2gNcwV9Z0gp4PzZ>}9BYsdkAJG4Ok29(d9^mUUocIUg*%`Rv zd5<%yPYV1~iC+{?HT^&FIHUT)z|XH>rhY1(<@Eo}2LEmqdLD* zoce+2V~LLw%&!7hT<&p3byL~1c>^9Ni1*%Zd0+2PFYdl?Dw`X78%^cfo*q-#-O}Dz zNww17;-AkK2r?2+7f9srj`a3H0pTKu73;j8JPPWOLi;O^j}!=^>caDzdfPU(^==Nc z;@kPRbS>)XZQIb;+t%3;8uaG%h}eIA?$ZH+LgUDI{vxX$23^`Szp05L9|Mq^!N(qPw%HC3gTV?OD*+-nN#jAY24u?lT2A@G5hjU!h7Dg0Jjt>_v%U zp|GN{yAf?}Pipo-6_wqc99A6YSw5-Qj;{DAHW=vkv6+o)*LJsT%*o{wKyn0m>X%yr z@l0h?=Y|a}9oQ5)I(u6x_dQ_sH2XA$oW&U$GS+AuqaI4nceeg_mSrXHPP2=%OAEp7Dba$yt@<=lHFU0?6`LggN%hkgPU8WB2OeZ0p zTW>fVjpO|YIE?qLPl)%NE>nkhrrU#fBfwdAjst$o5XRdEQsz1dd9J9b!@G-jS0dhfi1%0Ivwq|8@8Z3Xh*!8%|J&OS6Y<`?PVULa zcojjs|4PK0ig;s@?~<$EZxiwAuJ`So2(znS5f*?oULOk)?!- zquhg$@p$Uz;vJHR$KT4WVh3n)@eWGFdl2!SgT{E%@bBVvC*qZ3Qs#M?OD^7qM7#@b z!F-UGcvV3>{^W*>W7yerY>_d)>L(u04Z`*g{~Go)5LiF%OI`i0gAYxN_X{g9d57~A z^O*QkkfiSd$+EAE$Mk4FzQUk>&c~l`B;)nx<4TKkSIOKK8=DE0;e7bjvWr@fF6-lf+CeZ*n5u5}vO@W4yib@8a<%bzFvX z8PmlRjN$KEU1A>p`SZ5W_vBREOVXLt!+ic6jqffE;9w7u%i~Y99A-9s|G^!(CYQGc zzOY}GJcIkNmPtG6;dSlcPoUf~4Dr}p-Ybzv5`9eknN=9?q<2wg2<(@I_-Ec={GS0I z{<;8dDy%bRxnjP#viKgXcC)I^nCs9nOQ4^mWeo?$5Q?`UK=T21s(S_#uZzcH4=fg^ zXWldBvOsXYs_C`U%Yu}hU6Y+LqjvhtnPp{os&dx8A|H6xj2U>JGksRI^{*N9`9;eY zr&2Bw+wy+g9u~Z2k<>ws$tPidm@!9vdD`)&bT*oijs}`LwtVfZiV2VX{codAUS0IF z{N~i6t@&GidE^Z@Z_Cer>zbSXUJN#3@z#M`etFB8S0LiAPel(bn*R7r1E!pLTVCP( zGbRp1oGpKEy7X}~s&Vd@ooCyXrm%4SY)oEhd{NCyYlX^Wq$%P+X}v8Dz0naZ=C+jjcS--=sYgmN#an{wvOXv34g$X|5Mtz}>O5(NJg>Mu; zKFVBoWp4iBwB#3_=<+e2B5|y^lrl$nc(j8%x{h>NDRa1kJG$anJ7&cJcFg+!`cebT zMSJ`cZT^&=`Sb{%(lzlRXt16>r2{|3^=VZ=9*>o50-hA$f2QG|R-qB8i9?I?(?f@k zDIGc@wR#L@-5Dl5bZPOtUG^;6t7rhG(sU}d6no*k@n&f;zj~EF0fv2wiU11;i;DIE z+-Wqj(?husjxdT-MMVM!4zb}#YLPQ&7;MHARi;LyMi$hKy`p{>Stzp$%fwD1-wYTd z5{*ME>c<$2hYUg|I+ICEK2R0jeYIr^tKvyonOWrcR z7)%p*%d-cRg*#bmGnCYbovgKD_)eX4APv~1aOVNV+|${QKnCn=_j=}DW{t|Ty2Yal zEoK=5#tgRj`^001n?V$J+J+aV^!c{%e9V$a15&o|Hvm&3weVVBQ>+iVY~6}Ad%_?V zh}9`6br|1MqbSBbks7rP4GAc7homolRDE*Vgk7*MVuU!VER9hT4TW5Qe@NlV#pSRw38F_20YoU#pKu#PO{+S(z; zDqr}j+^ShR>=bSNSO<0(WJhpF`zS};3A%%+IoH%|O=&jIZhXyVCp&_`2b2!t$o?No zP3?^x>&iB^bobyxh_Y-=Wp!n?Y!aUFy{W9ev8SbMWoK*e360$?)AnDmx-45c9r^Xu z)w3s?s=l7?Y}MNChV^YVwX?GgJl6@dJ&j4QZPY1rxAgS2_cpY)wfDC4qf|D1cKMxs zyDI+TPjNi$^%mKltGJhc~QTdc>lJ zRfn%w)X)Hv)Kq--L!yqp4W z>PkEnT8doK(%9VAu`Ukn`0+iR-Myv{PljIC(b8PTBKms>a{T!0{ac#b8apJqvGrT9 zq04AA!bA;{oFAMewf!60I_&eco4d8zwtx7Ums4DITl+ei%>IiTP|{+;Hq&UniU9fH>sH+1}` z{uhVvXAjroTDm)0+N;{zdRsbs^sQlIP4(?p6NjEA-NZtiO7sa($^j-K9TgagJt$IfF7_+WQ^ zLuV`ByW2J)2M1s%uCKeL2}F))?Cv8yDwRKSP&$Pppj7^dbb)=ZNPphG=i`QB1O;gx zIi>PPsc*3A`N*+LA{T?(yT$mL)V*may6o+NGn5?XWI4$$W8MEo-nnVJ zWWO;rZ`YjCa6M1zcx&FjTc$2Ie?J7aABvmQe89Zn`Q00**R<7iRX1$lODkWR__7I~ zsc+iQn2q6D51RlJHN=n#lsxl?oNFrR{~(vUGrNt)TAFiCkkXiG;-h4%_s{JSdyqdN zjv@Z|yj|nP=kCh==WXI&m{^|IJ|#(hd|gJDZ*|$=VM^mui`@G6&;3%8KPV0&JU&~~ zcpQt8B;U7RxF0vdeSZk|{UO}{iqXO8`n|ziUdC@!Ph2ubHHN=kjD8V+fGO zHz{)ayMONcOY+O(Ai}E?d{%<{{t*A3L4FJY(q>qqKK*mQekI>;U&0s1L4yy3Z2S?4 z`2F+vtlLPwZ@=)JJ4@_qe;`}zs@^%L&v zC*0RhxUXNaeZD*E$T62n)GoaP_a$+ebYc&lw%_bvj-<3HbedG@o|W8!#uh8Kr?DzyEa7Yl`EHE=k8@}rS(erf^t?JqJLz{B~W58SWc5$5C^ zUTn?;_bJb81@UV!&pv0lJ~rf;>w&}m|3;igP+-1mU!7QB9tHH{v%owJ?#E|=c@ew} z|B?#KPaU-H1I=&nUJz>o4ZkPl;|(+)f%|v^d59f+zhIyl2woN}&#T&X0pA7Ory`R9 z_vIDY??;8>XEyTvd{$)Ufmg=?ip;*?e)}pi2ZH8?IhwF#mTMFa5uQ5x=VTRvB z3g@@ez{B~EKQr;;d6?lf;&41)1MbrZ^L21PenyzPbMlML!#VlIM!$NkA;uYgPkv4u zaGd#d&hlmEFW}z^^7S^Ls+1bul5>2#%s4X{oZnBBG|tq5*93fDaDG?J<@5V9rv|(g z+<$*&oaqBUJjmzwRN4Z5Dfotf-vr(paDIoqG2oAZ>reDhg>i}n)XRhNb_e%qh?xfN=Yt`J&(jzg_?LqF?SF_l z2;9$KL(Jje+{Pu1Gi~5{%UDR`%x3W4#QCGm+5ZoDZvtjTb*+Ebp$D3|=@tYUv^fW= zu?3{N866oK6-0tG66a>5qI4Wdzl%B&a^K`>}g!5|u99HJ%;sNfVeMAR5#5@(GX zV~nU*QNQ=CwN~wYiq;JG-v9Ufzi&U#=eORy_E@`i)v2me8}@oH|Epokr6lIiKG+QV z$6owhu>JXo>tdABH41HmCtx4y`TrjFpxAC7yq)D=9B@4h{`N&emmmj|_qf<@AGC#C zAKP8bG5XB$dV)d@j^BRB!JgL@=^3Wre-XZKa(xU7JPr*`*heR9zT=RA`&@{lhm{El951ZBIHZQ{Y{JjbPht)nhif+6o0F>BJq z8TeJqsG&pq)b`cSO8xAQ&tYRmRMz$}z)u_CSy?L{Rq>~!tg2;-p+oztJ|Oz!?StA$ z^;4(MWHt?Ft_T&SwA#Sg4z)WZkA8%nsaBJu+i`Ef}in)UKBWWzj@HTBFy zWhxTUth49MP2ic)2K8;$%(oL&sYuk6ThMn;RJ9^mxkPO$T}RBAH93)Yw4vi)?C3Vr zO_*q8RkGU2X0o2q*2R`)PF|fW*~GY*L`GFvk%`WTMqHdS(ex@-F^){um;GY(Nfa54 z`#2#TV}rdH8*E~1uzj(S+(=c)UQcv%v?saLiTz+SjK{oIaz`8_Ac=h{5k$0kWKFdu0D^doSzK)zVLW_ z3_D+#^*IbD{5%J+x{;&0scv;MANung!TibQZ_GN7OYy%GFG?Vk;=k36aV4sgP3L#v zP8Z@20@?JQ;1bozruP9CeThE^WYc-hQv4NFIe#&I4D4dPi$XS?*R%_NfIkRPo}W54 zpAL|QEfk$~9(Iv1%c{OuI2RwC&_4`hOIrXgQJri$uf-HKN#U&HoIaT>RSH|Nq<&zMXSrNI&yD(Hg3zDVf zGn$r`Y-#6GzZ8EE$fmREmX=vt{$%sHocd+>gFrU@da$M447U8q=5sUkmH2}|HvK+u zikTs7$N!ASWy(9K{}6u=$fo}eY-xEN($bR6=g-tv;SU1Y^pC)n_7kw>Pc|P;!I>-Y z2Z3xlU&CN&d41CIC!0?@>Q_cd1G4Eoz?PQR(d-=@Wb@%~dox!_TC(ZYV0$0OvGiFZ zK4g0z$0+J+MJJnHTUx$8$I_C` zhp)ZKte3Q8(|Ik<(r%`YwvlW;H&eex(vnTT&C|)I-$`BTNjCj4u$A>|&xdS2zoGsk zDT{3S3)DA=PB#4|>eq@+HvO;Q)ODi&ojx9yDes~FWAP!I-VE16EG-_-h|`kIr!Do3 zl9p_GM^7i4&SjJ`*NZ>d^zNQcHl5dfGdGAo+4Lj8sT)NfLLZOIl!sH_BtB%*Phwh5 z5(uZ!$Kx_(UTe+VBtB%*^C6|q6rFQ>>LEcQPQA< z%!wJ{K=S><<>Uv1dy}oQqNqicd5bZFgLzI_IC%L!wV6FBP6nepon~Lmm;{ zLVdaLt>6p~0tjR~j@(Y4ouc1QepL7&@?*kJk=c<5yU0%n|AG9Z@Sn-N>4oqv`6=NK z$WIG@PS#`7SK!PuqLXc|&c#?waYG@rA@33{CTo2TApchMG+FD@i~OwU6=bbX^xNj$ zq7SC7^*N6Goao;nKQDX+`AXqB@(aR0AnUw(3E1W-Vo+Joz$Dccqk6*v zBg`czQ-2X2L4H^Gc=CI~Tmmtr^Lh09*Y`!|Jsz7gxl~~0ucDJ}Zsc-*Delk+3(0>I zUPRV?Z53JP$*aJb55_^spp#xdRSZA^x6HCduy}FTgJN6*!aj+-(2K+(jga6i7eaYHa1IgO*_%Ur1c2aNQI8-0*3u$&R0y$Kl=cu<5ogAvqAE~z%ogAvqTh!Z# zP7c+FOA)4Li%t&J=WFWRfC%JJ`;9-WvUTRjw$5A|>O8ecq(rPjqsqK7Xa&UvzS)K6|JS5S<*V&zICW z86c2ty}CT?v*|&ilSB1sMg36G$)WnRqkfp^qGo1Pm(aE9u98Z0y=;Tm+PM|(lbaJRZQ>h;#Iyuz2 z?riGEicSvIXCCztqLXdiy9=m~6rCKZ&tmGwiB7h4?|2_R-5@$SRG%MHA0s;1)~nl0 z{RGj;wqD)M)aQv#4%O#D>f=QxhdNh3PW`*0lWm>3UDQt!oowsO{hs>CqLV}Qd5!uh zqLXc%x%a4_DmvNLnfn{{`J$6;ow>X`=o3UIhk6`oO?{&1nFP*!*XZ55ymY+4!I78DYd_sxN|M{>#X{#pg17WQI8|Q+*>O^WQ`s zEgVZ>#se+J3? z_ma;LA6|;hOmSRh`hWHw%&faJ-b)eV9{}$ADoeeO!JhCjPAd9 z(f*GG1fwv{{v;~_#y3fK9(3gL_&_uZ_KIw&^YF|2LJv1_}rMDMj*!Jw+ig%cR2E! z0FC+a^xf)rC)m%A??pZungwg`&mj2uZ9sn8p)o(6-dldV!G3;xPOcQ11m^W!y)QfL+|zxN>c`K|NvE7myX$Lmr4c&s&<1@*Aemya$wj-YTaZa)PCTV`$#~5;(2f(u&nEjH*f6I^e2(X!EGYvx@3_5>YS=RjYx+^#zej5vM zjs*Qv{AYeJqdCOe>_O*lcm^8nuweOdU-A7m4a0XVi$t8^A$|J{EcL=ad$(8rs{Z{Y z!9Rbu*NhLP4ss0X5%j}RXZtll;o^F{3u^5hxjTbZgIDKI`MSjm`KPX4ytwBb&F%^= zxv5#OdNH(z^G;0--+0aP`T-b8IX#*~&3ojIV_pbW-@SiOJfK5x`VXt%Kj`)7?Nd0t zq&<_($nig2M9UeEU_+p3MbUqtD)6h-1x)ZOaGjxohL<+~;2$uoLg` z%AYrD?BZ~V#jh@J7eIeN^k=-7FHfx6yg8`avlZ6^Go{Uf%^O*2US6j3=Agwf?Q;0u zEX!rUP3zYe=ijvc?wc~(S1(z+-gNt{>AuXdE)6F}+Ub=bF*Q+Mf%-dWzY|mX|hRu6)%S}#*`V%#4)^EJ!jhhGNV3hA}*Z2B^-?(>RUh`LTYnBh{`ufzZpLgA2zPp=k zE}i!vOWK_~vTIGd6&qJq@AT=l6>9pRXLyuM_&L`^>S4KC55ZCE90l z4nlu5Z&u*31;vjfX&wOqAoaq-g6g6zwV0pML=54REZLg~4JEPeG+o?2n@7*{O_Il=`kxOsJoPce$ z8@>0<+p31!s{29Fw#wbhp52Y@W#zVex~AQr>u;HkZPmRwwpF+553aj+;9_j6-MI&K zef{mNpKp%0RZX<5SSm}Kz9sIl{FVhd2j%YlpX{;jTbg3*)U;c?vDFhS=aO!D!J6&= zY`b23Rcd$zwrbyIvQ?$mtM^X6dS|e2pC5Z|`or*pk?)VjKC-wT+YS2#=695vH{!2P zb6YmOS+?m?e5OXazCNhyzWc=^*e`1Ku&?oEM(hEbHr`UVc_3SGaP+x;E0~Z zx+v4_&aX1*+^;YOzgnGF{gsWOt&3B`uYYLq^y0DVd?$uu{?Vhb( z^hELEX1&5SmIq6S-hsJ#XHXiy0h4cr+`7no@}3Ce{hn{6{P|zmnw&5%==x-`T}{^Z zi^k_AWqHBMUpK2qn;!|+@VJhn_>vvmOV{4CX4R0ZhISZ|OndRwso~jgrF^$AgIARl zFWwRSeE843cT;|Zw^tr}UHapNg&m*Xwy0&-i=M7r9+lCHGi(md6fS7rVt9VtMI%^7 zCY=|IUYu^|aow^BPfb`=mpU5f6zi&*-W4njmwsKd=cZuUD@()2zTUm(7r|4n>^HgQ zlShM9Z(Q;djFkL|O<$k+$=;PuE}O7>&;GmcF3%3jUTLu`KUKV>I{31E4txqG?Vcww zU$#FrebXy@K4Hpxf728_yR`cVyzg^4?&b7evou`%^|}d5%XWUFl^5YW4Ql3GVkq^%F_1+!#??RLRq&bWY5T-nD_duUwpoMPrF?Q zZDiiN^DuX#J~sC2A7a{^&CPp3Q}qy>@DN z%*Ne&b_QSWf9egtc;&C3uFh{C;4P|eJldqbiv;?#7qtoSRw&cysMu?A3dD zWZ_vrrYHWF1C*vr2t&foFH%J@C4 zlUwHP*R=bNFRTyBmv6gtz~=SqSGU}}e!ym&RpqW(KXUPuB{#)qqL&UDjxmzE*HU19 zTaguC!T4$yzoPf0S@DDVG5r@==bAS?aa3{3wd%g?+SWeXE_eOHt29SXTL{rwsC1O zzBd&2F9}XqdHkC>!&?L=KD79(;>DNts%m*lkkh>-w&9+yTZ{|qI2teMi8H)KsP)p8 zxsS(t54P6wWz#HoobRl7+*znC+v*=TMlN{<=Ql4by?6ujZ}-IN#h0#oY0cwxOE)jZ zOt!h8?AFa+Et|G<^G>n0ZT{-K(os&6=_zJ4b2a(PUjTRLMRey`QL`M!nDo?ROKtf#bo&YW3udX`SD zoj-f_5#6WsoT$)98rBc_^Cfqs=iudBr47^SOXp(2n9}GKZikj4dGxQ5v`m;)Al~=J z;?ABv6CaHvKw(iw{70olDH|!Sk#f$SI5oRsCq?ZjJy||Zkq^{XVfsu$BNhu;9KQ zSaLtBtcY(ZK0mn5E-yyepa&{leygfHj`eR#ldNnbzCFA=WBxY3#`EO$5ecaCL5;EG z*|=XaPk+mU8*TSD`6ToD9~vp&veo=8oeJu$@g64YbD6j%z$mTw2qR*xd1^mpmKyOXisv8jZI5U-3!i>kXx3 zl)vS?*}}tQibgsq-dK(L;@YFvN#EF^XqZ30$G1kmNl%vLHS$~52H3au3+lYu#ib^5 zZzSCWFI`;oWV(N?R#{&0QNdI9&DJ|W=z};sRy2nDrajGS?(LtABRlS|kGFDa{;?!g= z-sbvOJJZ{UF($M1yX4=A^Qx0fmI~t1JlxmI8;MhFvnRcBgC*X!PR9C`$662ne02(c z-HBYcGzD%5as7yVTeYI8TdJZU7g6#06g{v$MQ7Z;$I29V%%G9w9~xhmg6l!79@>Gw zMQfeCszjR>(K;H1ZiR}rjpWKjC5rZ4f1+5{uGlY`BG1;xXcw=Kk;nG6kIRnC{cU}W z4vl2MB0FZSW6?=g<0uKy^v>~08&OVOxC{tZ?TCy6!e~W}1F@_}o-FH8n!T(?SI@-v z`?OpCBbZhocXaVLx)GbWxvirlx*t3UMw4!Q{27-xb91USF10Dz)0*Z+PTa+tbkB>N zB3;+7h!U4+;)2L^IbB1QTITV&k^Bw#!xy?Dvu(5|7-XeLW&2C;H2`|Kcq_(ck=_d5*LfIbRy(l9!9SXA)#Zg(e5FEpdM|IjAY> z(<(KAKCMzRl_ir5$xbrl10-=dB+Y*ywl%Y3Xfli)5Isr5PhC8s$++ws$7Sc3G_!LY z-)N3gvvZtECs)VF)K>0OnYr0X=YE#eytz#ckdKuxv`S5qk7<#a+!E`utGX_`s_U|=dR=x^ug$K^hHUdk+2%EkRP}nP>Z-V^ zQ5{>QPHwcS_hnc0K33Ir)b{M+9?Ui$Xr%NW7mKDy8c62x;`~So2Vm@Rsg)J=EtC~#rqgML65FO`F5D9Bo6w4= z=UvF1wwO-Hr(8XIr?TtaJ4)I}X??!2v_q{l zZla)L3tTIXf^_k9i7q}E(NSjyo%#Svl9fBktK3nEPChDi0y?>K&J}VsqREh`(_r5g zU7ct$G`kbKuo_K9%G_GW=hhhtufidVp;ao{jogbWwR^^UH5i|oh!WjqIwLg&b|c+W zXPqE>NvD?Bx(BqypPbJ4!;n*T;K0r~hm?|!WkjE#Ys?kXnmMC#S5c5tW663QIIUSu zd6aAplN~I{I4W{_PQX3B3!z2_y1F1|xuxon?vRs?55{2_6M}ZpPbJ4!;o{- zfyZ{vIjod?G$Rg|Iz{z6Lh2NC*pY=n&W-d!$Qg9Nc>3-XGsx}KiJ5j{LI1xA|MBWA z|BFks#P?pJ1&7?NnBM;<*A|*Mr>0?I!}Q6+u#8XEnm+Sv-Jq$pyfi+Hm)wt@F>$Ic z8{}QC#|lBw1^Hv(_AN^k#ko(OHgQg%w~$7R9zSH%h-x!yP98n1w&uiP!?J{h|V#P|{8POd$1^l_uV^WD)-s2Mk8+=yY${_c=b$2n`{caCw!&=JQCch;~WW3!A} z&B=Nw6U?%^ZSC2u6WVp{5Rc*}dC>cJY)vmCt)8xrDxCuxfBt#d_h!V3IgySbJ zh|)!j)uUJ@ZyK^H@Mp^-f9mERGyG9KlMSIV_c3Fz9p}|+b%do4*!-l&Q@EuT%&4CkoT&>|$v#^j44K?8eg5=@XbaW{)8}%d z*UXz7{O4;`{g4kPM6cof_t&cWcNReUZ>}HppReo`&$<76L8t$qklwuy!9QIK>wl#L zS)i_d=KSe%X3adier5v}s+&A(>dfiq)&KMI{+%uKjZ0K{i%zBR=z7*e1UPcx>j*XM z_Vsh7Oq^UV>rqYAk?LyO*lJX`T#*-joyj>UmDgTZFRIGdHHWZV60aAe@?r&R4i!d9 zr<{i9vzhwZI!Zk>kHajFcvUFPbBKPnl21$5UQ3GCekzrC6oU7{yJ|j!+O)Ujjhe{< zNLJK-mYG{TDPI?UD$#0{nlFB*9@XC#tIBI@Fbv&yEY@o%UJ0)g+{cM%f)T>Qi$9ydV-7NL)mY;KORBA`v;BicOe$M$(OlR}O z^|MH5m!HFnTB*E)EC!=4DpzgwiWz|3@2HC(elbuyPIxx8~J(I zzoM<0XlJx^U|zYF6EBR2sz=*0?^~3f`8gNv({sAjvP$VDV<7LF`hy!q=67_R^aR$e zh&E1J{X|((pLqL)8q@86ECsqs%4n;7m?yT@$!erq*KZ-Jnl&$P!&tOs6Z1M~u68_+ zTYzmB^&dQ<87!|*Kl5~LO-tEX>tlAI9*=aX$gEoCVWdkdQj$xuZV#ev`^+R!`8r~3 zK}b73#v{E4T-n;TvTehD>T!gA;>|cwiZS|G ztDi;Iws@xPt}zg#FT2=W>~Ej!E%;6I+Y9KK<~D=aESiU@gtwtE^;xaa!!l#WTM{ED z^2sg-gITt#?SooZtZ*q?C_Wba3yRGtmRI6jkH72WEnlp`$Tcuqm%`?MKX_|kUX`zF zMRxNYz}0S@%&YR(G~H70zvP#!?--QbCsCJC*>zc4aCNhF&9}6;x#jJx?r42yo2X{V zG$X$)jke`qO0&MjmX-~Y7Z3+|d$(?tH?7MILx0@5ez zoY+p%H|twm)AC2HwzSrEeq)_AK3UFel+#n|Y9C%ZIUf9S8f`c0*~1d+=QrdLrT@Qa zt`S8&D40e|4F>-f3fv7OGqX5$VB?F3A-*~Pf6G_ z6E?TG1j&DanOfe$guN(XuT9w3BmRW^$#6q`U4_vL3Am#N;*nJcB;R$_P9*U? z5_X@2JuqQcC+uSr_NavI#+Q`m#+TUR6aMjoirOBxKZ^f?g#UR7+l?>rzc>-UBw?>e z*ls?O^lp5K?Z%VXcP7%`m$0`d?Dp~Ylk}YucISlMEn$ZVdsM<6ld$qPy;@x~D@oqec?Z%VXrzO%)NZ4*X ziT|`jyqoVO-iG-E3A;RDS0?Pf3EOQi$aMDPg?afUGYR|Ig#A*&el20Yo3KAf*dHeBj}rDL37gM!N|639 zNZ2hCwmTk)zdJt>`+$VMJ6=h=J3kSdYi9W6yYpX(ckdY#+no=K?aqhAu1@54Y{DL$ zu*WCt(-QWCgneJa{xD&Gm9SgJ6PnbI>xEl;jrf^^Hx(B7!Z+CN_#^)5IE~ol3A=Z~ zu1wf&K9ux_CgRo3P#fCh6VrR%|yO#lAg}{?3GbU&7v=upds?J3QOYD4Re_ z$+PouYz}PpCFA%MJLAjnd6;Unxi51`f+!h>Hp^u^>zc}udpET2g3ZtY|5H(_$c+B%yB2)LMS^mox8*u1Cwi-^ zZ})IUb!=W2I6$_-wC?e^E);7_pY@LxiH@D{+$_xS2{#Z;1U{1p{Ea`Mgyy81_gn zp671&cs8$Ho$1*p!S=7GPK0g0tiz9jf-_-XiT@H>1#`h$J^Orcu0^B1iy0r=ZGx4s zH+c3M*ls>+6I=_s+Kb-|+a2H91V4rC`nOGR7i|A}+yk)P`DvTrG1%^Wv`w@I+YD$D z+62D`7nq6qz6QIcXTJyA9Z%Z^|A4(Bj&B=$0o(0gZG#+)HO_Ss+6FCPpJpbm_i-(@ z{gB4uOJKYHFAg%W7g#i|HysT7$k=WdRKY&avk%MiZx;-M-7Svq7>t6=xmZHS;6&K2 ze>(?N?>csJ!IgZQ*({~h);&*qwK zZu^x4xtRM$d+~Tm*K2=C!1bjD#_?UEb*0?)?h+h?_*>)pbqTnZ+b=yEPs;=k$LS9Y zj)uL;v%dq|%|8bQC&6|hH<$w3^-peaHf(?XYJfdHPLLa%pOrp8SOL2*j?WLc){`6W z`2p8;dd7?AdQQ7Mdn@b?o_#y)8$A1$u-*QiA3O}(g@RxgY*&6k@FHwienIdGY?og_ z@DA)vaRvp!hp=7w1;J;q=X>#-d@l6t0@yBKeueFhF_>RrH;)~f2O(^?eVYfpVGs7= z`@?pjRZtCkWGu7_M!~+#v&X@{$Fom^UFq3%u-*RDDwqM=pMM)*yYJtvg7aaQdg&Lz zcKy{VxD2*G|6c`rY&`y21=qrM^G&OO>mK>@`!?9_c+@KR1?&x8c@Mx|=Gl+Jp5WQf zz;@feRqz6A7up1Gz^;ykHo;%B{M!Vd!1j*^U&D6i7j1$9{5*Asm%c4*H$SuqI>Gkm z{|s#Z_<$EnW*rZ>9?=0_en-M~?QIhr1N#jxehln7&psLU<(@qWw%dQ(1ZTm%*o$v~ zeTrva0DF^XFM;hs+kijEb@NNx;9A&j{I(5lg1sP4&^GuPY*${};2zj3y!eM;`^U2< zVUP9V@!r|2Yc;+3tT^ZgyS?XsBy4wlD-Mo|U<_;*+68C8c2c`wDva}Ehjzhi7YVgv z@B`T8aeT*M8EjWx$KVRsZh!9>TmyTr=YJz?|9E&S?B-tlU9h`(_5-lp@uOq#7;OLe zxeK;`e*H(-Za(c8yan5xk97?G2HPDkItHJ?UgVXR!cT>(J-a#V8J=AX+nsN84ETF( z|9qi4>`y%Z-msta>;bUd@uXug81}PX{0P`ClmsWicI_z%Cc<77JCp=x!gk}YB$x}^ zov)Mx=fif}za&@;+dm(;9JV_?lmu79PJ8)pgzfsHB)A#23tfVHV2_K1F2O^v`+GKj zuRYMScf&r^v-$gR7Y+>GgWWn74h%kqy~DHl!|_tj&M(M5f50*Z-u!c5&;hpVuLFaw zuw5t*`oQLQbP46bQCac5f*ROAvuKR`Nw8`KpG1)FQ-NGK0} z4Er$8-Uj{*`u1?($4n?F+7=-DN(f9}}_!@k6` z4}Lu-*A=d2lIgcRpJl{0KJJK)3qe0-NhAoBb=; zTzlEhshh_$u;0V}vdHEj?d#D$G3hev6_%mUj>BXM|+nocJ2TNhQ@tFy(g8ihI zeiQ6Xar%PbHrQu-_1g~no;W@eJPrFf&wdHEn}0LG+pyjB4D=UlH-Err5d;@_`4_?- z8E@ZA&;|B0Uj2H(p5nzH2K#w0{y5lI#`S3))WE(y_HPx`!oJKaZx-xp;`mH(0qmE( z{8qx=?#2HIHoqfE$OJdTe%;-Xro1hwYVcZ{W zg5zPk@!K{y8TL=T{+JHC4UXv&GQl~pPxI`>u!qLwl?Q8J^Bl(fZ-mV?T_uzUcfh{W zi+>3A7>h>ze+wH++i1uHe}?T}&v*y+{a*b(gZ;7RpO1rGr}!9{3HF2SwpV%34fa?s zz7jUSBS|O^hQbcb#PyNmU=Q}}aj?(y?9*ZU=XcX#yYXKhoC|w}SKd zp=W;u`!=t>E%Dy2*>qgXi(p?D?|2HU9ua|y1YXkPSwmZM*5?lu0oX&$ z9rt4&gYCXAbP0CBe%b^{)w002-v&^CZRky8TO5yJstLH&psFSK+j$d`-h&r9`-`dz8Usl&%PJ- z1kZi~_9V~#J?uKq{tIkgQ?vU07wnTfyBWT0kM!)0u+R1EgJAO-oTVQG`$n(-N5KBR zXP*rFhn_th_8QMV7xrS$UJmipTZ&n_>5f?KZ*fu-*5cHo>o8 zkB{TgSTE#6cio(j6CC0UP!8_e?Lc~lE%;x=^Ha5{VJHRfsJ$zS&ksIL#OL8Xofhcd zDq*)v*asx+gA;a@+MAG95w7G9Q=8{_Mfj#YHsODY+B_#K;{A+7Jl9{e!1`UBuve?i zbCe=HFTF`^9;1tJeg96i7b0yDj!%!N&0|mzju+3X-6OL158hTAX4HQls?G2CMY#U( zmD-%siZH*l+K-+RSikmabB-y(d~mSZI}lfd`|JJGMl@=d4u-?#aN>X3HLy9|nq3PU zr!>)j#_#(Yklv&Elm@*=^`6@>M?ZR37*rZm8T2*iXVBkZfWbh6K?W6lVv6&wh%>K< zbFYZAuZZ)nU;(wq*JD|dx?^U{nly37TnIyl_NiqC{A6-|(sAg}3e_uWnFVdpD^;&l zy;Ak6S{6EVXjPQYurVY0*0Q!khxS#6zM7zKZ3QdO2r0R5Et^bRY5)gI88wM9QHvsA zEs%RZ&Ap%I-cNJyrM%&_&|m!qYCeOkrF}HP0F9{VqcG4)(s~Zi5(a4N2eJfLKP|5! z+R$ixMWvNcsYO@x(HttG?xauL-+i@^ioRBjzLsGhOCAl!D3v)!134;7>sk>FUMkT* zjXh&rCo-;(yX0tZ;7`dO51>x%wX@&4u$Z4%c(){Fs!NUon* z7mK=?Dh65~4btIUVf|iVo33JD_Q;4+C{#u}k1IIZ1<;;K>%dCeG?muLl{R!Mtv!|2 zftA*!l{SPb2gG{=THtcmj;!pjU0WITI19GTTv=&VtkV9gtkQ0)>}!g3ZDn7}$M&Df z#13RbtupFT7G$Ho(uQ~CAnoBw+hHoLV=D*gR;?VMonIOCu-9=~rK&z!ld3+tQL1dO zsp>-?FNx+^WkbBGuV!9lEv>SFR%L^}DjM|D@m9iGoDEE$IhCb&COdY<^qKXw4HGBL zsE5zQISmOH)}pR{(!8m)bNJfCxvYklL&D?;^; z-M14piS}SWK2f#knCr(UDi=-Uete>O(NW5akB(Koov2@Q81&;4eG}~rw(};p0eea| z!i-sy6Ony&@31i&HQX{vR)UR)GfG58vr`<&?e0~#KTC}x6MfyEImMBQhDCFo)hCf_ zbQFveatp-pJQtf7o6-F4ViO~?KilPE6MIoKg}PX`!DaW&+Kkb3?zey?VYah_(ID2^ z`XW)sXr6WDWYsC!7vi|&$d67mTx?H()O&aS4j(P zt%yzo3DK#VwKmb`RoUfcjmKyZd%YO-UR;Z4Ncyp^R@j%l5hZnW(=B4{pjHtz%*!O2 z@m&#FiK41{zR@Af`6fG*1B9&~$dM5NJC%^N_37qi8ugXSG)}@{fV7o%6sxoYTxGPk zM70shf-CSY#(h6M=PNayE*-Lbx>CLe8=t z9+)+(qq8CBq$8s;8V6ptN9TBPv5Bfi-%MN{?77(Lm*^=wU#jY(}Jtfu%~W>-<}#W$r=3+hb>74|b-~>4&1sl|GMqkT;`AAszn5~v-2e7V#p8FO^F`C&_;&Gq zUX=a~uNhCiSAJ@(|1SD(dcS=1T;ySg%f<9cT!XB_e+FLfK3sLO>0`m27VyfZJi}%> zuWy&APB#4%aHsRcpKLm>kC&)UHvLSnl}k2#5xCR$B_Fcs%fKb7lTE*j{(LYVfo%FJ zaEa<<(|O6Z`X}Pg>%`StgvWq;-Yk5v$Gi?)e5CXn+4AW_{V37NrjMkqH%-W<&!?{W zkWIgwI^L(uKsJ3XxOk}OWYce;uKAEn|0VTd;!igHG;mLSXl)X>*Dcb!$fghU{K=+| zr_Kk+5y+;`0NZ{hpSFDoqf_tAExp9rzi9h)yd|6sHc-npARnLgZKz! z(>Yd)M~F@~eFt?N&t%hIqptl=HvMC;^*`D4&%oCIWYhV4sO3*KozH>Tb|IV2=Phiz zkWJ_B=sNuXe-Ox~cLtZJPBy(S*y>3(eIVHCNj9C&Ra-sDrk~{LWYhVal=+iQpAEKl zkxg#^Tf4}nFQEU0_=7+;ol|Ft>SWWe1l#x_o6aewSa0T%P4ACSXihzF$-=$u#F$G>5qeLJdjO)(bLJMzvby<(?0~;_#vDAG1$fr+4Rrozfk&zY&y45iRxt2 zi{NVQC7a$EZ0#kRUJADMl1(oMTYJf-_Xk`3$)+C)w)&GzKa&0z;SU1Y^r7Gq)ybxh z2irIyn?3_<LTRUb*8NAU;Y415gZ5BCrb!2eEa_%5y+;O zgG*E=o6cjpjd`-^>%g|H$)kd6(^(%I17y>CgKZ3uO|PW?BB>kM^#1f$ooxD%V5<+=^r2v@583o7V5<+= zboQ;)hiv*x`s+jaWYg!+Uv;wSt-(E?mHKl$^wbCTdyt+31WYc+mX#Ql=L(iXVdS9^3&t%hio?J9m`jc$>(O?_TWYb52Z9J1r=lQeM$3K^z z=ILbfU*PFv(=P|xyhk?uO0dm)WYgEue;NKDkWIe^T%tPJ^jpDp4nsEmmtZ@GA)DR@ z`BuLN0fEQ*UhfMZ39kOD@HlXx@)A$K$>T>o{=nnb$injJ?eS=^<#{J~*a!H7@bAt` ztg~%LvbF0_ux&@O>1>zncVyF#1>5!|n?Byt$)mtv zoi92;Ae&wc&hVg$KsKH4kjm^4ooqVKb5fs(-kUximnpOUnNP)sZ2Hk&+L2ybviXdr z{+XmDo6hZJI@$D7sQ;JvlTDuqwtCK?kJgQBKJ%$-S!B~M@N}~27g7IQ$|9S771+vJ zM;~oF*?cxo|3cD|P2WVF2YCdt>07{=FGVMtejhmXmFU~)<8hht4(eZv583n=!It)A zFD==8UZEbnX$!yE@$`2*ooxQ^Q%~V!1c7XNfa0yJT(H%XY(53lwJfsfZ9JW9dNFmL z=pm3z=dr`eDyNUOooqgwuQEB3mTY=|>batmO+S=+p6F!LIoGA~MITEakIR(DQ*SCh zWYf>|($4hKlFerh^#VytHvK$LC!2mD^=9HvHhqbwlTBYiohOnAWYez$r}$zcgd6DN zahdW>)b)qZWYc-eB-2XLl1=9=flO=B$)@iBTUn3ONAo9}&r{UfNLsS#{90%_*>s+= zX9~riZ2F(5w-udiI!~!HMWT~U=agr42pxbh7DXV5{4~^wGMJ&F2v6x{b)D51_t3{veP|=ewq?Ze-J|sp~c+ zn|>^H-KJ#I$57X{kWC*)UHh4A`stodHhm&>ez`#)o8ADnw)5R@)^@V_@I6-6cCzWq zJe_R%Wz_YD{AAOw@^rH4>!|CCI>@GP^mMZ6o2Y9al1;zW)5)gaMqT@sZ2EoFwQtF$ zZ>Qb?e-Ox~KL@tHdXYXlPRQo-GWC}DgFrU@9Zx5l{yudbKV;KCrmlTRHvKc|+IF(( z_`zAMlTFX1u5BlqUg+s$)AysUeL^<92iV%qcPLof$>!6Cy0)EcIv+cAe+w1k=Ayy=~$O9*2$*xw~5wvvg!Oyqv>SRr%~6olTAM#Y;9jipUzS@ zviU5cuG^7p`emL@HhmR!9rI+<*LgbG^bOSalXA(XZ}N1q>079G5r4Ajw^7$Nl1;yp zdI#|*oBlXBb%5wk(Z}O5t{p!OHrGKAJz-d_JL` zmb7Hkzw~sn>8V`!>q{WWrt@8AnQoE~+4PpwyNgaXy_k9^I@$F7sq+AWKsKH4L9n*) zy=a*p;zKr{O6uBgWYZ7zbh7D3Qa?!YA)7v&y7nj8^byqgLRSQ`>3px6)olWOv~Fbc z;d=zEZe-K>&b15=j0j}Y`MY|n8`<;))O8GyP3ODWtj=W97kN6_^kvj_JCaRb<>_S8 z`7SrxzGTyX>^fFH;n|?5L9dBgQtEg)ql1(2#UB?^Q^rJkTZ2BN-xyrcVW1+xZ?lYdhI|W>MF+lTH7=r;|*EZ9CcY z)t*i^{c7skcCzU=QrEVVP5%jXZ9CcYUxBUd57LJx$OvTfd4#&Qg>3q-J)La&Z>Z~- zC!78|PbZuH2kJUEl1+cz)5)g4O}&rQlWh9msB52)P5%dV?Gv);UwAs%^slLFUy)5O z&PQMAORe??XFM)bE}>p2bt9YJ+e=$XAHLugfowkgscTxY>3sK}>15M~QtvDIkWC*! zy`Si0(~qa#Uv#qR6TsH4I{Ikc$mTPRy4HRJ}r^n1Wo)_wFDDD@$m&vxqiA{w&kk9#`V^rxt6ACgUf&eO@J zzexR1DVJ>eE7bYr5`k>`8`KXMooxDN;M5VK@1>8&Wy%5Ghm$!{e8{FZ^>ni7EvO$Q z{$$e+09#pU`e>eH^9iXBmb7HkD?OcTdVlIe#Gh>Xk)BRAeJJ&z;!iexJlN`X3Vnu& z57~Uqpk6IH*>t{B(R8xuGpP?3f3oTGJ)La&dDOLTWYhW1#njP~&z1D?xJ-F1^<%_` zZ2GmHPB#5|>c@&d+4MWXsS%>{U5y!!%are2HFqZhxVV)`x69f2IB%NlP}J?}ap-Z2D)^c@YJHZ2H&KwJl`Ra|)oJ zApT_2n^PYvI@$Er)N4d1o8A>{ZRt)QZ423a4x&Cz(vnT*J19*jo8FhYwuNl^VbrxP zWYhWX%FKz9KiTx7scT!vrjMkqZ6TX}I@sDWkv`fMvia0gA1`H*O`kzs>qa(xHudj{ zKiTw4z*g2$`e^@<&F50;+7D#Y*HG88$fmESuH%zz`i<0ee3DK733VNxWYhUBPOIBP z^wF}&=ChOfNzyK|=}&t)+4SF1KUw_AroREUvflB0$ma7t^;0A*+4PS+ooxDN)V0sa zrnkiVx~!~1aOPCWlWacwQP(~so8H;e$)=Z5KTYx>n_dOBvIfxSbnzjZ&tcTh5S?uL za8D)cluBVetKb5*}ce3f{f>RSDp9|>YahdW()F+A$+4NXXEu zZ2D^IlSL<+el_(v(aEN71zX*=(MRh;HlN$6*GpQm>Gx8fB0Aah`>9VAooxCpu$A>3 zeYCw~^Ldf_G)YS~{e7^d{g6J>#fNM@A5+(Ql1(pYjN6xQ+4M^4XNyiYy+8GtqLWP@0Zz>lo$q_icwDA@0`=MALpJ>+PbZsx z8ujmqKiTwIU@L1beddS{*?jm8+00zg$)>LaTiPq=(;z-%^I1cEp6F!LajF=kR^o;X z0`GCB=8I1e`5fW)#}|k-sm@d-W;aC_~^g2C4H!A5OkNcog|U;giVf zAFV(11JUcKFBImp1m?qal~Napeu<~AC0{K1wd6~LZzV4hzMZ^S_#W~S;Rne}g`XiW z6Ml}oT=*sO3gK7CmkPf{zD$_+b5kpYKO$c){1y3!!g=VL)GFbYWPRR%&%9->5S?t# z545Mxm7;eguNLl3zDl@~yheBsd9CnKYzD;-l z`RBqz$+rvhYlGE+r?aU$MCa*X>Q3PaQ}-Xrq<`|`qX`*b91Kd7v^S2Js`~DQx6K$HML#%5i&ao;R!N33E^pcWFB&C z*I0Jb=V8(RL}msEuaUKX{z~2<`rpaAE%uUkiXPxTLh4cB7Uai-+mIg@?nGv#5Dp+e zDa^HPQok1NMSe_mp~Gblz`Dy&%l@m8O0td<*$S;a`w{FU)mq ztX(_FFNw}~m#6+9%=d&_yIv;0Ec$EYBZS`q+qDIS zQ-2n{Ir$agcH~!uJCZpl5PFbb7p@?`A*lpi7@XAq&^kS z!S&D7XTojB|0P^Z{#^J#@)yDxGIvCTL&#qWSCPLGK8k#t@G!7_Zz7keek^^y7N1dM z-H*5qP3mOPPX}kXqa%>ZROi|>sg&qb$W4UjlGXnluzjx~m#Ka}eR9NqAz91)Avss{ zHDpe@2O`MlmZS@LN~ZY4UeSKGOL zbiKN@=+X7+GsXXK`f#E}s3sQ*A4}G;H;&v^^pnU%!o0R@<81+1`)U!nSbUa&Gy6F% zQ+*|U+KGN0`7Ei=Psr^>-$vH7canLKM7Rf>;i6~CcK*zDYEm6Uf0W!&_(`(1%zcnvnigB3z=vX*ri z`9RT+CzlGJOztXNPfiP8Le2K_)u~m;p4~^!l#leg_%B8EZYv#6~>z|T!K`U z_(b1#`U)3P-(P(8Bkw2Nf!t2GGg;47dXRathR~Co7VbmtCwcZI_ZJ>WK3IGXCm$p{ znA}ykn%qrz47o~p9C?7`6Ma`2B>HL8`wLGXA0}K!)?;q;y-B}cG*G`nd=`-Pd%^kS zt3_W(*7Ng4=xzlyBqwCl(Rh`xdRknl!wh43b_p2KV*>$$#=e>S&w}?$TgDoak9?IPmy&_-bL1V={d5_S1*!v z-+!5``~D@!E`{;Rz@eP#B77^kw{YiN@Dak($RmUoasE78cq8}aD}-lq{NEz{5&3@M zaRp#j7GV|ndEw4jn?mrA<-h*LSM;+H!!|(nlbN>cgoyy`SjhP<=RErrU{54%LT; z{4_6wAdo}#;bAh(hy4-Aq5AL;lI|cnIaD7`<>`*1lSB34bevu-+m0Nn55H5S`9lW; za;W2NF!cjPCx_~D4E0jc$)Wo2yGFXJ=;Tm+PNtp~ogAvqBQ_mB zl0)_3_m{N3&Yv9WKKn5BK9UbPRG%lPSBOpy)#q92m7cj6`>9taSa;QG@sgD$YayUZxLh8pk4%KG~^--deL-kon{dm#Iq57<) zK3a5gs6IcY{vFZDq55p0K1OtMs6Mw*KS6YIs6O{nA1gXJRG){b*N9FI)#pj-<3uNi z>hmo16GbP7>hpW*<3%Tj>hl`)?}|ikg=0y$Kl zJRJMdr;1Jv)u%P}(?lnS>a#!f(?utT>cj7n=`%zphw9UVdadZ>P<<+>PY|6Ps?VX+ zCyGuE)n^FxNurZO^*M(6WYNi?`fwf8be-trP<{A4G+i$`IaHqs)Tf9}4%KHW^{Jwh zL-jeE`ZUqWq590HK3#Njs6OXWzgqSSa;QF6QlBaQfaNc9IDUl)aQs!4%LU>ThntzCx_~@gL;GLT@RbWulWq_4yw4<)V{A^*M+73em}- z`Yfb=sp#ZTeU?+dOmuRnK37s-DLOe+pS9H2$$mi&)ra5r(^rZ=IlMynZtANYhw5`b z^{YfDhw8)c{^>QMlSB3S4fVC6lSB1+k^0r5lSB1+h59Kq52G@euL=bP<@6_zfp8@s6Hd9ZxWpxs?Q13H;YaV)#tm^ZxWpxs?P-K zKM|cAs!tvD^)gP#q55z=-Sn;EPY!PpzL@$?9f#_(g8DYm$)WmOLH%cq!}WO6w~I~=)rZ$%(szhX4%O#Z)bA9X9IDSF)bA3V9IDR~)PEs5 zIaHr#soyO+IaHrNP`^iXa;QFUP`_7na;QGM=99ig`k5T64_}&+en9-m;r+r*sXypA zR3AQzmEJBoIaHr^)E^R^9I8)e>JN)f4%H_^{Snd0q5AN7t@IAj$)Wo2d9CzL(aE9u z450p~=;Tm+j-dXS=;Tm+_*_={anZ@4`tZ4|G;f3=kVEz1I>hOx#h)BLC446JXB>y> z!*z<&zY(1rs?T}UcZp68)#qaBzZIPvs?QSY8>BwuP<^hW{(|_E!{>$hJXQL4jzjhN z8TA)MCx_~D5B1-RP7c+F&s?Qn5}h2X&y&>uAUZizpJ%DREIK((gefm*^w;pHbA` z6P+BY&xzFE7o8lc&*{|vDmpn-pDENo5S<*V&rIrn6P+BY&pFgT6rCKZ&kv~oU37A& zK1->8Bsw`%pHq^GoWV ziB1mHXFK)(5}h2X&!f~o7o8lc&ok7&5S<*V&kNM|icSvI=g-u?6rCKZ&pXt=5}h2X z&)=zkEjl?=pUe9I6l3 z=T7H|P7c+F*CW&UqLV}Q=}En*=;Tm+`cmhM6A;Lu`fz>kbTiS(q55zQ&~$Ur$)Wo2 zd9ZW~(aE9ujHk|rdJxE=`qWZyB|14&pQ+Sai%t&JhtGqh`634da;QEFsPo|<1ahc8 z7g293IyqDyu1T6M5}h2X51$Q77mH2~)n`5R{X{2+>T^BycA}F*_1Q|jz3AjneeR&X zzv$#peSSr~gXrW?eIB9SQFL;sKEI~kNpy0kKD()xh)xdG=Vj`hMJI>q^9J=UqLah_ zr@Cu_lHw}Ux2C6OATtaD0|W_y4ozxEfO+#sz&H#{0?Ck&0B$g7(@ZzeGBZuOdnSpG zJd`{)Q8t8_mk|}RNzBGa#9cMIn4Rp=)m_~+diJ>Po~*{ByBp6j@e%i!#r?i}|G)co z4LL+T>hV8QRp0;pfBpB?ty{Mqe@&P8yhwhYDNjwcSq=YPp398VmIPfY{( zvm8$xiq9nS3mi`zicb^yq~nQ0@tIEkgN`Q-#phh|iyTiJwmRHJ{+tR9#pitT=Q^G^ z6rZ)^7dxIf6rTa|OB_!eiq97EOC3)fiqCfPZH^}n#V13)-SNbs_zaQna6EA+J|*&< zjwcSq=UwEx98VmI&wldVjwcSq=T7oHjwcSq=Wg=L98VmI&;8_=JDxZcpO27V;dtUu zd>$vi((%Nh_&iDeVaF4P;`8_9-{^SaP;xY1BY%P8i9_*ujyzx1gAj+}^BwZNjwcSq z=X>PWIG#8ZpZ_M`=Xl~!e11xPt>cM9@%a_`b&e+v#fRU!U(oM(;!u1V$Y1Dq;!u2A z$Y11m;!u3fAiv)6#G&{k$!~BxaVS2E$zSYv;!u3L$zS4l;!u26lOJ$AaVS3hu>E;`3$lA96f#C_c}V-|2YbFzxVvksqw! zP<&n{pK&~KC_cX;pLINOC_c4Q!0&QAaVS1h$nSPMaVS2s$nSAHaVS1#lFvDwI24~G z`L{csI24~H^23fN4#j63`4PtxhvKu5eBSZIq4>O+{65DM zhvJhWf3@R@L-E-|zTkM`P<*Z?UvxZiC_dMcFFBq#6rY>Ok2;<>6rVfDk2#(=6rcBz zKkRtoP<&=%91K3}__@S&92t#CU`oy*a=2Ca)zH29G-*cCX~;D!5hn`{?sg z%peaDKkat z<41BOd{-&AlZ9@;*HZnKss7-SSJ>v^e7>}YtMuj4CvD8CuP=FPmdippdA17oRVTmF zj=j=0@#E;W$ujmMtoSM*_MnC7ojVKJF{!Gf_(iTNqF}$-s%xMW(>9nN9?p)SAB^Nn z*|v)=-MZ9%zN%`qA$$|Iir7_150l9i2glmdC45VE=V&Qgbce?4nx6qL_Es4dO;2Pk zbZ0APVNSo8Qz!Vj9*^S>_DQe9uM=Z zKi+qtbL>>nco&24;~lsad1r8p$2QP-Ibc8D6HtzTQ_*-C5PrNnZ*%XRF&^7N84t7yD)BJrNag~JXwG2ZEzG#+nX z@K-*5Gl(}wgMe3fVIc=t!*ZFvaaC<4dro$tka zQsR-PJdDmRuLoNlX4}4B0O0YADp~mk4mMtMs<3{Pf0cMn!x#j=qdag$7?1Kz0It(Z z1@iO<5g!#}J(8God%quvH;Tr6R)fG#;V&Y7=cCd1fAuQr_Y#0#?)cNFGun{lhM2V6 zdNic2!x)d8jq5G~5w+F8&yV*IuJx`2$9Rh{X*|9X&2>6t{r91;AJZs88>d9X@13|7 zm&|-0A4}n@+i_VW-umf!fpsZB3k@fV7F$3^Byv+U1^(q8lx#((UGA8Y# zfab-kjoCYc$cb(*$4uYv)gK!(;uWBN?LFNc2~Rp#banRhtn6O4ERpE!=;*X_*nyY# z^du51I#!DRj?-@FAGk0GG!nPvr&ar`83z#S;I26qVO*O9?H%iSA6)RfY3{oH$=lDp zqowY~3vRj)gNym$jd-JYKlCqkFMGD;sk%eGuiX3W_)|BJ*IaS)HHXH>pIUazbl;&?y;7-y7{l%^AF>%%sDpR z5PIL@R zw#o@gV75)9-V&uy!nw)?(}J^`TH>*$=F`t;nifpQdAgXd406RS{h zo?5LoSF6(*%EZSptNS`;l-T_G=GYuNLen{RhCRL5`}f$~TFY~-*qM_oK9hJ}qp6$9 zP>`Aw%quqC@8Quo%5=sAYytN;)qNF>h%aE5uG^O_ zw(a4Gna=1h*sS!B1H00LS=j7w6Ssp>Y;q7k`?Oeq12c#(mSv(Y#*=ms$A5j;WwK5z zOVmS_^J9EbA&8$5tFg;j!cUXsSsDrVZPuYhBh7Rk;x|Kl?w8 znx+Kwg_wLJ1cMy&@awnG;~>N%}c*7D*&jguR<@6{g#ip#xMKCDg(CI z<5l;}7@|+ASI#reo+w9jdZpG*?~T~EMD(GE{+@__OGKB)xnN!Vha>inMD#}@`r{G( z$%y``i2j*~j#~r~SN?HTr9M2bIl*O;CozMYWlwCktkS(3Bk(bMhg@-pnWlD$=QYPO zp1uP(cz@ue-h2%D z$1yo+G@l2q9540e%g{gL*?E8e1$9UKA3*<{Xa6~H+S57mukrL5(7BCTUJ^RDQT1-< zY!lV{ptH?Xza08yo}Pv-DO9*LnyaDnxs&?e1bx)g)xu@WKG~}*X& z({a3i2=P>S>^&CIqbJI?fsTY}8(6z(Lr1CuVAtr#U}|S}cW#7QX&6JkU39K=%PzO* z7FMjwL|x&QvgpK#WuDo1$u5HWBj${~+kKTJj=T2G$*FsH(jw4o{_s7Z;D?gQdD`pU4z4q}{wUKi1>7N!S(t(q7MeN4D;?(k4W$3r z{VVbP{mV^KpT)ph2V$)QH!qNj2Zj!~^C7D-1*7mziE$4l@g z3+c>xFc z1g3x;5b|kE0V@mn3Z_6V=$<2%_|Fq>#0>Hxrr=Tw%`b^Bb9iz9yvbo+GX8Q~haUi5Fu8(5;rS}Zg3}yN9EuOGXBIR#p1Az`3*^~x zAWxAOAHHv)zrR3S{{02=P0oLu{1k`3Mt*7q>+dfx7pK3!KwSR)1@hCJ|98prq5<*( zd3IjG<=g@xpKkU@y`_ZRpRFZ%lk#G&{wbda>}_WmNMcQ}DX z@{9^@75+DRUu4279DE#AdBo*jaVVd^^|gc7d{M!9{_);QU~^zsmUEgtu6fFHG^>@f zFsEP4slW3(2}@2AkLOqw#VbMh^`kznPFQOFIJ|S6UQCoH(Dx5u$!;9SL>muD4ik*0 z@+!bTtAeH427vu|t8rX4qcFx}x6ydpy>$T1KOz9fO%;vD^QL0j_)fwKk5Kq_*!*$_ zaD4LEWVsxIwA^(a=Z0 zDW;izOLZrBwhsaO+p!Yk2FEIH2ZuD>j$__BfaVD_uAI`ST0bs7A-Ic{hIJ|Ac#CXk^IMi#O2Q)v!*!D4u=YeteE*5~g*Wwo0KPxG5!X>S2mPP@L9BoOi8tQfFl}b-M`QFUop`DL z%yLHXz5S&VFMRMTcLn{2{*$(Y@kA_$SU29)vTUZAb~xyNFG`GswZ9%b_^erYzm{XG zhFMT~@(|dI6lko2f zk!@0YrGxy|eV{F#=M{YAq|gIXj4CSgC(xuyCDyqtxZbG#GLtE0Oj}rPf?=#hPuY%^Tj* zpW3o*Q-3OD3Ry4LmMs(p^BFvVVTNrq`#Yq+UPcFwnX57XgQUN7SDrc{rRl3oA&1Q8 zsr~{qHP z@yZuPqVw9&iSs|8D(t?*%6A8jjk!}q*=1s`Np5(>W8$;#CfgoGn@8M?p!c$W0{-#yU%{q+!Z#&l9!^*%IC#O5g&&Qmk=XUdqM$$T60$ID!U z`2n!s-Y-GlY%e?Lg#87a_w=b{OnaTpE!|z_8q5;lN`I|0{5OxsJo^UVMO@WNt=R;9 zx@YG*t$Zfqq`~lCqn3O6yMfnv`klZzPk#`2%+vY&<$6zNZb|-?4MjAVuR_1qvunv* zPRxZi`)1gun}3sa*@n~6e_krba^pa(e4XZW|Gi*FYm3-VI_gUTr?0Og#ry%6%sFr= zX&63(pODs(bdG&sj}*;>oQ&9Q+5z@1N##h&Mj~s1$0kx3C6YXdW&==>p;KpXULzG0 z$vjjgQlbTMlgrOjqFEm{6Dx~_m)MA8MIw2dNTw!|#)za)CS*Y(McL-^ibmtV#w8jv zT!VXY#kn`Ndo*3hnAf@%j9wzs;B9Tq~Yd4wm(b4NjlHIMLV^7hUf`4sZv^9Axv&YxKG2+xvd$A=JW9)Zs)HIG27 zc?3SE(>wyP<`Mp#{B#$GSn~*cFGKSP#F|I=G5HzJpIGwv&?#Bg_V+c{iG? z{;yar5EJ0_|B8R3=k}HVxjgy!{HONd9_{eQdUkJ*VU*ADgu=u5fJJUrBX|jx9IJap zZ$#gG0k{Pdc~0!QybeY;D9bp|jDzpCquH#>3`S`8A_r-zu+F*~b3|XhV#~ literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..b65696aadd4196246641d096b1dac14d9527c2f9 GIT binary patch literal 196256 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 literal 0 HcmV?d00001 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 index 000000000..9c2f7fc30 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/pgnss_decoder/pgnss_decoder_interface.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. + * Description: pgnss include with pgnss data decode module + */ + +#ifndef PGNSS_DECODER_INTERFACE_H +#define PGNSS_DECODER_INTERFACE_H + +#include + +#ifndef WIN32 +#define EXPORT_API __attribute__((visibility("default"))) +#else +#define EXPORT_API __declspec(dllexport) +#endif + +/* + * 函数功能:获取种子文件可预测的起止时间 + * 入参:filePath:种子文件的完整路径,包括路径和文件名 + * 出参:startTimestamp:种子文件可预测的开始UTC时间对应的unix时间戳 + * endTimestamp:种子文件可预测的结束UTC时间对应的unix时间戳 + */ +EXPORT_API int32_t GetPgnssDataValidTime(const char *filePath, uint32_t *startTimestamp, uint32_t *endTimestamp); + +/* + * 函数功能:获取跳秒时间 + * 入参:filePath:种子文件的完整路径,包括路径和文件名 + * 返回值:LeapSecond跳秒 + */ +EXPORT_API int32_t GetLeapSecond(const char *filePath); + +/* + * 函数功能:读取PGNSS种子文件,解析PGNSS辅助数据,扩展星历,保存星历文件; + * 每一份星历文件可使用前后两小时,两份星历文件间隔两小时,支持一次扩展多份星历文件 + * 入参:filePath:种子文件的完整路径,包括路径和文件名 + * outputDir:扩展的辅助数据存放路径 + * timestamp:开始预测时间对应的unix时间戳,可取用当前时间,也可自行设置时间,单位:秒 + * hours:解析X小时星历,调用者需保证种子文件中从timestamp开始有X小时的有效星历 + */ +EXPORT_API int32_t ParsePgnssData(const char *filePath, const char *outputDir, uint32_t timestamp, uint32_t hours); + +/* + * 函数功能:读取PGNSS种子文件,解析PGNSS辅助数据,扩展星历,保存星历文件; + * 与ParsePgnssData不同,每次解析生成三份文件,分别为GLONASS星历、除GLONASS外其余星历以及其余辅助信息 + * 每一份星历文件可使用前后两小时,两份星历文件间隔两小时,支持一次扩展多份星历文件 + * 入参:与ParsePgnssData一致 + * filePath:种子文件的完整路径,包括路径和文件名 + * outputDir:扩展的辅助数据存放路径 + * timestamp:开始预测时间对应的unix时间戳,可取用当前时间,也可自行设置时间,单位:秒 + * hours:解析X小时星历,调用者需保证种子文件中从timestamp开始有X小时的有效星历 + */ +EXPORT_API int32_t ParsePgnssDataByLessFiles(const char *filePath, const char *outputDir, uint32_t timestamp, uint32_t hours); + +/* + * 函数功能:返回pgnss解码库的版本号 + * 入参:无 + * 返回值:版本号对应字符串 + */ +EXPORT_API const char *GetPgnssVersion(void); + +#endif 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 index 000000000..0311a264e --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/build_and_run.sh @@ -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 index 000000000..d773ad2a3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/clean.sh @@ -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 index 000000000..dfeec2fde --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/demo_data/EE_7days.dat @@ -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 index 000000000..4b75f2f4f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_decode_demo/server_pgnss_decode_demo.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) @CompanyNameMagicTag 2024-2024. All rights reserved. + * Description: pgnss decode demo on server + */ + +#include +#include +#include +#include +#include +#include + +#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 index 000000000..c87f7c294 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/pgnss/server_pgnss_download_demo/server_pgnss_download_demo.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# coding:utf-8 +# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. +import requests +import time +import calendar +import hmac +import base64 + + +# 网络连接相关 +HOST = r'geo-drcn.platform.dbankcloud.cn' # 域名 +PORT = 443 # 端口号 +URI = r'/higeo/v1/xgnss/pgnss' # uri路径 + +# 鉴权认证相关 +APP_ID = r'' # 账号,请联系销售代表获取 +APP_SECRET = b'' # 密钥,请联系销售代表获取 +UUID = r'' # 每台设备的唯一标识码,请根据产品进行适配 + +# 请求参数 +PERIOD = r'' # 一次性请求数据的天数,可选项(1,3,7,14,28),默认7天 + + +class PgnssRequest: + def __init__(self): + self.ts = 0 + self.qry_str = '' + self.signature = '' + self.url = '' + self.session = requests.session() + + def format_req_str(self): + qry_str = '' + if PERIOD and PERIOD != '7': + # period默认值7,则无需填写 + qry_str += f'period={PERIOD}' + self.qry_str = qry_str + + def gen_auth_str(self): + # 构造待签名字符串 + str_to_sign = f'GET&{URI}&{self.qry_str}&&appid={APP_ID}×tamp={self.ts}' + # 计算签名HMAC值 + h1 = hmac.new(key=APP_SECRET, digestmod='sha256') + h1.update(str_to_sign.encode('utf-8')) + b1 = base64.b64encode(h1.digest()) + signature = b1.decode('utf-8') + self.signature = signature + + def update_session(self): + # 填充完整url + self.url = r'https://{}:{}{}{}{}'.format(HOST, PORT, URI, '?' if self.qry_str else '', self.qry_str) + # 组装请求消息头 + self.session.headers.update( + { + 'X-Request-ID': f'{UUID}', + 'Authorization': f'HMAC-SHA256 appid={APP_ID},timestamp={self.ts},signature={self.signature}' + } + ) + + def connect_session(self): + try: + print(f'正在连接服务器...') + rsp = self.session.get(url=self.url, verify=False, timeout=(3, 27)) + print(f'Pgnss请求结果:{rsp.status_code},结果码:{rsp.reason}, 响应长度:{len(rsp.content)}') + + # 处理响应值 + if rsp.status_code == 200: + # 响应200表示请求成功 + print(r'响应内容:') + # 响应内容的Pgnss辅助数据保存成文件,后续配合解码库使用 + with open(r'.\EE.dat', 'wb') as f: + f.write(rsp.content) + print(f'EE.dat下载成功') + elif rsp.status_code == 401: + if rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'unix时间戳异常,请检查服务器下发的响应消息头中“X-Auth-Timestamp”与请求消息头的' + r'“Authorization”中的“timestamp”是否相差很大') + print(r'请检查“timestamp”是否取用正确的UNIX时间戳,单位是毫秒') + # 如设备本身无时间系统,可在此处取用服务器下发的“X-Auth-Timestamp”进行重新请求 + print(f'响应消息头:{rsp.headers}') + server_ts = rsp.headers.get('X-Auth-Timestamp', 0) + self.ts = server_ts + # 签名认证 + self.gen_auth_str() + # 更新请求消息头 + self.update_session() + # 重新请求 + rsp2 = self.session.get(url=self.url, verify=False, timeout=(3, 27)) + print(f'Pgnss重新请求结果:{rsp2.status_code},结果码:{rsp2.reason}, 响应长度:{len(rsp2.content)}') + + elif rsp.reason == 'authorization is missed': + print(r'“Authorization”字段异常,请检查请求消息头是否正确填写“Authorization”字段') + elif rsp.reason == 'appid is missed': + print(r'“appid”字段异常,请检查请求消息头的“Authorization”中是否正确填写“appid”字段') + elif rsp.reason == 'timestamp is invalid': + print(r'“timestamp”字段异常,请检查请求消息头的“Authorization”中是否正确填写“timestamp”字段') + elif rsp.reason == 'signature is invalid': + print(r'“signature”字段异常,请检查请求消息头的“Authorization”中已填写“signature”字段') + elif rsp.reason == "Can't get the keys of appid": + print(r'“appid”无效,请检查请求消息头的“Authorization”中的“appid”的合法性') + elif rsp.reason == 'SignatureInvalid': + print(r'“signature”异常,请检查请求消息头的“Authorization”中的“signature”正确性,' + r'检查appid和app_secret是否匹配') + elif rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'异常,请检查') + elif rsp.reason == 'TimestampMoreEarlierOrLater': + print(r'异常,请检查') + self.session.close() + except requests.exceptions.SSLError as e: + print(e) + print('请检查网络是否通畅') + except requests.exceptions.ProxyError as e: + print(e) + print('请检查网络是否通畅') + except Exception as e: + print(e) + + def request(self, ts=0): + self.ts = ts + + # step1. 构造规范化请求字符串 + self.format_req_str() + + # step2. 构造鉴权信息字符串 + self.gen_auth_str() + + # step3. 构造HTTP GET请求 + self.update_session() + print(f'请求URL:{self.url}') + + # step4. 发送请求 + self.connect_session() + + +if __name__ == '__main__': + # 获取当前UNIX时间,单位毫秒 + now = calendar.timegm(time.gmtime()) * 1000 + pgnss = PgnssRequest() + pgnss.request(now) 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 index 000000000..5b80af730 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/CMakeLists.txt @@ -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 index 000000000..9309437b0 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: agnss encode + * Author: + * Create: + */ +#include "agnss_encode.h" +#include +#include +#include +#include "securec.h" +#include "gnss_datatypes.h" +#include "tiot_service_interface.h" + +#define GNSS_ENCODE_BUFF_MAX_LEN 9300 +#define FILE_PATH_LEN 1024 +#define INJECT_SLEEP_MS_TIME 500 +#define REPORT_MAX_BYTES 10000 +#define LISTEN_TIME_THR 1000 +#define AGNSS_FILE_MAX_SIZE 1024000 +#define AGNSS_DATA_PATH "/user/xgnss/AGNSS.dat" // 可自行配置路径 + +// 监听消息 +static uint8_t g_ackBuff[REPORT_MAX_BYTES] = { 0 }; + +/* 计算命令内容校准和 */ +static uint16_t CalcChecksum(uint8_t *buff, uint16_t len) +{ + uint16_t checksum = 0; + uint16_t i = 0; + while (i++ < len) { + checksum += *buff; + buff++; + } + return checksum; +} + +/* AGNSS计算内容校准和, 校验和模256,与芯片侧的命令校验和计算不可混用 */ +uint8_t CalcAgnssCheckSum(uint8_t *data, uint16_t len) +{ + uint8_t sum = 0; + for (uint16_t i = 0; i < len; i++) { + sum += data[i]; + } + return sum; +} + +int32_t AgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime) +{ + uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN); + if (buff == NULL) { + printf("\nerror: malloc failed in AgnssInjectUtcTime\n"); + return 0; + } + memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN); + + GnssMsg *hdr = (GnssMsg *)buff; + hdr->cmd = CMD_XGNSS_INJECT_UTC_TIME; + hdr->sequence = 0; + errno_t copyRet = memcpy_s(hdr->data, (GNSS_ENCODE_BUFF_MAX_LEN - sizeof(GnssMsg)), utcTime, sizeof(GnssUtcTime)); + if (copyRet != EOK) { + printf("\nmemcpy UtcTime failed! Errno is %d\n", copyRet); + free(buff); + return 0; + } + hdr->dataLength = sizeof(GnssUtcTime); + hdr->checkSum = CalcChecksum(hdr->data, hdr->dataLength); + int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + hdr->dataLength)); + if (ret < 0) { + printf("\nerror: AgnssInjectUtcTime error: %d\n", ret); + free(buff); + return 0; + } + + free(buff); + return 1; +} + +static uint16_t FillGnssMessageData(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen) +{ + errno_t ret = memcpy_s(outBuff, outLen, inBuff, inLen); + if (ret != EOK) { + printf("memcpy XgnssData failed! Errno is %d", ret); + return 0; + } + + return inLen; +} + +static int32_t EncodeGnssMsg(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen) +{ + uint16_t len = FillGnssMessageData(inBuff, inLen, outBuff, outLen); + if (len > 0) { + return 1; + } + return 0; +} + +static void ListenAck(tiot_handle handle) +{ + int32_t i = 0; + for (;;) { + // 监听 + int32_t ret = tiot_service_read(handle, g_ackBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_ackBuff; + // 二进制消息类型 + if (type[0] == 0) { + g_ackBuff[ret] = '\0'; + printf("%s\n", (char *)&g_ackBuff[MSG_CONTENT_IDX]); + } + i++; + } + if (i >= 1) { + printf("\ncnt enough\n"); + break; + } + } +} + +static int32_t EncodeAndInjectCmd(tiot_handle handle, GnssCmdType cmdType, uint8_t* inBuff, uint32_t inLen) +{ + // 获取GNSS业务消息头 + int32_t len = 0; + uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN); + if (buff == NULL) { + printf("\nerror: malloc failed in EncodeAndInjectCmd\n"); + return 0; + } + memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN); + + GnssMsg *gnssHdr = (GnssMsg *)buff; + len += sizeof(GnssMsg); + + gnssHdr->sequence = 0; + + int32_t retLen = EncodeGnssMsg(inBuff, inLen, buff + len, (GNSS_ENCODE_BUFF_MAX_LEN - len)); + if (retLen != 1) { + printf("\nerror: Encode Cmd failed: %d\n", cmdType); + free(buff); + return retLen; + } + gnssHdr->cmd = cmdType; + gnssHdr->dataLength = inLen; + gnssHdr->checkSum = CalcChecksum(gnssHdr->data, gnssHdr->dataLength); + int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + gnssHdr->dataLength)); + if (ret < 0) { + printf("\nerror: Inject Cmd failed: %d\n", cmdType); + free(buff); + return 0; + } + ListenAck(handle); + printf("\nInject Cmd SUCCESS: %x\n", cmdType); + free(buff); + return 1; +} + +void ProcAndInjectAgnssCmd(tiot_handle handle, uint16_t dataType, uint8_t *data, uint16_t dataLen) +{ + /* 1.根据AGNSS dataType类型,转换为芯片侧消息类型 */ + const struct { + AgnssDataType agnssDataType; // AGNSS type类型, + GnssCmdType innerType; // 芯片侧消息类型 + } table[] = { + {AGNSS_GPS_INJECT_EPH, CMD_AGNSS_INJECT_NAV}, + {AGNSS_GPS_INJECT_UTC, CMD_AGNSS_INJECT_UTC}, + {AGNSS_GPS_INJECT_ION, CMD_AGNSS_INJECT_IONO}, + {AGNSS_GPS_INJECT_RTI, CMD_AGNSS_INJECT_RTI}, + {AGNSS_GLO_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV}, + {AGNSS_GLO_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI}, + {AGNSS_GLO_INJECT_AUX, CMD_AGNSS_INJECT_GANSS_AUXI}, + {AGNSS_BDS_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV}, + {AGNSS_BDS_INJECT_ION, CMD_AGNSS_INJECT_GANSS_ADDL_IONO}, + {AGNSS_BDS_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI}, + {AGNSS_GAL_INJECT_EPH, CMD_AGNSS_INJECT_GANSS_NAV}, + {AGNSS_GAL_INJECT_RTI, CMD_AGNSS_INJECT_GANSS_RTI} + }; + uint16_t cmdType = 0; + // 2.遍历对应关系表 + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) { + if (dataType == table[i].agnssDataType) { + cmdType = (uint16_t)table[i].innerType; + // 3.找到对应芯片侧消息类型,并下发消息 + EncodeAndInjectCmd(handle, cmdType, data, dataLen); + break; + } + } + osal_msleep(INJECT_SLEEP_MS_TIME); +} + +void AgnssInjectAllContent(tiot_handle handle, uint8_t *buff, int32_t len) +{ + int32_t remainLen = len; + // tlv + while ((uint32_t)remainLen >= sizeof(AgnssDataHeader) + sizeof(AgnssDataTail)) { + AgnssDataHeader *header = (AgnssDataHeader *)buff; + uint16_t dataLen = header->len; + if ((uint32_t)remainLen < sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen) { + printf("AgnssInjectAllContent: remainLen %d and dataLen %d not match\n", remainLen, dataLen); + return; + } + uint8_t localCheckSum = CalcAgnssCheckSum((uint8_t *)header, (header->data - (uint8_t *)header) + dataLen); + uint8_t checkSum = ((AgnssDataTail *)(header->data + dataLen))->checkSum; + if (localCheckSum != checkSum) { + printf("AgnssInjectAllContent: local CheckSum %d and CheckSum %d not match\n", localCheckSum, checkSum); + return; + } + ProcAndInjectAgnssCmd(handle, header->dataType, header->data, dataLen); + buff += sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen; + remainLen -= sizeof(AgnssDataHeader) + sizeof(AgnssDataTail) + dataLen; + } +} + +void ProcAgnssFileContent(tiot_handle handle) +{ + char fileName[] = AGNSS_DATA_PATH; + FILE *fp = fopen(fileName, "rb"); + if (fp == NULL) { + printf("\nerror: open file failed: %s\n", fileName); + return; + } + fseek(fp, 0, SEEK_END); + int32_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (len < 0 || len > AGNSS_FILE_MAX_SIZE) { + fclose(fp); + printf("\nerror: get file len failed: %s\n", fileName); + return; + } + uint8_t *buff = (uint8_t *)malloc(len); + if (buff == NULL) { + fclose(fp); + printf("\nerror: malloc file len failed: %s\n", fileName); + return; + } + int32_t dataSize = fread(buff, len, 1, fp); + if (dataSize < 0) { + fclose(fp); + printf("\nerror: read file failed: %s\n", fileName); + free(buff); + return; + } + fclose(fp); + AgnssInjectAllContent(handle, buff, len); + free(buff); +} + +void AgnssInject(tiot_handle handle) +{ + // 处理AGNSS文件,向芯片注入Agnss辅助数据 + ProcAgnssFileContent(handle); +} \ 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 index 000000000..bbef15353 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_encode.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: agnss encode + * Author: + * Create: + */ +#ifndef AGNSS_ENCODE_H +#define AGNSS_ENCODE_H + +#include "gnss_datatypes.h" +#include "tiot_service_interface.h" + +int32_t AgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime); +void AgnssInject(tiot_handle handle); +#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 index 000000000..537608d5c --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: agnss sample + * Author: + * Create: + */ +#include "agnss_sample.h" +#include +#include "securec.h" +#include "tiot_service_interface.h" +#include "pm_definition.h" +#include "gnss_datatypes.h" +#include "agnss_encode.h" + +#define AGNSS_FIXMODEALL_NMEADEF_SAMPLE 0 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define MSG_TYPE_BINRY 0 +#define MSG_TYPE_ASCII 1 +#define LISTEN_DATA_MAX_LINES 1000 +#define REPORT_MAX_BYTES 10000 + +static FILE* g_gnssLogFp = NULL; +static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 }; + +typedef int32_t (*GnssCfgFunc)(tiot_handle handle); + +typedef struct { + uint16_t sampleId; + GnssCfgFunc cfgHandle; +} GnssSamplesCfgTable; + +static int32_t QryVersion(tiot_handle handle) +{ + const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; + // 查询版本号 + int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion)); + if (ret < 0) { + printf("error: QryVersion error: %d\n", ret); + return 0; + } + return 1; +} + +// 注入AGNSS,使用默认配置启动 +int32_t InjectAgnss(tiot_handle handle) +{ + const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03}; + + // 配置log级别:info级别。 + int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo)); + if (ret < 0) { + printf("error: cfgLogLevelInfo error: %d\n", ret); + return 0; + } + + // 注入UTC时间, 注入Agnss辅助数据前必须先注入参考时间 + GnssUtcTime utcTime = {2024, 3, 22, 10, 0, 0, 0, 1}; // 需要用当前的UTC时间替换 + ret = AgnssInjectUtcTime(handle, &utcTime); + if (ret == 0) { + printf("error: AgnssInjectUtcTime failed!\n"); + return 0; + } + printf("AgnssInjectUtcTime success!\n"); + + // AGNSS注入 + // 注意,默认AGNSS文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换 + AgnssInject(handle); + + return 1; +} + +static const GnssSamplesCfgTable g_gnssSamplesCfg[] = { + {AGNSS_FIXMODEALL_NMEADEF_SAMPLE, InjectAgnss}, +}; + +static int32_t StartGnss(tiot_handle handle) +{ + const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 启动GNSS + int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd)); + if (ret < 0) { + printf("error: start gnss error: %d\n", ret); + return 0; + } + printf("start gnss\n"); + return 1; +} + +static int32_t StopGnss(tiot_handle handle) +{ + const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 停止GNSS + int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd)); + if (ret < 0) { + printf("error: stop gnss error: %d\n", ret); + return 0; + } + printf("stop gnss\n"); + return 1; +} + +static void ListenGnssData(tiot_handle handle) +{ + int32_t i = 0; + // 写日志 + for (;;) { // 写日志条件 + // 监听 + int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, 1000); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_gnssServiceBuff; + if (type[0] == MSG_TYPE_ASCII) { + g_gnssServiceBuff[ret] = '\0'; + printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + } + i++; + } + if (i >= LISTEN_DATA_MAX_LINES) { + printf("cnt enough\n"); + break; + } + } +} + +void AgnssExecuteSamples(void) +{ + uapi_pm_add_sleep_veto(PM_ID_SYS); + printf("enter gnss samples\n"); + // Step1: init + int32_t ret = tiot_service_init(); + if (ret != 0) { + printf("tiot service init fail\n"); + } + + // 打开日志文件 + g_gnssLogFp = fopen("/user/gnss.log", "w"); + if (g_gnssLogFp == NULL) { + printf("error: open log file error\n"); + return; + } + printf("before open tiot service\n"); + + // Step2: power on gnss + tiot_handle handle = tiot_service_open("gn71", NULL); + if (handle == 0) { + printf("open tiot service fail\n"); + return; + } + printf("open tiot service success\n"); + + int32_t cfgRet; + // ---- loop ---------- + for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) { + cfgRet = 0; + if (g_gnssSamplesCfg[i].sampleId == i) { + // Step3: config gnss + if (g_gnssSamplesCfg[i].cfgHandle != NULL) { + cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle); + } + if (cfgRet == 0) { + continue; + } + printf("cfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId); + QryVersion(handle); + + // Step4: start gnss + if (StartGnss(handle) == 0) { + continue; + } + // Step5: listening gnss data + ListenGnssData(handle); + // Step6: stop gnss + if (StopGnss(handle) == 0) { + continue; + } + } + } + // --------------------- + // Step7: power off gnss + tiot_service_close(handle); + // 关日志文件 + fclose(g_gnssLogFp); + g_gnssLogFp = NULL; + // Step8: deinit + tiot_service_deinit(); + uapi_pm_remove_sleep_veto(PM_ID_SYS); + printf("finish gnss samples\n"); +} \ 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 index 000000000..8c8823b90 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/agnss_sample.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: agnss sample + * Author: + * Create: + */ +#ifndef AGNSS_SAMPLE_H +#define AGNSS_SAMPLE_H + +void AgnssExecuteSamples(void); + +#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 index 000000000..97607f9c7 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/agnss_sample/gnss_datatypes.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: gnss datatypes + * Author: + * Create: + */ +#ifndef GNSS_DATATYPES_H +#define GNSS_DATATYPES_H + +#include + +#define MSG_CONTENT_IDX 2 + +// 消息类型 +typedef enum { + CMD_AGNSS_INJECT_REF_LOC = 0x0302, // 位置预测注入 + CMD_AGNSS_INJECT_NAV = 0x0303, // 星历数据注入 + CMD_AGNSS_INJECT_IONO = 0x0304, // 电离层参数注入 + CMD_AGNSS_INJECT_UTC = 0x0305, // UTC时间注入 + CMD_AGNSS_INJECT_RTI = 0x0306, // 完好性信息注入 + CMD_AGNSS_INJECT_GANSS_ADDL_IONO = 0x0308, // 非GPS电离层参数注入 + CMD_AGNSS_INJECT_GANSS_NAV = 0x0309, // 非GPS星历数据注入 + CMD_AGNSS_INJECT_GANSS_RTI = 0x030A, // 非GPS完好性信息注入 + CMD_AGNSS_INJECT_GANSS_AUXI = 0x030C, // 频点对应关系注入,GLONASS + CMD_XGNSS_INJECT_UTC_TIME = 0x0404, // 最开始注入的UTC时间 + CMD_BUTT, +} GnssCmdType; + +typedef enum { + AGNSS_GPS_INJECT_EPH = 0x0002, + AGNSS_GPS_INJECT_UTC = 0x0003, + AGNSS_GPS_INJECT_ION = 0x0004, + AGNSS_GPS_INJECT_RTI = 0x0005, + AGNSS_GLO_INJECT_EPH = 0x0022, + AGNSS_GLO_INJECT_RTI = 0x0025, + AGNSS_GLO_INJECT_AUX = 0x0026, + AGNSS_BDS_INJECT_EPH = 0x0042, + AGNSS_BDS_INJECT_ION = 0x0044, + AGNSS_BDS_INJECT_RTI = 0x0045, + AGNSS_GAL_INJECT_EPH = 0x0062, + AGNSS_GAL_INJECT_RTI = 0x0065 +} AgnssDataType; + +#pragma pack(1) +typedef struct { + uint16_t cmd; // 消息类型 + uint16_t checkSum; // 校验和,只计算实际数据部分,不包含头 + uint16_t sequence; // 序列号,host下发 + uint16_t dataLength; // 数据长度,实际数据的长度,不包含头 + uint8_t data[0]; +} GnssMsg; + +typedef struct { + uint16_t year; // YYYY + uint8_t month; // MM, 1~12 + uint8_t day; // DD, 1~31 + uint8_t hour; // hh, 0~23 + uint8_t minute; // mm, 0~59 + uint8_t second; // ss, 0~59 + uint16_t ms; // ms, 0~999 + uint8_t valid; // 0: invalid, 1: valid +} GnssUtcTime; + +typedef struct { + uint16_t dataType; + uint16_t len; + uint8_t data[0]; +} AgnssDataHeader; + +typedef struct { + uint8_t checkSum; +} AgnssDataTail; + +#pragma pack() + +#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 index 000000000..b82dac6ce --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/CMakeLists.txt @@ -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 index 000000000..18e1d8a71 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2024. All rights reserved. + * Description: gnss sample + * Author: + * Create: + */ +#include "gnss_sample.h" +#include +#include "securec.h" +#include "tiot_service_interface.h" +#include "pm_definition.h" + +#define COLDSTART_FIXMODEGPS_NMEAALL_SAMPLE 0 +#define AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE 1 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif +#define MSG_CONTENT_IDX 2 +#define MSG_TYPE_BINRY 0 +#define MSG_TYPE_ASCII 1 +#define LISTEN_DATA_MAX_LINES 1000 +#define REPORT_MAX_BYTES 10000 +#define LISTEN_TIME_THR 1000 + +static FILE* g_gnssLogFp = NULL; +static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 }; + +typedef int32_t (*GnssCfgFunc)(tiot_handle handle); + +typedef struct { + uint16_t sampleId; + GnssCfgFunc cfgHandle; +} GnssSamplesCfgTable; + +int32_t CfgColdStartFixModeGpsNmeaAll(tiot_handle handle) +{ + const uint8_t cfgColdStartCmd[] = {0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; + const uint8_t cfgFixModeGpsCmd[] = {0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x00, 0x00}; + const uint8_t cfgNmeaAllCmd[] = {0x03, 0x00, 0x04, 0x01, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, 0xff, + 0x00}; + // 配置启动模式:冷启动模式。 + int32_t ret = tiot_service_write(handle, cfgColdStartCmd, sizeof(cfgColdStartCmd)); + if (ret < 0) { + printf("\nerror: cfgColdStartCmd error: %d\n", ret); + return 0; + } + + // 配置使能的GNSS星座:GPS。 + ret = tiot_service_write(handle, cfgFixModeGpsCmd, sizeof(cfgFixModeGpsCmd)); + if (ret < 0) { + printf("\nerror: cfgFixModeGpsCmd error: %d\n", ret); + return 0; + } + + // 配置上报NMEA类型:PNT/ZDA/VTG/RMC/GSV/GSA/GLL/GGA。 + ret = tiot_service_write(handle, cfgNmeaAllCmd, sizeof(cfgNmeaAllCmd)); + if (ret < 0) { + printf("\nerror: cfgNmeaAllCmd error: %d\n", ret); + return 0; + } + return 1; +} + +// 如果有历史信息,自动模式启动会切换到热启动模式,如果无历史信息,则自动模式启动仍然为冷启动 +int32_t CfgAutoStartFixModeAllNmeaDefault(tiot_handle handle) +{ + const uint8_t cfgFixModeAllCmd[] = {0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x1f, + 0x00, 0x00, 0x00}; + const uint8_t cfgAutoStartCmd[] = {0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00}; + const uint8_t cfgNmeaDefaultCmd[] = {0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, 0x11, + 0x00}; + + // 配置启动模式:自动模式。 + int32_t ret = tiot_service_write(handle, cfgAutoStartCmd, sizeof(cfgAutoStartCmd)); + if (ret < 0) { + printf("\nerror: cfgAutoStartCmd error: %d\n", ret); + return 0; + } + + // 配置使能的GNSS星座:QZSS/GAL/BDS/GLO/GPS。 + ret = tiot_service_write(handle, cfgFixModeAllCmd, sizeof(cfgFixModeAllCmd)); + if (ret < 0) { + printf("\nerror: cfgFixModeAllCmd error: %d\n", ret); + return 0; + } + + // 配置上报NMEA类型:RMC/GGA。 + ret = tiot_service_write(handle, cfgNmeaDefaultCmd, sizeof(cfgNmeaDefaultCmd)); + if (ret < 0) { + printf("\nerror: cfgNmeaDefaultCmd error: %d\n", ret); + return 0; + } + return 1; +} + +static int32_t QryVersion(tiot_handle handle) +{ + const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; + // 查询版本号 + int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion)); + if (ret < 0) { + printf("\nerror: QryVersion error: %d\n", ret); + return 0; + } + return 1; +} + +static const GnssSamplesCfgTable g_gnssSamplesCfg[] = { + {COLDSTART_FIXMODEGPS_NMEAALL_SAMPLE, CfgColdStartFixModeGpsNmeaAll}, + {AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE, CfgAutoStartFixModeAllNmeaDefault} +}; + +static int32_t StartGnss(tiot_handle handle) +{ + const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 启动GNSS + int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd)); + if (ret < 0) { + printf("\nerror: start gnss error: %d\n", ret); + return 0; + } + printf("\nstart gnss\n"); + return 1; +} + +static int32_t StopGnss(tiot_handle handle) +{ + const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 停止GNSS + int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd)); + if (ret < 0) { + printf("\nerror: stop gnss error: %d\n", ret); + return 0; + } + printf("\nstop gnss\n"); + return 1; +} + +static void ListenGnssData(tiot_handle handle) +{ + int32_t i = 0; + // 写日志 + for (;;) { // 写日志条件 + // 监听 + int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_gnssServiceBuff; + if (type[0] == MSG_TYPE_ASCII) { + g_gnssServiceBuff[ret] = '\0'; + printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + } + i++; + } + if (i >= LISTEN_DATA_MAX_LINES) { + printf("\ncnt enough\n"); + break; + } + } +} + +void GnssExecuteSamples(void) +{ + uapi_pm_add_sleep_veto(PM_ID_SYS); + printf("\nenter gnss samples\n"); + // Step1: init + int32_t ret = tiot_service_init(); + if (ret != 0) { + printf("\ntiot service init fail\n"); + } + + // 打开日志文件 + g_gnssLogFp = fopen("/user/gnss.log", "w"); + if (g_gnssLogFp == NULL) { + printf("\nerror: open log file error\n"); + return; + } + printf("\nbefore open tiot service\n"); + + // Step2: power on gnss + tiot_handle handle = tiot_service_open("gn71", NULL); + if (handle == 0) { + printf("\nopen tiot service fail\n"); + return; + } + printf("\nopen tiot service success\n"); + + int32_t cfgRet; + // ---- loop ---------- + for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) { + cfgRet = 0; + if (g_gnssSamplesCfg[i].sampleId == i) { + // Step3: config gnss + if (g_gnssSamplesCfg[i].cfgHandle != NULL) { + cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle); + } + if (cfgRet == 0) { + continue; + } + printf("\ncfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId); + QryVersion(handle); + + // Step4: start gnss + if (StartGnss(handle) == 0) { + continue; + } + // Step5: listening gnss data + ListenGnssData(handle); + // Step6: stop gnss + if (StopGnss(handle) == 0) { + continue; + } + } + } + // --------------------- + // Step7: power off gnss + tiot_service_close(handle); + // 关日志文件 + fclose(g_gnssLogFp); + g_gnssLogFp = NULL; + // Step8: deinit + tiot_service_deinit(); + uapi_pm_remove_sleep_veto(PM_ID_SYS); + printf("\nfinish gnss samples\n"); +} \ 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 index 000000000..9d3d27544 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/gnss_sample/gnss_sample.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2024. All rights reserved. + * Description: gnss sample + * Author: + * Create: + */ +#ifndef GNSS_SAMPLE_H +#define GNSS_SAMPLE_H + +void GnssExecuteSamples(void); + +#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 index 000000000..f132ba6f0 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/CMakeLists.txt @@ -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 index 000000000..4d4a9a3b1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/gnss_datatypes.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: gnss datatypes + * Author: + * Create: + */ +#ifndef GNSS_DATATYPES_H +#define GNSS_DATATYPES_H + +#include + +#define MSG_CONTENT_IDX 2 +#define LISTEN_TIME_THR 1000 +#define REPORT_MAX_BYTES 10000 + +// 消息类型 +typedef enum { + CMD_INJECT_HIS_INFO = 0x0101, // 历史信息注入 + CMD_PGNSS_INJECT_REF_GPS_TIME = 0x0201, // GPS时间注入 + CMD_PGNSS_INJECT_REF_LOC = 0x0202, // 参考位置注入 + CMD_PGNSS_INJECT_EPH_GPS = 0x0203, // GPS星历注入 + CMD_PGNSS_INJECT_EPH_GANSS = 0x0204, // 非GPS星历注入 + CMD_PGNSS_INJECT_UTC_GPS = 0x0205, // GPS UTC注入 + CMD_PGNSS_INJECT_RTI_GPS = 0x0206, // GPS完好性信息注入 + CMD_PGNSS_INJECT_RTI_GANSS = 0x0207, // 非GPS完好性信息注入 + CMD_PGNSS_INJECT_ION_GPS = 0x0208, // GPS电离层参数注入 + CMD_PGNSS_INJECT_AUX_GANSS = 0x0209, // 非GPS频点转换关系信息注入 + CMD_XGNSS_INJECT_UTC_TIME = 0x0404, // 最开始注入的UTC时间 + CMD_BUTT, +} GnssCmdType; + +#pragma pack(1) +typedef struct { + uint16_t cmd; // 消息类型 + uint16_t checkSum; // 校验和,只计算实际数据部分,不包含头 + uint16_t sequence; // 序列号,host下发 + uint16_t dataLength; // 数据长度,实际数据的长度,不包含头 + uint8_t data[0]; +} GnssMsg; + +typedef struct { + uint16_t year; // YYYY + uint8_t month; // MM, 1~12 + uint8_t day; // DD, 1~31 + uint8_t hour; // hh, 0~23 + uint8_t minute; // mm, 0~59 + uint8_t second; // ss, 0~59 + uint16_t ms; // ms, 0~999 + uint8_t valid; // 0: invalid, 1: valid +} GnssUtcTime; + +typedef struct { + uint32_t time; // eph reference time + uint16_t cmd; // cmd type to injected eph + uint32_t len; // actual length of injected eph +} EphHeadInfo; + +typedef struct { + uint16_t cmd; // cmd type to injected other assist info + uint32_t len; // actual length of injected other assist info +} OtherAssistHeadInfo; + +#pragma pack() + +#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 index 000000000..a4815e63d --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.c @@ -0,0 +1,589 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pgnss encode + * Author: + * Create: + */ +#include "pgnss_encode.h" +#include +#include +#include +#include "securec.h" +#include "tiot_service_interface.h" +#include "gnss_datatypes.h" + +#define GNSS_ENCODE_BUFF_MAX_LEN 9300 +#define FILE_PATH_LEN 1024 +#define GLO_EPH_VALID_TIME 900 +#define OTHER_EPH_VALID_TIME 7200 +#define ONE_CENTURY_YEARS 100 +#define FOUR_CENTURY_YEARS 400 +#define LEAP_YEAR_LENGTH 4 +#define UNIX_TIME_START_YEAR 1970 // start year of unix time +#define TIME_UNIT 1000 +#define SECONDS_PER_MIN (60) +#define SECONDS_PER_HOUR (60 * SECONDS_PER_MIN) +#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) +#define SECONDS_PER_NORMAL_YEAR (365 * SECONDS_PER_DAY) +#define NON_GLO_GNSS_TYPES 4 +#define GLO_EPH_NUM_ONE_FILE 8 +#define OTHER_ASSIST_TYPES 7 +#define INJECT_SLEEP_MS_TIME 500 +#define PGNSS_FILE_MAX_SIZE 1024000 + +/** days per month on normal and leap year */ +int32_t g_normMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +int32_t g_leapMonthDays[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +// 监听消息 +static uint8_t g_ackBuff[REPORT_MAX_BYTES] = { 0 }; + +/* 获取begin和end年份之间的闰年数 */ +int32_t GetLeapYearNum(uint16_t begin, uint16_t end) +{ + if (end <= begin || end < 1) { + return 0; + } + int32_t numPer400Year = (end - 1) / FOUR_CENTURY_YEARS - begin / FOUR_CENTURY_YEARS; + int32_t numPer100Year = (end - 1) / ONE_CENTURY_YEARS - begin / ONE_CENTURY_YEARS; + int32_t numPer4Year = (end - 1) / LEAP_YEAR_LENGTH - begin / LEAP_YEAR_LENGTH; + return (numPer400Year + numPer4Year - numPer100Year); +} + +/* 闰年判断 */ +int32_t CheckIfLeapYear(uint16_t year) +{ + if ((year % ONE_CENTURY_YEARS) == 0) { + if ((year % FOUR_CENTURY_YEARS) == 0) { + return 1; + } + } else { + if ((year % LEAP_YEAR_LENGTH) == 0) { + return 1; + } + } + return 0; +} + +/* 将日历时(年月日时分秒) 转换为 unix时间(1970å¹´1月1日起的时间秒数) */ +int32_t Utc2UnixTime(GnssUtcTime utcTime, uint32_t *unixTime) +{ + if (unixTime == NULL) { + printf("\nerror: [Utc2UnixTime] null pointer!\n"); + return 0; + } + + if (utcTime.month > 12 || utcTime.valid == 0) { + printf("\nerror: [Utc2UnixTime] utcTime invalid!\n"); + return 0; + } + + // 判断是否为闰年 + int32_t *monthDays = (CheckIfLeapYear(utcTime.year) == 1) ? g_leapMonthDays : g_normMonthDays; + + // 计算从1970.01.01开始的unix 秒数 + uint32_t timestamp = 0; + timestamp += (uint32_t)(utcTime.year - UNIX_TIME_START_YEAR) * SECONDS_PER_NORMAL_YEAR; + timestamp += (uint32_t)GetLeapYearNum(UNIX_TIME_START_YEAR, utcTime.year) * SECONDS_PER_DAY; + + for (int32_t i = 1; i < utcTime.month; i++) { + timestamp += (uint32_t)monthDays[i - 1] * SECONDS_PER_DAY; + } + + timestamp += (uint32_t)(utcTime.day - 1) * SECONDS_PER_DAY; + timestamp += (uint32_t)utcTime.hour * SECONDS_PER_HOUR; + timestamp += (uint32_t)utcTime.minute * SECONDS_PER_MIN; + uint32_t timestampSec = (uint32_t)(utcTime.second + utcTime.ms / TIME_UNIT); + + *unixTime = timestamp + timestampSec; + return 1; +} + +/* 计算命令内容校准和 */ +static uint16_t CalcChecksum(uint8_t *buff, uint16_t len) +{ + uint16_t checksum = 0; + uint16_t i = 0; + while (i++ < len) { + checksum += *buff; + buff++; + } + return checksum; +} + +int32_t PgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime, uint32_t* ts) +{ + uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN); + if (buff == NULL) { + printf("\nerror: malloc failed in PgnssINjectUtcTime\n"); + return 0; + } + memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN); + + GnssMsg *hdr = (GnssMsg *)buff; + hdr->cmd = 0x0404; + hdr->sequence = 0; + errno_t copyRet = memcpy_s(hdr->data, (GNSS_ENCODE_BUFF_MAX_LEN - sizeof(GnssMsg)), utcTime, sizeof(GnssUtcTime)); + if (copyRet != EOK) { + printf("\nmemcpy UtcTime failed! Errno is %d\n", copyRet); + free(buff); + return 0; + } + hdr->dataLength = sizeof(GnssUtcTime); + hdr->checkSum = CalcChecksum(hdr->data, hdr->dataLength); + int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + hdr->dataLength)); + if (ret < 0) { + printf("\nerror: PgnssInjectUtcTime error: %d\n", ret); + free(buff); + return 0; + } + if (Utc2UnixTime((*utcTime), ts) == 0) { + printf("\nerror: Utc2UnixTime error\n"); + free(buff); + return 0; + } + + free(buff); + return 1; +} + +static uint16_t FillGnssMessageData(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen) +{ + errno_t ret = memcpy_s(outBuff, outLen, inBuff, inLen); + if (ret != EOK) { + printf("memcpy XgnssData failed! Errno is %d", ret); + return 0; + } + + return inLen; +} + +static int32_t EncodeGnssMsg(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen) +{ + uint16_t len = FillGnssMessageData(inBuff, inLen, outBuff, outLen); + if (len > 0) { + return 1; + } + return 0; +} + +static void ListenAck(tiot_handle handle) +{ + int32_t i = 0; + for (;;) { + // 监听 + int32_t ret = tiot_service_read(handle, g_ackBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_ackBuff; + // 二进制消息类型 + if (type[0] == 0) { + g_ackBuff[ret] = '\0'; + printf("%s\n", (char *)&g_ackBuff[MSG_CONTENT_IDX]); + } + i++; + } + if (i >= 1) { + printf("\ncnt enough\n"); + break; + } + } +} + +static int32_t EncodeAndInjectCmd(tiot_handle handle, GnssCmdType cmdType, uint8_t* inBuff, uint32_t inLen) +{ + // 获取GNSS业务消息头 + int32_t len = 0; + uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN); + if (buff == NULL) { + printf("\nerror: malloc failed in EncodeAndInjectCmd\n"); + return 0; + } + memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN); + + GnssMsg *gnssHdr = (GnssMsg *)buff; + len += sizeof(GnssMsg); + + gnssHdr->sequence = 0; + + int32_t retLen = EncodeGnssMsg(inBuff, inLen, buff + len, (GNSS_ENCODE_BUFF_MAX_LEN - len)); + if (retLen != 1) { + printf("\nerror: Encode Cmd failed: %d\n", cmdType); + free(buff); + return retLen; + } + gnssHdr->cmd = cmdType; + gnssHdr->dataLength = inLen; + gnssHdr->checkSum = CalcChecksum(gnssHdr->data, gnssHdr->dataLength); + int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + gnssHdr->dataLength)); + if (ret < 0) { + printf("\nerror: Inject Cmd failed: %d\n", cmdType); + free(buff); + return 0; + } + ListenAck(handle); + printf("\nInject Cmd SUCCESS: %x\n", cmdType); + free(buff); + return 1; +} + +void PgnssSendFileContent(tiot_handle handle, const char *fileName, GnssCmdType cmdType) +{ + FILE *fp = fopen(fileName, "rb"); + if (fp == NULL) { + printf("\nerror: open file failed: %s\n", fileName); + return; + } + fseek(fp, 0, SEEK_END); + int32_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (len < 0 || len > PGNSS_FILE_MAX_SIZE) { + fclose(fp); + printf("\nerror: get file len failed: %s\n", fileName); + return; + } + uint8_t *buff = (uint8_t *)malloc(len); + if (buff == NULL) { + fclose(fp); + printf("\nerror: malloc file len failed: %s\n", fileName); + return; + } + int32_t dataSize = fread(buff, len, 1, fp); + if (dataSize < 0) { + fclose(fp); + printf("\nerror: read file failed: %s\n", fileName); + free(buff); + return; + } + fclose(fp); + EncodeAndInjectCmd(handle, cmdType, buff, len); + free(buff); +} + +int32_t FormatFileName(char *fileName, char *dName) +{ + int32_t ret = snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%s", "/user/xgnss/", dName); + if (ret <= 0) { + return 0; + } + return 1; +} + +int32_t GetEphFileName(int32_t ts, const char *prefix, char *fileName) +{ + int32_t interval = (strcmp(prefix, "GLO") == 0) ? GLO_EPH_VALID_TIME : OTHER_EPH_VALID_TIME; + DIR *dir = opendir("/user/xgnss/"); + if (dir == NULL) { + printf("Failed to open /user/xgnss directory.\n"); + return 0; + } + int32_t time, ret; + struct dirent *entry; + for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) { + // 检查文件名 + if (strstr(entry->d_name, ".eph") != NULL) { + char *p = strrchr(entry->d_name, '_'); + if (p != NULL) { + char *q = strstr(entry->d_name, prefix); + if (q != NULL) { + time = atoi(p + 1); + if (abs(time - ts) <= interval) { + ret = FormatFileName(fileName, entry->d_name); + closedir(dir); + return ret; + } + } + } + } + } + closedir(dir); + return 0; +} + +void PgnssSendEphFile(tiot_handle handle, const char *prefix, GnssCmdType cmdType, uint32_t ts) +{ + char fileName[FILE_PATH_LEN] = {0}; + int32_t ret = GetEphFileName(ts, prefix, fileName); + if (ret == 0) { + printf("\nerror: GetEphFileName failed\n"); + return; + } + printf("\nGetEphFileName success\n"); + PgnssSendFileContent(handle, fileName, cmdType); +} + +void PgnssInjectAllEph(tiot_handle handle, uint32_t ts) +{ + PgnssSendEphFile(handle, "GPS", CMD_PGNSS_INJECT_EPH_GPS, ts); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GPS eph success\n"); + PgnssSendEphFile(handle, "GLO", CMD_PGNSS_INJECT_EPH_GANSS, ts); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GLO eph success\n"); + PgnssSendEphFile(handle, "BDS", CMD_PGNSS_INJECT_EPH_GANSS, ts); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send BDS eph success\n"); + PgnssSendEphFile(handle, "GAL", CMD_PGNSS_INJECT_EPH_GANSS, ts); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GAL eph success\n"); + PgnssSendEphFile(handle, "QZS", CMD_PGNSS_INJECT_EPH_GANSS, ts); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send QZS eph success\n"); +} + +void PgnssInjectOtherAssist(tiot_handle handle) +{ + PgnssSendFileContent(handle, "/user/xgnss/GPS_UTC.dat", CMD_PGNSS_INJECT_UTC_GPS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GPS_UTC success\n"); + PgnssSendFileContent(handle, "/user/xgnss/GPS_RTI.dat", CMD_PGNSS_INJECT_RTI_GPS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GPS_RTI success\n"); + PgnssSendFileContent(handle, "/user/xgnss/GPS_ION.dat", CMD_PGNSS_INJECT_ION_GPS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GPS_ION success\n"); + PgnssSendFileContent(handle, "/user/xgnss/GLO_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GLO_RTI success\n"); + PgnssSendFileContent(handle, "/user/xgnss/GLO_AUX.dat", CMD_PGNSS_INJECT_AUX_GANSS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GLO_AUX success\n"); + PgnssSendFileContent(handle, "/user/xgnss/BDS_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send BDS_RTI success\n"); + PgnssSendFileContent(handle, "/user/xgnss/GAL_RTI.dat", CMD_PGNSS_INJECT_RTI_GANSS); + osal_msleep(INJECT_SLEEP_MS_TIME); + printf("send GAL_RTI success\n"); +} + +void PgnssInject(tiot_handle handle, uint32_t ts) +{ + // 注入Pgnss辅助数据 + PgnssInjectAllEph(handle, ts); + PgnssInjectOtherAssist(handle); +} + + +// 以下为使用PGNSS解析数据合并输出接口生成的星历文件进行注入的代码 +int32_t GetNonGloEphFileName(int32_t ts, char *fileName) +{ + const char prefix[] = "NonGlo"; + DIR *dir = opendir("/user/xgnss/"); + if (dir == NULL) { + printf("Failed to open /user/xgnss directory.\n"); + return 0; + } + int32_t time, ret; + int32_t minDist = OTHER_EPH_VALID_TIME; + int32_t closestTime = 0; + struct dirent *entry; + for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) { + // 检查文件名 + if (strstr(entry->d_name, ".eph") != NULL) { + char *p = strrchr(entry->d_name, '_'); + if (p != NULL) { + char *q = strstr(entry->d_name, prefix); + if (q != NULL) { + time = atoi(p + 1); + // 查找星历文件时间戳与当前时间相差2小时以内且距离最近的 + if (abs(time - ts) < minDist) { + minDist = abs(time - ts); + closestTime = time; + } + } + } + } + } + if (closestTime != 0) { + ret = snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%d%s", "/user/xgnss/NonGlo_", closestTime, + ".eph"); + printf("closest eph fileName:%s\n", fileName); + closedir(dir); + return ((ret <= 0) ? 0 : 1); + } + closedir(dir); + return 0; +} + +int32_t GetGloEphFileName(int32_t ts, char *fileName) +{ + const char prefix[] = "GLO"; + DIR *dir = opendir("/user/xgnss/"); + if (dir == NULL) { + printf("Failed to open /user/xgnss directory.\n"); + return 0; + } + int32_t ephTime, ret; + struct dirent *entry; + for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) { + // 检查文件名 + if (strstr(entry->d_name, ".eph") != NULL) { + char *p = strrchr(entry->d_name, '_'); + if (p != NULL) { + char *q = strstr(entry->d_name, prefix); + if (q != NULL) { + ephTime = atoi(p + 1); + printf("ephTime:%ld, ts:%ld\n", ephTime, ts); + // 当前时间大于GLO星历文件时间戳,则需要选取相差2小时以内的星历 + // 当前时间小于GLO星历文件时间戳,则需要选取相差小于15分钟的星历 + if (((ts - ephTime) >= 0 && abs(ephTime - ts) < OTHER_EPH_VALID_TIME) || + ((ts - ephTime) <= 0 && abs(ephTime - ts) < GLO_EPH_VALID_TIME)) { + ret = FormatFileName(fileName, entry->d_name); + printf("glo eph fileName:%s\n", fileName); + closedir(dir); + return ret; + } + } + } + } + } + closedir(dir); + return 0; +} + +void PgnssSendNonGloEph(tiot_handle handle, const char *fileName) +{ + FILE *fp = fopen(fileName, "rb"); + if (fp == NULL) { + printf("\nerror: open file failed: %s\n", fileName); + return; + } + fseek(fp, 0, SEEK_END); + int32_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (len < 0 || len > PGNSS_FILE_MAX_SIZE) { + fclose(fp); + printf("\nerror: get file len failed: %s\n", fileName); + return; + } + uint8_t *buff = (uint8_t *)malloc(len); + if (buff == NULL) { + fclose(fp); + printf("\nerror: malloc file len failed: %s\n", fileName); + return; + } + int32_t dataSize = fread(buff, len, 1, fp); + if (dataSize < 0) { + fclose(fp); + printf("\nerror: read file failed: %s\n", fileName); + free(buff); + return; + } + fclose(fp); + int32_t fileLen = 0; + for (int32_t i = 0; i < NON_GLO_GNSS_TYPES && fileLen <= len; i++) { + EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen); + EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len); + fileLen += (ephHdr->len + sizeof(EphHeadInfo)); + osal_msleep(INJECT_SLEEP_MS_TIME); + } + free(buff); +} + +void PgnssSendGloEph(tiot_handle handle, const char *fileName, int32_t ts) +{ + FILE *fp = fopen(fileName, "rb"); + if (fp == NULL) { + printf("\nerror: open file failed: %s\n", fileName); + return; + } + fseek(fp, 0, SEEK_END); + int32_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (len < 0 || len > PGNSS_FILE_MAX_SIZE) { + fclose(fp); + printf("\nerror: get file len failed: %s\n", fileName); + return; + } + uint8_t *buff = (uint8_t *)malloc(len); + if (buff == NULL) { + fclose(fp); + printf("\nerror: malloc file len failed: %s\n", fileName); + return; + } + int32_t dataSize = fread(buff, len, 1, fp); + if (dataSize < 0) { + fclose(fp); + printf("\nerror: read file failed: %s\n", fileName); + free(buff); + return; + } + fclose(fp); + int32_t fileLen = 0; + for (int32_t i = 0; i < GLO_EPH_NUM_ONE_FILE && fileLen <= len; i++) { + EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen); + printf("glo eph, time:%u, ts:%d\n", ephHdr->time, ts); + if (abs((int32_t)ephHdr->time - ts) < GLO_EPH_VALID_TIME) { + EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len); + osal_msleep(INJECT_SLEEP_MS_TIME); + break; + } + fileLen += (ephHdr->len + sizeof(EphHeadInfo)); + } + free(buff); +} + +void PgnssInjectAllEphLessFiles(tiot_handle handle, uint32_t ts) +{ + char fileName[FILE_PATH_LEN] = {0}; + if (GetNonGloEphFileName(ts, fileName) == 0) { + printf("\nerror: GetNonGloEphFileName failed\n"); + return; + } + PgnssSendNonGloEph(handle, fileName); + if (GetGloEphFileName(ts, fileName) == 0) { + printf("\nerror: GetGloEphFileName failed\n"); + return; + } + PgnssSendGloEph(handle, fileName, ts); +} + +void PgnssSendOtherAssistInfo(tiot_handle handle, const char *fileName) +{ + FILE *fp = fopen(fileName, "rb"); + if (fp == NULL) { + printf("\nerror: open file failed: %s\n", fileName); + return; + } + fseek(fp, 0, SEEK_END); + int32_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (len < 0 || len > PGNSS_FILE_MAX_SIZE) { + fclose(fp); + printf("\nerror: get file len failed: %s\n", fileName); + return; + } + uint8_t *buff = (uint8_t *)malloc(len); + if (buff == NULL) { + fclose(fp); + printf("\nerror: malloc file len failed: %s\n", fileName); + return; + } + int32_t dataSize = fread(buff, len, 1, fp); + if (dataSize < 0) { + fclose(fp); + printf("\nerror: read file failed: %s\n", fileName); + free(buff); + return; + } + fclose(fp); + int32_t fileLen = 0; + for (int32_t i = 0; i < OTHER_ASSIST_TYPES && fileLen <= len; i++) { + OtherAssistHeadInfo *otherHdr = (OtherAssistHeadInfo *)(buff + fileLen); + EncodeAndInjectCmd(handle, otherHdr->cmd, (buff + fileLen + sizeof(OtherAssistHeadInfo)), otherHdr->len); + fileLen += (otherHdr->len + sizeof(OtherAssistHeadInfo)); + osal_msleep(INJECT_SLEEP_MS_TIME); + } + free(buff); +} + +void PgnssInjectOtherAssistLessFiles(tiot_handle handle) +{ + PgnssSendOtherAssistInfo(handle, "/user/xgnss/AssistInfo.dat"); +} + +// 注入PGNSS解析数据合并输出接口生成的星历文件 +void PgnssInjectLessFiles(tiot_handle handle, uint32_t ts) +{ + // 注入Pgnss辅助数据 + PgnssInjectAllEphLessFiles(handle, ts); + PgnssInjectOtherAssistLessFiles(handle); +} \ 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 index 000000000..a666edc91 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_encode.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pgnss encode + * Author: + * Create: + */ +#ifndef PGNSS_ENCODE_H +#define PGNSS_ENCODE_H + +#include "gnss_datatypes.h" +#include "tiot_service_interface.h" + +int32_t PgnssInjectUtcTime(tiot_handle handle, GnssUtcTime *utcTime, uint32_t* ts); +void PgnssInject(tiot_handle handle, uint32_t ts); +void PgnssInjectLessFiles(tiot_handle handle, uint32_t ts); +#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 index 000000000..21bd3355a --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pgnss sample + * Author: + * Create: + */ +#include "pgnss_sample.h" +#include +#include "securec.h" +#include "tiot_service_interface.h" +#include "pm_definition.h" +#include "gnss_datatypes.h" +#include "pgnss_encode.h" + +#define PGNSS_FIXMODEALL_NMEADEF_SAMPLE 0 +#define PGNSS_LESS_FILES_FIXMODEALL_NMEADEF_SAMPLE 1 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif +#define MSG_TYPE_BINRY 0 +#define MSG_TYPE_ASCII 1 +#define LISTEN_DATA_MAX_LINES 1000 + +static FILE* g_gnssLogFp = NULL; +static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 }; + +typedef int32_t (*GnssCfgFunc)(tiot_handle handle); + +typedef struct { + uint16_t sampleId; + GnssCfgFunc cfgHandle; +} GnssSamplesCfgTable; + +static int32_t QryVersion(tiot_handle handle) +{ + const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; + // 查询版本号 + int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion)); + if (ret < 0) { + printf("\nerror: QryVersion error: %d\n", ret); + return 0; + } + return 1; +} + +// 注入PGNSS,使用默认配置启动 +int32_t InjectPgnssCfgAutoStartFixModeAndNmeaDefault(tiot_handle handle) +{ + const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03}; + + // 配置log级别:info级别。 + int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo)); + if (ret < 0) { + printf("\nerror: cfgLogLevelInfo error: %d\n", ret); + return 0; + } + + // 注入UTC时间, 注入Pgnss辅助数据前必须先注入参考时间 + GnssUtcTime utcTime = {2024, 2, 26, 6, 0, 0, 0, 1}; // 需要用当前的UTC时间替换 + uint32_t ts = 0; + ret = PgnssInjectUtcTime(handle, &utcTime, &ts); + if (ret == 0) { + printf("\nerror: PgnssInjectUtcTime failed!\n"); + return 0; + } + printf("\nPgnssInjectUtcTime success!\n"); + + // PGNSS注入 + // 注意,默认PGNSS星历文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换 + PgnssInject(handle, ts); + + return 1; +} + +// 注入PGNSS,使用默认配置启动 +int32_t InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault(tiot_handle handle) +{ + const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03}; + + // 配置log级别:info级别。 + int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo)); + if (ret < 0) { + printf("\nerror: cfgLogLevelInfo error: %d\n", ret); + return 0; + } + + // 注入UTC时间, 注入Pgnss辅助数据前必须先注入参考时间 + GnssUtcTime utcTime = {2024, 3, 14, 12, 0, 0, 0, 1}; // 需要用当前的UTC时间替换 + uint32_t ts = 0; + ret = PgnssInjectUtcTime(handle, &utcTime, &ts); + if (ret == 0) { + printf("\nerror: PgnssInjectUtcTime failed!\n"); + return 0; + } + printf("\nPgnssInjectUtcTime success!\n"); + + // PGNSS注入 + // 注意,默认PGNSS星历文件存放在/user/xgnss/目录中,如修改目录,请全局搜索替换 + PgnssInjectLessFiles(handle, ts); + + return 1; +} + +static const GnssSamplesCfgTable g_gnssSamplesCfg[] = { + {PGNSS_FIXMODEALL_NMEADEF_SAMPLE, InjectPgnssCfgAutoStartFixModeAndNmeaDefault}, + {PGNSS_LESS_FILES_FIXMODEALL_NMEADEF_SAMPLE, InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault} +}; + +static int32_t StartGnss(tiot_handle handle) +{ + const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 启动GNSS + int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd)); + if (ret < 0) { + printf("\nerror: start gnss error: %d\n", ret); + return 0; + } + printf("\nstart gnss\n"); + return 1; +} + +static int32_t StopGnss(tiot_handle handle) +{ + const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 停止GNSS + int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd)); + if (ret < 0) { + printf("\nerror: stop gnss error: %d\n", ret); + return 0; + } + printf("\nstop gnss\n"); + return 1; +} + +static void ListenGnssData(tiot_handle handle) +{ + int32_t i = 0; + // 写日志 + for (;;) { // 写日志条件 + // 监听 + int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_gnssServiceBuff; + if (type[0] == MSG_TYPE_ASCII) { + g_gnssServiceBuff[ret] = '\0'; + printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + } + i++; + } + if (i >= LISTEN_DATA_MAX_LINES) { + printf("\ncnt enough\n"); + break; + } + } +} + +void PgnssExecuteSamples(void) +{ + uapi_pm_add_sleep_veto(PM_ID_SYS); + printf("\nenter gnss samples\n"); + // Step1: init + int32_t ret = tiot_service_init(); + if (ret != 0) { + printf("\ntiot service init fail\n"); + } + + // 打开日志文件 + g_gnssLogFp = fopen("/user/gnss.log", "w"); + if (g_gnssLogFp == NULL) { + printf("\nerror: open log file error\n"); + return; + } + printf("\nbefore open tiot service\n"); + + // Step2: power on gnss + tiot_handle handle = tiot_service_open("gn71", NULL); + if (handle == 0) { + printf("\nopen tiot service fail\n"); + return; + } + printf("\nopen tiot service success\n"); + + int32_t cfgRet; + // ---- loop ---------- + for (uint16_t i = 0; i < ARRAY_SIZE(g_gnssSamplesCfg); i++) { + cfgRet = 0; + if (g_gnssSamplesCfg[i].sampleId == i) { + // Step3: config gnss + if (g_gnssSamplesCfg[i].cfgHandle != NULL) { + cfgRet = g_gnssSamplesCfg[i].cfgHandle(handle); + } + if (cfgRet == 0) { + continue; + } + printf("\ncfg sample id:%u\n", g_gnssSamplesCfg[i].sampleId); + QryVersion(handle); + + // Step4: start gnss + if (StartGnss(handle) == 0) { + continue; + } + // Step5: listening gnss data + ListenGnssData(handle); + // Step6: stop gnss + if (StopGnss(handle) == 0) { + continue; + } + } + } + // --------------------- + // Step7: power off gnss + tiot_service_close(handle); + // 关日志文件 + fclose(g_gnssLogFp); + g_gnssLogFp = NULL; + // Step8: deinit + tiot_service_deinit(); + uapi_pm_remove_sleep_veto(PM_ID_SYS); + printf("\nfinish gnss samples\n"); +} \ 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 index 000000000..b274e1ee1 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/pgnss_sample/pgnss_sample.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pgnss sample + * Author: + * Create: + */ +#ifndef PGNSS_SAMPLE_H +#define PGNSS_SAMPLE_H + +void PgnssExecuteSamples(void); + +#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 index 000000000..48579a01a --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/CMakeLists.txt @@ -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 index 000000000..51c563165 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/gnss_datatypes.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: gnss datatypes + * Author: + * Create: + */ +#ifndef GNSS_DATATYPES_H +#define GNSS_DATATYPES_H + +#include + +#define MSG_CONTENT_IDX 2 + +// 消息类型 +typedef enum { + CMD_INJECT_HIS_INFO = 0x0101, // 历史信息注入 + CMD_PGNSS_INJECT_REF_GPS_TIME = 0x0201, // GPS时间注入 + CMD_PGNSS_INJECT_REF_LOC = 0x0202, // 参考位置注入 + CMD_PGNSS_INJECT_EPH_GPS = 0x0203, // GPS星历注入 + CMD_PGNSS_INJECT_EPH_GANSS = 0x0204, // 非GPS星历注入 + CMD_PGNSS_INJECT_UTC_GPS = 0x0205, // GPS UTC注入 + CMD_PGNSS_INJECT_RTI_GPS = 0x0206, // GPS完好性信息注入 + CMD_PGNSS_INJECT_RTI_GANSS = 0x0207, // 非GPS完好性信息注入 + CMD_PGNSS_INJECT_ION_GPS = 0x0208, // GPS电离层参数注入 + CMD_PGNSS_INJECT_AUX_GANSS = 0x0209, // 非GPS频点转换关系信息注入 + CMD_XGNSS_INJECT_UTC_TIME = 0x0404, // 最开始注入的UTC时间 + CMD_BUTT, +} GnssCmdType; + +#pragma pack(1) +typedef struct { + uint16_t cmd; // 消息类型 + uint16_t checkSum; // 校验和,只计算实际数据部分,不包含头 + uint16_t sequence; // 序列号,host下发 + uint16_t dataLength; // 数据长度,实际数据的长度,不包含头 + uint8_t data[0]; +} GnssMsg; + +typedef struct { + uint16_t year; // YYYY + uint8_t month; // MM, 1~12 + uint8_t day; // DD, 1~31 + uint8_t hour; // hh, 0~23 + uint8_t minute; // mm, 0~59 + uint8_t second; // ss, 0~59 + uint16_t ms; // ms, 0~999 + uint8_t valid; // 0: invalid, 1: valid +} GnssUtcTime; + +typedef struct { + uint32_t time; // eph reference time + uint16_t cmd; // cmd type to injected eph + uint32_t len; // actual length of injected eph +} EphHeadInfo; + +typedef struct { + uint16_t cmd; // cmd type to injected other assist info + uint32_t len; // actual length of injected other assist info +} OtherAssistHeadInfo; + +typedef struct { + uint16_t cmd; + uint16_t status; +} GnssAck; +#pragma pack() + +#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 index 000000000..60cc00d1f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pdr sample. 本文件中的魔鬼数字均是示例的输入。 + */ + +#include "pdr_sample.h" +#include +#include "securec.h" +#include "tiot_service_interface.h" +#include "pm_definition.h" +#include "gnss_datatypes.h" +#include "pdr_interface.h" + +#define ONE_LINE_SIZE 500 +#define SENSOR_AXIS_X 0 +#define SENSOR_AXIS_Y 1 +#define SENSOR_AXIS_Z 2 +#define SENSOR_AXIS_NUM 3 +#define ACC_TYPE 1 +#define GYRO_TYPE 2 +#define MSG_TYPE_BINRY 0 +#define MSG_TYPE_ASCII 1 +#define SLEEP_TIME 1000 +#define EXECUTE_MAX_TIMES 1000 +#define LISTEN_TIME_THR 1000 +#define REPORT_MAX_BYTES 10000 +#define REPORT_GNSS_LOC_CMD 0x1002 +#define REPORT_PDR_COMN_CMD 0x100b +#define REPORT_REPLAY_CMD 0xf001 +#define ACK_CMD 0xff01 + +static uint8_t g_gnssServiceBuff[REPORT_MAX_BYTES] = { 0 }; +static tiot_handle g_handle = 0; +static uint8_t g_isGnssLoc = 0; +static uint8_t g_isPdrComn = 0; +static FILE* g_sensorFile = NULL; +static FILE* g_gnssFile = NULL; + +static void ListenAck(tiot_handle handle) +{ + int32_t i = 0; + for (;;) { + // 监听 + int32_t ret = tiot_service_read(handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_gnssServiceBuff; + // 二进制消息类型 + if (type[0] == 0) { + g_gnssServiceBuff[ret] = '\0'; + } + i++; + } + if (i >= 1) { + printf("\ncnt enough\n"); + break; + } + } +} + +// sensor数据从文件读取。每行对应一个采样时刻,依次为x/y/z轴数据。加速度计单位:m/s2,陀螺仪单位:rad/s +static bool AssembleSensorData(SensorData *sensorSet, uint8_t sensorType) +{ + FILE *fp; + if (sensorType == ACC_TYPE) { + fp = fopen("/user/pdr_sample_acc.txt", "r"); + } else if (sensorType == GYRO_TYPE) { + fp = fopen("/user/pdr_sample_gyro.txt", "r"); + } else { + printf("SENSOR TYPE ERR\n"); + return false; + } + + if (fp == NULL) { + printf("OPEN SENSOR FILE ERR\n"); + return false; + } + + char buff[ONE_LINE_SIZE] = {0}; + int i = 0; + int j = 0; + float num[SENSOR_AXIS_NUM] = {0.0}; + char *token = NULL; + char *nextToken = NULL; + + while (fgets(buff, ONE_LINE_SIZE, fp) != NULL) { + token = strtok_s(buff, " ", &nextToken); + j = 0; + while (token != NULL) { + if (j >= SENSOR_AXIS_NUM) { + (void)fclose(fp); + return false; + } + num[j] = atof(token); + token = strtok_s(NULL, " ", &nextToken); + j++; + } + if (j != SENSOR_AXIS_NUM) { + printf("SENSOR AXIS NUM ERR\n"); + (void)fclose(fp); + return false; + } + + sensorSet->sensors[i].timestamp = 1679389794007 + 10 * (int64_t)i; + sensorSet->sensors[i].x = num[SENSOR_AXIS_X]; + sensorSet->sensors[i].y = num[SENSOR_AXIS_Y]; + sensorSet->sensors[i].z = num[SENSOR_AXIS_Z]; + sensorSet->sensors[i].status = 0; + i++; + } + sensorSet->cnt = i; + (void)fclose(fp); + return true; +} + +static void AssembleGnssData(GnssLocInfo *locInfo, GnssPdrCommInfo *gnssState) +{ + locInfo->timestamp = 1679389795000; + locInfo->flags = 63; + locInfo->longitude = 1825717451; + locInfo->latitude = 573764623; + locInfo->clkBias = 18578227782; + locInfo->clkDrift = 928111185; + locInfo->altitude = 381.298279; + locInfo->speede = -510312; + locInfo->speedn = -1449305; + locInfo->speedu = 36950; + locInfo->heading = 3.480144; + locInfo->posAcc = 3.834757; + locInfo->speedAcc = 1.2345; + + gnssState->context = 6; + gnssState->isStatic = 0; + gnssState->pvtState = 1; + gnssState->ems = 3.710260; + gnssState->hdop = 0.663898; + gnssState->inuseNum = 21; + gnssState->qop = 3.834757; +} + +int32_t CfgReportAndStartGnss(tiot_handle handle) +{ + const uint8_t cfgRptGnssLocCmd[] = {0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02}; + const uint8_t cfgRptPdrComnCmd[] = {0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0e, 0x10, 0x01, 0x00, 0x01}; + const uint8_t cfgCloseNmeaCmd[] = {0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x00, 0x00}; + const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + // 配置上报GNSS定位信息 + int32_t ret = tiot_service_write(handle, cfgRptGnssLocCmd, sizeof(cfgRptGnssLocCmd)); + if (ret < 0) { + printf("error: cfg report gnss location error: %d\n", ret); + return 0; + } + ListenAck(handle); + // 配置上报PDR COMMON信息 + ret = tiot_service_write(handle, cfgRptPdrComnCmd, sizeof(cfgRptPdrComnCmd)); + if (ret < 0) { + printf("error: cfg report pdr common error: %d\n", ret); + return 0; + } + ListenAck(handle); + // 配置关闭NMEA消息输出(避免每秒上报过多消息,导致获取sensor数据的短时间内就撑满消息队列) + ret = tiot_service_write(handle, cfgCloseNmeaCmd, sizeof(cfgCloseNmeaCmd)); + if (ret < 0) { + printf("error: cfg close nmea error: %d\n", ret); + return 0; + } + ListenAck(handle); + // 启动GNSS + ret = tiot_service_write(handle, startCmd, sizeof(startCmd)); + if (ret < 0) { + printf("error: start gnss error: %d\n", ret); + return 0; + } + ListenAck(handle); + printf("start gnss\n"); + return 1; +} + +int32_t GnssStartAndReport(void) +{ + printf("enter gnss samples\n"); + // Step1: init + int32_t ret = tiot_service_init(); + if (ret != 0) { + printf("tiot service init fail\n"); + return 0; + } + + // Step2: power on gnss + g_handle = tiot_service_open("gn71", NULL); + if (g_handle == 0) { + printf("open tiot service fail\n"); + return 0; + } + printf("open tiot service success\n"); + + // Step3: cfg report and start gnss + if (CfgReportAndStartGnss(g_handle) == 0) { + printf("CfgReportAndStartGnss fail\n"); + return 0; + } + return 1; +} + +void DecodeAndAssembleGnssLoc(const uint8_t *buff, uint32_t len, GnssLocInfo *locInfo) +{ + if (len != sizeof(GnssLocInfo)) { + printf("DecodeAndAssembleGnssLoc: len=%u expect=%u\n", len, sizeof(GnssLocInfo)); + return; + } + (void)memcpy_s(locInfo, sizeof(GnssLocInfo), buff, sizeof(GnssLocInfo)); + g_isGnssLoc = 1; +} + +void DecodeAndAssemblePdrComn(const uint8_t *buff, uint32_t len, GnssPdrCommInfo *pdrComn) +{ + if (len != sizeof(GnssPdrCommInfo)) { + printf("DecodeAndAssemblePdrComn: len=%u expect=%u\n", len, sizeof(GnssPdrCommInfo)); + return; + } + (void)memcpy_s(pdrComn, sizeof(GnssPdrCommInfo), buff, sizeof(GnssPdrCommInfo)); + g_isPdrComn = 1; +} + +void DecodeTimeSyncAck(const uint8_t *buff, uint32_t len) +{ + if (len != sizeof(GnssAck)) { + printf("DecodeTimeSyncAck failed: len:%u, expect:%u\n", len, sizeof(GnssAck)); + return; + } + GnssAck *ack = (GnssAck*)buff; + if (ack->cmd != 0x3 || ack->status != 0x0) { + printf("DecodeTimeSyncAck failed: cmd:%x, statuc:%x\n", ack->cmd, ack->status); + return; + } + // 接收到时间校准的ACK + // 记录此时MCU的时间戳,即可根据芯片上报的deltaTime得到芯片上报对应的MCU时间 +} + +// buff指向GnssMsg类型,len为GnssMsg包长度 +void DecodeBinaryGnss(const uint8_t *buff, GnssRptRslt *gnssRptRslt) +{ + GnssMsg *msg = (GnssMsg*)buff; + printf("DecodeBinaryGnss: gnss msg type:%x, len:%u\n", msg->cmd, msg->dataLength); + if (msg->cmd == REPORT_PDR_COMN_CMD) { // PDR COMMON信息 + DecodeAndAssemblePdrComn(buff + sizeof(GnssMsg), msg->dataLength, &(gnssRptRslt->gnssState)); + } else if (msg->cmd == REPORT_GNSS_LOC_CMD) { // GNSS定位信息 + g_isGnssLoc = 0; + g_isPdrComn = 0; + (void)memset_s(gnssRptRslt, sizeof(GnssRptRslt), 0, sizeof(GnssRptRslt)); + DecodeAndAssembleGnssLoc(buff + sizeof(GnssMsg), msg->dataLength, &(gnssRptRslt->locInfo)); + } else if (msg->cmd == ACK_CMD) { // GNSS回ACK信息 + DecodeTimeSyncAck(buff + sizeof(GnssMsg), msg->dataLength); + } +} + +void PdrDemo(void) +{ + // 1.获取PDR版本号 + printf("PDR VERSION: %s\n", GetPdrVersion()); + + // 2.初始化PDR。仅在开始调用一次。 + int32_t initRetVal = InitPdrFusion(); + if (initRetVal != RET_OK) { + printf("PDR INIT ERR\n"); + return; + } + + // 3.获取sensor和gnss数据,执行PDR主流程。每秒调用一次。 + EpochSensorData *sensorData = (EpochSensorData *)malloc(sizeof(EpochSensorData)); + if (sensorData == NULL) { + printf("SENSOR DATA MALLOC ERR"); + return; + } + + (void)memset_s(sensorData, sizeof(EpochSensorData), 0, sizeof(EpochSensorData)); + GnssRptRslt gnssRptRslt; + PdrResult pdrRslt; + (void)memset_s(&gnssRptRslt, sizeof(gnssRptRslt), 0, sizeof(gnssRptRslt)); + (void)memset_s(&pdrRslt, sizeof(pdrRslt), 0, sizeof(pdrRslt)); + + sensorData->sensorSts = SENSOR_SYNC_SUCC; + sensorData->utcMs = 1679389795000; + // 获取100Hz acc数据 + bool isAccSucc = AssembleSensorData(&sensorData->sensorDataSet.accl, ACC_TYPE); + if (!isAccSucc) { + printf("ACC DATA ERR\n"); + free(sensorData); + return; + } + // 获取100Hz gyro数据 + bool isGyroSucc = AssembleSensorData(&sensorData->sensorDataSet.gyro, GYRO_TYPE); + if (!isGyroSucc) { + printf("GYRO DATA ERR\n"); + free(sensorData); + return; + } + + // 获取gnss数据 + AssembleGnssData(&gnssRptRslt.locInfo, &gnssRptRslt.gnssState); + + // PDR融合 + int32_t execRetVal = ExecutePdrFusion(sensorData, &gnssRptRslt, &pdrRslt); + if (execRetVal == RET_OK) { + printf("PDR SUCCESS. time: %llu, valid: %d, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f\n", + pdrRslt.timeStampMs, + pdrRslt.posLla.valid, pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt, + pdrRslt.speed, pdrRslt.heading); + } else { + printf("PDR ERR. CODE: %d\n", execRetVal); + } + + // 4.停止PDR。仅在结束调用一次。 + int32_t quitRetVal = QuitPdrFusion(); + if (quitRetVal != RET_OK) { + printf("PDR QUIT ERR\n"); + } + free(sensorData); +} + +void GetSensorData(EpochSensorData *sensorData) +{ + // 获取时间戳与sensor状态 + // 获取100Hz acc数据 + // 获取100Hz gyro数据 + return; +} + +void InjectSensorTimeSyncCmd(tiot_handle handle) +{ + const uint8_t cfgSyncCmd[] = {0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x10, 0x01, 0x00, 0x01}; + int32_t ret = tiot_service_write(handle, cfgSyncCmd, sizeof(cfgSyncCmd)); + if (ret < 0) { + printf("error: cfg sync cmd error: %d\n", ret); + return; + } + return; +} + +void PdrDemoRealTime(void) +{ + uapi_pm_add_sleep_veto(PM_ID_SYS); + // 1.获取PDR版本号 + printf("PDR VERSION: %s\n", GetPdrVersion()); + + // 2.初始化PDR。仅在开始调用一次。 + int32_t initRetVal = InitPdrFusion(); + if (initRetVal != RET_OK) { + printf("PDR INIT ERR\n"); + return; + } + + EpochSensorData *sensorData = (EpochSensorData *)malloc(sizeof(EpochSensorData)); + if (sensorData == NULL) { + printf("SENSOR DATA MALLOC ERR"); + return; + } + + // 3.配置上报信息并启动GNSS + if (GnssStartAndReport() == 0) { + free(sensorData); + printf("GnssStartAndReport fail\n"); + return; + } + + g_sensorFile = fopen("/user/pdr_data.bin", "wb"); + if (g_sensorFile == NULL) { + free(sensorData); + printf("OPEN REPLAY FILE ERR\n"); + return; + } + g_gnssFile = fopen("/user/gnss_data.bin", "wb"); + if (g_gnssFile == NULL) { + free(sensorData); + (void)fclose(g_sensorFile); + g_sensorFile = NULL; + printf("OPEN REPLAY FILE ERR\n"); + return; + } + size_t wRet; + + // 下发PDR时间校准命令 + osal_msleep(SLEEP_TIME); + InjectSensorTimeSyncCmd(g_handle); + // 4.获取sensor和gnss数据,执行PDR主流程。每秒调用一次。 + int32_t i = 0; + while (1) { + GnssRptRslt gnssRptRslt; + // 监听GNSS数据,将上报数据填充到gnssRptRslt.gnssState + int32_t ret = tiot_service_read(g_handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR); + if (ret > 0) { + uint16_t *type = (uint16_t *)g_gnssServiceBuff; + if (type[0] == MSG_TYPE_BINRY) { + DecodeBinaryGnss(g_gnssServiceBuff + MSG_CONTENT_IDX, &gnssRptRslt); + } + } + if (g_isPdrComn == 1 && g_isGnssLoc == 1) { + printf("gnssRptRslt gnssState deltaTime: %d, pvtState: %u, qop: %.3f, gnssRptRslt locInfotime: %llu," + "valid: %d, lat: %lld, lon: %lld, alt: %.3f\n", (int32_t)(gnssRptRslt.gnssState.deltaTime), + gnssRptRslt.gnssState.pvtState, gnssRptRslt.gnssState.qop, gnssRptRslt.locInfo.timestamp, + gnssRptRslt.locInfo.flags, gnssRptRslt.locInfo.latitude, gnssRptRslt.locInfo.longitude, + gnssRptRslt.locInfo.altitude); + (void)memset_s(sensorData, sizeof(EpochSensorData), 0, sizeof(EpochSensorData)); + // 获取sensor数据 + GetSensorData(sensorData); + // GNSS数据和sensor数据写进文件 + wRet = fwrite(sensorData, sizeof(EpochSensorData), 1, g_sensorFile); + if (wRet != 1) { + printf("write sensorData fail\n"); + break; + } + wRet = fwrite(&gnssRptRslt, sizeof(GnssRptRslt), 1, g_gnssFile); + if (wRet != 1) { + printf("write gnssRptRslt fail\n"); + break; + } + PdrResult pdrRslt; + (void)memset_s(&pdrRslt, sizeof(pdrRslt), 0, sizeof(pdrRslt)); + // PDR融合 + int32_t execRetVal = ExecutePdrFusion(sensorData, &gnssRptRslt, &pdrRslt); + if (execRetVal == RET_OK) { + printf("PDR SUCCESS. time: %llu, valid: %d, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f\n", + pdrRslt.timeStampMs, + pdrRslt.posLla.valid, pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt, + pdrRslt.speed, pdrRslt.heading); + } else { + printf("PDR ERR. CODE: %d\n", execRetVal); + } + g_isPdrComn = 0; + g_isGnssLoc = 0; + // 设置执行次数 + if (i >= EXECUTE_MAX_TIMES) { + printf("\ncnt enough\n"); + break; + } + i++; + } + } + + // 4.停止PDR。仅在结束调用一次。 + int32_t quitRetVal = QuitPdrFusion(); + if (quitRetVal != RET_OK) { + printf("PDR QUIT ERR\n"); + } + free(sensorData); + (void)fclose(g_sensorFile); + g_sensorFile = NULL; + (void)fclose(g_gnssFile); + g_gnssFile = NULL; + uapi_pm_remove_sleep_veto(PM_ID_SYS); +} \ 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 index 000000000..17f755841 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: pdr demo + */ +#ifndef PDR_SAMPLE_H +#define PDR_SAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void PdrDemo(void); +void PdrDemoRealTime(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif 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 index 000000000..b3b9626f9 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_acc.txt @@ -0,0 +1,100 @@ +7.598692417 0.158006832 -1.833836913 +7.342529774 0.213069826 -1.735681176 +7.127066135 0.237010255 -1.627949238 +7.019333839 0.239404291 -1.570492148 +6.818234444 0.304043472 -1.592038631 +6.550101757 0.387834966 -1.587250471 +6.265210629 0.438109875 -1.632737279 +6.064110756 0.433321774 -1.690194368 +5.961166859 0.378258795 -1.745257378 +5.968348980 0.203493655 -1.752439499 +6.025805950 0.031122558 -1.714134812 +6.068899155 -0.052668944 -1.623161077 +6.061717033 -0.067033201 -1.575280309 +6.147902489 -0.038304687 -1.592038631 +6.310697079 -0.038304687 -1.565704107 +6.629105091 -0.184341311 -1.510641098 +7.139036179 -0.404593259 -1.532187462 +7.883583546 -0.564994156 -1.565704107 +8.661647797 -0.675120115 -1.558521986 +9.341555595 -0.802004397 -1.558521986 +10.861772537 -0.979163587 -1.766803741 +11.685323715 -1.110835910 -1.896082044 +12.183284760 -1.067743182 -1.967903376 +12.427476883 -0.869037569 -1.965509295 +12.650122643 -0.703848660 -1.982267618 +13.023593903 -0.802004397 -1.917628407 +13.377912521 -1.034226537 -1.771591783 +13.658015251 -1.106047869 -1.690194368 +13.985999107 -1.077319384 -1.613584995 +14.349893570 -1.046196818 -1.630343318 +14.675483704 -1.070137262 -1.613584995 +14.876583099 -1.017468214 -1.735681176 +14.991497040 -0.964799345 -1.982267618 +15.027407646 -0.900160134 -2.221671820 +15.041771889 -0.825944841 -2.331797838 +14.936433792 -0.734971166 -2.183367252 +14.503111839 -0.675120115 -1.898476124 +13.717865944 -0.526689470 -1.405303240 +12.695610046 -0.265738755 -0.859461427 +11.682929993 0.028728515 -0.361500502 +10.837832451 0.232222170 0.023940429 +10.133983612 0.354318351 0.256162584 +9.693479538 0.205887690 0.402199209 +9.485198021 -0.160400882 0.423745602 +9.410983086 -0.564994156 0.363894522 +9.317615509 -0.981557608 0.253768563 +9.166790962 -1.446002007 0.146036625 +8.934568405 -1.886505842 0.122096188 +8.764591217 -2.252794504 0.162794918 +8.632919312 -2.530503511 0.280103028 +8.472517967 -2.710056543 0.306437492 +8.278600693 -2.824970722 0.308831543 +8.077501297 -2.856093168 0.248980463 +7.869219303 -2.846517086 0.308831543 +7.744729042 -2.748361349 0.454868168 +7.795003891 -2.607112885 0.651179671 +8.015255928 -2.441923857 0.840309083 +8.295358658 -2.370102644 1.041408658 +8.525186539 -2.377284765 1.098865747 +8.697558403 -2.504168987 0.988739729 +9.401406288 -2.822576761 0.598510742 +9.980765343 -2.913550377 0.371076673 +10.615186691 -2.935096741 0.189129397 +11.070055008 -2.980583429 0.004788086 +11.292700768 -2.999735832 -0.172371089 +11.290307045 -3.011706114 -0.363894522 +11.275942802 -3.016494036 -0.653573751 +11.591956139 -3.064374924 -0.969587386 +12.255105972 -3.303779364 -1.168292999 +12.980501175 -3.536001444 -1.264054656 +13.346789360 -3.749071360 -1.388544917 +13.169630051 -3.782588005 -1.642313480 +12.791371346 -3.615004778 -2.171396971 +13.006834984 -3.507272959 -2.793848038 +14.053031921 -3.488120556 -3.318143606 +15.580431938 -3.497696877 -3.626975060 +16.810970306 -3.550365686 -3.471362352 +16.767877579 -3.605428696 -2.903974056 +15.288358688 -3.480938435 -2.089999437 +13.296514511 -3.289415121 -1.405303240 +11.637442589 -3.217593670 -1.163504839 +10.883318901 -3.308567286 -1.309541464 +11.096388817 -3.634157181 -1.809896469 +11.991761208 -3.763435602 -2.530503511 +13.100203514 -3.603034735 -3.188865185 +13.863903046 -3.313355446 -3.720342875 +14.251737595 -3.052404881 -4.194363117 +14.531841278 -2.779483795 -4.438555717 +14.826308250 -2.556837797 -4.371522427 +15.005861282 -2.305463314 -4.050720692 +14.814337730 -2.054088831 -3.514455080 +14.132035255 -1.881717801 -3.040434599 +13.207935333 -1.764409661 -2.674145937 +12.482540131 -1.647101521 -2.346162081 +12.118645668 -1.589644551 -2.178579092 +12.006125450 -1.654283643 -2.183367252 +12.020489693 -1.778773904 -2.377284765 +12.015701294 -1.860171437 -2.619082928 +11.884029388 -1.910446286 -2.793848038 +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 index 000000000..1876c6a65 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/realtime_pdr_sample/pdr_sample_gyro.txt @@ -0,0 +1,100 @@ +1.809382796 1.616349459 2.758667469 +1.676214218 1.589471340 2.662150621 +1.529606581 1.544267297 2.552195072 +1.359786034 1.486845970 2.422691584 +1.180191636 1.434311628 2.290744543 +0.990823388 1.384220600 2.145358801 +0.790459633 1.323134065 1.985311985 +0.580321968 1.242499948 1.817934990 +0.359188765 1.145983219 1.634675384 +0.140499011 1.044579506 1.431868076 +-0.072082095 0.941954195 1.210734844 +-0.254119933 0.828333259 0.987158239 +-0.399505854 0.701273322 0.755029440 +-0.516791999 0.552222192 0.514348507 +-0.608421803 0.376292974 0.271224171 +-0.678060412 0.185703039 0.012217305 +-0.730594814 -0.026878070 -0.266337246 +-0.766025007 -0.254119933 -0.560774267 +-0.794124782 -0.465479314 -0.864985168 +-0.819781125 -0.656069279 -1.174082994 +-0.874759018 -1.080009699 -1.800830722 +-0.888198078 -1.284038782 -2.102598190 +-0.864985168 -1.447750568 -2.361604929 +-0.817337692 -1.580919266 -2.581516504 +-0.786794424 -1.727526903 -2.761110783 +-0.778242290 -1.887573600 -2.904053450 +-0.747699022 -2.028072596 -3.016452551 +-0.697608113 -2.141693592 -3.095865011 +-0.626747727 -2.236988544 -3.147177696 +-0.541226625 -2.318844557 -3.164281845 +-0.432492584 -2.372600555 -3.152064562 +-0.305432618 -2.375044107 -3.112969160 +-0.183259577 -2.323731422 -3.055547953 +-0.079412483 -2.240653753 -2.977357149 +-0.013439035 -2.118480682 -2.893057823 +-0.013439035 -1.954768777 -2.807536602 +-0.087964594 -1.762957096 -2.718350410 +-0.238237441 -1.568701982 -2.625498772 +-0.469144493 -1.401324868 -2.525316954 +-0.761138082 -1.285260439 -2.410474300 +-1.089783549 -1.231504321 -2.279749155 +-1.444085479 -1.226617455 -2.131919622 +-1.792278647 -1.254717231 -1.988977194 +-2.106263399 -1.292590857 -1.858252048 +-2.373822212 -1.303586364 -1.749518037 +-2.580294847 -1.269377947 -1.668883801 +-2.706132889 -1.205847979 -1.620014668 +-2.741563082 -1.125213742 -1.587027907 +-2.698802710 -1.044579506 -1.576032281 +-2.582738161 -0.962723613 -1.573588848 +-2.420248032 -0.873537302 -1.574810624 +-2.228436470 -0.775798857 -1.573588848 +-2.021963835 -0.680503905 -1.563814998 +-1.817934990 -0.593761027 -1.544267297 +-1.634675384 -0.537561417 -1.510058880 +-1.486845970 -0.518013716 -1.463633060 +-1.380555391 -0.516791999 -1.403768301 +-1.312138557 -0.514348507 -1.337794900 +-1.274264932 -0.498466045 -1.263269305 +-1.247386813 -0.476474881 -1.191187263 +-1.142318010 -0.467922777 -1.083674908 +-1.065348983 -0.458148926 -1.043357849 +-0.994488597 -0.420275271 -0.994488597 +-0.929736912 -0.345749736 -0.934623837 +-0.879645944 -0.249233022 -0.855211318 +-0.846659243 -0.157603234 -0.753807724 +-0.825889826 -0.101403631 -0.627969444 +-0.824668050 -0.094073243 -0.481361806 +-0.821002901 -0.116064392 -0.316428185 +-0.808785558 -0.124616511 -0.129503429 +-0.755029440 -0.079412483 0.069638640 +-0.669508278 0.000000000 0.288328379 +-0.549778700 0.057421334 0.518013716 +-0.390953749 0.013439035 0.746477306 +-0.206472456 -0.074525557 0.965167105 +-0.025656341 -0.122173049 1.169196010 +0.116064392 -0.079412483 1.347568750 +0.226020142 0.057421334 1.496619821 +0.340862811 0.208915904 1.621236324 +0.483805269 0.272445887 1.732413769 +0.668286562 0.223576680 1.866804123 +0.910189211 0.101403631 2.002416134 +1.199739337 -0.019547688 2.113593817 +1.540602088 -0.078190751 2.214997292 +1.892460465 -0.009773844 2.306627035 +2.204001665 0.178372651 2.381152630 +2.448347807 0.416610092 2.450791359 +2.602285862 0.647517145 2.504547358 +2.674367905 0.846659243 2.536312580 +2.675589800 1.025031924 2.565634012 +2.580294847 1.194852352 2.610837936 +2.415361166 1.318247199 2.674367905 +2.241875410 1.364672899 2.757445574 +2.086715698 1.332907915 2.860070944 +1.946216702 1.253495455 2.981022358 +1.820378423 1.165530920 3.119077921 +1.715309620 1.106887817 3.254689932 +1.637118816 1.088561893 3.379306555 +1.572367072 1.112996459 3.488040447 +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 index 000000000..d10eb9813 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/CMakeLists.txt @@ -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 index 000000000..728716844 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.c @@ -0,0 +1,36 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 用于配置回放参数 + * Create: 2024-04-01 + */ +#include "hipdr_test_config.h" +#include +#include +#include +#include "securec.h" + +// 输入一个sensor文件和一个gnss上报数据文件 +void SetDefaultFilePath(SimulatePdrConfig* cfg) +{ + char* path = "/user"; + + (void)sprintf_s(cfg->replayFileSensor, sizeof(cfg->replayFileSensor) - 1, "%s/%s", path, "pdr_data.bin"); + (void)sprintf_s(cfg->replayFileGnss, sizeof(cfg->replayFileGnss) - 1, "%s/%s", path, "gnss_data.bin"); + (void)sprintf_s(cfg->logPath, sizeof(cfg->logPath) - 1, "%s", path); +} + +void PrintSimulateInfo(const SimulatePdrConfig* cfg) +{ + printf("------------------- Simulate Info PDR single thread----------------------\n"); + printf("sensor file: %s\n", cfg->replayFileSensor); + printf("gnss file: %s\n", cfg->replayFileGnss); + printf("log path : %s\n", cfg->logPath); + printf("--------------------------------------------------------\n"); +} + +void ParseConfigParams(SimulatePdrConfig* cfg) +{ + (void)memset_s(cfg, sizeof(SimulatePdrConfig), 0, sizeof(SimulatePdrConfig)); + SetDefaultFilePath(cfg); + PrintSimulateInfo(cfg); +} \ 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 index 000000000..9456dacc3 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_config.h @@ -0,0 +1,19 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 用于配置回放参数 + * Create: 2024-04-01 + */ +#ifndef HIPDR_TEST_CONFIG_H +#define HIPDR_TEST_CONFIG_H + +#define FILE_PATH_LEN 1024 + +typedef struct { + char replayFileSensor[FILE_PATH_LEN]; // 用于回放的二进制文件名称(包含路径)SENSOR + char replayFileGnss[FILE_PATH_LEN]; // 用于回放的二进制文件名称(包含路径)GNSS + char logPath[FILE_PATH_LEN]; // 生成回放日志的路径 +} SimulatePdrConfig; + +void ParseConfigParams(SimulatePdrConfig* cfg); + +#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 index 000000000..a0804182f --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.c @@ -0,0 +1,59 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 主流程框架 + * Create: 2024-04-01 + */ + +#include "hipdr_test_main.h" +// 引用标准头文件 +#include +#include +#include +#include +#include +#include "securec.h" +// 引用LIB库接口文件 +#include "pdr_interface.h" +// 引用内部接口文件 +#include "hipdr_test_config.h" +#include "hipdr_test_save_log.h" +#include "hipdr_test_run.h" + +int PdrReplay(void) +{ + // 读取配置参数 + SimulatePdrConfig cfg = {0}; + ParseConfigParams(&cfg); + + if (access(cfg.replayFileSensor, F_OK) != 0 || access(cfg.replayFileGnss, F_OK) != 0) { + printf("error: replay file not exist\n"); + return -1; + } + + printf("-- start to run simulate hipdr...\n"); + // 打开日志文件 + if (OpenHipdrLogFile(&cfg) != 0) { + printf("open log file error.\n"); + return -1; + } + + // 注册日志接口 + RegPdrLogHandle(LogImpl); + + int32_t initRetVal = InitPdrFusion(); + if (initRetVal != RET_OK) { + printf("PDR INIT ERR\n"); + CloseHipdrLogFile(); + return -1; + } + RunHiPdr(&cfg); + int32_t quitRetVal = QuitPdrFusion(); + if (quitRetVal != RET_OK) { + printf("PDR QUIT ERR\n"); + } + // 关闭日志文件 + CloseHipdrLogFile(); + + printf("-- finish simulate hipdr.\n"); + return 0; +} \ 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 index 000000000..e66e54637 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_main.h @@ -0,0 +1,12 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 主流程框架 + * Create: 2024-04-01 + */ + +#ifndef HIPDR_TEST_MAIN_H +#define HIPDR_TEST_MAIN_H + +int PdrReplay(void); + +#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 index 000000000..5f99c2233 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.c @@ -0,0 +1,75 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 运行仿真环境,调用业务代码 + * Create: 2024-04-01 + */ +#include "hipdr_test_run.h" +#include +#include +#include +#include +#include "securec.h" +#include "pdr_interface.h" + +#define PI 3.1415926535897932384626433832795 +#define R2D (180 / PI) + +// 仿真主代码在这儿实现,如适配运行环境和适配注入数据 +void RunHiPdr(SimulatePdrConfig* cfg) +{ + // 读取仿真数据 + FILE* fileSensor = fopen(cfg->replayFileSensor, "rb"); + if (fileSensor == NULL) { + printf("open file error"); + return; + } + FILE* fileGnss = fopen(cfg->replayFileGnss, "rb"); + if (fileGnss == NULL) { + (void)fclose(fileSensor); + printf("open file error"); + return; + } + + // 获取文件容量 + (void)fseek(fileSensor, 0, SEEK_END); + size_t size = ftell(fileSensor); + if (size == 0) { + (void)fclose(fileSensor); + (void)fclose(fileGnss); + return; + } + (void)fseek(fileSensor, 0, SEEK_SET); + + (void)fseek(fileGnss, 0, SEEK_END); + size = ftell(fileGnss); + if (size == 0) { + (void)fclose(fileSensor); + (void)fclose(fileGnss); + return; + } + (void)fseek(fileGnss, 0, SEEK_SET); + + // 逐历元读取数据 + EpochSensorData sensorData; + (void)memset_s(&sensorData, sizeof(sensorData), 0, sizeof(sensorData)); + GnssRptRslt gnssRptRslt; + (void)memset_s(&gnssRptRslt, sizeof(gnssRptRslt), 0, sizeof(gnssRptRslt)); + PdrResult pdrRslt; + int32_t execRetVal; + + while (fread(&sensorData, sizeof(EpochSensorData), 1, fileSensor) > 0 && + fread(&gnssRptRslt, sizeof(GnssRptRslt), 1, fileGnss) > 0) { + (void)memset_s(&pdrRslt, sizeof(PdrResult), 0, sizeof(PdrResult)); + execRetVal = ExecutePdrFusion(&sensorData, &gnssRptRslt, &pdrRslt); + if (execRetVal == RET_OK) { + printf("PDR SUCCESS. time: %llu, valid: %d, src: %u, lat: %lf, lon: %lf, alt: %f, speed: %f, heading: %f", + pdrRslt.timeStampMs, pdrRslt.posLla.valid, pdrRslt.src, + pdrRslt.posLla.lat, pdrRslt.posLla.lon, pdrRslt.posLla.alt, + pdrRslt.speed, pdrRslt.heading); + } else { + printf("PDR ERR. CODE: %d\n", execRetVal); + } + } + (void)fclose(fileSensor); + (void)fclose(fileGnss); +} \ 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 index 000000000..8664654fc --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_run.h @@ -0,0 +1,13 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 运行仿真环境,调用业务代码 + * Create: 2024-04-01 + */ +#ifndef HIPDR_TEST_RUN_H +#define HIPDR_TEST_RUN_H + +#include "hipdr_test_config.h" + +void RunHiPdr(SimulatePdrConfig* cfg); + +#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 index 000000000..e0b766cd8 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.c @@ -0,0 +1,51 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 存储日志 + * Create: 2024-04-01 + */ + +#include "hipdr_test_save_log.h" +#include +#include +#include "securec.h" + +static FILE* g_pdrLogFp = NULL; + +// 日志实现函数 +int LogImpl(const char *logLevel, const char* fmt, ...) +{ + if (g_pdrLogFp == NULL) { + return -1; + } + + va_list va; + va_start(va, fmt); + (void)fprintf(g_pdrLogFp, "[%s] ", logLevel); + (void)vfprintf(g_pdrLogFp, fmt, va); + va_end(va); + return 0; +} + +int OpenHipdrLogFile(const SimulatePdrConfig* cfg) +{ + printf("enter OpenHipdrLogFile\n"); + char pathName[FILE_PATH_LEN] = {0}; + (void)sprintf_s(pathName, sizeof(pathName) - 1, "%s/pdr_test.log", cfg->logPath); + g_pdrLogFp = fopen(pathName, "w"); + printf("open pathName: %s\n", pathName); + + if (g_pdrLogFp == NULL) { + printf("error: open log file error(%s)\n", pathName); + return -1; + } + return 0; +} + +void CloseHipdrLogFile(void) +{ + if (g_pdrLogFp == NULL) { + return; + } + (void)fclose(g_pdrLogFp); + g_pdrLogFp = NULL; +} 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 index 000000000..bb4e12927 --- /dev/null +++ b/code/sdk/zhihui/GS21_1.10.100/sample/replay_pdr_sample/hipdr_test_save_log.h @@ -0,0 +1,17 @@ + /* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2024-2024. All rights reserved. + * Description: 存储日志 + * Create: 2024-04-01 + */ + +#ifndef HIPDR_TEST_SAVE_LOG_H +#define HIPDR_TEST_SAVE_LOG_H + +#include +#include +#include "hipdr_test_config.h" + +int OpenHipdrLogFile(const SimulatePdrConfig* cfg); +void CloseHipdrLogFile(void); +int LogImpl(const char *logLevel, const char* fmt, ...); +#endif \ No newline at end of file -- 2.17.1