diff --git a/Makefile b/Makefile index d84daef..76c5ba6 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,16 @@ include scripts/generic_variables.mk PLATFORM := xilinx TARGET_PROJ ?= node -BUILD_DIR := $(PROJECT)/build -CONFIG_FILE := $(PROJECT)/config.json -include scripts/generic.mk +ifeq ($(TARGET_PROJ), node) +BUILD_DIR := $(PROJECT)/build/node +CONFIG_FILE := $(PROJECT)/config/node.json +else ifeq ($(TARGET_PROJ), ge) +XILINX_VITIS_CLASSIC := y +BUILD_DIR := $(PROJECT)/build/ge +CONFIG_FILE := $(PROJECT)/config/ge.json +else +$(error Unsupported target PROJECT: $(TARGET_PROJ)) +endif + +include scripts/generic.mk \ No newline at end of file diff --git a/README.md b/README.md index fdc21c3..c1a88af 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,10 @@ - 重写总线驱动程序,采用 **PS UART 控制器**完成总线信息的收发。 - 更新总线控制协议,基于《网控模块 GLINK 协议》实现核心交互逻辑。 +- 使用折算的方式模拟新体制中的三档速率: + - 2Kbps:10Kbps模拟,Payload 128b, 占空比 40% + - 128Kbps:200Kbps模拟,Payload 1280b, 占空比 50% + - 256Kbps:1.2Mbps模拟,Payload 2560b, 占空比 50% --- diff --git a/build.bat b/build.bat index 9f34e70..bff4c43 100644 --- a/build.bat +++ b/build.bat @@ -1,9 +1,35 @@ @echo off set "platform=xilinx" set "tools_dir=%~dp0scripts\platform\%platform%" -set "platform_ver=2019.1" -set "work_dir=%~dp0build" -set "config=%~dp0config.json" + +:menu +echo Please select the project needed to be built: +echo 1. NODE Project (SDK 2019.1) +echo 2. GE Project (Vitis 2024.1) +set /p choice="Choose a project (1 or 2): " + +if "%choice%"=="1" ( + echo Building NODE Project ^(SDK 2019.1^) + set "platform_ver=2019.1" + set "work_dir=%~dp0build\node" + set "config=%~dp0config\node.json" + goto end +) else if "%choice%"=="2" ( + echo Building GE Project ^(Vitis 2024.1^) + set "platform_ver=2024.1" + set "work_dir=%~dp0build\ge" + set "config=%~dp0config\ge.json" + goto end +) else ( + echo Invalid choice. Please enter 1 or 2. + goto menu +) +:end + +echo Start Building +echo Platform version: %platform_ver% +echo Build directory: %work_dir% +echo Configuration file: %config% REM Change working dir to the dir where this script is located cd /d "%~dp0" @@ -32,4 +58,4 @@ if "%ERRORLEVEL%" neq "0" ( exit /b 1 ) -exit /b 0 +exit /b 0 \ No newline at end of file diff --git a/config/ge.json b/config/ge.json new file mode 100644 index 0000000..691be5e --- /dev/null +++ b/config/ge.json @@ -0,0 +1,39 @@ +{ + "project_name": "ky-xtz", + "version": "0.0.0", + "hw_design": "hw/kykk_ge_hw_v0.0.hdf", + "apps": { + "xtzge_app": { + "sources": [ + "src/ge_app.c", + "src/include", + "src/ge_config", + "src/drivers", + "src/hardware", + "src/networking", + "src/time_ctrl", + "src/mpc", + "src/util", + "src/system_monitor.h", + "src/system_monitor.c" + ], + "target_cpu": "ps7_cortexa9_0", + "os": "standalone", + "language": "C", + "mem_layout" : { + "heap_size": "0x800000", + "stack_size": "0x20000" + }, + "build_config": { + "debug": { + "include-path": ["src", "src/include"], + "libraries": ["m"] + }, + "release": { + "include-path": ["src", "src/include"], + "libraries": ["m"] + } + } + } + } +} diff --git a/config.json b/config/node.json similarity index 60% rename from config.json rename to config/node.json index 70d62ef..f5c3c2b 100644 --- a/config.json +++ b/config/node.json @@ -1,10 +1,21 @@ { "project_name": "ky-xtz", "version": "0.0.0", - "hw_design": "hw/hsjl_node_v0.0.0.hdf", + "hw_design": "hw/kykk_node_hw_v0.0.hdf", "apps": { "xtz_app": { - "sources": ["src/*"], + "sources": [ + "src/node_app.c", + "src/include", + "src/node_config", + "src/drivers", + "src/networking", + "src/time_ctrl", + "src/systembus", + "src/util", + "src/system_monitor.h", + "src/system_monitor.c" + ], "target_cpu": "ps7_cortexa9_0", "os": "standalone", "language": "C", diff --git a/hw/hsjl_node_v0.0.0.hdf b/hw/hsjl_node_v0.0.0.hdf deleted file mode 100755 index f4b26e9..0000000 Binary files a/hw/hsjl_node_v0.0.0.hdf and /dev/null differ diff --git a/src/drivers/api/i2c.c b/src/drivers/api/i2c.c deleted file mode 100644 index 149e7cd..0000000 --- a/src/drivers/api/i2c.c +++ /dev/null @@ -1,135 +0,0 @@ -/***************************************************************************//** - * @file i2c.c - * @brief Implementation of the I2C Interface - * @author Antoniu Miclaus (antoniu.miclaus@analog.com) -******************************************************************************** - * Copyright 2020(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -#include -#include "i2c.h" -#include -#include "error.h" - -/** - * @brief Initialize the I2C communication peripheral. - * @param desc - The I2C descriptor. - * @param param - The structure that contains the I2C parameters. - * @return 0 in case of success, -1 otherwise. - */ -int32_t i2c_init(struct i2c_desc **desc, - const struct i2c_init_param *param) -{ - int32_t ret; - - if (!param || !param->platform_ops) - return -EINVAL; - - if (!param->platform_ops->i2c_ops_init) - return -ENOSYS; - - ret = param->platform_ops->i2c_ops_init(desc, param); - if (ret) - return ret; - - (*desc)->platform_ops = param->platform_ops; - - return 0; -} - -/** - * @brief Free the resources allocated by i2c_init(). - * @param desc - The I2C descriptor. - * @return 0 in case of success, -1 otherwise. - */ -int32_t i2c_remove(struct i2c_desc *desc) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->i2c_ops_remove) - return -ENOSYS; - - return desc->platform_ops->i2c_ops_remove(desc); -} - -/** - * @brief I2C Write data to slave device. - * @param desc - The I2C descriptor. - * @param data - The buffer with the transmitted/received data. - * @param bytes_number - Number of bytes to write. - * @param stop_bit - Stop conditional control. - * Example: 0 - A stop condition will not be generated. - * 1 - A stop condition will be generated. - * @return 0 in case of success, -1 otherwise. - */ -int32_t i2c_write(struct i2c_desc *desc, - uint8_t *data, - uint8_t bytes_number, - uint8_t stop_bit) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->i2c_ops_write) - return -ENOSYS; - - return desc->platform_ops->i2c_ops_write(desc, data, bytes_number, - stop_bit); -} - -/** - * @brief I2C Read data from slave device. - * @param desc - The i2c descriptor. - * @param data - The buffer with the transmitted/received data. - * @param bytes_number - Number of bytes to read. - * @param stop_bit - Stop conditional control. - * Example: 0 - A stop condition will not be generated. - * 1 - A stop condition will be generated. - * @return 0 in case of success, -1 otherwise. - */ -int32_t i2c_read(struct i2c_desc *desc, - uint8_t *data, - uint8_t bytes_number, - uint8_t stop_bit) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->i2c_ops_read) - return -ENOSYS; - - return desc->platform_ops->i2c_ops_read(desc, data, bytes_number, - stop_bit); -} diff --git a/src/drivers/api/spi.c b/src/drivers/api/spi.c deleted file mode 100644 index 954f669..0000000 --- a/src/drivers/api/spi.c +++ /dev/null @@ -1,161 +0,0 @@ -/***************************************************************************//** - * @file spi.c - * @brief Implementation of the SPI Interface - * @author Antoniu Miclaus (antoniu.miclaus@analog.com) -******************************************************************************** - * Copyright 2020(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -#include -#include "spi.h" -#include -#include "error.h" - -/** - * @brief Initialize the SPI communication peripheral. - * @param desc - The SPI descriptor. - * @param param - The structure that contains the SPI parameters. - * @return 0 in case of success, -1 otherwise. - */ -int32_t spi_init(struct spi_desc **desc, - const struct spi_init_param *param) -{ - int32_t ret; - - if (!param || !param->platform_ops) - return -EINVAL; - - if (!param->platform_ops->init) - return -ENOSYS; - - ret = param->platform_ops->init(desc, param); - if (ret) - return ret; - - (*desc)->platform_ops = param->platform_ops; - (*desc)->parent = param->parent; - - return 0; -} - -/** - * @brief Free the resources allocated by spi_init(). - * @param desc - The SPI descriptor. - * @return 0 in case of success, -1 otherwise. - */ -int32_t spi_remove(struct spi_desc *desc) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->remove) - return -ENOSYS; - - return desc->platform_ops->remove(desc); -} - -/** - * @brief Write and read data to/from SPI. - * @param desc - The SPI descriptor. - * @param data - The buffer with the transmitted/received data. - * @param bytes_number - Number of bytes to write/read. - * @return 0 in case of success, -1 otherwise. - */ -int32_t spi_write_and_read(struct spi_desc *desc, - uint8_t *data, - uint16_t bytes_number) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->write_and_read) - return -ENOSYS; - - return desc->platform_ops->write_and_read(desc, data, bytes_number); -} - -/** - * @brief Write and read data to/from SPI in 3 wire mode. - * @param desc - The SPI descriptor. - * @param write_data - The buffer with the transmitted data. - * @param read_data - The buffer with the received data. - * @param write_bytes_number - Number of bytes to write. - * @param read_bytes_number - Number of bytes to read. - * @return SUCCESS in case of success, FAILURE otherwise. - */ -int32_t spi_write_and_read_3wire(struct spi_desc *desc, - uint8_t *write_data, - uint8_t *read_data, - uint16_t write_bytes_number, - uint16_t read_bytes_number) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->write_and_read_3wire) - return -ENOSYS; - return desc->platform_ops->write_and_read_3wire(desc, write_data, read_data, - write_bytes_number, read_bytes_number); -} -/** - * @brief Iterate over head list and send all spi messages - * @param desc - The SPI descriptor. - * @param msgs - Array of messages. - * @param len - Number of messages in the array. - * @return 0 in case of success, negativ error code otherwise. - */ -int32_t spi_transfer(struct spi_desc *desc, - struct spi_msg *msgs, - uint32_t len) -{ - int32_t ret; - uint32_t i; - - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (desc->platform_ops->transfer) - return desc->platform_ops->transfer(desc, msgs, len); - - for (i = 0; i < len; i++) { - if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff) - return -EINVAL; - ret = spi_write_and_read(desc, msgs[i].rx_buff, - msgs[i].bytes_number); - if (IS_ERR_VALUE(ret)) - return ret; - } - - return 0; -} diff --git a/src/drivers/api/trng.c b/src/drivers/api/trng.c deleted file mode 100644 index 1f3827a..0000000 --- a/src/drivers/api/trng.c +++ /dev/null @@ -1,111 +0,0 @@ -/***************************************************************************//** - * @file trng.c - * @brief Implementation of the TRNG Interface - * @author Antoniu Miclaus (antoniu.miclaus@analog.com) -******************************************************************************** - * Copyright 2023(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -/******************************************************************************/ -/***************************** Include Files **********************************/ -/******************************************************************************/ -#include -#include "trng.h" -#include -#include "error.h" - -/******************************************************************************/ -/************************ Functions Definitions *******************************/ -/******************************************************************************/ - -/** - * @brief Initialize the TRNG. - * @param desc - The TRNG descriptor. - * @param param - The structure that contains the TRNG parameters. - * @return 0 in case of success, -1 otherwise. - */ -int trng_init(struct trng_desc **desc, - const struct trng_init_param *param) -{ - int ret; - - if (!param || !param->platform_ops) - return -EINVAL; - - if (!param->platform_ops->init) - return -ENOSYS; - - ret = param->platform_ops->init(desc, param); - if (ret) - return ret; - - (*desc)->platform_ops = param->platform_ops; - - return 0; -} - -/** - * @brief Free the resources allocated by trng_init(). - * @param desc - The TRNG descriptor. - * @return 0 in case of success, -1 otherwise. - */ -int trng_remove(struct trng_desc *desc) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->remove) - return -ENOSYS; - - return desc->platform_ops->remove(desc); -} - -/** - * @brief Fill buffer with rng data. - * @param desc - The TRNG descriptor. - * @param buff - Buffer to be filled - * @param len - Size of the buffer - * @return 0 in case of success, -1 otherwise. - */ -int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff, - uint32_t len) -{ - if (!desc || !desc->platform_ops) - return -EINVAL; - - if (!desc->platform_ops->fill_buffer) - return -ENOSYS; - - return desc->platform_ops->fill_buffer(desc, buff, len); -} diff --git a/src/drivers/axi_core/spi_engine/spi_engine.h b/src/drivers/axi_core/spi_engine/spi_engine.h index 9e6887e..7eea870 100644 --- a/src/drivers/axi_core/spi_engine/spi_engine.h +++ b/src/drivers/axi_core/spi_engine/spi_engine.h @@ -47,8 +47,8 @@ #include #include "spi_engine_private.h" -#include "../axi_dmac/axi_dmac.h" -#include "../../platform/xilinx_spi.h" +#include "drivers/axi_core/axi_dmac/axi_dmac.h" +#include "drivers/platform/xilinx_spi.h" /******************************************************************************/ /********************** Macros and Constants Definitions **********************/ diff --git a/src/drivers/platform/xilinx_i2c.c b/src/drivers/platform/xilinx_i2c.c deleted file mode 100644 index de4ecb4..0000000 --- a/src/drivers/platform/xilinx_i2c.c +++ /dev/null @@ -1,514 +0,0 @@ -/***************************************************************************//** - * @file xilinx/xilinx_i2c.c - * @brief Implementation of Xilinx I2C Generic Driver. - * @author Antoniu Miclaus (antoniu.miclaus@analog.com) -******************************************************************************** - * Copyright 2019(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -/******************************************************************************/ -/***************************** Include Files **********************************/ -/******************************************************************************/ - -#include - -#include -#ifdef XPAR_XIIC_NUM_INSTANCES -#include -#endif -#ifdef XPAR_XIICPS_NUM_INSTANCES -#include -#endif - -#include "error.h" -#include "i2c.h" -#include "xilinx_i2c.h" -#include "list.h" - -/******************************************************************************/ -/*************************** Types Declarations *******************************/ -/******************************************************************************/ - -static struct list_desc *pl_list = NULL; -static struct iterator *pl_it = NULL; - -#ifdef XIICPS_H -static struct list_desc *ps_list = NULL; -static struct iterator *ps_it = NULL; -#endif /* XIICPS_H */ - -/** - * @struct inst_table_item - * @brief Table item for I2C cores already started. - */ -struct inst_table_item { - /** Instance the BSP driver uses for this core. */ - void *instance; - /** Core ID in BSP. */ - uint32_t device_id; - /** Number of ADI driver instances running on this core. */ - uint32_t inst_no; -}; - -#ifdef XPAR_XIICPS_NUM_INSTANCES -/** Save the current state of the bitrate to not change it each time */ -static uint32_t ps_last_bitrate = 0; -#endif - -/** - * @brief Xilinx platform specific I2C platform ops structure - */ -const struct i2c_platform_ops xil_i2c_ops = { - .i2c_ops_init = &xil_i2c_init, - .i2c_ops_write = &xil_i2c_write, - .i2c_ops_read = &xil_i2c_read, - .i2c_ops_remove = &xil_i2c_remove -}; - -/******************************************************************************/ -/************************ Functions Definitions *******************************/ -/******************************************************************************/ - -/** - * @brief Compare two I2C cores by ID. - * @param el1 - First I2C core to compare. - * @param el2 - Second I2C core to compare. - * @return \ref 0 if the two cores have the same ID, - * \ref difference between the first and the second IDs otherwise. - */ -static int32_t xil_i2c_cmp(void *el1, void *el2) -{ - struct inst_table_item *sel1 = el1, *sel2 = el2; - - return (sel1->device_id - sel2->device_id); -} - -/** - * @brief Configure slave address and bitrate if needed - * @param desc - Descriptor of the I2C device - * @return 0 in case of success, -1 otherwise. - */ -static int32_t xil_i2c_set_transmission_config(struct i2c_desc *desc) -{ - struct xil_i2c_desc *xil_i2c_desc = desc->extra; -#ifdef XIICPS_H - int32_t ret; -#endif - - switch (xil_i2c_desc->type) { - case IIC_PL: -#ifdef XIIC_H - break; -#endif - return -1; - case IIC_PS: -#ifdef XIICPS_H - if (desc->max_speed_hz != ps_last_bitrate) { - ret = XIicPs_SetSClk(xil_i2c_desc->instance, desc->max_speed_hz); - if (ret != XST_SUCCESS) - return -1; - ps_last_bitrate = desc->max_speed_hz; - } - break; -#endif - return -1; - default: - - return -1; - } - - return 0; -} - -/** - * @brief Initialize the I2C communication peripheral. - * @param desc - The I2C descriptor. - * @param param - The structure that contains the I2C parameters. - * @return 0 in case of success, -1 otherwise. - */ -int32_t xil_i2c_init(struct i2c_desc **desc, - const struct i2c_init_param *param) -{ - int32_t ret; - struct i2c_desc *idesc; - struct xil_i2c_desc *xdesc; - struct xil_i2c_init_param *xinit; - - idesc = (struct i2c_desc *)malloc(sizeof(*idesc)); - xdesc = (struct xil_i2c_desc *)malloc(sizeof(*xdesc)); - - if(!idesc || !xdesc) - goto error; - - idesc->max_speed_hz = param->max_speed_hz; - idesc->slave_address = param->slave_address; - xinit = param->extra; - - idesc->extra = xdesc; - xdesc->type = xinit->type; - xdesc->device_id = xinit->device_id; - switch (xinit->type) { - case IIC_PL: -#ifdef XIIC_H - ; /** Intentional empty statement */ - struct inst_table_item tab_check_pl; - struct inst_table_item *temp_el_pl; - - if (!pl_list) - list_init(&pl_list, LIST_DEFAULT, xil_i2c_cmp); - if (!pl_it) - iterator_init(&pl_it, pl_list, true); - - tab_check_pl.device_id = xdesc->device_id; - - if (!IS_ERR_VALUE(list_read_find(pl_list, (void **)&temp_el_pl, - &tab_check_pl))) { - xdesc->instance = temp_el_pl->instance; - temp_el_pl->inst_no++; - break; - } - - xdesc->instance = (XIic *)malloc(sizeof(XIic)); - if(!xdesc->instance) - goto pl_error; - - xdesc->config = XIic_LookupConfig(xinit->device_id); - if(xdesc->config == NULL) - goto pl_error; - - ret = XIic_CfgInitialize(xdesc->instance, - xdesc->config, - ((XIic_Config*)xdesc->config) - ->BaseAddress); - if(ret != 0) - goto pl_error; - - ret = XIic_Start(xdesc->instance); - if(ret != 0) - goto pl_error; - - ret = XIic_SetAddress(xdesc->instance, - XII_ADDR_TO_SEND_TYPE, - param->slave_address); - if(ret != 0) - goto pl_error; - - ret = XIic_SelfTest(xdesc->instance); - if(ret < 0) - goto pl_error; - - ret = XIic_SetGpOutput(xdesc->instance, 1); - if(ret < 0) - goto pl_error; - - temp_el_pl = (struct inst_table_item*)calloc(1, sizeof(*temp_el_pl)); - temp_el_pl->device_id = xinit->device_id; - temp_el_pl->inst_no = 1; - temp_el_pl->instance = xdesc->instance; - pl_list->push(pl_list, temp_el_pl); - - break; -pl_error: - free(xdesc->instance); -#endif - goto error; - case IIC_PS: -#ifdef XIICPS_H - ; /** Intentional empty statement */ - struct inst_table_item tab_check_ps; - struct inst_table_item *temp_el_ps; - - if (!pl_list) - list_init(&ps_list, LIST_DEFAULT, xil_i2c_cmp); - if (!pl_it) - iterator_init(&ps_it, ps_list, true); - - tab_check_ps.device_id = xdesc->device_id; - - if (!IS_ERR_VALUE(list_read_find(ps_list, - (void **)&temp_el_ps, - &tab_check_ps))) { - xdesc->instance = temp_el_ps->instance; - temp_el_ps->inst_no++; - break; - } - - xdesc->instance = (XIicPs *)malloc(sizeof(XIicPs)); - if(!xdesc->instance) - goto ps_error; - - xdesc->config = XIicPs_LookupConfig(xinit->device_id); - if(xdesc->config == NULL) - goto ps_error; - - ret = XIicPs_CfgInitialize(xdesc->instance, - xdesc->config, - ((XIicPs_Config*)xdesc->config) - ->BaseAddress); - if(ret != 0) - goto ps_error; - - XIicPs_SetSClk(xdesc->instance, param->max_speed_hz); - - temp_el_ps = (struct inst_table_item*)calloc(1, sizeof(*temp_el_ps)); - temp_el_ps->device_id = xinit->device_id; - temp_el_ps->inst_no = 1; - temp_el_ps->instance = xdesc->instance; - ps_list->push(ps_list, temp_el_ps); - - break; -ps_error: - free(xdesc->instance); -#endif - goto error; - - default: - goto error; - break; - } - - *desc = idesc; - - return 0; - -error: - free(idesc); - free(xdesc); - - return -1; -} - -/** - * @brief Free the resources allocated by i2c_init(). - * @param desc - The I2C descriptor. - * @return 0 in case of success, -1 otherwise. - */ -int32_t xil_i2c_remove(struct i2c_desc *desc) -{ - struct xil_i2c_desc *xdesc; - int32_t ret; - - xdesc = desc->extra; - - switch (xdesc->type) { - case IIC_PL: -#ifdef XIIC_H - ; /** Intentional empty statement */ - struct inst_table_item tab_check_pl; - struct inst_table_item *temp_el_pl; - tab_check_pl.device_id = xdesc->device_id; - ret = iterator_find(pl_it, &tab_check_pl); - if (ret != 0) - goto error; - iterator_read(pl_it, (void **)&temp_el_pl); - temp_el_pl->inst_no--; - if (temp_el_pl->inst_no != 0) - break; - - ret = XIic_Stop(((XIic *)xdesc->instance)); - - if(ret != 0) - goto error; - - /** Remove list element */ - iterator_get(pl_it, (void **)&temp_el_pl); - free(temp_el_pl); - break; -#endif - goto error; - case IIC_PS: -#ifdef XIICPS_H - ; /** Intentional empty statement */ - struct inst_table_item tab_check_ps; - struct inst_table_item *temp_el_ps; - tab_check_ps.device_id = xdesc->device_id; - ret = iterator_find(ps_it, &tab_check_ps); - if (ret != 0) - goto error; - iterator_read(ps_it, (void **)&temp_el_ps); - temp_el_ps->inst_no--; - if (temp_el_ps->inst_no != 0) - break; - - /** Remove list element */ - iterator_get(ps_it, (void **)&temp_el_ps); - free(temp_el_ps); - break; -#endif - /* Intended fallthrough */ -error: - default: - - return -1; - } - - free(desc->extra); - free(desc); - - return 0; -} - -/** - * @brief Write data to a slave device. - * @param desc - The I2C descriptor. - * @param data - Buffer that stores the transmission data. - * @param bytes_number - Number of bytes to write. - * @param stop_bit - Stop condition control. - * Example: 0 - A stop condition will not be generated; - * 1 - A stop condition will be generated. - * @return 0 in case of success, -1 otherwise. - */ -int32_t xil_i2c_write(struct i2c_desc *desc, - uint8_t *data, - uint8_t bytes_number, - uint8_t stop_bit) -{ - struct xil_i2c_desc *xdesc; - int32_t ret; - - xdesc = desc->extra; - - switch (xdesc->type) { - case IIC_PL: -#ifdef XIIC_H - ret = xil_i2c_set_transmission_config(desc); - if (ret != 0) - return -1; - - XIic_Send(((XIic*)xdesc->instance)->BaseAddress, - desc->slave_address, - data, - bytes_number, - stop_bit ? XIIC_STOP : XIIC_REPEATED_START); - break; -#endif - goto error; - case IIC_PS: -#ifdef XIICPS_H - ret = xil_i2c_set_transmission_config(desc); - if (ret != 0) - return -1; - - ret = XIicPs_SetOptions(xdesc->instance, - stop_bit ? 0 : XIICPS_REP_START_OPTION); - if(ret != 0) - goto error; - - XIicPs_MasterSend(xdesc->instance, - data, - bytes_number, - desc->slave_address); - if(ret != 0) - goto error; - - break; -#endif - /* Intended fallthrough */ -error: - default: - - return -1; - } - - return 0; -} - -/** - * @brief Read data from a slave device. - * @param desc - The I2C descriptor. - * @param data - Buffer that will store the received data. - * @param bytes_number - Number of bytes to read. - * @param stop_bit - Stop condition control. - * Example: 0 - A stop condition will not be generated; - * 1 - A stop condition will be generated. - * @return 0 in case of success, -1 otherwise. - */ -int32_t xil_i2c_read(struct i2c_desc *desc, - uint8_t *data, - uint8_t bytes_number, - uint8_t stop_bit) -{ - struct xil_i2c_desc *xdesc; - int32_t ret; - - xdesc = desc->extra; - - switch (xdesc->type) { - case IIC_PL: -#ifdef XIIC_H - ret = xil_i2c_set_transmission_config(desc); - if (ret != 0) - return -1; - - ret = XIic_Recv(((XIic*)xdesc->instance)->BaseAddress, - desc->slave_address, - data, - bytes_number, - stop_bit ? XIIC_STOP : XIIC_REPEATED_START); - if(ret != bytes_number) - goto error; - - break; -#endif - goto error; - case IIC_PS: -#ifdef XIICPS_H - ret = xil_i2c_set_transmission_config(desc); - if (ret != 0) - return -1; - - ret = XIicPs_SetOptions(xdesc->instance, - stop_bit ? 0 : XIICPS_REP_START_OPTION); - if(ret != 0) - goto error; - - XIicPs_MasterRecv(xdesc->instance, - data, - bytes_number, - desc->slave_address); - if(ret != 0) - goto error; - - break; -#endif - /* Intended fallthrough */ -error: - default: - return -1; - - break; - } - - return 0; -} diff --git a/src/drivers/platform/xilinx_i2c.h b/src/drivers/platform/xilinx_i2c.h deleted file mode 100644 index b091318..0000000 --- a/src/drivers/platform/xilinx_i2c.h +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * @file xilinx/xilinx_i2c.h - * @brief Header containing types used in the i2c driver. - * @author scuciurean (sergiu.cuciurean@analog.com) -******************************************************************************** - * Copyright 2019(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -#ifndef XILINX_I2C_H_ -#define XILINX_I2C_H_ - -/******************************************************************************/ -/***************************** Include Files **********************************/ -/******************************************************************************/ - -#include - -/******************************************************************************/ -/*************************** Types Declarations *******************************/ -/******************************************************************************/ - -/** - * @enum xil_i2c_type - * @brief Xilinx platform architecture sections - */ -enum xil_i2c_type { - /** Programmable Logic */ - IIC_PL, - /** Processing System */ - IIC_PS -}; - -/** - * @struct xil_i2c_init - * @brief Structure holding the initialization parameters for Xilinx platform - * specific I2C parameters. - */ -struct xil_i2c_init_param { - /** Xilinx architecture */ - enum xil_i2c_type type; - /** Device ID */ - uint32_t device_id; -}; - -/** - * @struct xil_i2c_desc - * @brief Xilinx platform specific I2C descriptor - */ -struct xil_i2c_desc { - /** Xilinx architecture */ - enum xil_i2c_type type; - /** Device ID */ - uint32_t device_id; - /** Xilinx I2C configuration */ - void *config; - /** Xilinx I2C Instance */ - void *instance; -}; - -/** - * @brief Xilinx platform specific i2c platform ops structure - */ -extern const struct i2c_platform_ops xil_i2c_ops; - -/******************************************************************************/ -/************************ Functions Declarations ******************************/ -/******************************************************************************/ - -/* Initialize the I2C communication peripheral. */ -int32_t xil_i2c_init(struct i2c_desc **desc, - const struct i2c_init_param *param); - -/* Free the resources allocated by i2c_init(). */ -int32_t xil_i2c_remove(struct i2c_desc *desc); - -/* I2C Write data */ -int32_t xil_i2c_write(struct i2c_desc *desc, uint8_t *data, - uint8_t bytes_number, uint8_t stop_bit); - -/* I2C Read data. */ -int32_t xil_i2c_read(struct i2c_desc *desc, uint8_t *data, - uint8_t bytes_number, uint8_t stop_bit); - -#endif // XILINX_I2C_H_ diff --git a/src/ge_app.c b/src/ge_app.c new file mode 100644 index 0000000..6616965 --- /dev/null +++ b/src/ge_app.c @@ -0,0 +1,610 @@ +/*****************************************************************************/ +/** + * Description: main.c + * + + * Date: 2021-11-13 13:19 + * Last Editors: Fan Hao + * Last Edit Time: [2022-03-28 20:32] + * + * Revisions: Rev 0.0 + * History: + * [2021-11-13]: Initial edition. + * [2022-03-28]: Add bit error test mode. + * + * Copyright(c) 2021 Beijing Institute of Technology. + * Lab of Communication and Networking + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ +// Standard +#include +#include +#include +// Xilinx +#include "sleep.h" +#include "xil_cache.h" +#include "xscugic.h" +#include "xscutimer.h" +#include "xgpiops.h" +#include "drivers/platform/xilinx_irq.h" +#include "drivers/platform/xilinx_timer.h" +// App +#include "common.h" +#include "error.h" +#include "timer.h" +#include "mpc/mpc.h" +#include "networking/phy_layer/phy_layer.h" +#include "networking/link_layer/link_layer.h" +#include "ge_config/app_config.h" +#include "ge_config/dev_profile/dev_profile.h" +// RF-Driver +#include "hardware/headless.h" +#include "hardware/platform_drivers.h" + +/************************** Function Prototypes ******************************/ +static int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr); +static void Phy_IntrHandler(void *context); +static void PeriodicPull_Handler(void *callBackRef); +static void ScuTimer_IntrHandler(void *context); +static void Mpc_RxIntrHandler(void *context); +static void Mpc_TxIntrHandler(void *context); +static bool LinklayerPush2Up(RING_BUFFER *buff); +static bool LinklayerPopFromUp(RING_BUFFER **buff); +/************************** Constant Definitions *****************************/ +struct callback_desc phy_callback_desc = +{ + .callback = Phy_IntrHandler, + .ctx = NULL +}; + +struct callback_desc periodicpull_callback_desc = +{ + .callback = PeriodicPull_Handler, + .ctx = NULL +}; + + +struct callback_desc mpc_rx_callback_desc = +{ + .callback = Mpc_RxIntrHandler, + .ctx = NULL +}; + +struct callback_desc mpc_tx_callback_desc = +{ + .callback = Mpc_TxIntrHandler, + .ctx = NULL +}; + +struct callback_desc scutm_callback_desc = +{ + .callback = ScuTimer_IntrHandler, + .ctx = NULL +}; + +L2_CONFIG linkConfig = { + .myType = L2_NODE_HEAD, + .clustId = 1U, + .myId = 1U, + .headId = 1U, + .netScale = 2U, + .phyInstPtr = NULL, // physical layer reference + .tmcInstPtr = NULL, + .pushUpHandle = LinklayerPush2Up, + .popUpHandle = LinklayerPopFromUp +}; + +// L2_CONFIG linkConfig = { +// .myType = L2_NODE_MEMBER, +// .clustId = 1U, +// .myId = 2U, +// .headId = 1U, +// .netScale = 2U, +// .phyInstPtr = NULL, // physical layer reference +// .tmcInstPtr = NULL, +// .pushUpHandle = LinklayerPush2Up, +// .popUpHandle = LinklayerPopFromUp +// }; + +static PHY_CONFIG phyConfig = +{ + .devId = 0, + .baseAddr = PHY_BASEADDR, + .antBramId = PHY_ANTCONFIG_BRAM_DEVICE_ID, + .antInfoBramId = -1, + .txBramId = PHY_TXBUFF_BRAM_DEVICE_ID, + .rxBramId = PHY_RXBUFF_BRAM_DEVICE_ID, + .hwXadcId = PHY_HW_XADC_DEVICE_ID, + .get_clk_state = NULL, + .get_ad_lock_state = NULL, + .get_ad0_temp = NULL, + .get_ad1_temp = NULL +}; + +TMC_CONFIG tmcConfig = +{ + .baseAddr = TIME_CONTROLLER_BASEADDR, + .reset = 10 +}; + +static MPC_CONFIG mpcConfig = { + .bramId = MPC_BRAM_ID, + .gpioId = MPC_GPIO_ID, + .txQueueMax = 16, + .rxQueueMax = 16 +}; + +#ifdef APP_EMULATE_DATA +uint8_t testDataLj[] = +{ + 0xEA, 0xDF, 0x3F, 0x27, 0xCE, 0x9B, 0xE6, 0x3F, + 0xB5, 0xA3, 0x38, 0x47, 0x1D, 0x1D, 0xFA, 0x3F, + 0x39, 0xB4, 0xC8, 0x76, 0xBE, 0xAB, 0x8E, 0x40, + 0xC9, 0xE8, 0x80, 0x24, 0xEC, 0xCB, 0x13, 0x40, + 0x37, 0x38, 0x7F, 0x22, 0x72, 0x06, 0xF0, 0x01, + 0x00, 0x00, 0xB8, 0xAA, 0x08, 0x47, 0x1E, 0xC6, + 0xB0, 0x47, 0x54, 0xFD, 0xEB, 0x45, 0xA1, 0x8A, + 0x86, 0x44, 0x43, 0xB6, 0xC8, 0x44, 0x4E, 0x19, + 0xA8, 0x42 +}; + +uint8_t testDataFlj[] = +{ + 0xFD, 0x1E, 0xA5, 0x22, 0x72, 0x02, 0x5A, 0x02, + 0x00, 0x00, 0x81, 0x97, 0x39, 0x3F, 0xF1, 0xF4, + 0xC0, 0x3F, 0x27, 0xF1, 0x65, 0x44, 0x53, 0x5C, + 0xD3, 0x3F, 0xB5, 0x24, 0xA6, 0x22, 0x72, 0x02, + 0x83, 0x01, 0x00, 0x00, 0xFC, 0xE0, 0x44, 0x47, + 0xB7, 0x83, 0x35, 0x47, 0xA4, 0xBF, 0xE5, 0xC4, + 0xE8, 0xDC, 0xD1, 0x44, 0x5D, 0x5D, 0xE7, 0x44, + 0x7D, 0x1B, 0xE8, 0xC1, 0x60, 0x97, 0x57, 0x42, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5D, 0x86, 0xA6, 0x22, 0x72, 0x02, 0xA5, 0x02, + 0x00, 0x00, 0x97, 0x4E, 0xB5, 0x47, 0xC4, 0x2A, + 0xB0, 0x47, 0x2D, 0x00, 0x21, 0xC5, 0x8A, 0x85, + 0xD1, 0x44, 0x23, 0xFD, 0xC8, 0x44, 0xA1, 0xC4, + 0xEA, 0xC1, 0x91, 0x4E, 0x71, 0xC2, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0xAD, + 0xA6, 0x22, 0x72, 0x02, 0xA5, 0x02, 0x00, 0x00, + 0xCD, 0x07, 0xD6, 0x47, 0x1D, 0xA4, 0xCE, 0x47, + 0x6E, 0x61, 0x33, 0xC5, 0x85, 0x55, 0xD1, 0x44, + 0x9C, 0x16, 0xBD, 0x44, 0x36, 0xC0, 0xEB, 0xC1, + 0xF0, 0xFF, 0x5B, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x25, 0x03, 0x00 +}; +#endif + +/************************** Function Prototypes ******************************/ +static struct irq_ctrl_desc *intcDescPtr; // General interrupt controller descriptor +static struct timer_desc *logTmPtr; +static MPC *mpcDescPtr; +static PHY_INST *phyInstPtr; +static TMC_INST *tmcInstPtr = NULL; +L2_INST *linkInstPtr; + + +static bool LinklayerPush2Up(RING_BUFFER *buff){ + return Mpc_PushSvcFrame(mpcDescPtr, (void*)buff); +} +static bool LinklayerPopFromUp(RING_BUFFER **buff) { + return Mpc_PopSvcFrame(mpcDescPtr, (void**)buff); +} + +/****************************************************************************/ +/** + * This function is responsible for initializing the SCUGIC instance, looking + * for the device configuration based on the unique device ID, initializing a + * SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0] + * + * @param intcDesc A pointer to INTC descriptor + * + * @return SUCCESS if initialize successful. + * FAILURE if initialization failed. + * + *****************************************************************************/ +static int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) +{ + int32_t Status; + struct xil_irq_desc *xil_dev; + + Status = irq_ctrl_init(&descPtr, &intc_init_param); + if (Status != SUCCESS) + { + DBG_ERROR("Intc Init FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + xil_dev = (struct xil_irq_desc *)(descPtr->extra); + + // Clear any pending interrupt flags + uint32_t intrState = XScuGic_CPUReadReg((XScuGic *)(xil_dev->instance), XSCUGIC_INT_ACK_OFFSET); + XScuGic_CPUWriteReg((XScuGic *)(xil_dev->instance), XSCUGIC_EOI_OFFSET, intrState); + + /* Initialize physical layer interrupt. */ + Status = irq_trigger_level_set(descPtr, PHY_INTR_ID, IRQ_EDGE_RISING); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Set highest interrupt priority + Status = irq_set_priority(descPtr, PHY_INTR_ID, 0x08); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Connect the interrupt service routine isr1 to the interrupt controller + Status = irq_register_callback(descPtr, PHY_INTR_ID, &phy_callback_desc); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + /* Initialize linklayer layer interrupt. */ + Status = irq_trigger_level_set(descPtr, PERIODIC_5MS_INTR_ID, IRQ_EDGE_RISING); + if (Status != SUCCESS) + { + DBG_ERROR("PERIODIC_5MS_INTR_ID trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Set highest interrupt priority + Status = irq_set_priority(descPtr, PERIODIC_5MS_INTR_ID, 0x00); + if (Status != SUCCESS) + { + DBG_ERROR("PERIODIC_5MS_INTR_ID priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Connect the interrupt service routine isr1 to the interrupt controller + Status = irq_register_callback(descPtr, PERIODIC_5MS_INTR_ID, &periodicpull_callback_desc); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + /* Initialize system bus interrupt. */ + Status = irq_trigger_level_set(descPtr, MPC_TX_INTR_ID, IRQ_EDGE_RISING); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Set interrupt priority + Status = irq_set_priority(descPtr, MPC_TX_INTR_ID, 0x10); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + // Connect the interrupt service routine isr1 to the interrupt controller + Status = irq_register_callback(descPtr, MPC_TX_INTR_ID, &mpc_tx_callback_desc); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + Status = irq_trigger_level_set(descPtr, MPC_RX_INTR_ID, IRQ_EDGE_RISING); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + // Set interrupt priority + Status = irq_set_priority(descPtr, MPC_RX_INTR_ID, 0x18); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + // Connect the interrupt service routine isr1 to the interrupt controller + Status = irq_register_callback(descPtr, MPC_RX_INTR_ID, &mpc_rx_callback_desc); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + /* Initialize Scu timer interrupt. */ + // Connect the interrupt service routine isr1 to the interrupt controller + Status = irq_register_callback(descPtr, SCUTIMER_INTR_ID, &scutm_callback_desc); + if (Status != SUCCESS) + { + DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + // Enable interrupts + irq_enable(descPtr, PHY_INTR_ID); + irq_enable(descPtr, PERIODIC_5MS_INTR_ID); + irq_enable(descPtr, MPC_RX_INTR_ID); + irq_enable(descPtr, MPC_TX_INTR_ID); +// irq_enable(descPtr, SCUTIMER_INTR_ID); + + // Enable Exceptions + Status = irq_global_enable(descPtr); + if (Status != SUCCESS) + { + DBG_ERROR("IRQ global enable FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + return SUCCESS; +} // SetupInterruptSystem + +/****************************************************************************/ +/** + * This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1] + * tells CPU that the data in OCM is ready! + * + * @param context + * + * @return None. + * + *****************************************************************************/ +static void Phy_IntrHandler(void *context) +{ + Phy_UpdateState(phyInstPtr); +} // PhyIntr_Handler + + +/****************************************************************************/ +/** + * Handler of periodic 5ms interrupt + * + * @param callBackRef is the linklayer instance pointer. + * + * @return None. + * + *****************************************************************************/ +static void PeriodicPull_Handler(void *callBackRef) +{ + int32_t Status; + Status = Linklayer_Proc(linkInstPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Link layer runs failed, with error code: %" PRId32 "\n", Status); + _nop_(); + } +} // PeriodicPull_Handler + +/*****************************************************************************/ +/** + * @brief Handler of System Bus RX done interrupt. + * + * @param context + * + * @return None. + * + ******************************************************************************/ +static void Mpc_RxIntrHandler(void *context) +{ + int32_t Status; + Status = Mpc_RxIrqHandler(mpcDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_RxIrqHandler exit with error code %" PRId32 ",\n", Status); + } +} + +/*****************************************************************************/ +/** + * @brief Handler of System Bus TX done interrupt. + * + * @param context + * + * @return None. + * + ******************************************************************************/ +static void Mpc_TxIntrHandler(void *context) +{ + int32_t Status; + Status = Mpc_TxIrqHandler(mpcDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_TxIrqHandler exit with error code %" PRId32 ",\n", Status); + } +} + +/*****************************************************************************/ +/** + * @brief Handler of ScuTimer interrupt. + * + * @param context + * + * @return None. + * + ******************************************************************************/ +static void ScuTimer_IntrHandler(void *context) +{ + struct xil_timer_desc *xdesc; + xdesc = (struct xil_timer_desc *)(logTmPtr->extra); + if (XScuTimer_IsExpired((XScuTimer *)xdesc->instance)) + { + // Refresh log + Phy_RefreshHwSate(phyInstPtr); + if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE) + { + Phy_UpdateLogging(phyInstPtr); + } + + if (Mpc_IsEnable(mpcDescPtr)) + { + if (Mpc_PendRemoteTest(mpcDescPtr) != SUCCESS) + { + DBG_ERROR("Failed to apply remote test.\n"); + } +#ifdef APP_EMULATE_DATA + if (L2_GetNodeType(linkInstPtr) == L2_NODE_HEAD) + { + SysMonitor_UpdateSendPayload(testDataFlj, PAYLOAD_LEN_FLJ_TX); + } + else + { + SysMonitor_UpdateSendPayload(testDataLj, PAYLOAD_LEN_LJ_TX); + } +#endif + } + + XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance); + } + else + { + DBG_WARNING("UNEXPECTED CALL of ScuTimer_IntrHandler\n"); + } +} + +/*****************************************************************************/ +/** + * @brief Main function, initialize all the device needed, initialize + * interrupt system, halt in while(1) wait for event interrupt. + * + * @param None. + * + * @return + * + ******************************************************************************/ +int main(void) +{ + int32_t Status; + DBG_PRINT("Application Version: %2d.%2d.%4d.\n", _APP_VER_MAIN, _APP_VER_MINOR, _APP_VER_PATCH); + + /* System Monitor Initialize */ + Status = SysMonitor_Init(); + if (Status == SUCCESS) + { + DBG_PRINT("System monitor Init SUCCESS! \n"); + } + else + { + DBG_PRINT("System monitor Init FAILED! \n"); + return Status; + } + + Status = HARDWARE_initialize(); + if (Status == SUCCESS) + { + DBG_PRINT("Hardware Init SUCCESS! \n"); + } + else + { + DBG_PRINT("Hardware Init FAILED! \n"); + return Status; + } + + // Init time controller + Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig); + if (Status == SUCCESS) + { + DBG_PRINT("TmcCtrl Init SUCCESS! \n"); + } + else + { + DBG_PRINT("TmcCtrl Init FAILED! \n"); + return Status; + } + + /* Physical Layer Initialize */ + Status = Phy_Init(&phyInstPtr, &phyConfig); + if (Status == SUCCESS) + { + DBG_PRINT("Physical layer Init SUCCESS! \n"); + } + else + { + DBG_PRINT("Physical layer FAILED! \n"); + return Status; + } + + /* Link Layer Initialize */ + linkConfig.phyInstPtr = phyInstPtr; + linkConfig.tmcInstPtr = tmcInstPtr; + Status = Linklayer_Init(&linkInstPtr, &linkConfig); + if (Status == SUCCESS) + { + DBG_PRINT("LinkLayer Init SUCCESS! \n"); + } + else + { + DBG_PRINT("Linklayer Init FAILED! \n"); + return Status; + } + + /* System Bus Initialize */ + Status = Mpc_Init(&mpcDescPtr, &mpcConfig); + if (Status != SUCCESS) + { + DBG_ERROR("MPC init FAILED, with error code: %" PRId32 "\n", Status); + return Status; + } + + /* System Monitor log timer Initialize */ + Status = timer_init(&logTmPtr, &scutimer_init_param); + if (Status != SUCCESS) + { + DBG_ERROR("SCU Timer init FAILED, with error code: %" PRId32 "\n", Status); + return Status; + } + + /* interrupts Initialize */ + Status = SetupInterruptSystem(intcDescPtr); + if (Status == SUCCESS) + { + DBG_INFO("Interrupt system setup SUCCESS!\n"); + } + else + { + DBG_ERROR("Interrupt system setup FAILED, ErrorCode: %" PRId32 ".\n", Status); + return Status; + } + + // Start System Monitor logging. + timer_start(logTmPtr); + + DBG_PRINT("Physical started...\n"); + Phy_Start(phyInstPtr); + + while (true) + { + // System bus handler + if (Mpc_IsReqPending(mpcDescPtr)) + { + Status = Mpc_HandleCmd(mpcDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); + } + } + if (Mpc_IsRsqPending(mpcDescPtr) && (!Mpc_IsTxBusy(mpcDescPtr))) + { + usleep(2000); + Status = Mpc_MakeResp(mpcDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); + } + } + if (Mpc_IsSvcUpPending(mpcDescPtr)) + { + Status = Mpc_UploadSvcData(mpcDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); + } + } + if (Mpc_IsSvcDownPending(mpcDescPtr)) + { + RING_BUFFER *msg = NULL; + Mpc_PopSvcFrame(mpcDescPtr, (void**)&msg); + Mpc_PushSvcFrame(mpcDescPtr, (void*)msg); + if (Status != SUCCESS) + { + DBG_ERROR("Mpc_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); + } + } + } +} // main diff --git a/src/ge_config/app_config.h b/src/ge_config/app_config.h new file mode 100644 index 0000000..c7b80d6 --- /dev/null +++ b/src/ge_config/app_config.h @@ -0,0 +1,101 @@ +/*****************************************************************************/ +/** + * Description: Global configurations. + * + * Date: 2021-04-28 13:19 + * Last Editors: Fan Hao + * Last Edit Time: [2022-05-23 20:32] + * + * Revisions: Rev 0.0 + * History: + * [2021-04-28]: Initial edition. + * + * Copyright(c) 2021 Beijing Institute of Technology. + * Lab of Communication and Networking + * + ******************************************************************************/ + +#ifndef CONFIG_H_ +#define CONFIG_H_ + +#define XILINX_PLATFORM + +#include "xparameters.h" + +/******** Software Version ********/ +#define _APP_VER 0x00010008 + +#define _APP_VER_MAIN ((_APP_VER & 0xFF000000) >> 24) +#define _APP_VER_MINOR ((_APP_VER & 0x00FF0000) >> 16) +#define _APP_VER_PATCH (_APP_VER & 0x0000FFFF) + +/*********** Debug Info Level ************/ +// #define _DEBUG_LEVEL 1 +// 3 - print all debug info +// 2 - print warnings and errors +// 1 - print only errors +// other - print nothing + +#define APP_EMULATE_DATA +#define DATALINK_ENABLE_AUTORECONNECT +#define DATALINK_ENABLE_AUTOTIMESYNC +//#define DATALINK_ENABLE_BERTEST + + +/************ Hardware Configs ************/ +#define CPU_CLK_HZ XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ +#define GLOBAL_TIMER_CLK_HZ (CPU_CLK_HZ/2) +#define SCU_TIMER_CLK_HZ (CPU_CLK_HZ/2) +#define FCLK_CLK0_HZ 100000000 + +/********* Zynq Platform Configs **********/ +// SCU Timer (for logging) +#define SCUTIMER_DEVICE_ID XPAR_PS7_SCUTIMER_0_DEVICE_ID +#define SCUTIMER_INTR_ID XPAR_SCUTIMER_INTR + +// Physical Layer Configs +#define PHY_DEVICE_ID 0 +#define PHY_BASEADDR XPAR_PHYC_BASEADDR +#define PHY_BEAM_SET_PRESET +#define PHY_BEAM_FORMING_ENABLE +// -- Antenna Bram Configs +#define PHY_ANTCONFIG_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_INFO_BRAM_CTRL_DEVICE_ID +// -- Buffers +#define PHY_TXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_TX_FRAME_BRAM_CTRL_DEVICE_ID +#define PHY_RXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_RX_FRAME_BRAM_CTRL_DEVICE_ID +// -- Xadc +#define PHY_HW_XADC_DEVICE_ID XPAR_PS7_XADC_0_DEVICE_ID +// -- Interrupt id +#define PHY_INTR_ID XPAR_FABRIC_PHY_IRQ_INTR +#define PERIODIC_5MS_INTR_ID XPAR_FABRIC_PHY_5MS_DELAY_2MS_INTR + +// Time Controller Configs +#define TIME_CONTROLLER_BASEADDR XPAR_TMC_BASEADDR + +// System Bus Configs +#define MPC_BRAM_ID XPAR_MPC_BRAM_INTERFACE_MPC_BRAM_CTRL_DEVICE_ID +#define MPC_GPIO_ID XPAR_MPC_GPIO_DEVICE_ID +#define MPC_TX_INTR_ID XPAR_FABRIC_MPC_TX_IRQ_INTR +#define MPC_RX_INTR_ID XPAR_FABRIC_MPC_RX_IRQ_INTR + +// Global Timer config +#define GLOBAL_TIMER_DEVICE_ID XPAR_GLOBAL_TMR_DEVICE_ID +#define GLOBAL_TIMER_BASEADDR XPAR_GLOBAL_TMR_BASEADDR +#define GLOBAL_TIMER_INTR_ID XPAR_GLOBAL_TMR_INTR + +// INTC configis +#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID + +// Configuration Check +#if defined(PHY_BEAM_SET_PRESET) && !defined(PHY_BEAM_FORMING_ENABLE) +#define PHY_BEAM_FORMING_ENABLE +#warning To impliment beam scan must enable beam forming... +#endif + +#if defined(DATALINK_ENABLE_BERTEST) +#if !defined(DATALINK_ENABLE_AUTOTIMESYNC) + #warning To enbale bit error rate test, auto time-sync should be enabled... +#endif +#endif + +#endif diff --git a/src/ge_config/dev_profile/dev_profile.h b/src/ge_config/dev_profile/dev_profile.h new file mode 100644 index 0000000..dccd4cd --- /dev/null +++ b/src/ge_config/dev_profile/dev_profile.h @@ -0,0 +1,13 @@ +#ifndef _DEV_PROFILE_H_ +#define _DEV_PROFILE_H_ + +#include "irq.h" +#include "error.h" +#include "../app_config.h" + +// device parameters +extern struct irq_init_param intc_init_param; +extern struct timer_init_param scutimer_init_param; +extern struct global_timer_init_param globaltimer_init_param; + +#endif /* SRC_DEV_PROFILE_H_ */ diff --git a/src/dev_profile/global_timer_profile.c b/src/ge_config/dev_profile/global_timer_profile.c similarity index 84% rename from src/dev_profile/global_timer_profile.c rename to src/ge_config/dev_profile/global_timer_profile.c index 78fab27..eae497a 100644 --- a/src/dev_profile/global_timer_profile.c +++ b/src/ge_config/dev_profile/global_timer_profile.c @@ -1,6 +1,6 @@ #include "dev_profile.h" #include "global_timer.h" -#include "../config/app_config.h" +#include "../app_config.h" struct global_timer_init_param globaltimer_init_param = { .base_addr = GLOBAL_TIMER_BASEADDR, diff --git a/src/ge_config/dev_profile/intc_profile.c b/src/ge_config/dev_profile/intc_profile.c new file mode 100644 index 0000000..554c73c --- /dev/null +++ b/src/ge_config/dev_profile/intc_profile.c @@ -0,0 +1,13 @@ +#include "dev_profile.h" +#include "irq.h" +#include "../app_config.h" +#include "drivers/platform/xilinx_irq.h" +struct xil_irq_init_param xil_intc_init_param = { + .type = IRQ_PS +}; + +struct irq_init_param intc_init_param = { + .irq_ctrl_id = INTC_DEVICE_ID, + .platform_ops = &xil_irq_ops, + .extra = &xil_intc_init_param +}; diff --git a/src/ge_config/dev_profile/timer_profile.c b/src/ge_config/dev_profile/timer_profile.c new file mode 100644 index 0000000..1208b4b --- /dev/null +++ b/src/ge_config/dev_profile/timer_profile.c @@ -0,0 +1,17 @@ +#include "dev_profile.h" +#include "timer.h" +#include "../app_config.h" +#include "drivers/platform/xilinx_timer.h" + +struct xil_timer_init_param xil_scutimer_init_param = { + .active_tmr = 0, + .type = TIMER_PS +}; + +struct timer_init_param scutimer_init_param = { + .id = SCUTIMER_DEVICE_ID, + .freq_hz = SCU_TIMER_CLK_HZ, + .ticks_count = (SCU_TIMER_CLK_HZ/2), //update log every 500ms + .platform_ops = &xil_timer_ops, + .extra = &xil_scutimer_init_param +}; diff --git a/src/hardware/common.c b/src/hardware/common.c new file mode 100644 index 0000000..c4323b2 --- /dev/null +++ b/src/hardware/common.c @@ -0,0 +1,275 @@ +/** + * \file common.c + * \brief Contains Mykonos API common wrapper functions for user hardware platform drivers + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +#include +#include +#include +#include +#include "common.h" +#include "platform_drivers.h" +#include "parameters.h" + +ADI_LOGLEVEL CMB_LOGLEVEL = ADIHAL_LOG_NONE; + +static uint32_t _desired_time_to_elapse_us = 0; +struct spi_desc *spi_ad_desc; +struct gpio_desc *gpio_ad9371_resetb; +struct gpio_desc *gpio_ad9528_resetb; +struct gpio_desc *gpio_ad9528_sysref_req; + +commonErr_t CMB_initPlatform(void) +{ + struct spi_init_param spi_param; + int32_t status = COMMONERR_OK; + + status |= gpio_get(&gpio_ad9371_resetb, AD9371_RESET_B); + status |= gpio_get(&gpio_ad9528_resetb, AD9528_RESET_B); + status |= gpio_get(&gpio_ad9528_sysref_req, AD9528_SYSREF_REQ); + + spi_param.id = 0; + spi_param.mode = SPI_MODE_0; + spi_param.chip_select = AD9371_CS; + spi_param.max_speed_hz = 25000000u; + + status |= spi_init(&spi_ad_desc, &spi_param); + + if (status != SUCCESS) { + return COMMONERR_FAILED; + } + + return COMMONERR_OK; +} + +commonErr_t CMB_closeHardware(void) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_setGPIO(uint32_t GPIO) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_hardReset(uint8_t spiChipSelectIndex) +{ + struct gpio_desc *reset_gpio; + + switch (spiChipSelectIndex) { + case AD9371_CS: + reset_gpio = gpio_ad9371_resetb; + break; + case AD9528_CS: + reset_gpio = gpio_ad9528_resetb; + break; + default: + return(COMMONERR_FAILED); + } + + gpio_direction_output(reset_gpio, 1); + CMB_wait_ms(1); + gpio_direction_output(reset_gpio, 0); + CMB_wait_ms(1); + gpio_direction_output(reset_gpio, 1); + CMB_wait_ms(1); + + return(COMMONERR_OK); +} + +commonErr_t CMB_setSPIOptions(spiSettings_t *spiSettings) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_setSPIChannel(uint16_t chipSelectIndex ) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, + uint8_t data) +{ + uint8_t buf[3]; + + spi_ad_desc->chip_select = spiSettings->chipSelectIndex - 1; + + buf[0] = (uint8_t) ((addr >> 8) & 0x7f); + buf[1] = (uint8_t) (addr & 0xff); + buf[2] = (uint8_t) data; + + spi_write_and_read(spi_ad_desc, buf, 3); + + return(COMMONERR_OK); +} + +commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, + uint8_t *data, uint32_t count) +{ + uint32_t index; + + for (index = 0; index < count; index++) + if (CMB_SPIWriteByte(spiSettings, *(addr + index), + *(data + index)) != COMMONERR_OK) + return(COMMONERR_FAILED); + + return(COMMONERR_OK); +} + +commonErr_t CMB_SPIReadByte(spiSettings_t *spiSettings, uint16_t addr, + uint8_t *readdata) +{ + uint8_t buf[3]; + + spi_ad_desc->chip_select = spiSettings->chipSelectIndex - 1; + + buf[0] = (uint8_t) ((addr >> 8) | 0x80); + buf[1] = (uint8_t) (addr & 0xff); + buf[2] = (uint8_t) 0x00; + + spi_write_and_read(spi_ad_desc, buf, 3); + *readdata = buf[2]; + + return(COMMONERR_OK); +} + +commonErr_t CMB_SPIWriteField(spiSettings_t *spiSettings, uint16_t addr, + uint8_t field_val, uint8_t mask, uint8_t start_bit) +{ + uint8_t data; + + if (CMB_SPIReadByte(spiSettings, addr, &data) != COMMONERR_OK) + return(COMMONERR_FAILED); + + data = (data & ~mask) | ((field_val << start_bit) & mask); + + if (CMB_SPIWriteByte(spiSettings, addr, data) != COMMONERR_OK) + return(COMMONERR_FAILED); + + return(COMMONERR_OK); +} + +/* read a field in a single register space (not multibyte fields) */ +commonErr_t CMB_SPIReadField(spiSettings_t *spiSettings, uint16_t addr, + uint8_t *field_val, uint8_t mask, uint8_t start_bit) +{ + uint8_t data; + + if (CMB_SPIReadByte(spiSettings, addr, &data) != COMMONERR_OK) + return(COMMONERR_FAILED); + + data = (data & mask) >> start_bit; + *field_val = data; + + return(COMMONERR_OK); +} + + +commonErr_t CMB_writeToLog(ADI_LOGLEVEL level, uint8_t deviceIndex, + uint32_t errorCode, const char *comment) +{ + + if((CMB_LOGLEVEL & ADIHAL_LOG_ERROR) && (level == ADIHAL_LOG_ERROR)) { + printf("ERROR: %d: %s", (int)errorCode, comment); + } else if((CMB_LOGLEVEL & ADIHAL_LOG_WARNING) + && (level == ADIHAL_LOG_WARNING)) { + printf("WARNING: %d: %s",(int)errorCode, comment); + } else if((CMB_LOGLEVEL & ADIHAL_LOG_MESSAGE) + && (level == ADIHAL_LOG_MESSAGE)) { + printf("MESSAGE: %d: %s",(int)errorCode, comment); + } else if(CMB_LOGLEVEL == ADIHAL_LOG_NONE ) { + //printf("MESSAGE: %d: %s",(int)errorCode, comment); + } else { + printf("Undefined Log Level: 0x%X", level); + } + + return(COMMONERR_OK); +} + +/* if filename null, a default path will be used in logging.c */ +commonErr_t CMB_openLog(const char *filename) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_closeLog(void) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_flushLog(void) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_wait_ms(uint32_t time_ms) +{ + mdelay(time_ms); + + return(COMMONERR_OK); +} + +commonErr_t CMB_wait_us(uint32_t time_us) +{ + udelay(time_us); + + return(COMMONERR_OK); +} + +commonErr_t CMB_setTimeout_ms(uint32_t timeOut_ms) +{ +#ifdef _XPARAMETERS_PS_H_ + _desired_time_to_elapse_us = timeOut_ms * 1000; +#else + _desired_time_to_elapse_us = timeOut_ms * 50; // FIXME +#endif + + return(COMMONERR_OK); +} + +commonErr_t CMB_setTimeout_us(uint32_t timeOut_us) +{ + _desired_time_to_elapse_us = timeOut_us; + + return(COMMONERR_OK); +} + + +commonErr_t CMB_hasTimeoutExpired() +{ + udelay(1); + + _desired_time_to_elapse_us--; + if (_desired_time_to_elapse_us > 0) + return(COMMONERR_OK); + + return(COMMONERR_FAILED); +} + +commonErr_t CMB_regRead(uint32_t offset, uint32_t *data) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_regWrite(uint32_t offset, uint32_t data) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_memRead(uint32_t offset, uint32_t *data, uint32_t len) +{ + return(COMMONERR_OK); +} + +commonErr_t CMB_memWrite(uint32_t offset, uint32_t *data, uint32_t len) +{ + return(COMMONERR_OK); +} diff --git a/src/hardware/common.h b/src/hardware/common.h new file mode 100644 index 0000000..5a78efe --- /dev/null +++ b/src/hardware/common.h @@ -0,0 +1,131 @@ +/** + * \file common.h + * \brief Contains type definitions and prototype declarations for common.c + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _HW_COMMON_H_ +#define _HW_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* build project settings include the path to the desired platform folder for correct includes */ +#include "stdint.h" + +#define THROW_ERROR() + +#define SPIARRAYSIZE 1024 + +/* assuming 3 byte SPI message - integer math enforces floor() */ +#define SPIARRAYTRIPSIZE ((SPIARRAYSIZE / 3) * 3) + +/*======================================== + * Enums and structures + *=======================================*/ +/* proposed to increase number of error return values to make unique for each return */ +typedef enum +{ + ADIERR_OK=0, + ADIERR_INV_PARM, + ADIERR_FAILED +} ADI_ERR; + +/*!< \brief COMMON layer error reporting enumerated types */ +typedef enum +{ + COMMONERR_OK=0, + COMMONERR_FAILED +} commonErr_t; + +/* bit 0 is MESSAGE, bit 1 is WARNING, bit 2 is ERROR */ +typedef enum +{ + ADIHAL_LOG_NONE = 0x0, + ADIHAL_LOG_MESSAGE = 0x1, + ADIHAL_LOG_WARNING = 0x2, + ADIHAL_LOG_ERROR = 0x4, + ADIHAL_LOG_SPI = 0x8, + ADIHAL_LOG_AXI_REG = 0x10, + ADIHAL_LOG_AXI_MEM = 0x20, + ADIHAL_LOG_ALL = 0x3F +} ADI_LOGLEVEL; + +/** + * \brief Data structure to hold SPI settings for all system device types + */ +typedef struct +{ + uint8_t chipSelectIndex; ///< valid 1~8 + uint8_t writeBitPolarity; ///< the level of the write bit of a SPI write instruction word, value is inverted for SPI read operation + uint8_t longInstructionWord; ///< 1 = 16bit instruction word, 0 = 8bit instruction word + uint8_t MSBFirst; ///< 1 = MSBFirst, 0 = LSBFirst + uint8_t CPHA; ///< clock phase, sets which clock edge the data updates (valid 0 or 1) + uint8_t CPOL; ///< clock polarity 0 = clock starts low, 1 = clock starts high + uint8_t enSpiStreaming; ///< Not implemented. SW feature to improve SPI throughput. + uint8_t autoIncAddrUp; ///< Not implemented. For SPI Streaming, set address increment direction. 1= next addr = addr+1, 0:addr = addr-1 + uint8_t fourWireMode; ///< 1: Use 4-wire SPI, 0: 3-wire SPI (SDIO pin is bidirectional). NOTE: ADI's FPGA platform always uses 4-wire mode. + uint32_t spiClkFreq_Hz; ///< SPI Clk frequency in Hz (default 25000000), platform will use next lowest frequency that it's baud rate generator can create */ + +} spiSettings_t; + +/* global variable so application layer can set the log level */ +extern ADI_LOGLEVEL CMB_LOGLEVEL; +extern struct spi_desc *spi_ad_desc; +extern struct gpio_desc *gpio_ad9371_resetb; +extern struct gpio_desc *gpio_ad9528_resetb; +extern struct gpio_desc *gpio_ad9528_sysref_req; + +/* initialize hardware platform */ +commonErr_t CMB_initPlatform(void); + +/* close hardware pointers */ +commonErr_t CMB_closeHardware(void); + +/* GPIO function */ +commonErr_t CMB_setGPIO(uint32_t GPIO); + +/* hardware reset function */ +commonErr_t CMB_hardReset(uint8_t spiChipSelectIndex); + +/* SPI read/write functions */ +commonErr_t CMB_setSPIOptions(spiSettings_t *spiSettings); /* allows the platform HAL to work with devices with various SPI settings */ +commonErr_t CMB_setSPIChannel(uint16_t chipSelectIndex ); /* value of 0 deasserts all chip selects */ +commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t data); /* single SPI byte write function */ +commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, uint8_t *data, uint32_t count); +commonErr_t CMB_SPIReadByte (spiSettings_t *spiSettings, uint16_t addr, uint8_t *readdata); /* single SPI byte read function */ +commonErr_t CMB_SPIWriteField(spiSettings_t *spiSettings, uint16_t addr, uint8_t field_val, uint8_t mask, uint8_t start_bit); /* write a field in a single register */ +commonErr_t CMB_SPIReadField (spiSettings_t *spiSettings, uint16_t addr, uint8_t *field_val, uint8_t mask, uint8_t start_bit); /* read a field in a single register */ + +/* platform timer functions */ +commonErr_t CMB_wait_ms(uint32_t time_ms); +commonErr_t CMB_wait_us(uint32_t time_us); +commonErr_t CMB_setTimeout_ms(uint32_t timeOut_ms); +commonErr_t CMB_setTimeout_us(uint32_t timeOut_us); +commonErr_t CMB_hasTimeoutExpired(); + +/* platform logging functions */ +commonErr_t CMB_openLog(const char *filename); +commonErr_t CMB_closeLog(void); +commonErr_t CMB_writeToLog(ADI_LOGLEVEL level, uint8_t deviceIndex, uint32_t errorCode, const char *comment); +commonErr_t CMB_flushLog(void); + +/* platform FPGA AXI register read/write functions */ +commonErr_t CMB_regRead(uint32_t offset, uint32_t *data); +commonErr_t CMB_regWrite(uint32_t offset, uint32_t data); + +/* platform DDR3 memory read/write functions */ +commonErr_t CMB_memRead(uint32_t offset, uint32_t *data, uint32_t len); +commonErr_t CMB_memWrite(uint32_t offset, uint32_t *data, uint32_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/hardware/headless.c b/src/hardware/headless.c new file mode 100644 index 0000000..642e7bc --- /dev/null +++ b/src/hardware/headless.c @@ -0,0 +1,1177 @@ +/******************************************************************************* * @file ad9371/src/app/headless.c + * @brief Implementation of Main Function. + ******************************************************************************** + * Copyright 2017(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *******************************************************************************/ + +/***************************** Include Files ********************************/ +#include "headless.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +// XGpio GpioFreqCtrl; +// XGpio GpioGainCtrl; +// XGpio GpioAttnCtrl; +XScuGic Intc; + +/************************** Function Prototypes ******************************/ + +int HARDWARE_initialize() +{ + int Status; + + // use configuration + mykDevice.rx->rxPllLoFrequency_Hz = 2500000000u; + mykDevice.tx->txPllLoFrequency_Hz = 2500000000u; + mykDevice.tx->tx1Atten_mdB = 20000; + mykDevice.tx->tx2Atten_mdB = 20000; + + Status = HARDWARE_ad9371Config(); + + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + // /**********************************************************/ + // /************ AD9371 Dynamical Reconfiguration ************/ + // /**********************************************************/ + // Status = HW_ad9371DynamicCfgInit(); + // if (Status != ADIERR_OK){ + // HW_PRINT("HW:: AD9371 dynamic configuration initialization failed!\n"); + // return ADIERR_FAILED; + // } + // + // HW_PRINT("HW:: AD9371 ready to be reconfigured!\n"); + // + // // main loop + // while(1); + + // never reach + return ADIERR_OK; +} + +// this function is NOT safe +int HARDWARE_ad9371Config(void) +{ + int Status; + uint8_t reg508; + uint8_t framerStatus; + uint8_t obsFramerStatus; + uint8_t deframerStatus; + + /**********************************************************/ + /*********** Initialize Configuration Interface ***********/ + /**********************************************************/ + Status = CMB_initPlatform(); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + Status = HW_adiCfgProfileInit(); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + HW_PRINT("HW:: Initialize configuration interface done!\n"); + + /**********************************************************/ + /****************** AD9528 Configuration ******************/ + /**********************************************************/ + Status = HW_9528Config(ad9528Init); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + HW_PRINT("HW:: AD9528 configuration done!\n"); + + Status = HW_9528GetLockStatus(ad9528Init, ®508); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + HW_PRINT("HW:: AD9528 REG508: 0x%02x\n", reg508); + + /**********************************************************/ + /****************** AD9371 Configuration ******************/ + /**********************************************************/ + Status = HW_9371Config(ad9528Init, &mykDevice); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + + Status = HW_9371CheckJesdStatus(&mykDevice, &framerStatus, + &obsFramerStatus, &deframerStatus); + if (Status != ADIERR_OK) + { + return ADIERR_FAILED; + } + else + { + // typical value: 0x3E + HW_PRINT("HW:: RxFramerStatus = 0x%x\n", framerStatus); + // typical value: 0x3E + HW_PRINT("HW:: OrxFramerStatus = 0x%x\n", obsFramerStatus); + // typical value: 0x28 + HW_PRINT("HW:: DeframerStatus = 0x%x\n", deframerStatus); + } + + HW_PRINT("HW:: All configuration done!\n"); + + return ADIERR_OK; +} + +// this function is NOT safe +// int HW_ad9371DynamicCfgInit(void) +//{ +// int Status; +// +// Status = HW_setupIntrSystem(INTC_DEVICE_ID, &Intc); +// if (Status != XST_SUCCESS) { +// HW_PRINT("HW: HW_setupIntrSystem() failed!\n"); +// return XST_FAILURE; +// } +// +// Status = XGpio_Initialize(&GpioFreqCtrl, FREQ_CTRL_DEVICE_ID); +// Status |= XGpio_Initialize(&GpioGainCtrl, GAIN_CTRL_DEVICE_ID); +// Status |= XGpio_Initialize(&GpioAttnCtrl, ATTN_CTRL_DEVICE_ID); +// if (Status != XST_SUCCESS) { +// HW_PRINT("HW: GPIO init failed!\n"); +// return XST_FAILURE; +// } +// +// /* Set the direction for all signals as inputs. */ +// XGpio_SetDataDirection(&GpioFreqCtrl, AXI_GPIO_BANK_1, 0xFFFFFFFF); +// XGpio_SetDataDirection(&GpioFreqCtrl, AXI_GPIO_BANK_2, 0xFFFFFFFF); +// +// XGpio_SetDataDirection(&GpioGainCtrl, AXI_GPIO_BANK_1, 0xFFFFFFFF); +// XGpio_SetDataDirection(&GpioGainCtrl, AXI_GPIO_BANK_2, 0xFFFFFFFF); +// +// XGpio_SetDataDirection(&GpioAttnCtrl, AXI_GPIO_BANK_1, 0xFFFFFFFF); +// XGpio_SetDataDirection(&GpioAttnCtrl, AXI_GPIO_BANK_2, 0xFFFFFFFF); +// +// Status = HW_connectIntr(&Intc, FREQ_CTRL_INTR_ID, +// (Xil_InterruptHandler)FreqIntrHandler, &GpioFreqCtrl, 0xA0, 0x3); +// Status |= HW_connectIntr(&Intc, GAIN_CTRL_INTR_ID, +// (Xil_InterruptHandler)GainIntrHandler, &GpioGainCtrl, 0xA0, 0x3); +// Status |= HW_connectIntr(&Intc, ATTN_CTRL_INTR_ID, +// (Xil_InterruptHandler)AttnIntrHandler, &GpioAttnCtrl, 0xA0, 0x3); +// +// XGpio_InterruptEnable(&GpioFreqCtrl, XGPIO_IR_MASK); +// XGpio_InterruptGlobalEnable(&GpioFreqCtrl); +// +// XGpio_InterruptEnable(&GpioGainCtrl, XGPIO_IR_MASK); +// XGpio_InterruptGlobalEnable(&GpioGainCtrl); +// +// XGpio_InterruptEnable(&GpioAttnCtrl, XGPIO_IR_MASK); +// XGpio_InterruptGlobalEnable(&GpioAttnCtrl); +// +// return XST_SUCCESS; +//} + +/*****************************************************************************/ +/* + * + * This function setups the interrupt system. + * + * @param DeviceId is the unique identifier for a GIC device. + * @param GicPtr is a pointer to the instance of the INTC. + * + * @return + * - XST_SUCCESS if successful, + * - XST_FAILURE.if not succesful + * + * @note None. + * + ******************************************************************************/ +int HW_setupIntrSystem(u16 DeviceId, XScuGic *GicPtr) +{ + int Status; + XScuGic_Config *CfgPtr; + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + CfgPtr = XScuGic_LookupConfig(DeviceId); + if (!CfgPtr) + { + HW_PRINT("No interrupt config found for %d\n", DeviceId); + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(GicPtr, CfgPtr, CfgPtr->CpuBaseAddress); + if (Status != XST_SUCCESS) + { + HW_PRINT("No interrupt config found for %d\n", DeviceId); + return XST_FAILURE; + } + + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XScuGic_InterruptHandler, + (void *)GicPtr); + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +int HW_connectIntr(XScuGic *GicPtr, u32 IntrId, Xil_InterruptHandler Handler, + void *CallBackRef, u8 Priority, u8 Trigger) +{ + int Status; + // Register interrupt handler + Status = XScuGic_Connect(GicPtr, IntrId, (Xil_InterruptHandler)Handler, + CallBackRef); + if (Status != XST_SUCCESS) + { + return XST_FAILURE; + } + XScuGic_SetPriorityTriggerType(GicPtr, IntrId, Priority, Trigger); + + XScuGic_Enable(GicPtr, IntrId); + + return XST_SUCCESS; +} + +int HW_adiCfgProfileInit(void) +{ + if (!ad9528Init) + { + HW_PRINT("Cannot find ad9528 configuration profile with name 'ad9528Init'!"); + return ADIERR_FAILED; + } + + if (!&mykDevice) + { + HW_PRINT("Cannot find ad9371 configuration profile with name 'mykDevice'!"); + return ADIERR_FAILED; + } + + ad9528Init->spiSettings->chipSelectIndex = AD9528_CS; + mykDevice.spiSettings->chipSelectIndex = AD9371_CS; + + mykDevice.rx->framer->serializerLanesEnabled = 0x03; + mykDevice.rx->framer->serializerLaneCrossbar = 0xE4; + mykDevice.obsRx->framer->serializerLanesEnabled = 0x04; + mykDevice.tx->deframer->deserializerLanesEnabled = 0x03; + mykDevice.tx->deframer->deserializerLaneCrossbar = 0xE4; + + return ADIERR_OK; +} + +int HW_9528Config(ad9528Device_t *clockAD9528_device) +{ + ADI_ERR error; + /**************************************************************************/ + /***** System Clocks Initialization Initialization Sequence *****/ + /**************************************************************************/ + + /* Perform a hard reset on the AD9528 DUT */ + error = AD9528_resetDevice(clockAD9528_device); + if (error != ADIERR_OK) + { + HW_PRINT("AD9528_resetDevice() failed\n"); + return ADIERR_FAILED; + } + + error = AD9528_initDeviceDataStruct(clockAD9528_device, + clockAD9528_device->pll1Settings->vcxo_Frequency_Hz, + clockAD9528_device->pll1Settings->refA_Frequency_Hz, + clockAD9528_device->outputSettings->outFrequency_Hz[1]); + if (error != ADIERR_OK) + { + HW_PRINT("AD9528_initDeviceDataStruct() failed\n"); + return ADIERR_FAILED; + } + + /* Initialize the AD9528 by writing all SPI registers */ + error = AD9528_initialize(clockAD9528_device); + if (error != ADIERR_OK) + { + HW_PRINT("WARNING: AD9528_initialize() issues.\n"); + } + + return ADIERR_OK; +} + +int HW_9528GetLockStatus(ad9528Device_t *device, uint8_t *reg508) +{ + ADI_ERR error; + + error = CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_STATUS_READBACK0, reg508); + if (error != ADIERR_OK) + { + HW_PRINT("HW_9528GetLockStatus failed.\n"); + return ADIERR_FAILED; + } + + return ADIERR_OK; +} + +int HW_9371Config(ad9528Device_t *clockAD9528_device, mykonosDevice_t *mykDevice) +{ + ADI_ERR error; + mykonosErr_t mykError; + const char *errorString; + uint8_t pllLockStatus; + uint8_t mcsStatus; + uint8_t arm_major; + uint8_t arm_minor; + uint8_t arm_release; + uint32_t initCalMask = TX_BB_FILTER | ADC_TUNER | TIA_3DB_CORNER | DC_OFFSET | + TX_ATTENUATION_DELAY | RX_GAIN_DELAY | FLASH_CAL | + PATH_DELAY | TX_LO_LEAKAGE_INTERNAL | TX_QEC_INIT | + LOOPBACK_RX_LO_DELAY | LOOPBACK_RX_RX_QEC_INIT | + RX_LO_DELAY | RX_QEC_INIT; + uint8_t errorFlag = 0; + uint8_t errorCode = 0; + uint32_t initCalsCompleted; + uint32_t trackingCalMask = TRACK_ORX1_QEC | TRACK_ORX2_QEC | TRACK_RX1_QEC | + TRACK_RX2_QEC | TRACK_TX1_QEC | TRACK_TX2_QEC; + + /* Allocating memory for the errorString */ + errorString = NULL; + + /*************************************************************************/ + /***** Mykonos Initialization Sequence *****/ + /*************************************************************************/ + + /* Perform a hard reset on the MYKONOS DUT (Toggle RESETB pin on device) */ + if ((mykError = MYKONOS_resetDevice(mykDevice)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_initialize(mykDevice)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /*************************************************************************/ + /***** Mykonos CLKPLL Status Check *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_checkPllsLockStatus(mykDevice, + &pllLockStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /*************************************************************************/ + /***** Mykonos Perform MultiChip Sync *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_enableMultichipSync(mykDevice, 1, + &mcsStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /* Minimum 3 SYSREF pulses from Clock Device has to be produced for MulticChip Sync */ + + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + + /*************************************************************************/ + /***** Mykonos Verify MultiChip Sync *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_enableMultichipSync(mykDevice, 0, + &mcsStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mcsStatus & 0x0B) == 0x0B) + HW_PRINT("MCS successful\n"); + else + HW_PRINT("MCS failed\n"); + + /*************************************************************************/ + /***** Mykonos Load ARM file *****/ + /*************************************************************************/ + + if (pllLockStatus & 0x01) + { + HW_PRINT("CLKPLL locked\n"); + if ((mykError = MYKONOS_initArm(mykDevice)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_loadArmFromBinary(mykDevice, + &firmware_Mykonos_M3_bin[0], firmware_Mykonos_M3_bin_len)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + } + else + { + HW_PRINT("CLKPLL not locked (0x%x)\n", pllLockStatus); + error = ADIERR_FAILED; + goto error_2; + } + + /* Read back the version of the ARM binary loaded into the Mykonos ARM memory */ + if ((mykError = MYKONOS_getArmVersion(mykDevice, &arm_major, &arm_minor, + &arm_release, NULL)) == MYKONOS_ERR_OK) + HW_PRINT("AD9371 ARM version %d.%d.%d\n", arm_major, arm_minor, arm_release); + + /*************************************************************************/ + /***** Mykonos Set RF PLL Frequencies *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_setRfPllFrequency(mykDevice, RX_PLL, + mykDevice->rx->rxPllLoFrequency_Hz)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_setRfPllFrequency(mykDevice, TX_PLL, + mykDevice->tx->txPllLoFrequency_Hz)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_setRfPllFrequency(mykDevice, SNIFFER_PLL, + mykDevice->obsRx->snifferPllLoFrequency_Hz)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /* Wait 200ms for PLLs to lock */ + mdelay(200); + + if ((mykError = MYKONOS_checkPllsLockStatus(mykDevice, + &pllLockStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((pllLockStatus & 0x0F) == 0x0F) + HW_PRINT("PLLs locked\n"); + else + { + HW_PRINT("PLLs not locked (0x%x)\n", pllLockStatus); + error = ADIERR_FAILED; + goto error_2; + } + + // /*************************************************************************/ + // /***** Mykonos Set GPIOs *****/ + // /*************************************************************************/ + // + // if ((mykGpioErr = MYKONOS_setRx1GainCtrlPin(mykDevice, 0, 0, 0, 0, + // 0)) != MYKONOS_ERR_GPIO_OK) { + // errorString = getGpioMykonosErrorMessage(mykGpioErr); + // goto error_11; + // } + // + // if ((mykGpioErr = MYKONOS_setRx2GainCtrlPin(mykDevice, 0, 0, 0, 0, + // 0)) != MYKONOS_ERR_GPIO_OK) { + // errorString = getGpioMykonosErrorMessage(mykGpioErr); + // goto error_11; + // } + // + // if ((mykGpioErr = MYKONOS_setTx1AttenCtrlPin(mykDevice, 0, 0, 0, 0, + // 0)) != MYKONOS_ERR_GPIO_OK) { + // errorString = getGpioMykonosErrorMessage(mykGpioErr); + // goto error_11; + // } + // + // if ((mykGpioErr = MYKONOS_setTx2AttenCtrlPin(mykDevice, 0, 0, 0, + // 0)) != MYKONOS_ERR_GPIO_OK) { + // errorString = getGpioMykonosErrorMessage(mykGpioErr); + // goto error_11; + // } + // + // if ((mykGpioErr = MYKONOS_setupGpio(mykDevice)) != MYKONOS_ERR_GPIO_OK) { + // errorString = getGpioMykonosErrorMessage(mykGpioErr); + // goto error_11; + // } + // + // /*************************************************************************/ + // /***** Mykonos Set manual gains values *****/ + // /*************************************************************************/ + // + // if ((mykError = MYKONOS_setRx1ManualGain(mykDevice, 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setRx2ManualGain(mykDevice, 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setObsRxManualGain(mykDevice, OBS_RX1_TXLO, + // 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setObsRxManualGain(mykDevice, OBS_RX2_TXLO, + // 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setObsRxManualGain(mykDevice, OBS_SNIFFER_A, + // 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setObsRxManualGain(mykDevice, OBS_SNIFFER_B, + // 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // if ((mykError = MYKONOS_setObsRxManualGain(mykDevice, OBS_SNIFFER_C, + // 255)) != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // /*************************************************************************/ + // /***** Mykonos Initialize attenuations *****/ + // /*************************************************************************/ + // + // mykError = MYKONOS_setTx1Attenuation(mykDevice, 10000); + // if (mykError != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + // + // mykError = MYKONOS_setTx2Attenuation(mykDevice, 10000); + // if (mykError != MYKONOS_ERR_OK) { + // errorString = getMykonosErrorMessage(mykError); + // goto error_11; + // } + + /*************************************************************************/ + /***** Mykonos ARM Initialization Calibrations *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_runInitCals(mykDevice, + (initCalMask & ~TX_LO_LEAKAGE_EXTERNAL))) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_waitInitCals(mykDevice, 60000, &errorFlag, + &errorCode)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((errorFlag != 0) || (errorCode != 0)) + { + /*** < Info: abort init cals > ***/ + if ((mykError = MYKONOS_abortInitCals(mykDevice, + &initCalsCompleted)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + if (initCalsCompleted) + HW_PRINT("Completed calibrations: %x\n", (unsigned int)initCalsCompleted); + } + else + HW_PRINT("Calibrations completed successfully\n"); + + /*************************************************************************/ + /***** Mykonos ARM Initialization External LOL Calibrations with PA *****/ + /*************************************************************************/ + + /* Please ensure PA is enabled operational at this time */ + if (initCalMask & TX_LO_LEAKAGE_EXTERNAL) + { + if ((mykError = MYKONOS_runInitCals(mykDevice, + TX_LO_LEAKAGE_EXTERNAL)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_waitInitCals(mykDevice, 60000, &errorFlag, + &errorCode)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((errorFlag != 0) || (errorCode != 0)) + { + /*** < Info: abort init cals > ***/ + if ((mykError = MYKONOS_abortInitCals(mykDevice, + &initCalsCompleted)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + } + else + HW_PRINT("External LOL Calibrations completed successfully\n"); + } + + /*************************************************************************/ + /***** SYSTEM JESD bring up procedure *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_enableSysrefToRxFramer(mykDevice, + 1)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + /*** < Info: Mykonos is waiting for sysref in order to start + * transmitting CGS from the RxFramer> ***/ + + if ((mykError = MYKONOS_enableSysrefToObsRxFramer(mykDevice, + 1)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + /*** < Info: Mykonos is waiting for sysref in order to start + * transmitting CGS from the ObsRxFramer> ***/ + + if ((mykError = MYKONOS_enableSysrefToDeframer(mykDevice, + 0)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_resetDeframer(mykDevice)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + if ((mykError = MYKONOS_enableSysrefToDeframer(mykDevice, 1)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /*************************************************************************/ + /***** Enable SYSREF to Mykonos and BBIC *****/ + /*************************************************************************/ + + /* Request a SYSREF from the AD9528 */ + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + + /*** < Info: Mykonos is actively transmitting CGS from the RxFramer> ***/ + + /*** < Info: Mykonos is actively transmitting CGS from the ObsRxFramer> ***/ + + /* Request two SYSREFs from the AD9528 */ + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(1); + AD9528_requestSysref(clockAD9528_device, 1); + mdelay(5); + + /*************************************************************************/ + /***** Mykonos enable tracking calibrations *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_enableTrackingCals(mykDevice, + trackingCalMask)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /*** < Info: Allow Rx1/2 QEC tracking and Tx1/2 QEC tracking to run when in the radioOn state + * Tx calibrations will only run if radioOn and the obsRx path is set to OBS_INTERNAL_CALS > ***/ + + /*** < Info: Function to turn radio on, Enables transmitters and receivers + * that were setup during MYKONOS_initialize() > ***/ + if ((mykError = MYKONOS_radioOn(mykDevice)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + /*** < Info: Allow TxQEC to run when User: is not actively using ORx receive path > ***/ + if ((mykError = MYKONOS_setObsRxPathSource(mykDevice, + OBS_RXOFF)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + if ((mykError = MYKONOS_setObsRxPathSource(mykDevice, + OBS_INTERNALCALS)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + mdelay(1000); + + if ((mykError = MYKONOS_setObsRxPathSource(mykDevice, + OBS_RX1_SNIFFERLO)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + goto error_11; + } + + Xil_DCacheInvalidateRange(DDR_MEM_BASEADDR + 0x800000, 16384 * 8); + + HW_PRINT("Done\n"); + + return 0; + +error_11: + HW_PRINT("%s", errorString); + +error_2: + // axi_clkgen_remove(rx_clkgen); + return FAILURE; +} + +int HW_9371CheckJesdStatus(mykonosDevice_t *mykDevice, uint8_t *framerStatus, + uint8_t *obsFramerStatus, uint8_t *deframerStatus) +{ + mykonosErr_t mykError; + const char *errorString; + /* Allocating memory for the errorString */ + errorString = NULL; + + /*************************************************************************/ + /***** Check Mykonos Framer Status *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_readRxFramerStatus(mykDevice, + framerStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + return ADIERR_FAILED; + } + else + { + // typical value: 0x3E + } + + if ((mykError = MYKONOS_readOrxFramerStatus(mykDevice, + obsFramerStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + return ADIERR_FAILED; + } + else + { + // typical value: 0x3E + } + + /*************************************************************************/ + /***** Check Mykonos Deframer Status *****/ + /*************************************************************************/ + + if ((mykError = MYKONOS_readDeframerStatus(mykDevice, + deframerStatus)) != MYKONOS_ERR_OK) + { + errorString = getMykonosErrorMessage(mykError); + return ADIERR_FAILED; + } + else + { + // typical value: 0x28 + } + + return ADIERR_OK; +} + +int HW_9371SmallFrequencyChange(mykonosDevice_t *mykDevice, uint64_t freq_Hz) +{ + mykonosErr_t mykError = MYKONOS_ERR_OK; + uint8_t pllLockStatus = 0; + /* + * Move the device into the radio off state. + */ + if ((mykError = MYKONOS_radioOff(mykDevice)) != MYKONOS_ERR_OK) + { + HW_PRINT("Turn radio off failed!\n\r"); + return ADIERR_FAILED; + } + + /* + * Program the new local oscillator (LO) frequency. Check if PLL is locked. + */ + if ((mykError = MYKONOS_setRfPllFrequency(mykDevice, TX_PLL, + freq_Hz)) != MYKONOS_ERR_OK) + { + HW_PRINT("Set TX PLL failed!\n\r"); + return ADIERR_FAILED; + } + mykError = MYKONOS_checkPllsLockStatus(mykDevice, &pllLockStatus); + if ((pllLockStatus & 0x07) != 0x07) + { + /*** < Info: Clock, Rx and Tx PLLs not locked > ***/ + HW_PRINT("Not all PLLs locked, lock status: 0x%02x\n", pllLockStatus); + } + + /* + * Reset the external channel. + */ + // If((mykError = MYKONOS_resetExtTxLolChannel(mykDevice, TX1_TX2)) + // != MYKONOS_ERR_OK) ; //where TX1_TX2 is part of the enum mykonosTxChannels_t + // { + // HW_PRINT("Reset external channel FAILED!"); + // } + + /* + * Move the device back into the radio on state. + */ + if ((mykError = MYKONOS_radioOn(mykDevice)) != MYKONOS_ERR_OK) + { + HW_PRINT("Turn radio on failed!\n\r"); + return ADIERR_FAILED; + } + + /* + * Reenable tracking calibrations. + */ + // If((mykError = MYKONOS_MYKONOS_setObsRxPathSource(mykDevice, OBS_INTERNALCALS)) + // != MYKONOS_ERR_OK) ; //where TX1_TX2 is part of the enum mykonosTxChannels_t + // { + // HW_PRINT("Reenable tracking calibrations FAILED!"); + // } + return ADIERR_OK; +} + +int HW_9371LargeFrequencyChange(mykonosDevice_t *mykDevice, uint64_t freq_Hz) +{ + mykonosErr_t mykError = MYKONOS_ERR_OK; + uint8_t pllLockStatus = 0; + uint8_t errorFlag = 0; + uint8_t errorCode = 0; + uint32_t initCalsCompleted = 0; + uint16_t errorWord = 0; + uint16_t statusWord = 0; + uint8_t status = 0; + mykonosInitCalStatus_t initCalStatus = {0}; + + /* + * Move the device into the radio off state. + */ + if ((mykError = MYKONOS_radioOff(mykDevice)) != MYKONOS_ERR_OK) + { + HW_PRINT("Turn radio off failed!\n\r"); + return ADIERR_FAILED; + } + + /* + * Program the new local oscillator (LO) frequency. Check if PLL is locked. + */ + if ((mykError = MYKONOS_setRfPllFrequency(mykDevice, TX_PLL, + freq_Hz)) != MYKONOS_ERR_OK) + { + HW_PRINT("Set TX PLL failed!\n\r"); + return ADIERR_FAILED; + } + mykError = MYKONOS_checkPllsLockStatus(mykDevice, &pllLockStatus); + if ((pllLockStatus & 0x07) != 0x07) + { + /*** < Info: Clock, Rx and Tx PLLs not locked > ***/ + HW_PRINT("Not all PLLs locked, lock status: 0x%02x\n", pllLockStatus); + } + + /* + * Rerun the initialization calibrations. + */ + uint32_t initCalMask = TX_QEC_INIT | LOOPBACK_RX_LO_DELAY | + LOOPBACK_RX_RX_QEC_INIT | RX_LO_DELAY | RX_QEC_INIT; + if ((mykError = MYKONOS_runInitCals(mykDevice, initCalMask)) != MYKONOS_ERR_OK) + { + HW_PRINT("Rerun the initialization calibrations FAILED!"); + return ADIERR_FAILED; + } + if ((mykError = MYKONOS_waitInitCals(mykDevice, 60000, &errorFlag, + &errorCode)) != MYKONOS_ERR_OK) + { + HW_PRINT("Initialize calibration TIME OUT!"); + return ADIERR_FAILED; + } + if ((errorFlag != 0) || (errorCode != 0)) + { + HW_PRINT("initial cals error!\n\r"); + + if ((mykError = MYKONOS_getInitCalStatus(mykDevice, &initCalStatus)) != MYKONOS_ERR_OK) + { + /*** < User log error return value to debug why init failed > ***/ + } + + // abort init calibrations + if ((mykError = MYKONOS_abortInitCals(mykDevice, &initCalsCompleted)) != MYKONOS_ERR_OK) + { + /*** < User log error return value to debug why init failed > ***/ + } + if (initCalsCompleted) + { + /*** < which calls had completed, per the mask > ***/ + } + if ((mykError = MYKONOS_readArmCmdStatus(mykDevice, &errorWord, + &statusWord)) != MYKONOS_ERR_OK) + { + /*** < User log error return value to debug why init failed > ***/ + } + if ((mykError = MYKONOS_readArmCmdStatusByte(mykDevice, 2, &status)) != MYKONOS_ERR_OK) + { + } + if (status != 0) + { + /*** < Arm Mailbox Status Error errorWord > ***/ + /*** < Pending Flag per opcode statusWord, this follows the mask > ***/ + } + } + + /* + * Move the device back into the radio on state. + */ + if ((mykError = MYKONOS_radioOn(mykDevice)) != MYKONOS_ERR_OK) + { + HW_PRINT("Turn radio on failed!\n\r"); + return ADIERR_FAILED; + } + + return ADIERR_OK; +} + +// void FreqIntrHandler(void *CallbackRef) +// { +// XGpio *GpioPtr = (XGpio *)CallbackRef; +// uint8_t IntrStatus; +// uint32_t NewFreqHz; +// IntrStatus = XGpio_InterruptGetStatus(GpioPtr); + +// if (IntrStatus & XGPIO_IR_CH1_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH1_MASK); + +// NewFreqHz = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_1); +// if (NewFreqHz != mykDevice.tx->txPllLoFrequency_Hz) +// { +// if (NewFreqHz > 300000000 && NewFreqHz < 6000000000) +// { +// if (abs(NewFreqHz - mykDevice.tx->txPllLoFrequency_Hz) <= 100000000) +// { +// HW_9371SmallFrequencyChange(&mykDevice, NewFreqHz); +// } +// else +// { +// HW_9371LargeFrequencyChange(&mykDevice, NewFreqHz); +// } +// mykDevice.tx->txPllLoFrequency_Hz = NewFreqHz; +// HW_PRINT("New Tx frequency set to %d Hz!\n", NewFreqHz); +// } +// else +// { +// HW_PRINT("The desired Tx Frequency is out of range(300 ~ 6000 MHz)!\n"); +// } +// } +// } + +// if (IntrStatus & XGPIO_IR_CH2_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH2_MASK); + +// NewFreqHz = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_2); +// if (NewFreqHz != mykDevice.rx->rxPllLoFrequency_Hz) +// { +// if (NewFreqHz > 300000000 && NewFreqHz < 6000000000) +// { +// if (abs(NewFreqHz - mykDevice.rx->rxPllLoFrequency_Hz) <= 100000000) +// { +// HW_9371SmallFrequencyChange(&mykDevice, NewFreqHz); +// } +// else +// { +// HW_9371LargeFrequencyChange(&mykDevice, NewFreqHz); +// } +// mykDevice.rx->rxPllLoFrequency_Hz = NewFreqHz; +// HW_PRINT("New Rx frequency set to %d Hz!\n", NewFreqHz); +// } +// else +// { +// HW_PRINT("The desired Rx Frequency is out of range(300 ~ 6000 MHz)!\n"); +// } +// } +// } +// } + +// void GainIntrHandler(void *CallbackRef) +// { +// XGpio *GpioPtr = (XGpio *)CallbackRef; +// uint8_t IntrStatus; +// uint32_t NewRxGain; +// IntrStatus = XGpio_InterruptGetStatus(GpioPtr); + +// if (IntrStatus & XGPIO_IR_CH1_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH1_MASK); + +// NewRxGain = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_1); +// if (NewRxGain != mykDevice.rx->rxGainCtrl->rx1GainIndex) +// { +// if ((NewRxGain >= 195) && (NewRxGain <= 255)) +// { +// MYKONOS_setRx1ManualGain(&mykDevice, NewRxGain); +// mykDevice.rx->rxGainCtrl->rx1GainIndex = NewRxGain; +// char buf[BUFSIZ]; +// sHW_PRINT(buf, "%u", NewRxGain); +// HW_PRINT("New Rx1 gain index set to %s!\n", buf); +// } +// else +// { +// HW_PRINT("The desired Rx1 gain index is out of range(195 ~ 255), 0.5dB per stage!\n"); +// } +// } +// } + +// if (IntrStatus & XGPIO_IR_CH2_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH2_MASK); + +// NewRxGain = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_2); +// if (NewRxGain != mykDevice.rx->rxGainCtrl->rx2GainIndex) +// { +// if ((NewRxGain >= 195) && (NewRxGain <= 255)) +// { +// MYKONOS_setRx2ManualGain(&mykDevice, NewRxGain); +// mykDevice.rx->rxGainCtrl->rx2GainIndex = NewRxGain; +// char buf[BUFSIZ]; +// sHW_PRINT(buf, "%u", NewRxGain); +// HW_PRINT("New Rx2 gain index set to %s!\n", buf); +// } +// else +// { +// HW_PRINT("The desired Rx2 gain index is out of range(195 ~ 255), 0.5dB per stage!\n"); +// } +// } +// } +// } + +// void AttnIntrHandler(void *CallbackRef) +// { +// XGpio *GpioPtr = (XGpio *)CallbackRef; +// uint8_t IntrStatus; +// uint32_t NewTxAttn; +// IntrStatus = XGpio_InterruptGetStatus(GpioPtr); + +// if (IntrStatus & XGPIO_IR_CH1_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH1_MASK); + +// NewTxAttn = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_1); +// if (NewTxAttn != mykDevice.tx->tx1Atten_mdB) +// { +// if ((NewTxAttn >= 0) && (NewTxAttn <= 41950)) +// { +// MYKONOS_setTx1Attenuation(&mykDevice, NewTxAttn); +// mykDevice.tx->tx1Atten_mdB = NewTxAttn; +// char buf[BUFSIZ]; +// sHW_PRINT(buf, "%u", NewTxAttn); +// HW_PRINT("New Tx1 attenuation set to %s dBm!\n", buf); +// } +// else +// { +// HW_PRINT("The desired Tx1 attenuation is out of range(0 ~ 41950 dBm), 50 dBm step!\n"); +// } +// } +// } + +// if (IntrStatus & XGPIO_IR_CH2_MASK) +// { +// /* Clear the Interrupt */ +// XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH2_MASK); + +// NewTxAttn = XGpio_DiscreteRead(GpioPtr, AXI_GPIO_BANK_2); +// if (NewTxAttn != mykDevice.tx->tx2Atten_mdB) +// { +// if ((NewTxAttn >= 0) && (NewTxAttn <= 41950)) +// { +// MYKONOS_setTx2Attenuation(&mykDevice, NewTxAttn); +// mykDevice.tx->tx2Atten_mdB = NewTxAttn; +// char buf[BUFSIZ]; +// sHW_PRINT(buf, "%u", NewTxAttn); +// HW_PRINT("New Tx2 attenuation set to %s dBm!\n", buf); +// } +// else +// { +// HW_PRINT("The desired Tx2 attenuation is out of range(0 ~ 41950 dBm), 50 dBm step!\n"); +// } +// } +// } +// } diff --git a/src/hardware/headless.h b/src/hardware/headless.h new file mode 100644 index 0000000..384f8cf --- /dev/null +++ b/src/hardware/headless.h @@ -0,0 +1,349 @@ +/* + * headless.h + * + * Created on: 2021��6��8�� + * Author: Josh + */ + +#ifndef SRC_HEADLESS_H_ +#define SRC_HEADLESS_H_ + +/***************************** Include Files ********************************/ +#include +#include +#include "xil_cache.h" +#include "xscugic.h" +//#include "xgpio.h" + +#include "common.h" +#include "./mykonos/ad9528.h" +#include "./mykonos/mykonos.h" +#include "./mykonos/Mykonos_M3.h" +#include "./mykonos/mykonos_gpio.h" +#include "myk_ad9528init.h" +#include "myk_init.h" + +#include "parameters.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +#define HW_PRINT(...) __asm__("nop") +// #define HW_PRINT(...) printf(__VA_ARGS__) +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/* +* +* This function setups ad9528 and ad9371 via spi. +* +* @param None. +* +* @return +* - ADIERR_FAILED if successful, +* - ADIERR_OK if not succesful +* +* @note None. +* +******************************************************************************/ +int HARDWARE_initialize(); + +int HARDWARE_ad9371Config(void); + +/*****************************************************************************/ +/* +* +* Setup up Axi Gpio, through which ad9371 can be reconfigured. Axi Gpio +* instance and interrupt system initialization are included. +* +* @param None. +* +* @return +* - ADIERR_FAILED if successful, +* - ADIERR_OK if not succesful +* +* @note None. +* +******************************************************************************/ +int HW_ad9371DynamicCfgInit(void); + +/*****************************************************************************/ +/* +* +* Setup up interrupt system, initialize exception handlers. +* +* @param DeviceId is the unique identifier for a device. +* @param GicPtr is a pointer to the XScuGic instance. +* +* @return +* - XST_SUCCESS if successful, +* - XST_FAILURE if not succesful +* +* @note None. +* +******************************************************************************/ +int HW_setupIntrSystem(u16 DeviceId, XScuGic * GicPtr); + +/*****************************************************************************/ +/* +* +* Make the connection between the Int_Id of the interrupt source and the +* associated handler. Set the interrupt priority and trigger type for the +* specified IRQ source.. +* +* @param GicPtr is a pointer to the XScuGic instance. +* @param Int_Id contains the ID of the interrupt source and should be +* in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1 +* @param Handler to the handler for that interrupt. +* @param CallBackRef is the callback reference, usually the instance +* pointer of the connecting driver. +* @param Priority is the new priority for the IRQ source. 0 is highest +* priority, 0xF8(248) is lowest. There are 32 priority levels +* supported with a step of 8. Hence the supported priorities are +* 0, 8, 16, 32, 40 ..., 248. +* @param Trigger is the new trigger type for the IRQ source. +* Each bit pair describes the configuration for an INT_ID. +* SFI Read Only b10 always +* PPI Read Only depending on how the PPIs are configured. +* b01 Active HIGH level sensitive +* b11 Rising edge sensitive +* SPI LSB is read only. +* b01 Active HIGH level sensitive +* b11 Rising edge sensitive/ +* +* @return +* - XST_SUCCESS if successful, +* - XST_FAILURE if not succesful +* +* @note None. +* +******************************************************************************/ +int HW_connectIntr(XScuGic *GicPtr,u32 IntrId,Xil_InterruptHandler Handler, + void *CallBackRef, u8 Priority, u8 Trigger); + +/*****************************************************************************/ +/* +* +* Initialize Analog Device related configuration profile. This is a HARDWARE- +* ASSOTIATED function, which may differ between different board. +* +* @param None. +* +* @return +* - ADIERR_OK if configuration profile exists, +* - ADIERR_FAILED if onfiguration profile does not exist +* +* @note None. +* +******************************************************************************/ +int HW_adiCfgProfileInit(void); + +/******************************************************************************/ +/** +* +* This function conducts AD9528 device configuration initializing procedure. +* +* @param clockAD9528_device is a pointer to the data structure holding +* AD9528 settings, which contains basic AD9528 settings such as +* spi and gpio. +* +* @return +* - ADIERR_OK if successful. +* - ADIERR_FAILED if not successful. +* +* @note None. +* +*******************************************************************************/ +int HW_9528Config(ad9528Device_t *clockAD9528_device); + +/******************************************************************************/ +/** +* +* This function read AD9528 reg508 status, to check whether ad9528 is locked or +* not. +* +* @param clockAD9528_device is a pointer to the data structure holding +* AD9528 settings, which contains basic AD9528 settings. +* +* @return +* - ADIERR_OK if successful. +* - ADIERR_FAILED if not successful. +* +* @note None. +* +*******************************************************************************/ +int HW_9528GetLockStatus(ad9528Device_t *device, uint8_t *reg508); + +/******************************************************************************/ +/** +* +* Conduct AD9371 device configuration initializing procedure. +* +* @param clockAD9528_device is a pointer to the data structure holding +* AD9528 settings, which contains basic AD9528 settings. +* @param mykDevice is ADI hardware layer settings pointer specific to +* a Mykonos instance which contains basic settings such as spi, +* gpio, tx/rx and jesd configurations. +* +* @return +* - ADIERR_OK if successful. +* - ADIERR_FAILED if not successful. +* +* @note None. +* +*******************************************************************************/ +int HW_9371Config(ad9528Device_t *clockAD9528_device, mykonosDevice_t *mykDevice); + +/******************************************************************************/ +/** +* +* Read AD9371's RX framer, ORX framer and TX deframer status, to check jesd204b +* sync status. +* +* @param mykDevice is ADI hardware layer settings pointer specific to +* a Mykonos instance which contains basic settings such as spi, +* gpio, tx/rx and jesd configurations. +* @param framerStatus is the RX framer status byte read +* framerStatus | Description +* -------------|----------------------------------------------------------------------------- +* [7] | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing. +* [6] | Framer lane FIFO read/write pointer delta has changed. Can help debug issues with deterministic latency. +* [5] | Framer has received the SYSREF and has retimed its LMFC +* [4:2] | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete +* [1:0] | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data +* @param obsFramerStatus is the ORX framer status byte read +* obsFramerStatus | Description +* ----------------|----------------------------------------------------------------------------- +* [7] | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing. +* [6] | Framer lane FIFO read/write pointer delta has changed. Can help debug issues with deterministic latency. +* [5] | Framer has received the SYSREF and has retimed its LMFC +* [4:2] | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete +* [1:0] | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data +* @param deframerStatus is the TX deframer status byte read +* deframerStatus | Bit Name | Description +* ----------------|--------------------------|--------------------------------------------- +* [7] | Unused | Unused +* [6] | Deframer IRQ | This bit indicates that the IRQ interrupt was asserted. +* [5] | Deframer SYSREF Received | When this bit is set, it indicates that the SYSREF pulse was received by the deframer IP +* [4] | Deframer Receiver Error | This bit is set when PRBS has received an error. +* [3] | Valid Checksum | This bit is set when the received ILAS checksum is valid. +* [2] | EOF Event | This bit captures the internal status of the framer End of Frame event. Value =1 if framing error during ILAS +* [1] | EOMF Event | This bit captures the internal status of the framer End of Multi-Frame event. Value =1 if framing error during ILAS +* [0] | FS Lost | This bit captures the internal status of the framer Frame Symbol event. Value =1 if framing error during ILAS or user data (invalid replacement characters) +* +* @return +* - ADIERR_OK if successful. +* - ADIERR_FAILED if not successful. +* +* @note None. +* +*******************************************************************************/ +int HW_9371CheckJesdStatus(mykonosDevice_t *mykDevice, uint8_t *framerStatus, + uint8_t *obsFramerStatus, uint8_t *deframerStatus); + +/******************************************************************************/ +/** +* +* This function conducts AD9371/9375 samll RF PLL frequcny change procedure. The +* procedure is performed as follows: +* 1. Move the device into the radio off state. +* 2. Program the new local oscillator (LO) frequency. +* 3. Reset the external channel.(ignored) +* 4. Move the device back into the radio on state. +* 5. Reenable tracking calibrations.(ignored) +* +* @param mykDevice is ADI hardware layer settings pointer specific to +* a Mykonos instance which contains basic settings such as spi, +* gpio, tx/rx and jesd configurations. +* @param freq_Hz is the target frequancy in Hz. +* +* @return None. +* +* @note The procedure is used when a radio frequency (RF) phased-lock loop +* (PLL) change is required with the following conditions: +* - A desire to change the Rx, Tx, and ORx frequencies. +* - The frequency step change is less than 100 MHz. +* - The frequency step does not cross the divide by 2 boundaries outlined +* in AD9371/9375-UG-992-Rev.B-Table 96. +* +*******************************************************************************/ +int HW_9371SmallFrequencyChange(mykonosDevice_t *mykDevice, uint64_t freq_Hz); + +/******************************************************************************/ +/** +* +* This function conducts AD9371/9375 large RF PLL frequcny change procedure. The +* procedure is performed as follows: +* 1. Move the device into the radio off state. +* 2. Program the new local oscillator (LO) frequency. +* 3. Rerun the initialization calibrations. +* 4. Move the device back into the radio on state. +* 5. Reenable tracking calibrations.(ignored) +* +* @param mykDevice is ADI hardware layer settings pointer specific to +* a Mykonos instance which contains basic settings such as spi, +* gpio, tx/rx and jesd configurations. +* @param freq_Hz is the target frequancy in Hz. +* +* @return None. +* +* @note The procedure is used when a radio frequency (RF) phased-lock loop +* (PLL) change is required with the following conditions: +* - A desire to change the Rx, Tx, and ORx frequencies. +* - The frequency step change is more than 100 MHz. +* - The frequency step does cross the divide by 2 boundaries outlined +* in AD9371/9375-UG-992-Rev.B-Table 96. +* +*******************************************************************************/ +int HW_9371LargeFrequencyChange(mykonosDevice_t *mykDevice, uint64_t freq_Hz); + +/******************************************************************************/ +/** +* +* Handles AD9371 TX & RX frequency change axi gpio interruput. +* +* @param CallBackRef is the callback reference, usually the instance +* pointer of the connecting driver. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void FreqIntrHandler(void *CallbackRef); + +/******************************************************************************/ +/** +* +* Handles AD9371 Rx gain index change axi gpio interruput. +* +* @param CallBackRef is the callback reference, usually the instance +* pointer of the connecting driver. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void GainIntrHandler(void *CallbackRef); + +/******************************************************************************/ +/** +* +* Handles AD9371 Tx attenuation change axi gpio interruput. +* +* @param CallBackRef is the callback reference, usually the instance +* pointer of the connecting driver. +* +* @return None. +* +* @note None. +* +*******************************************************************************/ +void AttnIntrHandler(void *CallbackRef); + +#endif /* SRC_HEADLESS_H_ */ diff --git a/src/hardware/myk_ad9528init.c b/src/hardware/myk_ad9528init.c new file mode 100644 index 0000000..0cb935d --- /dev/null +++ b/src/hardware/myk_ad9528init.c @@ -0,0 +1,189 @@ +///* +// * myk_clock_init.c +// * +// */ +// +///** +//* \page Disclaimer Legal Disclaimer +//* Copyright 2015-2017 Analog Devices Inc. +//* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +//* +//*/ +// +//#ifndef MYK_CLOCK_INIT_C_ +//#define MYK_CLOCK_INIT_C_ +//#include +//#include +//#include +//#include "common.h" +// +//#include "ad9528.h" +//#include "t_ad9528.h" +//#include "myk_ad9528init.h" +//#include "parameters.h" +// +//static ad9528pll1Settings_t clockPll1Settings = +//{ +// .refA_Frequency_Hz = 30720000, +// .refA_Divider = 1, +// .refA_bufferCtrl = DISABLED, +// .refB_Frequency_Hz = 0, +// .refB_Divider = 1, +// .refB_bufferCtrl = DISABLED, +// .vcxo_Frequency_Hz = 122880000, +// .vcxoBufferCtrl = NEG_SINGLE_ENDED, +// .nDivider = 4, +// .bypassPll1 = 0 +//}; +// +//static ad9528pll2Settings_t clockPll2Settings = +//{ +// .rfDivider = 4, +// .n2Divider = 10, +// .totalNdiv = 30 +//}; +// +//static ad9528outputSettings_t clockOutputSettings = +//{ +// .outPowerDown = 53237, // 0xCFF5 +// .outSource = { +// CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, SYSREF, +// CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, +// CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, +// SYSREF, CHANNEL_DIV}, +// .outBufferCtrl = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +// .outAnalogDelay = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +// .outDigitalDelay = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +// .outChannelDiv = {10,10,10,10,10,10,10,10,10,10,10,10,10,10}, +// .outFrequency_Hz = {122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000, 122880000} +//}; +// +//static ad9528sysrefSettings_t clockSysrefSettings = +//{ +// .sysrefRequestMethod = PIN, +// .sysrefSource = INTERNAL, +// .sysrefPinEdgeMode = LEVEL_ACTIVE_HIGH, +// .sysrefPinBufferMode = DISABLED, +// .sysrefPatternMode = NSHOT, +// .sysrefNshotMode = ONE_PULSE, +// .sysrefDivide = 512 +//}; +// +//static spiSettings_t clockSpiSettings = +//{ +// .chipSelectIndex = AD9528_CS, //chip select Index +// .writeBitPolarity = 0, //Write bit polarity +// .longInstructionWord = 1, //16bit instruction word +// .MSBFirst = 1, //MSB first +// .CPHA = 0, //Clock phase +// .CPOL = 0, //Clock polarity +// .enSpiStreaming = 0, //uint8_t enSpiStreaming; +// .autoIncAddrUp = 1, //uint8_t autoIncAddrUp; +// .fourWireMode = 1 //uint8_t fourWireMode; +//}; +// +//ad9528Device_t clockAD9528_ = +//{ +// &clockSpiSettings, +// &clockPll1Settings, +// &clockPll2Settings, +// &clockOutputSettings, +// &clockSysrefSettings +//}; +// +//ad9528Device_t *ad9528Init = &clockAD9528_; +// +//#endif /* MYK_CLOCK_INIT_C_ */ + + +/* AD9528 data structure initialization file */ +#include +#include +#include +#include "common.h" + +#include "./mykonos/ad9528.h" +#include "./mykonos/t_ad9528.h" +#include "myk_ad9528init.h" +#include "parameters.h" + +static ad9528pll1Settings_t clockPll1Settings = { + .refA_Frequency_Hz = 122880000, + .refA_Divider = 1, + .refA_bufferCtrl = SINGLE_ENDED, + .refB_Frequency_Hz = 0, + .refB_Divider = 1, + .refB_bufferCtrl = DISABLED, + .vcxo_Frequency_Hz = 122880000, + .vcxoBufferCtrl = DIFFERENTIAL, + .nDivider = 1, + .bypassPll1 = 0 +}; + +static ad9528pll2Settings_t clockPll2Settings = { + .rfDivider = 3, + .n2Divider = 10, + .totalNdiv = 30 +}; + +/******************************************************************* + * Output Distribution Settings + * 9369CE02A uses the following clock outputs + * OUT 1: FPGA_REF_CLK + * OUT 2: FPGA_AUX_CLK + * OUT 3: FPGA_SYSREF + * OUT 12: SYSREF_IN + * OUT 13: DEV_CLK_IN + ******************************************************************* + */ +static ad9528outputSettings_t clockOutputSettings = { + .outPowerDown = 0x0, + .outSource = { + SYSREF, SYSREF, CHANNEL_DIV, SYSREF, + CHANNEL_DIV, CHANNEL_DIV, SYSREF, SYSREF, + CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, CHANNEL_DIV, + SYSREF , CHANNEL_DIV + }, + .outBufferCtrl = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .outAnalogDelay = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .outDigitalDelay = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .outChannelDiv = {10,10,10,10,10,10,10,10,10,10,10,10,10,10}, + .outFrequency_Hz = { + 122880000, 122880000, 122880000, 122880000, + 122880000, 122880000, 122880000, 122880000, + 122880000, 122880000, 122880000, 122880000, + 122880000, 122880000 + } +}; + +static ad9528sysrefSettings_t clockSysrefSettings = { + .sysrefRequestMethod = SPI, + .sysrefSource = INTERNAL, + .sysrefPinEdgeMode = LEVEL_ACTIVE_HIGH, + .sysrefPinBufferMode = DISABLED, + .sysrefPatternMode = CONTINUOUS, + .sysrefNshotMode = FOUR_PULSES, + .sysrefDivide = 512 +}; + +static spiSettings_t clockSpiSettings = { + .chipSelectIndex = 2, //chip select Index + .writeBitPolarity = 0, //Write bit polarity + .longInstructionWord = 1, //16bit instruction word + .MSBFirst = 1, //MSB first + .CPHA = 0, //Clock phase + .CPOL = 0, //Clock polarity + .enSpiStreaming = 0, //uint8_t enSpiStreaming; + .autoIncAddrUp = 1, //uint8_t autoIncAddrUp; + .fourWireMode = 1 //uint8_t fourWireMode; +}; + +ad9528Device_t clockAD9528_ = { + &clockSpiSettings, + &clockPll1Settings, + &clockPll2Settings, + &clockOutputSettings, + &clockSysrefSettings +}; + +ad9528Device_t *ad9528Init = &clockAD9528_; diff --git a/src/hardware/myk_ad9528init.h b/src/hardware/myk_ad9528init.h new file mode 100644 index 0000000..53e8be6 --- /dev/null +++ b/src/hardware/myk_ad9528init.h @@ -0,0 +1,20 @@ +/* + * myk_clock_init.h + * + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef MYK_CLOCK_INIT_H_ +#define MYK_CLOCK_INIT_H_ + +#include "./mykonos/ad9528.h" + +extern ad9528Device_t *ad9528Init; + +#endif /* MYK_CLOCK_INIT_H_ */ diff --git a/src/hardware/myk_init.c b/src/hardware/myk_init.c new file mode 100644 index 0000000..d585d1a --- /dev/null +++ b/src/hardware/myk_init.c @@ -0,0 +1,558 @@ +/** + * \file myk_init.c + * + * \brief Contains init setting structure declarations for the _instance API + * + * The top level structure mykonosDevice_t mykDevice uses keyword + * extern to allow the application layer main() to have visibility + * to these settings. + * + * All data structures required for operation have been initialized with values which reflect + * these settings: + * + * Device Clock = $122.88$ Mhz + * Rx enabled channels = $2$ + * Tx enabled channels = $2$ + * + * Mykonos Framer: + * Lane Rate = $4915.2$ Mbs + * L = $2$ + * K = $32$ + * M = $4$ + * F = $4$ + * + * Mykonos Deframer: + * Lane Rate = $4915.2$ Mbs + * L = $2$ + * K = $32$ + * M = $4$ + * F = $4$ + * + * Mykonos Observation framer: + * Lane Rate = $4915.2$ Mbs + * L = $2$ + * K = $32$ + * M = $4$ + * F = $4$ + * + * Using these profiles: + * $Rx 100Mhz, IQrate 122.88Mhz, Dec5$ + * $Tx 100/100Mhz, IQrate 122.88Mhz, Dec5$ + * $ORX 100Mhz, IQrate 122.88Mhz, Dec5$ + * $SRx 20Mhz, IQrate 30.72Mhz, Dec5$ + * + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +#include "./mykonos/t_mykonos.h" +#include "myk_init.h" +#include "parameters.h" +#include "./mykonos/mykonos_gpio.h" + +static int16_t txFirCoefs[] = {-94,-26,282,177,-438,-368,756,732,-1170,-1337,1758,2479,-2648,-5088,4064,16760,16759,4110,-4881,-2247,2888,1917,-1440,-1296,745,828,-358,-474,164,298,-16,-94}; + +static mykonosFir_t txFir = +{ + 6, /* Filter gain in dB*/ + 32, /* Number of coefficients in the FIR filter*/ + &txFirCoefs[0] /* A pointer to an array of filter coefficients*/ +}; + +static int16_t rxFirCoefs[] = {-20,6,66,22,-128,-54,240,126,-402,-248,634,444,-956,-756,1400,1244,-2028,-2050,2978,3538,-4646,-7046,9536,30880,30880,9536,-7046,-4646,3538,2978,-2050,-2028,1244,1400,-756,-956,444,634,-248,-402,126,240,-54,-128,22,66,6,-20}; + +static mykonosFir_t rxFir = +{ + -6, /* Filter gain in dB*/ + 48, /* Number of coefficients in the FIR filter*/ + &rxFirCoefs[0] /* A pointer to an array of filter coefficients*/ +}; + +static int16_t obsrxFirCoefs[] = {-14,-19,44,41,-89,-95,175,178,-303,-317,499,527,-779,-843,1184,1317,-1781,-2059,2760,3350,-4962,-7433,9822,32154,32154,9822,-7433,-4962,3350,2760,-2059,-1781,1317,1184,-843,-779,527,499,-317,-303,178,175,-95,-89,41,44,-19,-14}; +static mykonosFir_t obsrxFir = +{ + -6, /* Filter gain in dB*/ + 48, /* Number of coefficients in the FIR filter*/ + &obsrxFirCoefs[0]/* A pointer to an array of filter coefficients*/ +}; + +static int16_t snifferFirCoefs[] = {-1,-5,-14,-23,-16,24,92,137,80,-120,-378,-471,-174,507,1174,1183,98,-1771,-3216,-2641,942,7027,13533,17738,17738,13533,7027,942,-2641,-3216,-1771,98,1183,1174,507,-174,-471,-378,-120,80,137,92,24,-16,-23,-14,-5,-1}; +static mykonosFir_t snifferRxFir= +{ + -6, /* Filter gain in dB*/ + 48, /* Number of coefficients in the FIR filter*/ + &snifferFirCoefs[0]/* A pointer to an array of filter coefficients*/ +}; + +static mykonosJesd204bFramerConfig_t rxFramer = +{ + 0, /* JESD204B Configuration Bank ID -extension to Device ID (Valid 0..15)*/ + 0, /* JESD204B Configuration Device ID - link identification number. (Valid 0..255)*/ + 0, /* JESD204B Configuration starting Lane ID. If more than one lane used, each lane will increment from the Lane0 ID. (Valid 0..31)*/ + 4, /* number of ADCs (0, 2, or 4) - 2 ADCs per receive chain*/ + 32, /* number of frames in a multiframe (default=32), F*K must be a multiple of 4. (F=2*M/numberOfLanes)*/ + 0, /* scrambling off if framerScramble= 0, if framerScramble>0 scramble is enabled.*/ + 1, /* 0=use internal SYSREF, 1= use external SYSREF*/ + 0x03, /* serializerLanesEnabled - bit per lane, [0] = Lane0 enabled, [1] = Lane1 enabled*/ + 0xE4, /* serializerLaneCrossbar*/ + 22, /* serializerAmplitude - default 22 (valid (0-31)*/ + 4, /* preEmphasis - < default 4 (valid 0 - 7)*/ + 0, /* invertLanePolarity - default 0 ([0] will invert lane [0], bit1 will invert lane1)*/ + 0, /* lmfcOffset - LMFC_Offset offset value for deterministic latency setting*/ + 0, /* Flag for determining if SYSREF on relink should be set. Where, if > 0 = set, 0 = not set*/ + 0, /* Flag for determining if auto channel select for the xbar should be set. Where, if > 0 = set, '0' = not set*/ + 0, /* Selects SYNCb input source. Where, 0 = use RXSYNCB for this framer, 1 = use OBSRX_SYNCB for this framer*/ + 0, /* Flag for determining if CMOS mode for RX Sync signal is used. Where, if > 0 = CMOS, '0' = LVDS*/ + 0, /* Selects framer bit repeat or oversampling mode for lane rate matching. Where, 0 = bitRepeat mode (changes effective lanerate), 1 = overSample (maintains same lane rate between ObsRx framer and Rx framer and oversamples the ADC samples)*/ + 0 /* Flag for determining if API will calculate the appropriate settings for framer lane outputs to physical lanes. Where, if '0' = API will set automatic lane crossbar, '1' = set to manual mode and the value in serializerLaneCrossbar will be used*/ +}; + +static mykonosJesd204bFramerConfig_t obsRxFramer = +{ + 0, /* JESD204B Configuration Bank ID -extension to Device ID (Valid 0..15)*/ + 0, /* JESD204B Configuration Device ID - link identification number. (Valid 0..255)*/ + 0, /* JESD204B Configuration starting Lane ID. If more than one lane used, each lane will increment from the Lane0 ID. (Valid 0..31)*/ + 2, /* number of ADCs (0, 2, or 4) - 2 ADCs per receive chain*/ + 32, /* number of frames in a multiframe (default=32), F*K must be a multiple of 4. (F=2*M/numberOfLanes)*/ + 0, /* scrambling off if framerScramble= 0, if framerScramble>0 scramble is enabled.*/ + 1, /* 0=use internal SYSREF, 1= use external SYSREF*/ + 0x04, /* serializerLanesEnabled - bit per lane, [0] = Lane0 enabled, [1] = Lane1 enabled*/ + 0xE4, /* Lane crossbar to map framer lane outputs to physical lanes*/ + 22, /* serializerAmplitude - default 22 (valid (0-31)*/ + 4, /* preEmphasis - < default 4 (valid 0 - 7)*/ + 0, /* invertLanePolarity - default 0 ([0] will invert lane [0], bit1 will invert lane1)*/ + 0, /* lmfcOffset - LMFC_Offset offset value for deterministic latency setting*/ + 0, /* Flag for determining if SYSREF on relink should be set. Where, if > 0 = set, 0 = not set*/ + 0, /* Flag for determining if auto channel select for the xbar should be set. Where, if > 0 = set, '0' = not set*/ + 1, /* Selects SYNCb input source. Where, 0 = use RXSYNCB for this framer, 1 = use OBSRX_SYNCB for this framer*/ + 0, /* Flag for determining if CMOS mode for RX Sync signal is used. Where, if > 0 = CMOS, '0' = LVDS*/ + 0, /* Selects framer bit repeat or oversampling mode for lane rate matching. Where, 0 = bitRepeat mode (changes effective lanerate), 1 = overSample (maintains same lane rate between ObsRx framer and Rx framer and oversamples the ADC samples)*/ + 0 /* Flag for determining if API will calculate the appropriate settings for framer lane outputs to physical lanes. Where, if '0' = API will set automatic lane crossbar, '1' = set to manual mode and the value in serializerLaneCrossbar will be used*/ +}; + +static mykonosJesd204bDeframerConfig_t deframer = +{ + 0, /* bankId extension to Device ID (Valid 0..15)*/ + 0, /* deviceId link identification number. (Valid 0..255)*/ + 0, /* lane0Id Lane0 ID. (Valid 0..31)*/ + 4, /* M number of DACss (0, 2, or 4) - 2 DACs per transmit chain */ + 32, /* K #frames in a multiframe (default=32), F*K=multiple of 4. (F=2*M/numberOfLanes)*/ + 0, /* scramble scrambling off if scramble= 0.*/ + 1, /* External SYSREF select. 0 = use internal SYSREF, 1 = external SYSREF*/ + 0x03, /* Deserializer lane select bit field. Where, [0] = Lane0 enabled, [1] = Lane1 enabled, etc */ + 0xE4, /* Lane crossbar to map physical lanes to deframer lane inputs [1:0] = Deframer Input 0 Lane section, [3:2] = Deframer Input 1 lane select, etc */ + 1, /* Equalizer setting. Applied to all deserializer lanes. Range is 0..4*/ + 0, /* PN inversion per each lane. bit[0] = 1 Invert PN of Lane 0, bit[1] = Invert PN of Lane 1, etc).*/ + 0, /* LMFC_Offset offset value to adjust deterministic latency. Range is 0..31*/ + 0, /* Flag for determining if SYSREF on relink should be set. Where, if > 0 = set, '0' = not set*/ + 0, /* Flag for determining if auto channel select for the xbar should be set. Where, if > 0 = set, '0' = not set*/ + 0, /* Flag for determining if CMOS mode for TX Sync signal is used. Where, if > 0 = CMOS, '0' = LVDS*/ + 0 /* Flag for determining if API will calculate the appropriate settings for deframer lane in to physical lanes. Where, if '0' = API will set automatic lane crossbar, '1' = set to manual mode and the value in deserializerLaneCrossbar will be used*/ +}; + +static mykonosRxGainControl_t rxGainControl = +{ + MGC, /* Current Rx gain control mode setting*/ + 255, /* Rx1 Gain Index, can be used in different ways for manual and AGC gain control*/ + 255, /* Rx2 Gain Index, can be used in different ways for manual and AGC gain control*/ + 255, /* Max gain index for the currently loaded Rx1 Gain table*/ + 195, /* Min gain index for the currently loaded Rx1 Gain table*/ + 255, /* Max gain index for the currently loaded Rx2 Gain table*/ + 195, /* Min gain index for the currently loaded Rx2 Gain table*/ + 0, /* Stores Rx1 RSSI value read back from the Mykonos*/ + 0 /* Stores Rx2 RSSI value read back from the Mykonos*/ +}; + + +static mykonosORxGainControl_t orxGainControl = +{ + MGC, /* Current ORx gain control mode setting*/ + 255, /* ORx1 Gain Index, can be used in different ways for manual and AGC gain control*/ + 255, /* ORx2 Gain Index, can be used in different ways for manual and AGC gain control*/ + 255, /* Max gain index for the currently loaded ORx Gain table*/ + 237 /* Min gain index for the currently loaded ORx Gain table*/ +}; + +static mykonosSnifferGainControl_t snifferGainControl = +{ + MGC, /* Current Sniffer gain control mode setting*/ + 255, /* Current Sniffer gain index. Can be used differently for MANUAL Gain control/AGC*/ + 255, /* Max gain index for the currently loaded Sniffer Gain table*/ + 203 /* Min gain index for the currently loaded Sniffer Gain table*/ +}; + +static mykonosPeakDetAgcCfg_t rxPeakAgc = +{ + 0x0C, /* apdHighThresh: */ + 0x08, /* apdLowThresh */ + 0xB5, /* hb2HighThresh */ + 0x80, /* hb2LowThresh */ + 0x40, /* hb2VeryLowThresh */ + 0x06, /* apdHighThreshExceededCnt */ + 0x04, /* apdLowThreshExceededCnt */ + 0x06, /* hb2HighThreshExceededCnt */ + 0x04, /* hb2LowThreshExceededCnt */ + 0x04, /* hb2VeryLowThreshExceededCnt */ + 0x4, /* apdHighGainStepAttack */ + 0x2, /* apdLowGainStepRecovery */ + 0x4, /* hb2HighGainStepAttack */ + 0x2, /* hb2LowGainStepRecovery */ + 0x4, /* hb2VeryLowGainStepRecovery */ + 0x1, /* apdFastAttack */ + 0x1, /* hb2FastAttack */ + 0x1, /* hb2OverloadDetectEnable */ + 0x1, /* hb2OverloadDurationCnt */ + 0x1 /* hb2OverloadThreshCnt */ +}; + +static mykonosPowerMeasAgcCfg_t rxPwrAgc = +{ + 0x01, /* pmdUpperHighThresh */ + 0x03, /* pmdUpperLowThresh */ + 0x0C, /* pmdLowerHighThresh */ + 0x00, /* pmdLowerLowThresh */ + 0x4, /* pmdUpperHighGainStepAttack */ + 0x2, /* pmdUpperLowGainStepAttack */ + 0x2, /* pmdLowerHighGainStepRecovery */ + 0x4, /* pmdLowerLowGainStepRecovery */ + 0x08, /* pmdMeasDuration */ + 0x02 /* pmdMeasConfig */ +}; + +static mykonosAgcCfg_t rxAgcConfig = +{ + 255, /* agcRx1MaxGainIndex */ + 195, /* agcRx1MinGainIndex */ + 255, /* agcRx2MaxGainIndex */ + 195, /* agcRx2MinGainIndex: */ + 255, /* agcObsRxMaxGainIndex */ + 203, /* agcObsRxMinGainIndex */ + 1, /* agcObsRxSelect */ + 1, /* agcPeakThresholdMode */ + 1, /* agcLowThsPreventGainIncrease */ + 30720, /* agcGainUpdateCounter */ + 3, /* agcSlowLoopSettlingDelay */ + 2, /* agcPeakWaitTime */ + 1, /* agcResetOnRxEnable */ + 0, /* agcEnableSyncPulseForGainCounter */ + &rxPeakAgc, + &rxPwrAgc +}; + +static mykonosPeakDetAgcCfg_t obsRxPeakAgc = +{ + 0x1F, /* apdHighThresh: */ + 0x16, /* apdLowThresh */ + 0xB5, /* hb2HighThresh */ + 0x80, /* hb2LowThresh */ + 0x40, /* hb2VeryLowThresh */ + 0x06, /* apdHighThreshExceededCnt */ + 0x04, /* apdLowThreshExceededCnt */ + 0x06, /* hb2HighThreshExceededCnt */ + 0x04, /* hb2LowThreshExceededCnt */ + 0x04, /* hb2VeryLowThreshExceededCnt */ + 0x4, /* apdHighGainStepAttack */ + 0x2, /* apdLowGainStepRecovery */ + 0x4, /* hb2HighGainStepAttack */ + 0x2, /* hb2LowGainStepRecovery */ + 0x4, /* hb2VeryLowGainStepRecovery */ + 0x1, /* apdFastAttack */ + 0x1, /* hb2FastAttack */ + 0x1, /* hb2OverloadDetectEnable */ + 0x1, /* hb2OverloadDurationCnt */ + 0x1 /* hb2OverloadThreshCnt */ +}; + +static mykonosPowerMeasAgcCfg_t obsRxPwrAgc = +{ + 0x01, /* pmdUpperHighThresh */ + 0x03, /* pmdUpperLowThresh */ + 0x0C, /* pmdLowerHighThresh */ + 0x00, /* pmdLowerLowThresh */ + 0x4, /* pmdUpperHighGainStepAttack */ + 0x2, /* pmdUpperLowGainStepAttack */ + 0x2, /* pmdLowerHighGainStepRecovery */ + 0x4, /* pmdLowerLowGainStepRecovery */ + 0x08, /* pmdMeasDuration */ + 0x02 /* pmdMeasConfig */ +}; + +static mykonosAgcCfg_t obsRxAgcConfig = +{ + 255, /* agcRx1MaxGainIndex */ + 195, /* agcRx1MinGainIndex */ + 255, /* agcRx2MaxGainIndex */ + 195, /* agcRx2MinGainIndex: */ + 255, /* agcObsRxMaxGainIndex */ + 203, /* agcObsRxMinGainIndex */ + 1, /* agcObsRxSelect */ + 1, /* agcPeakThresholdMode */ + 1, /* agcLowThsPreventGainIncrease */ + 30720, /* agcGainUpdateCounter */ + 3, /* agcSlowLoopSettlingDelay */ + 2, /* agcPeakWaitTime */ + 1, /* agcResetOnRxEnable */ + 0, /* agcEnableSyncPulseForGainCounter */ + &obsRxPeakAgc, + &obsRxPwrAgc +}; + + +static mykonosRxProfile_t rxProfile = +{/* Rx 100MHz, IQrate 122.88MSPS, Dec5 */ + 1, /* The divider used to generate the ADC clock*/ + &rxFir, /* Pointer to Rx FIR filter structure*/ + 2, /* Rx FIR decimation (1,2,4)*/ + 5, /* Decimation of Dec5 or Dec4 filter (5,4)*/ + 1, /* If set, and DEC5 filter used, will use a higher rejection DEC5 FIR filter (1=Enabled, 0=Disabled)*/ + 1, /* RX Half band 1 decimation (1 or 2)*/ + 122880, /* Rx IQ data rate in kHz*/ + 100000000, /* The Rx RF passband bandwidth for the profile*/ + 100000, /* Rx BBF 3dB corner in kHz*/ + NULL /* pointer to custom ADC profile*/ +}; + +static mykonosRxProfile_t orxProfile = +{/* ORX 100MHz, IQrate 122.88MSPS, Dec5 */ + 1, /* The divider used to generate the ADC clock*/ + &obsrxFir, /* Pointer to Rx FIR filter structure or NULL*/ + 2, /* Rx FIR decimation (1,2,4)*/ + 5, /* Decimation of Dec5 or Dec4 filter (5,4)*/ + 0, /* If set, and DEC5 filter used, will use a higher rejection DEC5 FIR filter (1=Enabled, 0=Disabled)*/ + 1, /* RX Half band 1 decimation (1 or 2)*/ + 122880, /* Rx IQ data rate in kHz*/ + 100000000, /* The Rx RF passband bandwidth for the profile*/ + 100000, /* Rx BBF 3dB corner in kHz*/ + NULL /* pointer to custom ADC profile*/ +}; + + +static mykonosRxProfile_t snifferProfile = +{ /* SRx 20MHz, IQrate 30.72MSPS, Dec5 */ + 1, /* The divider used to generate the ADC clock*/ + &snifferRxFir, /* Pointer to Rx FIR filter structure or NULL*/ + 4, /* Rx FIR decimation (1,2,4)*/ + 5, /* Decimation of Dec5 or Dec4 filter (5,4)*/ + 0, /* If set, and DEC5 filter used, will use a higher rejection DEC5 FIR filter (1=Enabled, 0=Disabled)*/ + 2, /* RX Half band 1 decimation (1 or 2)*/ + 30720, /* Rx IQ data rate in kHz*/ + 10000000, /* The Rx RF passband bandwidth for the profile*/ + 100000, /* Rx BBF 3dB corner in kHz*/ + NULL /* pointer to custom ADC profile*/ +}; + + + +static mykonosTxProfile_t txProfile = +{ /* Tx 20/100MHz, IQrate 122.88MSPS, Dec5 */ + DACDIV_2p5, /* The divider used to generate the DAC clock*/ + &txFir, /* Pointer to Tx FIR filter structure*/ + 2, /* The Tx digital FIR filter interpolation (1,2,4)*/ + 2, /* Tx Halfband1 filter interpolation (1,2)*/ + 1, /* Tx Halfband2 filter interpolation (1,2)*/ + 1, /* TxInputHbInterpolation (1,2)*/ + 122880, /* Tx IQ data rate in kHz*/ + 100000000, /* Primary Signal BW*/ + 100000000, /* The Tx RF passband bandwidth for the profile*/ + 710539, /* The DAC filter 3dB corner in kHz*/ + 50000, /* Tx BBF 3dB corner in kHz*/ + 0 /* Enable DPD, only valid for AD9373*/ +}; + +static mykonosDigClocks_t mykonosClocks = +{ + 122880, /* CLKPLL and device reference clock frequency in kHz*/ + 9830400, /* CLKPLL VCO frequency in kHz*/ + VCODIV_2, /* CLKPLL VCO divider*/ + 4 /* CLKPLL high speed clock divider*/ +}; + +static mykonosRxSettings_t rxSettings = +{ + &rxProfile, /* Rx datapath profile, 3dB corner frequencies, and digital filter enables*/ + &rxFramer, /* Rx JESD204b framer configuration structure*/ + &rxGainControl, /* Rx Gain control settings structure*/ + &rxAgcConfig, /* Rx AGC control settings structure*/ + RX1_RX2, /* The desired Rx Channels to enable during initialization*/ + 0, /* Internal LO = 0, external LO*2 = 1*/ + 2550000000U, /* Rx PLL LO Frequency (internal or external LO)*/ + 0 /* Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where, if > 0 = real IF data, '0' = zero IF (IQ) data*/ +}; + +static mykonosDpdConfig_t dpdConfig = +{ + 5, /* 1/2^(damping + 8) fraction of power `forgotten' per sample (default: `1/8192' = 5, valid 0 to 15), 0 = infinite damping*/ + 1, /* number of weights to use for int8_cpx weights weights member of this structure (default = 1)*/ + 2, /* DPD model version: one of four different generalized polynomial models: 0 = same as R0 silicon, 1-3 are new and the best one depends on the PA (default: 2)*/ + 1, /* 1 = Update saved model whenever peak Tx digital RMS is within 1dB of historical peak Tx RMS*/ + 20, /* Determines how much weight the loaded prior model has on DPD modeling (Valid 0 - 32, default 20)*/ + 0, /* Default off = 0, 1=enables automatic outlier removal during DPD modeling */ + 512, /* Number of samples to capture (default: 512, valid 64-32768)*/ + 4096, /* threshold for sample in AM-AM plot outside of 1:1 line to be thrown out. (default: 50% = 8192/2, valid 8192 to 1)*/ + 0, /* 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64)*/ + 255, /* Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191)*/ + {{64,0},{0,0},{0,0}}/* DPD model error weighting (real/imag valid from -128 to 127)*/ +}; + +static mykonosClgcConfig_t clgcConfig = +{ + -2000, /* (value = 100 * dB (valid range -32768 to 32767) - total gain and attenuation from Mykonos Tx1 output to ORx1 input in (dB * 100)*/ + -2000, /* (value = 100 * dB (valid range -32768 to 32767) - total gain and attenuation from Mykonos Tx2 output to ORx2 input in (dB * 100)*/ + 0, /* (valid range 0 - 40dB), no default, depends on PA, Protects PA by making sure Tx1Atten is not reduced below the limit*/ + 0, /* (valid range 0 - 40dB), no default, depends on PA, Protects PA by making sure Tx2Atten is not reduced below the limit*/ + 75, /* valid range 1-100, default 75*/ + 75, /* valid range 1-100, default 45*/ + 0, /* 0= allow CLGC to run, but Tx1Atten will not be updated. User can still read back power measurements. 1=CLGC runs, and Tx1Atten automatically updated*/ + 0, /* 0= allow CLGC to run, but Tx2Atten will not be updated. User can still read back power measurements. 1=CLGC runs, and Tx2Atten automatically updated*/ + 0, /* 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64)*/ + 255, /* Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191)*/ + 600, /* Threshold for Tx1 in order to stop tracking, value = 100 * dB, default 6db then value = 600*/ + 600, /* Threshold for Tx2 in order to stop tracking, value = 100 * dB, default 6db then value = 600*/ + 0, /* Threshold feature enable for Tx1, 0 = disable, 1 = enable, default = 0*/ + 0 /* Threshold feature enable for Tx1, 0 = disable, 1 = enable, default = 0*/ +}; + +static mykonosVswrConfig_t vswrConfig = +{ + 0, /* 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64)*/ + 255, /* Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191)*/ + 0, /* 3p3V GPIO pin to use to control VSWR switch for Tx1 (valid 0-11) (output from Mykonos)*/ + 1, /* 3p3V GPIO pin to use to control VSWR switch for Tx2 (valid 0-11) (output from Mykonos)*/ + 0, /* 3p3v GPIO pin polarity for forward path of Tx1, opposite used for reflection path (1 = high level, 0 = low level)*/ + 0, /* 3p3v GPIO pin polarity for forward path of Tx2, opposite used for reflection path (1 = high level, 0 = low level)*/ + 50, /* Delay for Tx1 after flipping the VSWR switch until measurement is made. In us resolution*/ + 50 /* Delay for Tx2 after flipping the VSWR switch until measurement is made. In us resolution*/ +}; + +static mykonosTxSettings_t txSettings = +{ + &txProfile, /* Tx datapath profile, 3dB corner frequencies, and digital filter enables*/ + &deframer, /* Mykonos JESD204b deframer config for the Tx data path*/ + TX1_TX2, /* The desired Tx channels to enable during initialization*/ + 0, /* Internal LO=0, external LO*2 if =1*/ + 2500000000U, /* Tx PLL LO frequency (internal or external LO)*/ + TXATTEN_0P05_DB,/* Initial and current Tx1 Attenuation*/ + 10000, /* Initial and current Tx1 Attenuation mdB*/ + 10000, /* Initial and current Tx2 Attenuation mdB*/ + NULL, /* DPD,CLGC,VSWR settings. Only valid for AD9373 device, set pointer to NULL otherwise*/ + NULL, /* CLGC Config Structure. Only valid for AD9373 device, set pointer to NULL otherwise*/ + NULL /* VSWR Config Structure. Only valid for AD9373 device, set pointer to NULL otherwise*/ +}; + + +static mykonosObsRxSettings_t obsRxSettings = +{ + &orxProfile, /* ORx datapath profile, 3dB corner frequencies, and digital filter enables*/ + &orxGainControl,/* ObsRx gain control settings structure*/ + &obsRxAgcConfig,/* ORx AGC control settings structure*/ + &snifferProfile,/* Sniffer datapath profile, 3dB corner frequencies, and digital filter enables*/ + &snifferGainControl,/* SnRx gain control settings structure*/ + &obsRxFramer, /* ObsRx JESD204b framer configuration structure */ + (MYK_ORX1_ORX2 | MYK_SNRXA_B_C),/* obsRxChannel */ + OBSLO_TX_PLL, /* (obsRxLoSource) The Obs Rx mixer can use the Tx Synth(TX_PLL) or Sniffer Synth (SNIFFER_PLL) */ + 2600000000U, /* SnRx PLL LO frequency in Hz */ + 0, /* Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where if > 0 = real IF data, '0' = complex data*/ + NULL, /* Custom Loopback ADC profile to set the bandwidth of the ADC response */ + OBS_RXOFF /* Default ObsRx channel to enter when radioOn called */ +}; + +static mykonosArmGpioConfig_t armGpio = +{ + 1, // useRx2EnablePin; /*!< 0= RX1_ENABLE controls RX1 and RX2, 1 = separate RX1_ENABLE/RX2_ENABLE pins */ + 1, // useTx2EnablePin; /*!< 0= TX1_ENABLE controls TX1 and TX2, 1 = separate TX1_ENABLE/TX2_ENABLE pins */ + 1, // txRxPinMode; /*!< 0= ARM command mode, 1 = Pin mode to power up Tx/Rx chains */ + 0, // orxPinMode; /*!< 0= ARM command mode, 1 = Pin mode to power up ObsRx receiver*/ + + /*Mykonos ARM input GPIO pins -- Only valid if orxPinMode = 1 */ + 0, // orxTriggerPin; /*!< Select desired GPIO pin (valid 4-15) */ + 0, // orxMode2Pin; /*!< Select desired GPIO pin (valid 0-18) */ + 0, // orxMode1Pin; /*!< Select desired GPIO pin (valid 0-18) */ + 0, // orxMode0Pin; /*!< Select desired GPIO pin (valid 0-18) */ + + /* Mykonos ARM output GPIO pins -- always available, even when pin mode not enabled*/ + 0, // rx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // rx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // tx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // tx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // orx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // orx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0, // srxEnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + 0 // txObsSelect; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + /* When 2Tx are used with only 1 ORx input, this GPIO tells the BBIC which Tx channel is */ + /* active for calibrations, so BBIC can route correct RF Tx path into the single ORx input*/ +}; + +static mykonosGpio3v3_t gpio3v3 = +{ + 0, /*!< Oe per pin, 1=output, 0 = input */ + GPIO3V3_BITBANG_MODE, /*!< Mode for GPIO3V3[3:0] */ + GPIO3V3_BITBANG_MODE, /*!< Mode for GPIO3V3[7:4] */ + GPIO3V3_BITBANG_MODE, /*!< Mode for GPIO3V3[11:8] */ +}; + +static mykonosGpioLowVoltage_t gpio = +{ + 0,/* Oe per pin, 1=output, 0 = input */ + GPIO_MONITOR_MODE,/* Mode for GPIO[3:0] */ + GPIO_MONITOR_MODE,/* Mode for GPIO[7:4] */ + GPIO_MONITOR_MODE,/* Mode for GPIO[11:8] */ + GPIO_MONITOR_MODE,/* Mode for GPIO[15:12] */ + GPIO_MONITOR_MODE,/* Mode for GPIO[18:16] */ +}; + +static mykonosAuxIo_t mykonosAuxIo = +{ + 0, //auxDacEnableMask uint16_t + {0,0,0,0,0,0,0,0,0,0}, //AuxDacValue uint16[10] + {0,0,0,0,0,0,0,0,0,0}, //AuxDacSlope uint8[10] + {0,0,0,0,0,0,0,0,0,0}, //AuxDacVref uint8[10] + &gpio3v3, //pointer to gpio3v3 struct + &gpio, //pointer to gpio1v8 struct + &armGpio +}; + +static spiSettings_t mykSpiSettings = +{ + 1, /* chip select index - valid 1~8 */ + 0, /* the level of the write bit of a SPI write instruction word, value is inverted for SPI read operation */ + 1, /* 1 = 16-bit instruction word, 0 = 8-bit instruction word */ + 1, /* 1 = MSBFirst, 0 = LSBFirst */ + 0, /* clock phase, sets which clock edge the data updates (valid 0 or 1) */ + 0, /* clock polarity 0 = clock starts low, 1 = clock starts high */ + 0, /* Not implemented in ADIs platform layer. SW feature to improve SPI throughput */ + 1, /* Not implemented in ADIs platform layer. For SPI Streaming, set address increment direction. 1= next addr = addr+1, 0:addr=addr-1 */ + 1 /* 1: Use 4-wire SPI, 0: 3-wire SPI (SDIO pin is bidirectional). NOTE: ADI's FPGA platform always uses 4-wire mode */ +}; + +static mykonosTempSensorConfig_t tempSensor = +{ + 7, /* 3-bit value that controls the AuxADC decimation factor when used for temp sensor calculations; AuxADC_decimation = 256 * 2^tempDecimation*/ + 67, /* 8-bit offset that gets added to temp sensor code internally*/ + 1, /* this bit overrides the factory-calibrated fuse offset and uses the value stored in the offset member*/ + 15, /* 4-bit code with a resolution of 1°C/LSB, each time a temperature measurement is performed, the device compares the current temperature against the previous value.*/ +}; + +static mykonosTempSensorStatus_t tempStatus = +{ + 0, /* 16-bit signed temperature value (in deg C) that is read back*/ + 0, /* If the absolute value of the difference is greater than the value in temperature configuration tempWindow, the windowExceeded flag is set.*/ + 0, /* when windowExceeded member gets set, this bit is set to 1 if current value is greater than previous value, else reset*/ + 0, /* when the reading is complete and a valid temperature value stored in tempCode.*/ +}; + +mykonosDevice_t mykDevice = +{ + &mykSpiSettings, /* SPI settings data structure pointer */ + &rxSettings, /* Rx settings data structure pointer */ + &txSettings, /* Tx settings data structure pointer */ + &obsRxSettings, /* ObsRx settings data structure pointer */ + &mykonosAuxIo, /* Auxiliary IO settings data structure pointer */ + &mykonosClocks, /* Holds settings for CLKPLL and reference clock */ + 0 /* Mykonos initialize function uses this as an output to remember which profile data structure pointers are valid */ +}; diff --git a/src/hardware/myk_init.h b/src/hardware/myk_init.h new file mode 100644 index 0000000..ef11bad --- /dev/null +++ b/src/hardware/myk_init.h @@ -0,0 +1,24 @@ +/** + * \file myk_init.h + * + * \brief Contains structure definitions for myk_init.c + * + * The top level structure mykonosDevice_t mykDevice uses keyword + * extern to allow the application layer main() to have visibility + * to these settings. + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef MYK_INIT_H_ +#define MYK_INIT_H_ + + +extern mykonosDevice_t mykDevice; + +#endif diff --git a/src/hardware/mykonos/Mykonos_M3.c b/src/hardware/mykonos/Mykonos_M3.c new file mode 100644 index 0000000..369ad92 --- /dev/null +++ b/src/hardware/mykonos/Mykonos_M3.c @@ -0,0 +1,8518 @@ +/** + +SOFTWARE LICENSE AGREEMENT +20180301-AD937X-CTSLA + +This Software License Agreement (the 鈥淎greement鈥�) is a legal agreement +between Analog Devices, Inc., a Massachusetts corporation, with its principal +office at One Technology Way, Norwood, Massachusetts, USA 02062 (鈥淎nalog +Devices鈥�) and you (personally or on behalf of your employer, as applicable) +(鈥淟icensee鈥�) for the software and related documentation that accompanies +this Agreement (the 鈥淟icensed Software鈥�). YOU AGREE THAT YOU ARE BOUND BY +THE TERMS AND CONDITIONS OF THIS AGREEMENT BY DOWNLOADING, INSTALLING, COPYING +OR USING THE SOFTWARE. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY OR +USE THE SOFTWARE. + +1. Development License. Subject to terms of this Agreement, Analog Devices +grants to Licensee a non-exclusive, non-transferable, non-sublicensable +license, without charge, to incorporate Licensed Software in object code form +into Licensee products solely for use within Analog Devices products that are +incorporated into such Licensee products. The licenses granted under Sections +1 and 2 of this Agreement are limited to the specific Analog Devices products +identified in Appendix A to this Agreement. + +2. Distribution License. Subject to the terms of this Agreement, Analog +Devices grants to Licensee a non-exclusive, non-transferrable, +non-sublicensable license, to copy and distribute Licensed Software in object +code form solely for use within Analog Devices products that are incorporated +into Licensee products. Distribution is limited to Licensed Software in object +code form that is incorporated into Licensee products. + +3. License to Analog Devices. During the term of this Agreement Licensee +grants to Analog Devices (and its affiliates) under any and all Licensee (and +its affiliates) patents a non-exclusive, worldwide, fully paid-up, royalty-free +license to make, use, sell, import, export, copy, distribute and otherwise +exploit Licensed Software in-whole or in-part (including updated versions of +Licensed Software), and to directly or indirectly sub-license others to do the +same. + +4. Restrictions. Licensee shall not modify, reverse engineer, decompile, +disassemble or create derivative works of Licensed Software. Licensee may only +copy the Licensed Software as expressly authorized in Sections 1 and 2 above. +In no event shall Licensee deliver or disclose the Licensed Software apart from +Licensee products to any third party without entering into a written license +agreement with Analog Devices expressly permitting such distribution. The +Licensed Software may not be used with any products other than Analog +Devices鈥� products or for any other purpose. + +Licensee shall not use or distribute the Licensed Software in any manner that +would cause Licensed Software, in whole or in part to become subject to any +terms of an Excluded License. An 鈥淓xcluded License鈥� means any license, +including licenses for 鈥渙pen source鈥� code (as defined by the Free Software +Foundation), that requires as a condition of use, modification, and/or +distribution of software subject to the Excluded License, that such software or +other software combined and/or distributed with such software be (i) disclosed +or distributed in source code form; (ii) licensed for the purpose of making +derivative works; or (iii) redistributable at no charge. The restrictions of +this section apply regardless of whether the Licensed Software is intended or +designed to run in an environment that includes software under an Excluded +License. Any license, agreement or other document issued, entered into or +granted by Licensee that purports to apply any Excluded License to any portion +of Licensed Software shall be null and void with regard to Licensed Software. +Under no circumstances will Licensee offer, provide, distribute, or license any +Licensed Software (whether in source code form or object code form) under any +form of Excluded License. + +All rights not expressly granted in this Agreement are reserved to Analog +Devices and its licensors. Analog Devices and its licensors retain all right, +title and interest in the Licensed Software and modifications thereof, +including all related patent, copyright and other intellectual property rights, +and Licensee shall not take any action inconsistent with such ownership. Any +use of the Licensed Software for any purpose other than as expressly licensed +hereunder is outside the scope of this Agreement. It is agreed that because of +the proprietary nature of the Licensed Software, Analog Devices鈥� remedies at +law for a breach by the Licensee of its obligations under this License or for +use of the Licensed Software beyond the scope of the license granted herein +will be inadequate and that Analog Devices will, in the event of such breach, +be entitled to equitable relief, including injunctive relief, without the +posting of any bond, in addition to all other remedies provided under this +License or available at law. + +If Analog Devices elects to make any update, upgrade or new version of the +Licensed Software (鈥淯pdates鈥�) available to Licensee, such Updates shall be +deemed to be Licensed Software under this Agreement. If requested by Analog +Devices, Licensee shall only use the latest version of the Licensed Software +(including Updates). Analog Devices shall have no obligation to provide +support or Updates. + +5. Publicity. Notwithstanding anything in this Agreement, Licensee may not use +any trademark or trade name of Analog Devices or make any public announcement +regarding the existence of this Agreement without Analog Devices鈥� prior +written consent. Licensee may not publish or provide the results of any +benchmark or comparison tests run on the Licensed Software to any third party +without the prior written consent of Analog Devices. + +6. Feedback. Licensee may from time to time provide suggestions, ideas, +comments or other feedback (鈥淔eedback鈥�) to Analog Devices with respect to +the Licensed Software. Licensee agrees that all Feedback is and shall be given +entirely voluntarily. To the extent Licensee provides such Feedback, however, +Licensee hereby grants to Analog Devices a non-exclusive, irrevocable, +perpetual, worldwide, royalty-free, transferable license, with the right to +sublicense, under Licensee鈥檚 intellectual property, to use and disclose +Feedback in any manner Analog Devices chooses and to display, perform, copy, +make, have made, use, sell, and otherwise dispose of Analog Devices鈥� and its +licensee鈥檚 products embodying such Feedback in any manner and via any media +Analog Devices chooses, without reference to its source or other obligation to +Analog Devices, even if the Feedback is designated as confidential. + +7. Confidentiality. Licensed Software in source code form and accompanying +documentation shall be regarded as 鈥淐onfidential Information鈥� of Analog +Devices and Licensee agrees to protect the confidentiality of Analog Devices鈥� +Confidential Information with at least the same degree of care that it utilizes +with respect to its own similar proprietary information (but in no event less +than a reasonable degree of care), including without limitation agreeing (i) +not to disclose or otherwise permit any other person or entity access to +Confidential Information or to use Confidential Information or any part thereof +in any form whatsoever, except that such disclosure or access shall be +permitted to an employee or consultant of Licensee requiring access to +Confidential Information in connection with this Agreement who has signed an +agreement obligating the employee/consultant to maintain the confidentiality of +confidential information in Licensee鈥檚 possession, (ii) to notify Analog +Devices promptly and in writing of the circumstances surrounding any suspected +possessions, use, or knowledge of Confidential Information other than those +authorized by this Agreement, and (iii) not to use Confidential Information for +any purpose other than as explicitly set forth herein. Nothing shall restrict +Licensee with respect to information or data that is independently developed or +is available to the general public otherwise than through any act or default of +Licensee. + +8. Copyright Notice. In no event shall Licensee remove any copyright or other +intellectual property notice or other legend contained on or in copies of +Licensed Software or displayed by any Licensed Software. + +9. Third Party Software. The Licensed Software may be accompanied by or +include software made available by one or more third parties (鈥淭hird Party +Software鈥�). Each portion of Third Party Software is subject to its own +separate software license terms and conditions (鈥淭hird Party Licenses鈥�). +The Third Party Licenses for Third Party Software delivered with the Licensed +Software may be set forth or identified (by URL or otherwise) in (i) Appendix A +to this license (if any), (ii) the applicable software header or footer text, +(iii) a text file located in the directory of the applicable Third Party +Software component and/or (iv) such other location customarily used for +licensing terms. The use of each portion of Third Party Software is subject to +the Third Party Licenses, and you agree that your use of any Third Party +Software is bound by the applicable Third Party License. You agree to review +and comply with all applicable Third Party Licenses prior to any use or +distribution of any Third Party Software. Third Party Software is provided on +an 鈥渁s is鈥� basis without any representation, warranty or liability of any +kind. Analog Devices (including its licensors) shall have no liability or +responsibility for the operation or performance of the Third Party Software and +shall not be liable for any damages, costs, or expenses, direct or indirect, +arising out of the performance or failure to perform of the Third Party +Software. Analog Devices (including its licensors) shall be entitled to the +benefit of any and all limitations of liability and disclaimers of warranties +contained in the Third Party Licenses. + +In the event that Third Party Software has only been provided to you in object +code form under this Agreement, and the Third Party License requires +distribution of the corresponding source code, you may contact +software.licensing@analog.com regarding receiving a copy of such source code. + +10. Licensee Requirements. Licensee acknowledges that use or distribution of +the Licensed Software may require Licensee to obtain licenses to intellectual +property or other consents from one or more third parties. Licensee is +responsible for obtaining any and all such required licenses, or permissions +regarding the Licensed Software and for the performance of any and all required +tests or analysis necessary or appropriate for the determination of the +suitability of the Licensed Software for its or its customers鈥� purposes. +Licensee shall defend, indemnify and hold Analog Devices, its licensors, and +their respective officers, directors, employees and agents (each an +鈥淚ndemnified Party鈥�) harmless from and against any damages, fines, +penalties, assessments, liabilities, costs and expenses (including reasonable +attorneys鈥� fees and court costs) in the event that any claim is brought +against an Indemnified Party (i) arising or alleged to arise from Licensee鈥檚 +use or distribution of Licensed Software or Third Party Software, or (ii) on +account of Licensee鈥檚 failure to obtain any required license or consent to +use or distribute Licensed Software or Third Party Software. Licensee shall +bear any and all expenses and pay any and all taxes that may be payable in +relation to this Agreement. + +11. Audit. Analog Devices shall have the right upon ten (10) days prior +written notice to audit Licensee鈥檚 compliance with the terms of this +Agreement during normal business hours. In connection with such audit Analog +Devices shall have access to all reasonably requested documents, equipment, +information and personnel. Licensee shall maintain complete and accurate +records of its use of the Licensed Software for a period of at least three +years from the applicable use of the Licensed Software. + +12. License Term; Term of Agreement. This Agreement is effective upon receipt +of the Licensed Software and shall continue for three (3) years, unless earlier +terminated as permitted in this Agreement. This Agreement will automatically +renew for additional one (1) year terms unless indicated otherwise in writing +by either of the parties thirty (30) days prior to any renewal date. Licensee +may terminate this Agreement at any time by giving written notice to Analog +Devices. Analog Devices may terminate this Agreement at any time in the event +of any failure by Licensee to comply with any term or condition of the +Agreement. In the event of termination, Licensee must permanently delete all +copies of Licensed Software and all of its component parts, including any +backup or archival copies. Licenses granted to end users prior to termination +shall survive. The provisions of Sections 3-22 shall survive any termination +or expiration of this Agreement according to their terms. + +13. DISCLAIMER AND LIMITATION OF WARRANTIES. LICENSED SOFTWARE AND THIRD PARTY +SOFTWARE ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, AND ANALOG DEVICES, +FOR ITSELF AND ITS LICENSORS, HEREBY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS +OR IMPLIED, ORAL OR WRITTEN, WITH RESPECT TO THE LICENSED SOFTWARE AND THIRD +PARTY SOFTWARE, INCLUDING, BUT NOT LIMITED TO, ANY EXPRESS AND IMPLIED +WARRANTIES OF MERCHANTABILITY; FITNESS FOR PARTICULAR PURPOSE AND SYSTEM +INTEGRATION; CONDITIONS OF QUALITY AND ACCURACY OF INFORMATIONAL CONTENT; +NON-INFRINGEMENT; QUIET ENJOYMENT; AND TITLE. LICENSEE AGREES THAT ANY EFFORTS +BY ANALOG DEVICES TO MODIFY OR UPDATE LICENSED SOFTWARE OR THIRD PARTY SOFTWARE +SHALL NOT BE DEEMED A WAIVER OF THESE LIMITATIONS, AND THAT ANY ANALOG DEVICES +WARRANTIES SHALL NOT BE DEEMED TO HAVE FAILED OF THEIR ESSENTIAL PURPOSE. + +14. Limitation of Liability. TO THE MAXIMUM EXTENT PERMITTED BY LAW ANALOG +DEVICES (INCLUDING ITS LICENSORS) SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING +FROM OR RELATED TO THE LICENSED SOFTWARE, THIRD PARTY SOFTWARE, THEIR USE OR +ANY RELATED INFORMATION AND/OR SERVICES, INCLUDING BUT NOT LIMITED TO ANY +INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, EXEMPLARY, CONSEQUENTIAL OR ANALOGOUS +DAMAGES (INCLUDING WITHOUT LIMITATION ANY DAMAGES RESULTING FROM LOSS OF USE, +DATA, REVENUE, PROFITS, OR SAVINGS, COMPUTER DAMAGE OR ANY OTHER CAUSE), UNDER +ANY LEGAL THEORY (INCLUDING WITHOUT LIMITATION CONTRACT, WARRANTY, TORT, +NEGLIGENCE, STRICT OR PRODUCT LIABILITY), EVEN IF IT HAS BEEN INFORMED OF THE +POSSIBILITY OF SUCH DAMAGES. + +IN NO EVENT SHALL ANALOG DEVICES鈥� OR ITS LICENSORS鈥� CUMULATIVE LIABILITY +FOR DAMAGES TO LICENSEE FOR ANY AND ALL CAUSES WHATSOEVER, REGARDLESS OF THE +FORM OF ANY CLAIMS OR ACTIONS, EXCEED THE GREATER OF (1) ONE HUNDRED U.S. +DOLLARS ($100.00 U.S.) OR (2) THE AMOUNT PAID TO ANALOG DEVICES HEREUNDER FOR +THE LICENSED SOFTWARE. + +Some jurisdictions do not permit the exclusion or limitation of liability for +consequential or incidental damages, and, as such, some portion of the above +limitation may not apply to Licensee. In such jurisdictions, Analog Devices' +liability is limited to the greatest extent permitted by law. + +15. HIGH RISK APPLICATIONS. THE LICENSED SOFTWARE IS NOT DESIGNED OR INTENDED +FOR USE IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE PERFORMANCE, INCLUDING, +WITHOUT LIMITATION, IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION +OR CONTROL SYSTEMS, AIR TRAFFIC CONTROL, LIFE SUPPORT MACHINES, WEAPONS +SYSTEMS, OR ANY OTHER APPLICATION IN WHICH THE FAILURE OF THE LICENSED SOFTWARE +COULD LEAD TO DEATH, PERSONAL INJURY OR SEVERE PHYSICAL OR ENVIRONMENTAL +DAMAGES (鈥淗IGH RISK ACTIVITIES鈥�). LICENSED SOFTWARE IS NOT DESIGNED, +AUTHORIZED, OR WARRANTED TO BE SUITABLE FOR USE IN CONNECTION WITH HIGH RISK +ACTIVITIES. USE OF LICENSED SOFTWARE IN CONNECTION WITH HIGH RISK ACTIVITIES +IS UNDERSTOOD TO BE FULLY AT LICENSEE鈥橲 RISK. + +16. Choice of Law. This Agreement and any dispute related to the Licensed +Software shall be governed by the laws of the Commonwealth of Massachusetts, +United States of America, without reference to its principles of conflicts of +laws, and, as to matters affecting copyrights, trademarks and patents, in +addition, by applicable United States federal law. The parties agree that the +jurisdiction and venue of any action with respect to this Agreement shall be in +a court of competent subject matter jurisdiction located in the Commonwealth of +Massachusetts, and each of the parties hereby agrees to submit itself to the +exclusive jurisdiction and venue of such courts for the purpose of any such +action, except that Analog Devices may seek injunctive relief in any venue of +its choosing. Licensee hereby submits to personal jurisdiction in such courts. +The parties hereto specifically exclude the United Nations Convention on +Contracts for the International Sale of Goods and the Uniform Computer +Information Transactions Act from this Agreement and any transaction between +them that may be implemented in connection with this Agreement. The original of +this Agreement has been written in English. The parties hereto waive any +statute, law, or regulation that might provide an alternative law or forum or +to have this Agreement written in any language other than English. + +17. U.S. Government Restricted Rights. Licensed Software is provided with +RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is +subject to restrictions as set forth in subparagraphs (a) through (d) of the +Commercial Computer Software - Restricted Rights clause at FAR 52.227-19, +(c)(1)(ii) of The Rights in Technical Data and Computer Software clause at +DFARS 252.227-7013, and in similar clauses in the NASA FAR Supplement, as +applicable. The contractor/manufacturer of this Licensed Software is Analog +Devices, Inc., One Technology Way, Norwood, Massachusetts 02062 USA, or its +authorized licensors. + +18. Export. Licensee shall not export, directly or indirectly, Licensed +Software, or other information or materials provided by Analog Devices or its +suppliers hereunder, to any country for which the United States or any other +relevant jurisdiction requires any export license or other governmental +approval at the time of export without first obtaining such license or +approval. Licensee shall defend indemnify and hold harmless Analog Devices +from and against any damages, fines, penalties, assessments, liabilities, costs +and expenses (including reasonable attorneys鈥� fees and court costs) arising +out of any failure by Licensee to comply with this Section. + +19. Compliance with Laws of Other Jurisdictions. Licensee shall comply with +all laws, legislation, rules, regulations, governmental requirements and +industry standards with respect to Licensed Software, and the performance by +Licensee of its obligations hereunder, existing in any applicable jurisdiction. + +20. Assignment. This Agreement is personal to Licensee and Licensee may not +transfer, sublicense, lease, rent, or assign its rights under this License, and +any such attempt shall be null and void. Analog Devices may assign, transfer, +or sublicense this Agreement or any rights or obligations hereunder at any time +in its sole discretion. + +21. Waiver; Modification; Severability. No waiver, consent, modification or +change of terms of this Agreement shall bind either party unless in writing +signed by both parties, and then such waiver, consent, modification or change +shall be effective only in the specific instance and for the specific purpose +given. If any provision of this Agreement is unenforceable, such provision +shall be enforced to the extent possible under applicable law, and the +remaining provisions will remain in effect. + +22. Entire Agreement. This Agreement supersedes any and all other agreements, +either oral or in writing, between the parties with respect to the matters +stated herein. If, for any reason, any provision of this Agreement is held +invalid, such invalidity shall not affect the remainder of this Agreement, and +this Agreement shall continue in force and effect to the full extent allowed by +law. For the avoidance of doubt, all Licensed Software under this Agreement is +subject to the terms and conditions of this Agreement and not any agreement or +terms for purchase of Analog Devices products, even if the Licensed Software is +delivered with such products. + + +Appendix A + +License limited to Analog Devices transceiver / receiver / transmitter products. + +*/ +#include "Mykonos_M3.h" +// Version 5.2.2 + +unsigned char firmware_Mykonos_M3_bin[] = { + 0x90, 0xbc, 0x00, 0x20, 0x35, 0x6b, 0x01, 0x01, 0xf1, 0x66, 0x01, 0x01, + 0xf1, 0x66, 0x01, 0x01, 0xf1, 0x66, 0x01, 0x01, 0xf1, 0x66, 0x01, 0x01, + 0xf1, 0x66, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x6a, 0x01, 0x01, + 0xf7, 0x6a, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7a, 0x00, 0x01, + 0x2d, 0x7a, 0x00, 0x01, 0xf9, 0x6a, 0x01, 0x01, 0xd7, 0x8b, 0x00, 0x01, + 0xe7, 0xeb, 0x00, 0x01, 0x71, 0x52, 0x00, 0x01, 0xfb, 0x6a, 0x01, 0x01, + 0x8d, 0x69, 0x00, 0x01, 0x9d, 0x69, 0x00, 0x01, 0xad, 0x69, 0x00, 0x01, + 0xd9, 0x69, 0x00, 0x01, 0x3f, 0xfd, 0x00, 0x01, 0x07, 0x8d, 0x00, 0x01, + 0x43, 0x8e, 0x00, 0x01, 0xc3, 0x8d, 0x00, 0x01, 0xeb, 0x8e, 0x00, 0x01, + 0xff, 0x32, 0x00, 0x01, 0x31, 0xf1, 0x00, 0x01, 0xd3, 0x8c, 0x00, 0x01, + 0x7b, 0xf2, 0x00, 0x01, 0xfd, 0x6a, 0x01, 0x01, 0x6b, 0x5f, 0x00, 0x01, + 0xff, 0x6a, 0x01, 0x01, 0x01, 0x6b, 0x01, 0x01, 0x03, 0x6b, 0x01, 0x01, + 0x05, 0x6b, 0x01, 0x01, 0x07, 0x6b, 0x01, 0x01, 0x51, 0xf4, 0x00, 0x01, + 0x09, 0x6b, 0x01, 0x01, 0x0b, 0x6b, 0x01, 0x01, 0x93, 0xfd, 0x00, 0x01, + 0x53, 0x8d, 0x00, 0x01, 0x7f, 0x8e, 0x00, 0x01, 0x65, 0x8f, 0x00, 0x01, + 0xbd, 0x9d, 0x00, 0x01, 0x11, 0xf3, 0x00, 0x01, 0x2d, 0xf2, 0x00, 0x01, + 0x5f, 0xf2, 0x00, 0x01, 0x0d, 0x6b, 0x01, 0x01, 0x0f, 0x6b, 0x01, 0x01, + 0x11, 0x6b, 0x01, 0x01, 0x13, 0x6b, 0x01, 0x01, 0x15, 0x6b, 0x01, 0x01, + 0x17, 0x6b, 0x01, 0x01, 0x19, 0x6b, 0x01, 0x01, 0x1b, 0x6b, 0x01, 0x01, + 0x1d, 0x6b, 0x01, 0x01, 0x1f, 0x6b, 0x01, 0x01, 0x21, 0x6b, 0x01, 0x01, + 0xf7, 0x82, 0x00, 0x01, 0x23, 0x6b, 0x01, 0x01, 0xdb, 0x82, 0x00, 0x01, + 0x25, 0x6b, 0x01, 0x01, 0x27, 0x6b, 0x01, 0x01, 0x29, 0x6b, 0x01, 0x01, + 0x2b, 0x6b, 0x01, 0x01, 0x2d, 0x6b, 0x01, 0x01, 0x2f, 0x6b, 0x01, 0x01, + 0x31, 0x6b, 0x01, 0x01, 0x33, 0x6b, 0x01, 0x01, 0x1a, 0xc4, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x1f, 0x15, 0x00, 0x00, 0x74, 0x72, 0x75, 0x6e, + 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xb7, 0x00, 0x20, 0xb8, 0x82, 0x00, 0x20, 0x00, 0xf2, 0x00, 0x20, + 0x10, 0xf1, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, 0xa4, 0x2b, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0x09, 0x00, 0x20, 0xf0, 0xb2, 0x00, 0x20, 0x98, 0xb4, 0x00, 0x20, + 0x00, 0x00, 0x70, 0x47, 0x4c, 0xbd, 0x00, 0x20, 0x38, 0xb2, 0x00, 0x20, + 0xe0, 0xb3, 0x00, 0x20, 0xb8, 0x00, 0xff, 0xff, 0xef, 0xf3, 0x11, 0x80, + 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x38, 0xb5, 0x14, 0x46, + 0x00, 0x22, 0x82, 0x70, 0x00, 0xf1, 0x4c, 0x05, 0xdf, 0xf8, 0x14, 0x29, + 0x82, 0x61, 0x00, 0x22, 0xc2, 0x61, 0x02, 0x62, 0x02, 0x80, 0x82, 0x81, + 0x01, 0x22, 0xc2, 0x81, 0x02, 0x82, 0x42, 0x82, 0x00, 0x22, 0xa0, 0xf8, + 0x18, 0x22, 0x40, 0x22, 0xea, 0x83, 0x2a, 0x84, 0x00, 0x22, 0x6a, 0x85, + 0x2a, 0x80, 0xaa, 0x61, 0x41, 0xb1, 0x4f, 0xf0, 0x00, 0x41, 0x41, 0x61, + 0x4f, 0xf0, 0xff, 0x31, 0x01, 0x81, 0x41, 0x81, 0x81, 0x80, 0xc1, 0x80, + 0x01, 0xf0, 0x82, 0xf8, 0xdf, 0xf8, 0xd4, 0x08, 0x34, 0xb9, 0x41, 0x78, + 0x02, 0x78, 0x42, 0xea, 0x01, 0x21, 0xc2, 0x78, 0x80, 0x78, 0x05, 0xe0, + 0x41, 0x79, 0x02, 0x79, 0x42, 0xea, 0x01, 0x21, 0xc2, 0x79, 0x80, 0x79, + 0x09, 0xb2, 0x40, 0xea, 0x02, 0x20, 0xb1, 0xf5, 0x00, 0x5f, 0xa8, 0xbf, + 0xa1, 0xf5, 0x80, 0x41, 0x00, 0xb2, 0xb0, 0xf5, 0x00, 0x5f, 0xa8, 0xbf, + 0xa0, 0xf5, 0x80, 0x40, 0x69, 0x84, 0xa8, 0x84, 0x01, 0xf0, 0x96, 0xfd, + 0xdf, 0xf8, 0x94, 0x08, 0x34, 0x21, 0x01, 0xfb, 0x04, 0x04, 0x20, 0x46, + 0x02, 0xf0, 0xb0, 0xfe, 0x64, 0x20, 0x60, 0x60, 0xbd, 0xe8, 0x31, 0x40, + 0x01, 0xf0, 0x9d, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, 0x04, 0x46, 0x0e, 0x46, + 0x15, 0x46, 0xff, 0xf7, 0x9b, 0xff, 0x00, 0x27, 0x80, 0x46, 0xe1, 0x5f, + 0x70, 0x1e, 0x81, 0x42, 0xbc, 0xbf, 0x72, 0x42, 0x8a, 0x42, 0x05, 0xda, + 0xb4, 0xf9, 0x02, 0x10, 0x81, 0x42, 0xb8, 0xbf, 0x8a, 0x42, 0x02, 0xdb, + 0x27, 0x80, 0x67, 0x80, 0x01, 0x27, 0xb4, 0xf9, 0x00, 0x00, 0x00, 0x12, + 0x00, 0xf0, 0x3f, 0x01, 0xa5, 0xb9, 0x40, 0xf6, 0x15, 0x20, 0x02, 0xf0, + 0xc5, 0xfe, 0x20, 0x88, 0xc1, 0xb2, 0x40, 0xf6, 0x14, 0x20, 0x02, 0xf0, + 0xbf, 0xfe, 0x00, 0xf0, 0x2b, 0xf8, 0x40, 0xf6, 0x17, 0x20, 0x02, 0xf0, + 0xb9, 0xfe, 0x60, 0x88, 0xc1, 0xb2, 0x40, 0xf6, 0x16, 0x20, 0x13, 0xe0, + 0x40, 0xf6, 0x19, 0x20, 0x02, 0xf0, 0xb0, 0xfe, 0x20, 0x88, 0xc1, 0xb2, + 0x40, 0xf6, 0x18, 0x20, 0x02, 0xf0, 0xaa, 0xfe, 0x00, 0xf0, 0x16, 0xf8, + 0x40, 0xf6, 0x1b, 0x20, 0x02, 0xf0, 0xa4, 0xfe, 0x60, 0x88, 0xc1, 0xb2, + 0x40, 0xf6, 0x1a, 0x20, 0x02, 0xf0, 0x9e, 0xfe, 0x01, 0x20, 0xa8, 0x40, + 0xc1, 0xb2, 0x40, 0xf6, 0x1c, 0x20, 0x02, 0xf0, 0x97, 0xfe, 0x88, 0xf3, + 0x11, 0x88, 0x38, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0xb4, 0xf9, 0x02, 0x00, + 0x00, 0x12, 0x00, 0xf0, 0x3f, 0x01, 0x70, 0x47, 0x2d, 0xe9, 0xf8, 0x4f, + 0x80, 0x46, 0xdf, 0xf8, 0x0c, 0x0e, 0x4f, 0xf4, 0x08, 0x71, 0x01, 0xfb, + 0x08, 0x0a, 0xff, 0xf7, 0x3b, 0xff, 0x83, 0x46, 0x40, 0x46, 0x0a, 0xf1, + 0x6a, 0x05, 0x02, 0xf0, 0xe3, 0xff, 0x2a, 0x88, 0xdf, 0xf8, 0xf0, 0x1d, + 0x40, 0x56, 0x56, 0x56, 0x00, 0x24, 0x81, 0x1b, 0x04, 0xd4, 0xb1, 0x46, + 0x06, 0x46, 0x04, 0xd0, 0x01, 0x21, 0x02, 0xe0, 0x81, 0x46, 0x4f, 0xf0, + 0xff, 0x31, 0x40, 0x2a, 0x1f, 0xd0, 0x01, 0x24, 0x00, 0x29, 0x4c, 0xbf, + 0x1f, 0xfa, 0x89, 0xf7, 0xb7, 0xb2, 0xda, 0xe9, 0x82, 0x01, 0x3a, 0x46, + 0x03, 0xf0, 0x64, 0xf8, 0xc0, 0x07, 0x18, 0xd5, 0x0a, 0xeb, 0xc7, 0x00, + 0xb1, 0x45, 0xc1, 0x6f, 0x04, 0xd0, 0x80, 0x6f, 0x40, 0x11, 0xa8, 0x80, + 0x48, 0x11, 0xe8, 0x80, 0x42, 0x46, 0xdf, 0xf8, 0xd8, 0x0d, 0xb0, 0xf9, + 0x24, 0x10, 0x0a, 0xf1, 0x6e, 0x00, 0xff, 0xf7, 0x61, 0xff, 0xac, 0x81, + 0x8b, 0xf3, 0x11, 0x88, 0x00, 0x20, 0xbd, 0xe8, 0xf2, 0x8f, 0x00, 0x24, + 0xf7, 0xe7, 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x26, 0x68, 0x60, 0x68, + 0xb6, 0xf9, 0x34, 0xc0, 0x03, 0xeb, 0x02, 0x17, 0x81, 0x1c, 0x67, 0x44, + 0x3f, 0x11, 0xcf, 0x80, 0xb7, 0x8e, 0x4a, 0x80, 0xff, 0x18, 0xb1, 0xf9, + 0x0a, 0x20, 0x8b, 0x80, 0x07, 0xf0, 0x0f, 0x07, 0x0f, 0x81, 0x00, 0x2a, + 0x14, 0xbf, 0x02, 0x22, 0x01, 0x22, 0xb1, 0xf9, 0x0c, 0x70, 0x13, 0x46, + 0x1f, 0xb1, 0x37, 0x69, 0xe7, 0x61, 0x01, 0x27, 0x08, 0xe0, 0x02, 0x2b, + 0x03, 0xd1, 0x77, 0x69, 0xe7, 0x61, 0x37, 0x8c, 0x02, 0xe0, 0xb7, 0x69, + 0xe7, 0x61, 0x77, 0x8c, 0x27, 0x84, 0xb1, 0xf9, 0x0e, 0x70, 0x00, 0x2f, + 0x01, 0xbf, 0xb1, 0xf9, 0x10, 0x70, 0x00, 0x2f, 0x0f, 0x78, 0xba, 0x42, + 0x24, 0xd0, 0x00, 0xf1, 0x18, 0x07, 0xdf, 0xf8, 0xb4, 0xc6, 0xc7, 0xf8, + 0x00, 0xc0, 0x4f, 0xf0, 0x00, 0x0c, 0xc7, 0xf8, 0x04, 0xc0, 0xc7, 0xf8, + 0x08, 0xc0, 0xb4, 0xf8, 0x12, 0xc0, 0xa4, 0xf8, 0x16, 0xc0, 0x4f, 0xf0, + 0x00, 0x0c, 0xa0, 0xf8, 0x00, 0xc0, 0xa1, 0xf8, 0x0e, 0xc0, 0x0a, 0x70, + 0xc7, 0xf8, 0x4c, 0xc0, 0x32, 0x69, 0xe2, 0x61, 0x01, 0x22, 0x22, 0x84, + 0xb1, 0xf9, 0x0c, 0x20, 0x00, 0x2a, 0x1a, 0xbf, 0x01, 0x2b, 0x08, 0x22, + 0x20, 0x22, 0xba, 0x86, 0xb1, 0xf9, 0x10, 0x10, 0x21, 0xb1, 0x00, 0xf0, + 0x4b, 0xff, 0x61, 0x68, 0x00, 0x20, 0x48, 0x82, 0x25, 0x81, 0xf1, 0xbd, + 0x2d, 0xe9, 0xf9, 0x4f, 0x97, 0xb0, 0x00, 0x20, 0x0c, 0x46, 0x01, 0x90, + 0xe0, 0x8a, 0x17, 0x99, 0x40, 0x08, 0x02, 0x90, 0x01, 0x20, 0x88, 0x40, + 0x11, 0x90, 0x00, 0x21, 0x00, 0x20, 0x03, 0xf0, 0x20, 0xf8, 0x11, 0x98, + 0x02, 0xf0, 0x32, 0xfe, 0x00, 0x25, 0x30, 0xb9, 0x04, 0xf0, 0x99, 0xf8, + 0x18, 0xb9, 0x03, 0xf0, 0x73, 0xf8, 0x02, 0x20, 0x0c, 0xe3, 0x00, 0xf0, + 0x26, 0xfb, 0x02, 0xf0, 0xec, 0xfd, 0xdf, 0xf8, 0x34, 0x0e, 0x00, 0x68, + 0x60, 0x62, 0x04, 0xf1, 0x28, 0x00, 0x04, 0xf0, 0xb6, 0xfe, 0x00, 0xf0, + 0x81, 0xff, 0x00, 0x28, 0x04, 0xf1, 0x2c, 0x00, 0x02, 0xd0, 0x04, 0xf0, + 0xe6, 0xff, 0x01, 0xe0, 0x05, 0xf0, 0x55, 0xfa, 0x17, 0x99, 0x20, 0x46, + 0x00, 0xf0, 0x16, 0xff, 0x06, 0x46, 0x60, 0x68, 0xb0, 0xf9, 0x0c, 0x10, + 0x00, 0x29, 0x17, 0x99, 0x14, 0xbf, 0xb0, 0xf9, 0x08, 0x00, 0xb0, 0xf9, + 0x04, 0x00, 0x00, 0x29, 0x14, 0xbf, 0xdf, 0xf8, 0xf0, 0x1d, 0xdf, 0xf8, + 0xf0, 0x1d, 0x09, 0x68, 0xc9, 0x07, 0x05, 0xd5, 0x01, 0x21, 0xc0, 0x1d, + 0x80, 0x28, 0x02, 0xd3, 0x7f, 0x20, 0x00, 0xe0, 0x00, 0x21, 0x17, 0x9a, + 0xdf, 0xf8, 0xd8, 0x3d, 0x00, 0x04, 0x00, 0xf4, 0xfe, 0x00, 0x40, 0xea, + 0x82, 0x70, 0x40, 0xea, 0xc1, 0x32, 0x1a, 0x43, 0x16, 0x92, 0x00, 0x27, + 0x22, 0x8b, 0xd2, 0x05, 0x02, 0xf0, 0x7e, 0x52, 0x10, 0x43, 0x40, 0xea, + 0xc1, 0x30, 0xdf, 0xf8, 0xb8, 0x1d, 0x08, 0x43, 0x10, 0x90, 0x10, 0x98, + 0x05, 0xf0, 0x3b, 0xfb, 0x20, 0x68, 0xc0, 0x8e, 0x41, 0x42, 0x09, 0xb2, + 0x00, 0xb2, 0x05, 0xf0, 0xa3, 0xfd, 0x60, 0x68, 0xb0, 0xf9, 0x0e, 0x10, + 0x39, 0xb1, 0xdf, 0xf8, 0x84, 0x2d, 0x4f, 0xf4, 0x88, 0x71, 0xd1, 0x61, + 0x11, 0x62, 0x4f, 0xf4, 0x84, 0x77, 0x61, 0x6a, 0xdf, 0xf8, 0x70, 0x2d, + 0x39, 0x43, 0x41, 0xf0, 0x02, 0x01, 0x11, 0x60, 0xd0, 0xf8, 0x6e, 0x00, + 0x03, 0x90, 0x17, 0x98, 0x06, 0xf0, 0x60, 0xf8, 0x04, 0xe0, 0x1f, 0xfa, + 0x89, 0xf8, 0x01, 0x98, 0x40, 0x1c, 0x01, 0x90, 0x02, 0x98, 0x01, 0x99, + 0x88, 0x42, 0xc0, 0xf2, 0x66, 0x82, 0x00, 0x2d, 0x08, 0xbf, 0x00, 0x2e, + 0x40, 0xf0, 0x61, 0x82, 0x08, 0x46, 0x02, 0x99, 0x88, 0x42, 0x08, 0xbf, + 0x4f, 0xf0, 0x01, 0x0a, 0x1c, 0xd0, 0x00, 0xf0, 0x05, 0xff, 0x4f, 0xf0, + 0x00, 0x0a, 0x20, 0xb9, 0x17, 0x98, 0x01, 0x21, 0xc0, 0xb2, 0x05, 0xf0, + 0xfa, 0xf9, 0x20, 0x68, 0x80, 0x8f, 0x06, 0xf0, 0x6d, 0xf9, 0x05, 0xf0, + 0x9c, 0xfa, 0x01, 0x98, 0x17, 0x9a, 0x64, 0x21, 0x48, 0x43, 0x02, 0x99, + 0x90, 0xfb, 0xf1, 0xf0, 0xdf, 0xf8, 0xe8, 0x14, 0x34, 0x23, 0x03, 0xfb, + 0x02, 0x11, 0x48, 0x60, 0x01, 0x98, 0x01, 0x28, 0x2d, 0xdb, 0xdd, 0xe9, + 0x08, 0x01, 0x06, 0xf0, 0xf7, 0xf9, 0x0f, 0x90, 0xdd, 0xe9, 0x06, 0x01, + 0x06, 0xf0, 0xf2, 0xf9, 0xb8, 0xf1, 0x00, 0x0f, 0x0e, 0x90, 0x20, 0xd1, + 0x60, 0x68, 0xdd, 0xe9, 0x14, 0x23, 0xd0, 0xe9, 0x0a, 0x71, 0xba, 0x18, + 0x4b, 0x41, 0xc0, 0xe9, 0x0a, 0x23, 0xd0, 0xe9, 0x0c, 0x71, 0xdd, 0xe9, + 0x12, 0x23, 0xba, 0x18, 0x4b, 0x41, 0xc0, 0xe9, 0x0c, 0x23, 0xd0, 0xe9, + 0x0e, 0x71, 0xdd, 0xe9, 0x08, 0x23, 0xba, 0x18, 0x4b, 0x41, 0xc0, 0xe9, + 0x0e, 0x23, 0xd0, 0xe9, 0x10, 0x71, 0xdd, 0xe9, 0x06, 0x23, 0xba, 0x18, + 0x4b, 0x41, 0xc0, 0xe9, 0x10, 0x23, 0x17, 0x98, 0x02, 0xf0, 0x4e, 0xfe, + 0xdf, 0xf8, 0xc8, 0x2a, 0xdf, 0xf8, 0x48, 0x1d, 0x80, 0x56, 0x31, 0xf8, + 0x10, 0x00, 0x06, 0xf0, 0xfd, 0xf9, 0xdf, 0xf8, 0x40, 0x1d, 0x06, 0xf0, + 0x09, 0xfa, 0x00, 0xf0, 0x6d, 0xfd, 0xba, 0xf1, 0x00, 0x0f, 0x0d, 0x90, + 0x39, 0xd1, 0x05, 0xf0, 0x62, 0xfa, 0x02, 0x28, 0x0c, 0xbf, 0x06, 0x26, + 0x01, 0x28, 0x00, 0xd1, 0x01, 0x25, 0xdf, 0xf8, 0x20, 0x2d, 0xd2, 0xe9, + 0x00, 0x01, 0xcd, 0xe9, 0x14, 0x01, 0xd2, 0xe9, 0x02, 0x01, 0xcd, 0xe9, + 0x12, 0x01, 0xd2, 0xe9, 0x04, 0x01, 0xcd, 0xe9, 0x08, 0x01, 0xd2, 0xe9, + 0x06, 0x01, 0xcd, 0xe9, 0x06, 0x01, 0x60, 0x68, 0xb0, 0xf9, 0x0c, 0x00, + 0xb0, 0xb9, 0x17, 0x98, 0x00, 0x21, 0xc0, 0xb2, 0x05, 0xf0, 0x7d, 0xf9, + 0xdd, 0xe9, 0x08, 0x01, 0x40, 0x42, 0x61, 0xeb, 0x41, 0x01, 0xcd, 0xe9, + 0x08, 0x01, 0xdd, 0xe9, 0x06, 0x01, 0x40, 0x42, 0x61, 0xeb, 0x41, 0x01, + 0xcd, 0xe9, 0x06, 0x01, 0x20, 0x68, 0x80, 0x8f, 0x06, 0xf0, 0xe2, 0xf8, + 0x00, 0x2d, 0x04, 0xbf, 0x00, 0x2e, 0x05, 0xf0, 0x0e, 0xfa, 0x01, 0x98, + 0x02, 0x28, 0xc0, 0xf2, 0xcc, 0x80, 0x0f, 0x98, 0x00, 0x99, 0x06, 0xf0, + 0x3f, 0xfa, 0x0c, 0x90, 0x59, 0x46, 0x0e, 0x98, 0x06, 0xf0, 0x3a, 0xfa, + 0x0b, 0x90, 0xbd, 0xf9, 0x14, 0x10, 0xbd, 0xf9, 0x10, 0x00, 0x40, 0x1a, + 0x06, 0xf0, 0x9a, 0xf9, 0x07, 0x46, 0xbd, 0xf9, 0x12, 0x00, 0xbd, 0xf9, + 0x16, 0x10, 0x40, 0x1a, 0x06, 0xf0, 0x92, 0xf9, 0x00, 0xf0, 0x1c, 0xfd, + 0x83, 0x46, 0x48, 0x46, 0x00, 0xf0, 0xfc, 0xfc, 0x59, 0x46, 0x06, 0xf0, + 0x95, 0xfa, 0x06, 0xf0, 0xd5, 0xfa, 0x00, 0x21, 0x06, 0xf0, 0x0c, 0xfb, + 0x83, 0x46, 0x1d, 0xd0, 0x20, 0x68, 0x30, 0xf8, 0x42, 0x1f, 0x81, 0xb1, + 0x61, 0x68, 0x4c, 0x31, 0x00, 0x91, 0x40, 0x88, 0x06, 0xf0, 0x82, 0xf9, + 0x01, 0x46, 0x00, 0x98, 0x80, 0x69, 0x06, 0xf0, 0x09, 0xfb, 0x04, 0xd3, + 0x00, 0x98, 0x00, 0x88, 0x08, 0x28, 0xc0, 0xf2, 0x90, 0x80, 0x11, 0x98, + 0x02, 0xf0, 0xbe, 0xfc, 0x00, 0x28, 0x03, 0xd0, 0x04, 0x20, 0x02, 0xf0, + 0xab, 0xfc, 0x00, 0x28, 0x00, 0xf0, 0x85, 0x80, 0x0c, 0x98, 0x00, 0xf0, + 0xd6, 0xfc, 0x00, 0x90, 0x49, 0x46, 0x0b, 0x98, 0x06, 0xf0, 0x02, 0xfb, + 0x00, 0x99, 0x06, 0xf0, 0x63, 0xfa, 0x59, 0x46, 0x06, 0xf0, 0x6e, 0xf9, + 0x00, 0x90, 0x39, 0x46, 0x0b, 0x98, 0x06, 0xf0, 0xf7, 0xfa, 0x07, 0x46, + 0x0c, 0x98, 0x00, 0xf0, 0xbb, 0xfc, 0x01, 0x46, 0x38, 0x46, 0x06, 0xf0, + 0xdf, 0xf9, 0x59, 0x46, 0x06, 0xf0, 0x5e, 0xf9, 0x0a, 0x90, 0x4f, 0xf0, + 0x7e, 0x50, 0x18, 0x99, 0x06, 0xf0, 0xd6, 0xf9, 0xb8, 0xf1, 0x00, 0x0f, + 0x81, 0x46, 0x5c, 0xd1, 0x67, 0x68, 0x00, 0xf0, 0xa6, 0xfc, 0x0d, 0x99, + 0x06, 0xf0, 0xdc, 0xfa, 0xb9, 0x69, 0x06, 0xf0, 0x3d, 0xfa, 0xb8, 0x61, + 0x49, 0x46, 0x00, 0x98, 0x06, 0xf0, 0xd4, 0xfa, 0xf9, 0x69, 0x06, 0xf0, + 0x35, 0xfa, 0xf8, 0x61, 0x49, 0x46, 0x0a, 0x98, 0x06, 0xf0, 0xcc, 0xfa, + 0x39, 0x6a, 0x06, 0xf0, 0x2d, 0xfa, 0x38, 0x62, 0x4f, 0xf0, 0x7e, 0x51, + 0x38, 0x6d, 0x06, 0xf0, 0x27, 0xfa, 0x38, 0x65, 0x59, 0x46, 0x0d, 0x98, + 0x06, 0xf0, 0xbe, 0xfa, 0x81, 0x46, 0x00, 0x98, 0x49, 0x46, 0x06, 0xf0, + 0x2b, 0xf9, 0x79, 0x6d, 0x83, 0x46, 0x06, 0xf0, 0xa5, 0xf9, 0x00, 0x90, + 0x39, 0x6d, 0x06, 0xf0, 0x23, 0xf9, 0x79, 0x6d, 0x06, 0xf0, 0x12, 0xfa, + 0x01, 0x46, 0x79, 0x65, 0x00, 0xf0, 0x76, 0xfc, 0x00, 0x99, 0x06, 0xf0, + 0xa7, 0xfa, 0xf9, 0x6d, 0x06, 0xf0, 0x08, 0xfa, 0xf8, 0x65, 0x49, 0x46, + 0x0a, 0x98, 0x06, 0xf0, 0x11, 0xf9, 0xb9, 0x6d, 0x81, 0x46, 0x06, 0xf0, + 0x8b, 0xf9, 0x39, 0x6d, 0x83, 0x46, 0x06, 0xf0, 0x09, 0xf9, 0xb9, 0x6d, + 0x06, 0xf0, 0xf8, 0xf9, 0x01, 0x46, 0xb9, 0x65, 0x48, 0x46, 0x06, 0xf0, + 0x7f, 0xf9, 0x59, 0x46, 0x06, 0xf0, 0x8c, 0xfa, 0x39, 0x6e, 0x06, 0xf0, + 0xed, 0xf9, 0x38, 0x66, 0x01, 0xe0, 0x01, 0x28, 0x03, 0xdb, 0x0f, 0x98, + 0xdd, 0xf8, 0x38, 0xb0, 0x00, 0x90, 0xba, 0xf1, 0x00, 0x0f, 0x04, 0x98, + 0x05, 0x90, 0x03, 0x98, 0x04, 0x90, 0x7f, 0xf4, 0x70, 0xae, 0x60, 0x68, + 0xdf, 0xf8, 0x74, 0x2d, 0x50, 0xf8, 0x14, 0x7f, 0xdf, 0xf8, 0x6c, 0x3d, + 0x07, 0xf0, 0x01, 0x01, 0x51, 0x43, 0x81, 0xea, 0x57, 0x01, 0x00, 0xf0, + 0x05, 0xf9, 0x00, 0xf0, 0x03, 0xf9, 0x01, 0x60, 0x07, 0xf0, 0x01, 0x02, + 0x07, 0xf0, 0x02, 0x01, 0x49, 0x1e, 0x7b, 0x07, 0x05, 0xd5, 0xfb, 0x43, + 0x03, 0xf0, 0x01, 0x03, 0x4b, 0x43, 0x51, 0x43, 0x01, 0xe0, 0x52, 0x00, + 0x53, 0x1e, 0x07, 0x8f, 0x79, 0x43, 0x07, 0xfb, 0x03, 0xf2, 0xb0, 0xf9, + 0x5a, 0x70, 0x13, 0xb2, 0x3b, 0x44, 0xbd, 0xf9, 0x10, 0x70, 0xbb, 0x42, + 0x07, 0xd1, 0xb0, 0xf9, 0x5c, 0x70, 0x0b, 0xb2, 0x3b, 0x44, 0xbd, 0xf9, + 0x12, 0x70, 0xbb, 0x42, 0x04, 0xd0, 0x02, 0x9f, 0x01, 0x9b, 0x7f, 0x1e, + 0xbb, 0x42, 0x01, 0xdb, 0x00, 0x22, 0x00, 0x21, 0x83, 0x8e, 0xd3, 0x18, + 0x83, 0x86, 0xc3, 0x8e, 0xcb, 0x18, 0xc3, 0x86, 0xb0, 0xf8, 0x5a, 0x30, + 0xd2, 0x18, 0xad, 0xf8, 0x0c, 0x20, 0xb0, 0xf8, 0x5c, 0x00, 0x08, 0x18, + 0xad, 0xf8, 0x0e, 0x00, 0x00, 0x2d, 0x08, 0xbf, 0x00, 0x2e, 0x07, 0xd1, + 0x05, 0xf0, 0xfb, 0xf8, 0x02, 0x28, 0x0c, 0xbf, 0x06, 0x26, 0x01, 0x28, + 0x00, 0xd1, 0x01, 0x25, 0xdf, 0xf8, 0x50, 0xca, 0xdd, 0xe9, 0x14, 0x23, + 0xdc, 0xe9, 0x00, 0x01, 0x10, 0x18, 0x59, 0x41, 0xcd, 0xe9, 0x14, 0x01, + 0xdd, 0xe9, 0x12, 0x23, 0xdc, 0xe9, 0x02, 0x01, 0x10, 0x18, 0x59, 0x41, + 0xcd, 0xe9, 0x12, 0x01, 0xdd, 0xe9, 0x08, 0x23, 0xdc, 0xe9, 0x04, 0x01, + 0x10, 0x18, 0x59, 0x41, 0xcd, 0xe9, 0x08, 0x01, 0xdd, 0xe9, 0x06, 0x23, + 0xdc, 0xe9, 0x06, 0x01, 0x10, 0x18, 0x59, 0x41, 0xcd, 0xe9, 0x06, 0x01, + 0x4f, 0xea, 0x68, 0x09, 0x20, 0x68, 0x24, 0x30, 0xc1, 0x8b, 0x00, 0x29, + 0x47, 0xd0, 0x16, 0x98, 0x4f, 0xf0, 0x8a, 0x41, 0x00, 0x2d, 0x08, 0x60, + 0x48, 0xd1, 0x00, 0x2e, 0x7f, 0xf4, 0xe5, 0xad, 0x05, 0xf0, 0xa5, 0xf8, + 0x20, 0x68, 0xb0, 0xf9, 0x24, 0x10, 0x17, 0x9a, 0x03, 0xa8, 0xff, 0xf7, + 0x41, 0xfc, 0x00, 0xf0, 0x96, 0xf8, 0x05, 0xf0, 0xb6, 0xf8, 0x02, 0x28, + 0x0c, 0xbf, 0x06, 0x26, 0x01, 0x28, 0x00, 0xd1, 0x01, 0x25, 0x10, 0x98, + 0x4f, 0xf0, 0x8a, 0x41, 0x08, 0x60, 0x67, 0x68, 0xdf, 0xf8, 0xec, 0x1d, + 0x78, 0x6e, 0x06, 0xf0, 0xd3, 0xf9, 0xdf, 0xf8, 0x90, 0x1d, 0x84, 0x46, + 0xdf, 0xf8, 0xac, 0x09, 0xc7, 0xf8, 0x64, 0xc0, 0xd1, 0xe9, 0x00, 0x23, + 0x00, 0x68, 0x00, 0xf0, 0x68, 0xf8, 0x08, 0xbf, 0x00, 0x28, 0x0b, 0xd0, + 0xdf, 0xf8, 0x70, 0x1d, 0xdf, 0xf8, 0x90, 0x09, 0x80, 0x68, 0xd1, 0xe9, + 0x12, 0x23, 0x00, 0xf0, 0x5c, 0xf8, 0x08, 0xbf, 0x00, 0x28, 0x0d, 0xd1, + 0x4f, 0xf0, 0x7e, 0x51, 0x60, 0x46, 0x06, 0xf0, 0x17, 0xf9, 0x78, 0x66, + 0x06, 0xe0, 0x41, 0x5e, 0x17, 0x9a, 0x03, 0xa8, 0xff, 0xf7, 0x06, 0xfc, + 0x00, 0xf0, 0x5b, 0xf8, 0x00, 0x2d, 0x3f, 0xf4, 0x9c, 0xad, 0x02, 0x98, + 0x80, 0x1c, 0x08, 0xf0, 0x01, 0x01, 0x40, 0x1a, 0x09, 0xf0, 0x01, 0x01, + 0x40, 0x1a, 0x02, 0x90, 0x4f, 0xf0, 0x03, 0x08, 0x91, 0xe5, 0x20, 0x68, + 0xb0, 0xf9, 0x24, 0x10, 0x60, 0x68, 0x17, 0x9a, 0x6e, 0x30, 0xff, 0xf7, + 0xed, 0xfb, 0x00, 0xf0, 0x42, 0xf8, 0x00, 0xf0, 0x3a, 0xf8, 0x02, 0xf0, + 0xed, 0xfa, 0x60, 0x6a, 0xdf, 0xf8, 0x58, 0x18, 0x08, 0x60, 0x00, 0xf0, + 0x99, 0xfc, 0x28, 0xb1, 0x00, 0x21, 0x04, 0xf1, 0x2c, 0x00, 0x04, 0xf0, + 0x10, 0xfd, 0x03, 0xe0, 0x04, 0xf1, 0x2c, 0x00, 0x04, 0xf0, 0x78, 0xff, + 0x04, 0xf1, 0x28, 0x00, 0x04, 0xf0, 0xc4, 0xfb, 0x00, 0x20, 0x02, 0xf0, + 0x69, 0xfd, 0x15, 0xb1, 0x00, 0x2e, 0x3f, 0xf4, 0xe4, 0xac, 0x30, 0x46, + 0x19, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x00, 0x00, 0xff, 0xe6, 0xdb, 0x2e, + 0x14, 0x0a, 0x00, 0x46, 0x98, 0xf1, 0x00, 0x20, 0x01, 0x60, 0x01, 0xf0, + 0x01, 0x02, 0x5a, 0x43, 0x82, 0xea, 0x51, 0x01, 0x70, 0x47, 0xdb, 0x01, + 0x43, 0xea, 0x52, 0x63, 0x40, 0x43, 0xd2, 0x01, 0xc1, 0x17, 0x10, 0x1a, + 0x73, 0xeb, 0x01, 0x01, 0x70, 0x47, 0x02, 0x22, 0x04, 0xf1, 0x22, 0x01, + 0x0f, 0xf6, 0x68, 0x50, 0x70, 0x47, 0x22, 0x99, 0x09, 0x68, 0x08, 0x43, + 0x22, 0x99, 0x08, 0x60, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, 0x8d, 0xb0, + 0x53, 0x78, 0x12, 0x78, 0x04, 0x46, 0x88, 0x46, 0xff, 0xf7, 0x41, 0xfc, + 0x20, 0x8b, 0xc0, 0xb2, 0x05, 0xf0, 0x56, 0xf8, 0x4f, 0xea, 0x40, 0x0b, + 0xe0, 0x69, 0x05, 0xf0, 0x99, 0xff, 0xdf, 0xf8, 0xc8, 0x1c, 0x05, 0xf0, + 0xa5, 0xff, 0x05, 0x90, 0x26, 0x68, 0xf0, 0x8d, 0x05, 0xf0, 0x90, 0xff, + 0xdf, 0xf8, 0xb8, 0x1c, 0x05, 0xf0, 0x9c, 0xff, 0x01, 0x46, 0x06, 0xf0, + 0x27, 0xf9, 0x07, 0x46, 0xe0, 0x8a, 0x05, 0xf0, 0x85, 0xff, 0x00, 0xf0, + 0xf0, 0xfa, 0x07, 0x46, 0x05, 0x99, 0x4f, 0xf0, 0x7e, 0x50, 0x06, 0xf0, + 0x0b, 0xf8, 0x4f, 0xf0, 0x80, 0x41, 0x06, 0xf0, 0x17, 0xf9, 0x01, 0x46, + 0x38, 0x46, 0x05, 0xf0, 0x85, 0xff, 0x82, 0x46, 0x4f, 0xf0, 0x7a, 0x50, + 0x51, 0x46, 0x06, 0xf0, 0x0d, 0xf9, 0x07, 0x90, 0x00, 0x20, 0x63, 0x68, + 0x03, 0xf1, 0x28, 0x02, 0xc2, 0xe9, 0x00, 0x00, 0xc2, 0xe9, 0x02, 0x00, + 0xc2, 0xe9, 0x04, 0x00, 0xc2, 0xe9, 0x06, 0x00, 0x10, 0x84, 0x50, 0x84, + 0x90, 0x62, 0x50, 0x63, 0xd0, 0x62, 0x90, 0x63, 0x10, 0x63, 0xa3, 0xf8, + 0x68, 0x00, 0x04, 0x90, 0x71, 0x8d, 0x90, 0x8c, 0x88, 0x42, 0x26, 0xbf, + 0xb1, 0x8d, 0x81, 0x42, 0x91, 0x84, 0x04, 0xa8, 0x00, 0x90, 0x5a, 0x46, + 0x05, 0x9b, 0x21, 0x46, 0x40, 0x46, 0xff, 0xf7, 0x4d, 0xfc, 0x00, 0x28, + 0x40, 0xf0, 0xa0, 0x82, 0x40, 0x46, 0x02, 0xf0, 0x82, 0xfb, 0x06, 0x46, + 0x40, 0x46, 0x02, 0xf0, 0x87, 0xfb, 0x07, 0x46, 0x40, 0xf2, 0x47, 0x30, + 0x86, 0x42, 0x0d, 0xda, 0x0f, 0xf6, 0xdc, 0x40, 0x30, 0x5c, 0x00, 0xf2, + 0x01, 0x10, 0x80, 0xb2, 0x05, 0xf0, 0x32, 0xff, 0x4f, 0xf0, 0x72, 0x51, + 0x06, 0xf0, 0xcc, 0xf8, 0x06, 0x46, 0x01, 0xe0, 0x4f, 0xf0, 0x82, 0x46, + 0xdf, 0xf8, 0x10, 0x15, 0x0f, 0xf6, 0x54, 0x40, 0x79, 0x56, 0x30, 0xf8, + 0x11, 0x00, 0x05, 0xf0, 0x21, 0xff, 0xdf, 0xf8, 0x88, 0x17, 0x05, 0xf0, + 0x2d, 0xff, 0x00, 0xf0, 0x91, 0xfa, 0x0b, 0x90, 0xe0, 0x8a, 0x40, 0x08, + 0x05, 0xf0, 0x16, 0xff, 0x07, 0x46, 0x60, 0x68, 0x0a, 0x90, 0x00, 0xf1, + 0x18, 0x05, 0xd5, 0xe9, 0x04, 0x01, 0x05, 0xf0, 0xd1, 0xfe, 0x00, 0xf0, + 0x7e, 0xfa, 0x81, 0x46, 0xd5, 0xe9, 0x06, 0x01, 0x05, 0xf0, 0xca, 0xfe, + 0x00, 0xf0, 0x77, 0xfa, 0x06, 0x90, 0xd5, 0xe9, 0x08, 0x01, 0x05, 0xf0, + 0xc3, 0xfe, 0x00, 0xf0, 0x70, 0xfa, 0x09, 0x90, 0xd5, 0xe9, 0x0a, 0x01, + 0x05, 0xf0, 0xbc, 0xfe, 0x00, 0xf0, 0x69, 0xfa, 0x08, 0x90, 0x2f, 0x68, + 0x69, 0x6c, 0xa8, 0x6c, 0x05, 0xf0, 0xf2, 0xff, 0x01, 0x90, 0x00, 0xf0, + 0x6b, 0xfa, 0x00, 0x90, 0xa9, 0x68, 0x00, 0xf0, 0x68, 0xfa, 0x00, 0x99, + 0x05, 0xf0, 0xe8, 0xff, 0x00, 0x90, 0x39, 0x46, 0x38, 0x46, 0x06, 0xf0, + 0x7f, 0xf8, 0x01, 0x46, 0x00, 0x98, 0x05, 0xf0, 0xed, 0xfe, 0x07, 0x46, + 0xa9, 0x6b, 0xdf, 0xf8, 0x54, 0x0b, 0x05, 0xf0, 0xd9, 0xff, 0x00, 0xf0, + 0x42, 0xfa, 0x01, 0x46, 0x01, 0x98, 0x05, 0xf0, 0xe1, 0xfe, 0x01, 0x46, + 0x50, 0x46, 0x06, 0xf0, 0x59, 0xf8, 0x02, 0xd2, 0xa8, 0x8e, 0x40, 0x1c, + 0xa8, 0x86, 0x08, 0x46, 0x07, 0x99, 0x06, 0xf0, 0x51, 0xf8, 0x04, 0xd2, + 0xa9, 0x8e, 0xa1, 0xeb, 0x11, 0x10, 0x40, 0x1e, 0xa8, 0x86, 0x20, 0x68, + 0x00, 0xf1, 0x26, 0x07, 0xb8, 0x8b, 0x02, 0x28, 0x0b, 0xd1, 0xf8, 0x8b, + 0x05, 0xf0, 0xb6, 0xfe, 0xe9, 0x6c, 0x06, 0xf0, 0x3f, 0xf8, 0x04, 0xd2, + 0xa8, 0x8e, 0x08, 0x28, 0xbc, 0xbf, 0x08, 0x20, 0xa8, 0x86, 0x48, 0x46, + 0x00, 0x21, 0x06, 0xf0, 0x35, 0xf8, 0xca, 0x46, 0x38, 0xbf, 0x8a, 0xf0, + 0x00, 0x4a, 0x06, 0x98, 0x06, 0xf0, 0x2e, 0xf8, 0x38, 0xbf, 0x80, 0xf0, + 0x00, 0x40, 0x00, 0x90, 0x58, 0x46, 0x05, 0xf0, 0x91, 0xfe, 0x07, 0x90, + 0x51, 0x46, 0x00, 0x98, 0x05, 0xf0, 0x98, 0xff, 0x82, 0x46, 0xdf, 0xf8, + 0xcc, 0x0a, 0x00, 0xf0, 0xf3, 0xf9, 0x07, 0x99, 0x05, 0xf0, 0x9e, 0xfe, + 0x51, 0x46, 0x06, 0xf0, 0x29, 0xf8, 0xdf, 0xf8, 0xbc, 0x1a, 0x06, 0xf0, + 0x25, 0xf8, 0x06, 0xf0, 0x8f, 0xf8, 0xad, 0xf8, 0x04, 0x00, 0xbd, 0xf8, + 0x04, 0x10, 0xa8, 0x8e, 0x88, 0x42, 0x38, 0xbf, 0x08, 0x46, 0xa8, 0x86, + 0xf9, 0x88, 0xa8, 0x8e, 0x81, 0x42, 0x26, 0xbf, 0xb9, 0x88, 0x88, 0x42, + 0xa9, 0x86, 0x00, 0xf0, 0xf1, 0xf9, 0xa9, 0x68, 0x82, 0x46, 0x00, 0xf0, + 0xee, 0xf9, 0x51, 0x46, 0x05, 0xf0, 0x6e, 0xff, 0x0b, 0x99, 0x06, 0xf0, + 0x07, 0xf8, 0x29, 0x68, 0x05, 0xf0, 0x76, 0xfe, 0x4f, 0xf0, 0x7e, 0x51, + 0x05, 0xf0, 0xee, 0xff, 0x82, 0x46, 0x38, 0xbf, 0x8a, 0x46, 0x09, 0x99, + 0x68, 0x68, 0x05, 0xf0, 0xf9, 0xff, 0x83, 0x46, 0x08, 0x99, 0xa8, 0x68, + 0x05, 0xf0, 0xf4, 0xff, 0x59, 0x46, 0x05, 0xf0, 0x55, 0xff, 0x00, 0xf0, + 0xc1, 0xf9, 0x83, 0x46, 0x08, 0x99, 0x68, 0x68, 0x05, 0xf0, 0xea, 0xff, + 0x00, 0x90, 0x09, 0x99, 0xa8, 0x68, 0x05, 0xf0, 0xe5, 0xff, 0x01, 0x46, + 0x00, 0x98, 0x05, 0xf0, 0xd1, 0xfe, 0x00, 0xf0, 0xb1, 0xf9, 0x00, 0x90, + 0xe0, 0x8a, 0x40, 0x08, 0x05, 0xf0, 0x3c, 0xfe, 0x82, 0x46, 0xb5, 0xf9, + 0x30, 0x00, 0x05, 0xf0, 0x2d, 0xfe, 0x00, 0xf0, 0xa5, 0xf9, 0x00, 0xf0, + 0x9c, 0xf9, 0x83, 0x46, 0xb5, 0xf9, 0x32, 0x00, 0x05, 0xf0, 0x24, 0xfe, + 0x00, 0xf0, 0x9c, 0xf9, 0x01, 0x46, 0x00, 0x98, 0x05, 0xf0, 0xb6, 0xfe, + 0x05, 0x46, 0xb8, 0x89, 0x90, 0xb1, 0x07, 0x99, 0x30, 0x46, 0x05, 0xf0, + 0x31, 0xfe, 0x06, 0x46, 0x48, 0x46, 0x00, 0xf0, 0x7f, 0xf9, 0x00, 0xf0, + 0x84, 0xf9, 0x83, 0x46, 0x06, 0x98, 0x00, 0xf0, 0x79, 0xf9, 0x01, 0x46, + 0x28, 0x46, 0x05, 0xf0, 0xa1, 0xfe, 0x05, 0x46, 0x58, 0x46, 0x06, 0xf0, + 0x3b, 0xf8, 0x06, 0xf0, 0x17, 0xf8, 0xad, 0xf8, 0x0c, 0x00, 0x28, 0x46, + 0x06, 0xf0, 0x34, 0xf8, 0x06, 0xf0, 0x10, 0xf8, 0xad, 0xf8, 0x0e, 0x00, + 0x78, 0x88, 0x05, 0xf0, 0x01, 0xfe, 0x06, 0x46, 0xbd, 0xf8, 0x04, 0x00, + 0x05, 0xf0, 0xfc, 0xfd, 0x01, 0x46, 0xdf, 0xf8, 0x9c, 0x09, 0x05, 0xf0, + 0x85, 0xfe, 0x00, 0xf0, 0x57, 0xf9, 0xdf, 0xf8, 0x94, 0x19, 0x05, 0xf0, + 0x01, 0xfe, 0xdf, 0xf8, 0x90, 0x19, 0x05, 0xf0, 0x79, 0xff, 0x81, 0x46, + 0x38, 0xbf, 0x89, 0x46, 0x00, 0xf0, 0x4d, 0xf9, 0x06, 0xf0, 0x12, 0xf8, + 0x05, 0xf0, 0xee, 0xff, 0xad, 0xf8, 0x08, 0x00, 0x49, 0x46, 0x28, 0x46, + 0x05, 0xf0, 0x7c, 0xff, 0x06, 0xf0, 0x08, 0xf8, 0x05, 0xf0, 0xe4, 0xff, + 0xad, 0xf8, 0x0a, 0x00, 0x0a, 0x98, 0xb0, 0xf8, 0x76, 0x00, 0x28, 0xb3, + 0xbd, 0xf9, 0x0a, 0x00, 0xbd, 0xf9, 0x08, 0x10, 0x23, 0x8c, 0x00, 0xfb, + 0x00, 0xf2, 0x01, 0xfb, 0x01, 0x22, 0x9a, 0x42, 0x1a, 0xda, 0x3a, 0x88, + 0x8a, 0x42, 0xbc, 0xbf, 0x12, 0xb2, 0xad, 0xf8, 0x08, 0x20, 0x39, 0x88, + 0x81, 0x42, 0xb8, 0xbf, 0xad, 0xf8, 0x0a, 0x10, 0x38, 0x88, 0xbd, 0xf9, + 0x08, 0x10, 0x40, 0x42, 0x81, 0x42, 0xb8, 0xbf, 0xad, 0xf8, 0x08, 0x00, + 0x38, 0x88, 0xbd, 0xf9, 0x0a, 0x10, 0x40, 0x42, 0x81, 0x42, 0xb8, 0xbf, + 0xad, 0xf8, 0x0a, 0x00, 0xff, 0xf7, 0x46, 0xf9, 0x06, 0x46, 0x60, 0x68, + 0xbd, 0xf8, 0x0c, 0x20, 0xb0, 0xf9, 0x6e, 0x10, 0xbd, 0xf8, 0x0e, 0x30, + 0x8a, 0x1a, 0xad, 0xf8, 0x0c, 0x20, 0xb0, 0xf8, 0x70, 0x20, 0xd2, 0x1a, + 0xad, 0xf8, 0x0e, 0x20, 0xbd, 0xf8, 0x08, 0x20, 0x89, 0x1a, 0xad, 0xf8, + 0x08, 0x10, 0x42, 0x46, 0xb0, 0xf8, 0x70, 0x00, 0xbd, 0xf8, 0x0a, 0x10, + 0x40, 0x1a, 0xad, 0xf8, 0x0a, 0x00, 0x20, 0x68, 0xb0, 0xf9, 0x24, 0x10, + 0x02, 0xa8, 0xff, 0xf7, 0x81, 0xf9, 0x04, 0x99, 0x08, 0x43, 0x04, 0x90, + 0x61, 0x68, 0x02, 0x98, 0xc1, 0xf8, 0x6e, 0x00, 0x86, 0xf3, 0x11, 0x88, + 0x34, 0x21, 0xdf, 0xf8, 0x4c, 0x04, 0x01, 0xfb, 0x08, 0x06, 0x23, 0x46, + 0x30, 0x69, 0x40, 0x1c, 0x30, 0x61, 0xf0, 0x68, 0x40, 0x1c, 0xf0, 0x60, + 0x04, 0x9a, 0x02, 0x99, 0x03, 0x98, 0xcd, 0xf8, 0x00, 0x80, 0x00, 0xf0, + 0xf4, 0xf8, 0x20, 0x68, 0x30, 0xf8, 0x42, 0x1f, 0x69, 0xb1, 0x61, 0x68, + 0x40, 0x88, 0x01, 0xf1, 0x4c, 0x07, 0x05, 0xf0, 0x63, 0xfd, 0x01, 0x46, + 0xb8, 0x69, 0x05, 0xf0, 0xeb, 0xfe, 0x02, 0xd3, 0x38, 0x88, 0x08, 0x28, + 0x14, 0xdb, 0xff, 0xf7, 0xf3, 0xf8, 0x67, 0x68, 0xb9, 0x69, 0x80, 0x46, + 0x05, 0x98, 0x05, 0xf0, 0xf1, 0xfe, 0xb8, 0x61, 0xf9, 0x69, 0x05, 0x98, + 0x05, 0xf0, 0xec, 0xfe, 0xf8, 0x61, 0x39, 0x6a, 0x05, 0x98, 0x05, 0xf0, + 0xe7, 0xfe, 0x38, 0x62, 0x88, 0xf3, 0x11, 0x88, 0x00, 0xf0, 0xc4, 0xfe, + 0x64, 0x68, 0x04, 0xf1, 0x18, 0x08, 0xd8, 0xf8, 0x04, 0x10, 0xd8, 0xf8, + 0x08, 0x70, 0x00, 0xf0, 0xba, 0xf8, 0x00, 0xf0, 0xbb, 0xf8, 0x49, 0x46, + 0x05, 0xf0, 0x38, 0xfe, 0x05, 0xf0, 0x78, 0xfe, 0x01, 0x46, 0x0b, 0x98, + 0x05, 0xf0, 0xce, 0xfe, 0xd8, 0xf8, 0x00, 0x10, 0x05, 0xf0, 0x3c, 0xfd, + 0xb0, 0x61, 0xd8, 0xf8, 0x08, 0x00, 0xd8, 0xf8, 0x04, 0x10, 0x80, 0xf0, + 0x00, 0x40, 0x05, 0xf0, 0x63, 0xff, 0xf0, 0x61, 0xb8, 0xf8, 0x34, 0x00, + 0x30, 0x86, 0x34, 0xf9, 0x0e, 0x0f, 0x00, 0x28, 0x6a, 0xd1, 0x58, 0x46, + 0x59, 0x46, 0x05, 0xf0, 0xb5, 0xfe, 0x07, 0x46, 0x28, 0x46, 0x29, 0x46, + 0x05, 0xf0, 0xb0, 0xfe, 0x39, 0x46, 0x05, 0xf0, 0x11, 0xfe, 0x05, 0xf0, + 0x51, 0xfe, 0x05, 0x46, 0xb1, 0x6a, 0x4f, 0xf0, 0x7e, 0x50, 0x05, 0xf0, + 0x09, 0xfe, 0xb0, 0x62, 0x28, 0x46, 0x31, 0x6a, 0x05, 0xf0, 0x90, 0xfd, + 0xb1, 0x6a, 0x07, 0x46, 0x05, 0xf0, 0x0e, 0xfd, 0x31, 0x6a, 0x05, 0xf0, + 0xfd, 0xfd, 0x01, 0x46, 0x31, 0x62, 0x28, 0x46, 0x05, 0xf0, 0x84, 0xfd, + 0x00, 0xf0, 0x61, 0xf8, 0x71, 0x6a, 0x05, 0xf0, 0xf3, 0xfd, 0x70, 0x62, + 0xdf, 0xf8, 0x90, 0x17, 0xb0, 0x6a, 0x05, 0xf0, 0x91, 0xff, 0x39, 0xd8, + 0x01, 0x46, 0xdf, 0xf8, 0x70, 0x07, 0xdf, 0xf8, 0x48, 0x57, 0x05, 0xf0, + 0xe5, 0xfd, 0x01, 0x46, 0x70, 0x6a, 0x05, 0xf0, 0xef, 0xfc, 0x01, 0x46, + 0xf1, 0x62, 0xdf, 0xf8, 0x70, 0x07, 0x05, 0xf0, 0xdb, 0xfd, 0x01, 0x46, + 0xdf, 0xf8, 0x68, 0x07, 0x05, 0xf0, 0xe4, 0xfc, 0x05, 0xf0, 0xfe, 0xfe, + 0x05, 0xf0, 0xda, 0xfe, 0xb0, 0x60, 0x65, 0x28, 0x24, 0xbf, 0x64, 0x20, + 0xb0, 0x60, 0xb0, 0x6a, 0x29, 0x46, 0x05, 0xf0, 0x65, 0xfe, 0xdf, 0xf8, + 0x2c, 0x17, 0x05, 0xf0, 0xc5, 0xfd, 0x71, 0x6a, 0x05, 0xf0, 0x5e, 0xfe, + 0x07, 0x46, 0xb1, 0x6a, 0xdf, 0xf8, 0x18, 0x07, 0x05, 0xf0, 0xbc, 0xfd, + 0x01, 0x46, 0x38, 0x46, 0x05, 0xf0, 0xc6, 0xfc, 0x70, 0x62, 0x29, 0x46, + 0xb0, 0x6a, 0x05, 0xf0, 0x4f, 0xfe, 0xb0, 0x62, 0x04, 0x98, 0x20, 0xb1, + 0x01, 0x20, 0x60, 0x80, 0x70, 0x69, 0x40, 0x1c, 0x70, 0x61, 0x00, 0xf0, + 0x3c, 0xfe, 0x00, 0x20, 0x0d, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x00, 0x00, + 0x48, 0xad, 0x00, 0x20, 0x24, 0x2b, 0x00, 0x20, 0x31, 0x46, 0x05, 0xf0, + 0x39, 0xbe, 0x58, 0x46, 0x49, 0x46, 0x05, 0xf0, 0x35, 0xbe, 0x01, 0x46, + 0x58, 0x46, 0x05, 0xf0, 0x21, 0xbd, 0x39, 0x46, 0x05, 0xf0, 0x2e, 0xbe, + 0x51, 0x46, 0x05, 0xf0, 0x9d, 0xbc, 0x39, 0x46, 0x05, 0xf0, 0x9a, 0xbc, + 0x01, 0x46, 0xdf, 0xf8, 0xd0, 0x06, 0x06, 0xf0, 0x9a, 0xb8, 0x00, 0x00, + 0xdc, 0x2a, 0x00, 0x20, 0x69, 0x68, 0x08, 0x46, 0x05, 0xf0, 0x1c, 0xbe, + 0x81, 0x46, 0x38, 0x46, 0x39, 0x46, 0x05, 0xf0, 0x17, 0xbe, 0x2d, 0xe9, + 0xfa, 0x4f, 0x83, 0xb0, 0x1e, 0x68, 0xd3, 0xf8, 0x04, 0x80, 0x22, 0xb1, + 0x40, 0x46, 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x4f, 0xb6, 0xe0, 0x0e, 0x98, + 0x02, 0xf0, 0xb2, 0xf8, 0x08, 0xf1, 0x68, 0x05, 0x83, 0x46, 0xa9, 0x88, + 0xdf, 0xf8, 0x8c, 0x06, 0x09, 0x56, 0x02, 0x91, 0x1b, 0xf9, 0x00, 0x00, + 0x40, 0x1a, 0x7d, 0xd0, 0x28, 0x88, 0x00, 0x28, 0x7a, 0xd1, 0xb8, 0xf9, + 0x0c, 0x00, 0xe8, 0xb1, 0x04, 0x98, 0x40, 0x68, 0x02, 0x9a, 0x00, 0xf5, + 0x02, 0x74, 0xd4, 0xe9, 0x02, 0x01, 0x02, 0xf0, 0x35, 0xf9, 0xc0, 0x07, + 0x12, 0xd4, 0xd4, 0xe9, 0x02, 0x01, 0xcd, 0xe9, 0x00, 0x01, 0x02, 0x9a, + 0x01, 0x20, 0x00, 0x21, 0x06, 0xf0, 0x5c, 0xf8, 0xdd, 0xe9, 0x00, 0x23, + 0x10, 0x43, 0x19, 0x43, 0xc4, 0xe9, 0x02, 0x01, 0x00, 0x26, 0x4f, 0xf0, + 0x7e, 0x5a, 0x0d, 0xe0, 0xf0, 0x69, 0x05, 0xf0, 0x37, 0xfc, 0xdf, 0xf8, + 0x04, 0x16, 0x05, 0xf0, 0x43, 0xfc, 0x06, 0x46, 0x4f, 0xf0, 0x7e, 0x50, + 0x31, 0x46, 0x05, 0xf0, 0xbb, 0xfc, 0x82, 0x46, 0xb5, 0xf9, 0x0a, 0x00, + 0x44, 0x01, 0xb5, 0xf9, 0x0c, 0x00, 0x4f, 0xea, 0x40, 0x19, 0x02, 0x98, + 0x08, 0xeb, 0xc0, 0x07, 0x04, 0x98, 0x42, 0x68, 0xd2, 0xe9, 0x82, 0x01, + 0x02, 0x9a, 0x02, 0xf0, 0x01, 0xf9, 0xc0, 0x07, 0x2b, 0xd5, 0x20, 0x46, + 0x05, 0xf0, 0x0c, 0xfc, 0x01, 0x46, 0x50, 0x46, 0x05, 0xf0, 0xb0, 0xfd, + 0x04, 0x46, 0xb8, 0x6f, 0x05, 0xf0, 0x04, 0xfc, 0x01, 0x46, 0x30, 0x46, + 0x05, 0xf0, 0xa8, 0xfd, 0x01, 0x46, 0x20, 0x46, 0x05, 0xf0, 0x08, 0xfd, + 0x05, 0xf0, 0x0e, 0xfe, 0x04, 0x46, 0x48, 0x46, 0x05, 0xf0, 0xf6, 0xfb, + 0x01, 0x46, 0x50, 0x46, 0x05, 0xf0, 0x9a, 0xfd, 0x82, 0x46, 0xf8, 0x6f, + 0x05, 0xf0, 0xee, 0xfb, 0x01, 0x46, 0x30, 0x46, 0x05, 0xf0, 0x92, 0xfd, + 0x01, 0x46, 0x50, 0x46, 0x05, 0xf0, 0xf2, 0xfc, 0x05, 0xf0, 0xf8, 0xfd, + 0x81, 0x46, 0xfe, 0xf7, 0x85, 0xff, 0xbc, 0x67, 0x06, 0x46, 0xc7, 0xf8, + 0x7c, 0x90, 0x02, 0x98, 0x81, 0xb2, 0x04, 0x98, 0x00, 0xf0, 0xd6, 0xfa, + 0x86, 0xf3, 0x11, 0x88, 0x28, 0x88, 0x48, 0xb9, 0xfe, 0xf7, 0x76, 0xff, + 0x06, 0x46, 0x03, 0x98, 0xc8, 0xf8, 0x72, 0x00, 0xa5, 0xf8, 0x04, 0xb0, + 0x86, 0xf3, 0x11, 0x88, 0x01, 0x20, 0xe8, 0x81, 0x58, 0xe1, 0x38, 0xb5, + 0x14, 0x46, 0xdf, 0xf8, 0x64, 0x15, 0x4f, 0xf4, 0x08, 0x72, 0x02, 0xfb, + 0x00, 0x15, 0xff, 0xf7, 0x1b, 0xf8, 0x05, 0xf1, 0x68, 0x00, 0x01, 0x21, + 0x44, 0x80, 0x01, 0x80, 0x31, 0xbd, 0x00, 0x00, 0x04, 0x00, 0x00, 0x51, + 0x00, 0x00, 0x50, 0x59, 0x00, 0x00, 0x40, 0x59, 0x06, 0x40, 0x80, 0x83, + 0x07, 0x40, 0x00, 0x80, 0x00, 0xf5, 0x02, 0x70, 0x00, 0x22, 0xc0, 0xe9, + 0x00, 0x22, 0xc0, 0xe9, 0x02, 0x22, 0x70, 0x47, 0x70, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x00, 0xf0, 0x59, 0xf8, 0x40, 0xf2, 0x42, 0x66, 0x88, 0xb3, + 0xdf, 0xf8, 0x14, 0x05, 0xb0, 0xf8, 0x54, 0x10, 0x28, 0x46, 0x03, 0xf0, + 0xa6, 0xfb, 0x08, 0xb1, 0x07, 0x20, 0x70, 0xbd, 0xdf, 0xf8, 0x04, 0x05, + 0x01, 0x78, 0x03, 0x22, 0x11, 0x42, 0x06, 0xd0, 0x00, 0x7e, 0x00, 0xf0, + 0x03, 0x00, 0x02, 0x28, 0x01, 0xd1, 0x06, 0x20, 0x70, 0xbd, 0xe8, 0xb2, + 0x02, 0xf0, 0xea, 0xfb, 0x00, 0x28, 0xe0, 0x60, 0x01, 0xd5, 0x08, 0x20, + 0x70, 0xbd, 0x00, 0x22, 0x10, 0x21, 0x30, 0x46, 0x01, 0xf0, 0x6c, 0xfe, + 0x08, 0x20, 0x04, 0xf0, 0x03, 0xf9, 0x08, 0xb1, 0x09, 0x20, 0x70, 0xbd, + 0xe0, 0x68, 0x04, 0xf0, 0xbc, 0xf8, 0x04, 0xf0, 0xdb, 0xf8, 0x00, 0xf0, + 0x1f, 0xf8, 0x13, 0xe0, 0xe5, 0x60, 0x01, 0x21, 0xe8, 0xb2, 0x04, 0xf0, + 0xfd, 0xf9, 0x04, 0xf0, 0x38, 0xfa, 0x00, 0xf0, 0x15, 0xf8, 0x00, 0x22, + 0x18, 0x21, 0x40, 0xf2, 0x7a, 0x60, 0x01, 0xf0, 0x4f, 0xfe, 0x00, 0x22, + 0x20, 0x21, 0x30, 0x46, 0x01, 0xf0, 0x4a, 0xfe, 0x00, 0x20, 0x70, 0xbd, + 0x68, 0x18, 0x00, 0x01, 0x00, 0x00, 0xc8, 0xc3, 0xc0, 0x01, 0x00, 0x45, + 0x98, 0xf1, 0x00, 0x20, 0xe0, 0x68, 0x80, 0x1c, 0x28, 0x21, 0x80, 0xb2, + 0x03, 0xf0, 0x46, 0xbf, 0x60, 0x68, 0xb0, 0xf9, 0x0c, 0x00, 0x70, 0x47, + 0x2d, 0xe9, 0xf0, 0x4f, 0xdf, 0xf8, 0x64, 0x04, 0x85, 0xb0, 0x80, 0x7a, + 0x00, 0xf0, 0x03, 0x00, 0x04, 0x90, 0x0c, 0x46, 0xdf, 0xf8, 0x58, 0x04, + 0x20, 0x60, 0x20, 0x46, 0x00, 0xf0, 0x8c, 0xf9, 0x05, 0x00, 0x40, 0xf0, + 0xc0, 0x80, 0x00, 0x26, 0x0f, 0xf2, 0x74, 0x4a, 0x04, 0x98, 0xf0, 0x40, + 0xc0, 0x07, 0x40, 0xf1, 0xb4, 0x80, 0x34, 0x20, 0x00, 0xfb, 0x06, 0xfb, + 0xdf, 0xf8, 0x34, 0x04, 0xdf, 0xf8, 0x30, 0x14, 0x0b, 0xeb, 0x00, 0x09, + 0x00, 0x20, 0x4b, 0xf8, 0x01, 0x00, 0xc9, 0xf8, 0x04, 0x00, 0x4f, 0xf4, + 0x08, 0x71, 0xdf, 0xf8, 0x08, 0x04, 0x01, 0xfb, 0x06, 0x00, 0x60, 0x60, + 0x00, 0x21, 0x81, 0x81, 0x01, 0x21, 0xc1, 0x81, 0x01, 0x82, 0x41, 0x82, + 0xff, 0xf7, 0x5e, 0xff, 0x60, 0x68, 0x00, 0x21, 0x20, 0xf8, 0x6e, 0x1f, + 0x41, 0x80, 0x32, 0x46, 0x21, 0x68, 0xb1, 0xf9, 0x24, 0x10, 0xfe, 0xf7, + 0x01, 0xff, 0x30, 0x46, 0x01, 0xf0, 0x4e, 0xff, 0x80, 0x46, 0x60, 0x68, + 0xa0, 0xf8, 0x6a, 0x80, 0x69, 0x46, 0x30, 0x46, 0x05, 0xf0, 0x28, 0xff, + 0xdd, 0xe9, 0x00, 0x01, 0xcd, 0xe9, 0x02, 0x01, 0x02, 0xaa, 0x00, 0x20, + 0x8d, 0xf8, 0x0a, 0x00, 0x01, 0x21, 0x30, 0x46, 0x05, 0xf0, 0x53, 0xff, + 0x20, 0x68, 0x90, 0xf8, 0x3a, 0x00, 0x3a, 0xf8, 0x10, 0x10, 0x00, 0xf0, + 0x79, 0xf8, 0x60, 0x8a, 0xe0, 0x82, 0x31, 0x46, 0x01, 0x20, 0x20, 0x82, + 0x00, 0xf0, 0xca, 0xf8, 0x05, 0x46, 0x02, 0x20, 0x20, 0x82, 0x31, 0x46, + 0x60, 0x8a, 0x00, 0x09, 0xe0, 0x82, 0x00, 0xf0, 0xc1, 0xf8, 0x05, 0xb9, + 0x05, 0x46, 0x20, 0x68, 0x90, 0xf8, 0x3a, 0x00, 0x47, 0x1c, 0x09, 0xe0, + 0x3a, 0xf8, 0x17, 0x10, 0x00, 0xf0, 0x5e, 0xf8, 0x01, 0x20, 0x00, 0xf0, + 0xb1, 0xf8, 0x05, 0xb9, 0x05, 0x46, 0x7f, 0x1c, 0x20, 0x68, 0x90, 0xf8, + 0x3b, 0x00, 0xbf, 0xb2, 0xb8, 0x42, 0xef, 0xd2, 0x07, 0x46, 0x12, 0xe0, + 0x20, 0x68, 0x90, 0xf8, 0x3b, 0x00, 0x02, 0xeb, 0xc0, 0x00, 0x00, 0xf1, + 0x70, 0x0c, 0x02, 0xeb, 0xc7, 0x02, 0xdc, 0xe9, 0x00, 0x01, 0x78, 0x32, + 0xc2, 0xe9, 0x00, 0x01, 0x39, 0x46, 0x20, 0x46, 0x00, 0xf0, 0xa4, 0xf9, + 0x7f, 0x1c, 0xbf, 0xb2, 0x62, 0x68, 0x32, 0x2f, 0xe8, 0xdb, 0xa2, 0xf8, + 0x6c, 0x80, 0x69, 0x46, 0x30, 0x46, 0x05, 0xf0, 0xef, 0xfe, 0x00, 0xf0, + 0x2e, 0xf8, 0x03, 0x20, 0x00, 0xf0, 0x84, 0xf8, 0x05, 0xb9, 0x05, 0x46, + 0x1d, 0xb9, 0x61, 0x68, 0x01, 0x20, 0xa1, 0xf8, 0x18, 0x02, 0x00, 0xf0, + 0x28, 0xf8, 0x30, 0xf8, 0x02, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x00, 0xf0, + 0x1c, 0xf8, 0x00, 0xf0, 0x20, 0xf8, 0x30, 0xf8, 0x04, 0x1c, 0x00, 0xf0, + 0x19, 0xf8, 0x00, 0xf0, 0x14, 0xf8, 0x69, 0x46, 0x30, 0x46, 0x05, 0xf0, + 0xcf, 0xfe, 0x00, 0xf0, 0x0e, 0xf8, 0x64, 0x20, 0xc9, 0xf8, 0x04, 0x00, + 0xb6, 0x48, 0x4b, 0xf8, 0x00, 0x50, 0x76, 0x1c, 0x02, 0x2e, 0xff, 0xf4, + 0x43, 0xaf, 0x28, 0x46, 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x30, 0x46, + 0xfe, 0xf7, 0xc6, 0xbe, 0x30, 0x46, 0x05, 0xf0, 0x1d, 0xbf, 0x20, 0x68, + 0x90, 0xf8, 0x3b, 0x00, 0x0a, 0xeb, 0x40, 0x00, 0x70, 0x47, 0x2d, 0xe9, + 0xf0, 0x47, 0x0c, 0x46, 0xa8, 0x48, 0xa7, 0x49, 0x20, 0x60, 0x49, 0x89, + 0xc0, 0x8f, 0x08, 0x40, 0x00, 0xf0, 0x03, 0x08, 0x20, 0x46, 0x00, 0xf0, + 0xab, 0xf8, 0x05, 0x00, 0x37, 0xd1, 0x00, 0x26, 0xdf, 0xf8, 0x88, 0xa2, + 0x28, 0xfa, 0x06, 0xf0, 0xc0, 0x07, 0x2d, 0xd5, 0x00, 0xf0, 0xd0, 0xfb, + 0x34, 0x20, 0x00, 0xfb, 0x06, 0xf9, 0x09, 0xeb, 0x0a, 0x07, 0x00, 0x20, + 0x78, 0x60, 0x49, 0xf8, 0x0a, 0x00, 0x00, 0xf0, 0xda, 0xfb, 0x94, 0x48, + 0x4f, 0xf4, 0x08, 0x71, 0x01, 0xfb, 0x06, 0x00, 0x60, 0x60, 0x01, 0x21, + 0x81, 0x81, 0xc1, 0x81, 0x21, 0x82, 0x31, 0x46, 0x60, 0x8a, 0xe0, 0x82, + 0x00, 0xf0, 0x1c, 0xf8, 0x05, 0x46, 0xa0, 0x8a, 0xe0, 0x82, 0x31, 0x46, + 0x02, 0x20, 0x20, 0x82, 0x00, 0xf0, 0x14, 0xf8, 0x05, 0xb9, 0x05, 0x46, + 0x00, 0xf0, 0xaa, 0xfb, 0x64, 0x20, 0x78, 0x60, 0x49, 0xf8, 0x0a, 0x50, + 0x00, 0xf0, 0xb9, 0xfb, 0x76, 0x1c, 0x02, 0x2e, 0xca, 0xd3, 0x28, 0x46, + 0xbd, 0xe8, 0xf0, 0x87, 0x49, 0x03, 0x00, 0x80, 0x20, 0x82, 0x31, 0x46, + 0x20, 0x46, 0xad, 0xe0, 0x2d, 0xe9, 0xf8, 0x43, 0x80, 0x46, 0x0d, 0x46, + 0x7f, 0x48, 0x80, 0x4f, 0x28, 0x60, 0x4f, 0xf4, 0x08, 0x71, 0x79, 0x48, + 0x01, 0xfb, 0x08, 0x00, 0x68, 0x60, 0x00, 0xf0, 0x89, 0xfb, 0x34, 0x20, + 0x00, 0xfb, 0x08, 0xf6, 0xf4, 0x19, 0x00, 0x20, 0x60, 0x60, 0xf0, 0x51, + 0x00, 0xf0, 0x95, 0xfb, 0x28, 0x46, 0x00, 0xf0, 0x4d, 0xf8, 0x5f, 0xea, + 0x00, 0x09, 0x2b, 0xd1, 0x68, 0x68, 0xb0, 0xf8, 0x18, 0x12, 0x11, 0xb9, + 0x4f, 0xf0, 0x04, 0x09, 0x24, 0xe0, 0x30, 0xf9, 0x0c, 0x1f, 0x00, 0x29, + 0x02, 0xbf, 0x29, 0x68, 0xb1, 0xf8, 0x40, 0x10, 0x00, 0x29, 0x10, 0xd1, + 0x01, 0x21, 0x01, 0x80, 0x03, 0x21, 0x29, 0x82, 0x00, 0x21, 0x41, 0x80, + 0x01, 0x20, 0x00, 0xf0, 0x1e, 0xf8, 0x81, 0x46, 0x02, 0x20, 0x00, 0xf0, + 0x1a, 0xf8, 0xb9, 0xf1, 0x00, 0x0f, 0x0b, 0xd1, 0x09, 0xe0, 0x01, 0x21, + 0x29, 0x82, 0x00, 0x21, 0x41, 0x80, 0x41, 0x46, 0xa8, 0x8a, 0xe8, 0x82, + 0x28, 0x46, 0x00, 0xf0, 0x65, 0xf8, 0x81, 0x46, 0x00, 0xf0, 0x4c, 0xfb, + 0x64, 0x20, 0x60, 0x60, 0x46, 0xf8, 0x07, 0x90, 0x00, 0xf0, 0x5b, 0xfb, + 0x48, 0x46, 0xbd, 0xe8, 0xf2, 0x83, 0x28, 0x82, 0x41, 0x46, 0x28, 0x46, + 0x54, 0xe0, 0x80, 0xb5, 0x53, 0x49, 0x56, 0x4a, 0x09, 0x6c, 0xa0, 0xfb, + 0x01, 0x01, 0x00, 0x23, 0x05, 0xf0, 0xc4, 0xfe, 0x04, 0xf0, 0x76, 0xfa, + 0xbd, 0xe8, 0x02, 0x40, 0x04, 0xf0, 0x68, 0xba, 0x70, 0xb5, 0x04, 0x46, + 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xfd, 0x06, 0x46, 0x20, 0x68, 0x01, 0x88, + 0x0a, 0x25, 0x8e, 0x42, 0xb8, 0xbf, 0x0e, 0x46, 0x03, 0xdb, 0x40, 0x88, + 0xb0, 0x42, 0xb8, 0xbf, 0x06, 0x46, 0x10, 0x2e, 0x18, 0xdb, 0x40, 0xf2, + 0xee, 0x20, 0xff, 0xf7, 0xda, 0xff, 0x05, 0x46, 0xa6, 0xf1, 0x0f, 0x00, + 0xff, 0xf7, 0xd5, 0xff, 0x06, 0x46, 0x04, 0xf0, 0x53, 0xfa, 0x20, 0x83, + 0x20, 0x68, 0x41, 0x68, 0x69, 0x43, 0xb1, 0xfb, 0xf6, 0xf1, 0x61, 0x82, + 0x80, 0x68, 0x68, 0x43, 0xb0, 0xfb, 0xf6, 0xf0, 0xa0, 0x82, 0x00, 0x25, + 0x28, 0x46, 0x70, 0xbd, 0x70, 0xb5, 0x00, 0x24, 0x38, 0x4d, 0x31, 0x4e, + 0x4f, 0xf4, 0x08, 0x70, 0x22, 0x46, 0x01, 0x21, 0x00, 0xfb, 0x04, 0x60, + 0xfe, 0xf7, 0x16, 0xfd, 0x2b, 0x46, 0x00, 0x22, 0xe1, 0xb2, 0x00, 0x20, + 0x01, 0xf0, 0x7c, 0xfd, 0x64, 0x1c, 0x02, 0x2c, 0xee, 0xd3, 0x70, 0xbd, + 0x00, 0x01, 0x00, 0x45, 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x00, 0x20, + 0x05, 0xf0, 0x5b, 0xff, 0x90, 0xb1, 0x29, 0x46, 0x00, 0x20, 0x05, 0xf0, + 0x5b, 0xff, 0x06, 0x46, 0x32, 0x46, 0x29, 0x46, 0x20, 0x46, 0xff, 0xf7, + 0xae, 0xf9, 0x21, 0x8a, 0x49, 0x1e, 0x21, 0x82, 0x09, 0xb2, 0x01, 0x29, + 0x03, 0xdb, 0x00, 0x28, 0xf2, 0xd0, 0x70, 0xbd, 0x03, 0x20, 0x70, 0xbd, + 0x18, 0x49, 0xc2, 0x07, 0x44, 0xbf, 0x01, 0x22, 0x0a, 0x82, 0x80, 0x07, + 0x44, 0xbf, 0x01, 0x20, 0xa1, 0xf8, 0x30, 0x02, 0x70, 0x47, 0x00, 0x00, + 0xa4, 0x70, 0x7d, 0x3f, 0x11, 0x49, 0xc2, 0x07, 0x44, 0xbf, 0x01, 0x22, + 0x4a, 0x82, 0x80, 0x07, 0x44, 0xbf, 0x01, 0x20, 0xa1, 0xf8, 0x32, 0x02, + 0x70, 0x47, 0x00, 0x00, 0x00, 0x24, 0x74, 0x49, 0x00, 0x00, 0x7a, 0x44, + 0x00, 0x00, 0x80, 0xbf, 0x02, 0x56, 0xfd, 0x37, 0x00, 0x00, 0x34, 0x44, + 0x00, 0xa0, 0x8c, 0x47, 0xcd, 0xcc, 0x4c, 0x3d, 0x01, 0x00, 0x80, 0x3f, + 0xff, 0xe6, 0xdb, 0x2e, 0x00, 0x00, 0xc8, 0x42, 0x00, 0x00, 0x20, 0x41, + 0x24, 0x2b, 0x00, 0x20, 0x48, 0xad, 0x00, 0x20, 0x4c, 0x1f, 0x00, 0x20, + 0x48, 0x04, 0x00, 0x46, 0x78, 0x29, 0x00, 0x20, 0xdc, 0x2a, 0x00, 0x20, + 0x98, 0xf1, 0x00, 0x20, 0x80, 0x8d, 0x5b, 0x00, 0xbf, 0x12, 0x00, 0x01, + 0xd0, 0xb5, 0x44, 0x68, 0x0a, 0x46, 0xd4, 0xe9, 0x82, 0x67, 0x01, 0x20, + 0x00, 0x21, 0x05, 0xf0, 0x1b, 0xfd, 0x30, 0x43, 0x39, 0x43, 0xc4, 0xe9, + 0x82, 0x01, 0xd0, 0xbd, 0x42, 0x06, 0x7a, 0x06, 0x00, 0x00, 0x06, 0x00, + 0x0c, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x1e, 0x00, 0x24, 0x00, + 0x28, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x41, 0x00, + 0x46, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x56, 0x00, 0x5b, 0x00, 0x60, 0x00, + 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, + 0x84, 0x00, 0x91, 0x00, 0x96, 0x00, 0x9d, 0x00, 0xab, 0x00, 0xba, 0x00, + 0xc3, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xe7, 0x00, 0xf1, 0x00, 0x09, 0x01, + 0x15, 0x01, 0x23, 0x01, 0x32, 0x01, 0x55, 0x01, 0x6b, 0x01, 0x83, 0x01, + 0x9d, 0x01, 0xbe, 0x01, 0xe2, 0x01, 0x14, 0x02, 0x5a, 0x02, 0xd3, 0x02, + 0xff, 0xfc, 0xf9, 0xf6, 0xf4, 0xf1, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, + 0xfd, 0xfa, 0xf7, 0xfd, 0xfa, 0xf7, 0xf4, 0xf1, 0xee, 0xfd, 0xfa, 0xf7, + 0xf4, 0xf1, 0xee, 0xfd, 0xfa, 0xf7, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, + 0xff, 0xfd, 0xfa, 0xf7, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, 0xec, 0xfd, + 0xfb, 0xf8, 0xff, 0xfc, 0xf9, 0xf6, 0xf4, 0xfb, 0xf8, 0xf5, 0xf3, 0xf0, + 0xed, 0xea, 0xfd, 0xfa, 0xf7, 0xff, 0xfd, 0xfa, 0xf7, 0xf4, 0xfd, 0xfa, + 0xf7, 0xf4, 0xf1, 0xfa, 0xf7, 0xf4, 0xf1, 0xee, 0xec, 0xe9, 0xfe, 0xfb, + 0xf8, 0xf5, 0xff, 0xfc, 0xfa, 0xf7, 0xf4, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, + 0xfd, 0xfa, 0xf7, 0xf4, 0xf1, 0xfc, 0xf9, 0xf6, 0xf3, 0xff, 0xfc, 0xf9, + 0xf6, 0xf3, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xff, 0xfd, 0xfa, 0xf7, 0xf4, + 0xf1, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf1, + 0xfe, 0xfb, 0xf8, 0xf5, 0xf3, 0xf0, 0xed, 0xea, 0xe7, 0xe4, 0xe2, 0xdf, + 0xdc, 0xfb, 0xf8, 0xf5, 0xf2, 0xf0, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf1, + 0xee, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, 0xec, 0xea, 0xe7, 0xe4, 0xe1, + 0xde, 0xdc, 0xd9, 0xfd, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, 0xec, 0xe9, 0xe6, + 0xe4, 0xe1, 0xde, 0xdb, 0xd9, 0xd6, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, + 0xec, 0xea, 0xe7, 0xfb, 0xf8, 0xf5, 0xf2, 0xf0, 0xed, 0xea, 0xe7, 0xe4, + 0xe1, 0xdf, 0xdc, 0xd9, 0xd6, 0xd4, 0xd1, 0xff, 0xfc, 0xf9, 0xf6, 0xf4, + 0xf1, 0xee, 0xeb, 0xe8, 0xe5, 0xfd, 0xfa, 0xf8, 0xf5, 0xf2, 0xef, 0xec, + 0xe9, 0xe6, 0xe4, 0xfd, 0xfa, 0xf7, 0xf4, 0xf2, 0xef, 0xec, 0xe9, 0xe6, + 0xe3, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, 0xed, 0xeb, 0xe8, 0xe5, 0xe2, + 0xdf, 0xdd, 0xda, 0xd7, 0xd4, 0xd2, 0xcf, 0xcc, 0xca, 0xc7, 0xc4, 0xc2, + 0xbf, 0xfc, 0xf9, 0xf7, 0xf4, 0xf1, 0xee, 0xeb, 0xe8, 0xe5, 0xe3, 0xe0, + 0xdd, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, 0xee, 0xeb, 0xe8, 0xe5, 0xe2, + 0xe0, 0xdd, 0xda, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, 0xed, 0xea, 0xe8, + 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 0xd7, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, + 0xee, 0xeb, 0xe8, 0xe5, 0xe2, 0xe0, 0xdd, 0xda, 0xd7, 0xd5, 0xd2, 0xcf, + 0xcd, 0xca, 0xc7, 0xc5, 0xc2, 0xc0, 0xbd, 0xba, 0xb8, 0xb5, 0xb3, 0xb0, + 0xae, 0xab, 0xa9, 0xa6, 0xa4, 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, 0xed, + 0xea, 0xe8, 0xe5, 0xe2, 0xdf, 0xdc, 0xda, 0xd7, 0xd4, 0xd2, 0xcf, 0xcc, + 0xca, 0xc7, 0xc4, 0xfa, 0xf7, 0xf4, 0xf1, 0xef, 0xec, 0xe9, 0xe6, 0xe3, + 0xe0, 0xde, 0xdb, 0xd8, 0xd6, 0xd3, 0xd0, 0xcd, 0xcb, 0xc8, 0xc6, 0xc3, + 0xc0, 0xbe, 0xbb, 0xf8, 0xf5, 0xf2, 0xef, 0xec, 0xe9, 0xe7, 0xe4, 0xe1, + 0xde, 0xdc, 0xd9, 0xd6, 0xd3, 0xd1, 0xce, 0xcb, 0xc9, 0xc6, 0xc3, 0xc1, + 0xbe, 0xbc, 0xb9, 0xb7, 0xb4, 0xfa, 0xf7, 0xf4, 0xf1, 0xee, 0xec, 0xe9, + 0xe6, 0xe3, 0xe0, 0xde, 0xdb, 0xd8, 0xd5, 0xd3, 0xd0, 0xcd, 0xcb, 0xc8, + 0xc6, 0xc3, 0xc0, 0xbe, 0xbb, 0xb9, 0xb6, 0xb4, 0xb1, 0xaf, 0xac, 0xaa, + 0xa7, 0xa5, 0xf6, 0xf3, 0xf0, 0xee, 0xeb, 0xe8, 0xe5, 0xe2, 0xe0, 0xdd, + 0xda, 0xd7, 0xd5, 0xd2, 0xcf, 0xcd, 0xca, 0xc7, 0xc5, 0xc2, 0xbf, 0xbd, + 0xba, 0xb8, 0xb5, 0xb3, 0xb0, 0xae, 0xab, 0xa9, 0xa6, 0xa4, 0xa2, 0x9f, + 0x9d, 0x9a, 0xfe, 0xfb, 0xf8, 0xf5, 0xf3, 0xf0, 0xed, 0xea, 0xe7, 0xe4, + 0xe2, 0xdf, 0xdc, 0xd9, 0xd7, 0xd4, 0xd1, 0xcf, 0xcc, 0xc9, 0xc7, 0xc4, + 0xc1, 0xbf, 0xbc, 0xba, 0xb7, 0xb5, 0xb2, 0xb0, 0xad, 0xab, 0xa8, 0xa6, + 0xa3, 0xa1, 0x9f, 0x9c, 0x9a, 0x97, 0x95, 0x93, 0x90, 0x8e, 0x8c, 0x8a, + 0x87, 0x85, 0x83, 0x81, 0xfe, 0xfb, 0xf8, 0xf5, 0xf3, 0xf0, 0xed, 0xea, + 0xe7, 0xe4, 0xe2, 0xdf, 0xdc, 0xd9, 0xd7, 0xd4, 0xd1, 0xcf, 0xcc, 0xc9, + 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xba, 0xb7, 0xb5, 0xb2, 0xb0, 0xad, 0xab, + 0xa8, 0xa6, 0xa3, 0xa1, 0x9f, 0x9c, 0x9a, 0x97, 0x95, 0x93, 0x90, 0x8e, + 0x8c, 0x8a, 0x87, 0x85, 0x83, 0x81, 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x73, + 0x71, 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61, 0x5f, 0x5d, 0x5b, + 0x59, 0x57, 0xff, 0xfc, 0xfa, 0xf7, 0xf4, 0xf1, 0xee, 0xeb, 0xe8, 0xe6, + 0xe3, 0xe0, 0xdd, 0xda, 0xd8, 0xd5, 0xd2, 0xd0, 0xcd, 0xca, 0xc8, 0xc5, + 0xc3, 0xc0, 0xbd, 0xbb, 0xb8, 0xb6, 0xb3, 0xb1, 0xae, 0xac, 0xa9, 0xa7, + 0xa4, 0xa2, 0xa0, 0x9d, 0x9b, 0x98, 0x96, 0x94, 0x91, 0x8f, 0x8d, 0x8b, + 0x88, 0x86, 0x84, 0x82, 0x7f, 0x7d, 0x7b, 0x79, 0x77, 0x74, 0x72, 0x70, + 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62, 0x60, 0x5e, 0x5c, 0x5a, 0x58, + 0x56, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x41, + 0x3f, 0x3d, 0x3b, 0x39, 0x37, 0x36, 0x34, 0x32, 0x30, 0x2f, 0x2d, 0x2b, + 0x29, 0x28, 0x26, 0x24, 0x23, 0x21, 0x1f, 0x1e, 0x1c, 0x1a, 0x19, 0x17, + 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0c, 0x0b, 0x09, 0x07, 0x06, 0x04, + 0x03, 0x01, 0x00, 0xfe, 0xfb, 0xf8, 0xf5, 0xf2, 0xef, 0xec, 0xea, 0xe7, + 0xe4, 0xe1, 0xde, 0xdc, 0xd9, 0xd6, 0xd3, 0xd1, 0xce, 0xcb, 0xc9, 0xc6, + 0xc4, 0xc1, 0xbe, 0xbc, 0xb9, 0xb7, 0xb4, 0xb2, 0xaf, 0xad, 0xaa, 0xa8, + 0xa5, 0xa3, 0xa1, 0x9e, 0x9c, 0x99, 0x97, 0x95, 0x92, 0x90, 0x8e, 0x8b, + 0x89, 0x87, 0x85, 0x82, 0x80, 0x7e, 0x7c, 0x7a, 0x77, 0x75, 0x73, 0x71, + 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x64, 0x62, 0x60, 0x5e, 0x5c, 0x5a, 0x58, + 0x56, 0x54, 0x52, 0x50, 0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, + 0x3f, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x35, 0x33, 0x31, 0x2f, 0x2e, 0x2c, + 0x2a, 0x28, 0x27, 0x25, 0x23, 0x22, 0x20, 0x1e, 0x1d, 0x1b, 0x19, 0x18, + 0x16, 0x15, 0x13, 0x11, 0x10, 0x0e, 0x0d, 0x0b, 0x0a, 0x08, 0x07, 0x00, + 0x70, 0xb5, 0x86, 0xb0, 0x05, 0xf0, 0xac, 0xfe, 0xdf, 0xf8, 0x14, 0x19, + 0xdf, 0xf8, 0x14, 0x49, 0x00, 0x20, 0x08, 0x60, 0x20, 0x70, 0x60, 0x70, + 0xa0, 0x71, 0x60, 0x71, 0x20, 0x61, 0xe0, 0x61, 0x20, 0x72, 0x20, 0x71, + 0x00, 0x21, 0x04, 0xf1, 0x0c, 0x00, 0xa1, 0x70, 0x01, 0x60, 0xe1, 0x70, + 0xa1, 0x62, 0x21, 0x62, 0x04, 0xf5, 0x45, 0x75, 0x4f, 0xf4, 0xfc, 0x61, + 0x28, 0x46, 0x00, 0xf0, 0x78, 0xf9, 0x64, 0x21, 0x04, 0xf1, 0x30, 0x00, + 0x00, 0xf0, 0x73, 0xf9, 0x00, 0x20, 0xad, 0xa1, 0x54, 0x22, 0x02, 0xfb, + 0x00, 0x43, 0x03, 0xf5, 0x45, 0x76, 0x40, 0x1c, 0x03, 0xf5, 0x5a, 0x73, + 0x17, 0x28, 0x73, 0x61, 0xf1, 0x64, 0xf4, 0xd3, 0x02, 0xfb, 0x00, 0x40, + 0x00, 0xf5, 0x45, 0x70, 0x00, 0x22, 0x42, 0x61, 0xc1, 0x64, 0x65, 0x62, + 0xe2, 0x62, 0x04, 0xf1, 0x94, 0x05, 0x4f, 0xf4, 0xa0, 0x71, 0x28, 0x46, + 0x00, 0xf0, 0x55, 0xf9, 0x00, 0x20, 0x00, 0x23, 0x04, 0xeb, 0x00, 0x11, + 0x01, 0xf1, 0x94, 0x02, 0x40, 0x1c, 0xa4, 0x31, 0x13, 0x28, 0x13, 0x70, + 0x51, 0x60, 0xf5, 0xd3, 0x04, 0xeb, 0x00, 0x10, 0x00, 0xf8, 0x94, 0x3f, + 0x43, 0x60, 0x65, 0x61, 0x00, 0xf0, 0xea, 0xfb, 0x00, 0xf0, 0x5c, 0xfd, + 0x03, 0x21, 0x04, 0x91, 0x00, 0x21, 0x03, 0x91, 0x80, 0x21, 0x02, 0x91, + 0x4f, 0xf6, 0xff, 0x71, 0xdf, 0xf8, 0x64, 0x08, 0x01, 0x90, 0x00, 0x91, + 0x00, 0xf5, 0xfe, 0x72, 0x18, 0x23, 0x00, 0x21, 0x0f, 0xf2, 0xc1, 0x30, + 0x00, 0xf0, 0x0d, 0xfe, 0x05, 0xaa, 0x0f, 0xf2, 0x14, 0x01, 0x18, 0x20, + 0x00, 0xf0, 0xbe, 0xfe, 0x01, 0xf0, 0x74, 0xf8, 0xc0, 0x46, 0xc0, 0x46, + 0x06, 0xb0, 0x70, 0xbd, 0x75, 0x43, 0x2f, 0x4f, 0x53, 0x2d, 0x49, 0x49, + 0x20, 0x49, 0x64, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x38, 0xb5, 0x00, 0xf0, + 0x31, 0xf8, 0x1e, 0xd1, 0x05, 0xf0, 0x9a, 0xfe, 0x05, 0x46, 0x20, 0x78, + 0x08, 0xb1, 0x40, 0x1e, 0x20, 0x70, 0x20, 0x78, 0x61, 0x78, 0x08, 0x43, + 0x11, 0xd1, 0x00, 0xf0, 0x2c, 0xf9, 0xe0, 0x78, 0xa2, 0x78, 0x04, 0xeb, + 0x80, 0x01, 0x90, 0x42, 0x09, 0x6b, 0xa1, 0x62, 0x07, 0xd0, 0x88, 0x6b, + 0x40, 0x1c, 0x88, 0x63, 0x20, 0x69, 0x40, 0x1c, 0x20, 0x61, 0x05, 0xf0, + 0x9a, 0xfe, 0x28, 0x46, 0x15, 0xe1, 0x31, 0xbd, 0x10, 0xb5, 0x00, 0xf0, + 0x0d, 0xf8, 0x0a, 0xd1, 0x05, 0xf0, 0x76, 0xfe, 0x21, 0x78, 0x21, 0xb9, + 0x61, 0x78, 0xff, 0x29, 0x1c, 0xbf, 0x49, 0x1c, 0x61, 0x70, 0x00, 0xf0, + 0xe3, 0xbe, 0x10, 0xbd, 0xdf, 0xf8, 0xb4, 0x47, 0x60, 0x79, 0x01, 0x28, + 0x70, 0x47, 0x10, 0xb5, 0xff, 0xf7, 0xf8, 0xff, 0x10, 0xd1, 0x05, 0xf0, + 0x61, 0xfe, 0x21, 0x78, 0x51, 0xb9, 0x61, 0x78, 0x41, 0xb1, 0x49, 0x1e, + 0x61, 0x70, 0xc9, 0xb2, 0x21, 0xb9, 0x80, 0xf3, 0x11, 0x88, 0xbd, 0xe8, + 0x10, 0x40, 0xcf, 0xe0, 0x00, 0xf0, 0xc8, 0xbe, 0x10, 0xbd, 0x10, 0xb5, + 0xdf, 0xf8, 0x7c, 0x47, 0x60, 0x79, 0x60, 0xb9, 0x00, 0xf0, 0xe7, 0xf8, + 0xe0, 0x78, 0xa0, 0x70, 0x04, 0xeb, 0x80, 0x00, 0x00, 0x6b, 0xa0, 0x62, + 0x20, 0x62, 0xbd, 0xe8, 0x10, 0x40, 0x05, 0xf0, 0x48, 0xbe, 0x10, 0xbd, + 0x70, 0xb5, 0x05, 0xf0, 0x14, 0xfe, 0x05, 0xf0, 0x39, 0xfe, 0xdf, 0xf8, + 0x4c, 0x17, 0xdf, 0xf8, 0x4c, 0x47, 0x0a, 0x68, 0x52, 0x1c, 0x0a, 0x60, + 0x80, 0xf3, 0x11, 0x88, 0x60, 0x79, 0x01, 0x28, 0x35, 0xd1, 0xe0, 0x79, + 0x38, 0xb1, 0x02, 0x28, 0x01, 0xd0, 0x30, 0xd3, 0x01, 0xe0, 0x01, 0x20, + 0x00, 0xe0, 0x00, 0x20, 0xe0, 0x71, 0xe6, 0x6a, 0x12, 0xe0, 0x69, 0x77, + 0x29, 0x7f, 0x09, 0x07, 0x0b, 0xd4, 0x06, 0xf1, 0x34, 0x01, 0x22, 0x79, + 0x8b, 0x78, 0x1a, 0x43, 0x22, 0x71, 0x0a, 0x78, 0x49, 0x78, 0x12, 0x19, + 0x13, 0x7b, 0x19, 0x43, 0x11, 0x73, 0x2e, 0x68, 0x80, 0xf3, 0x11, 0x88, + 0x06, 0xf1, 0x14, 0x05, 0xa8, 0x7f, 0x18, 0x28, 0x11, 0xd0, 0x05, 0xf0, + 0x07, 0xfe, 0xa9, 0x69, 0x00, 0x29, 0xf2, 0xd0, 0x49, 0x1e, 0xa9, 0x61, + 0xef, 0xd1, 0x29, 0x7f, 0x37, 0x22, 0x11, 0x42, 0x1d, 0xbf, 0x01, 0xf0, + 0xc8, 0x01, 0x29, 0x77, 0x01, 0x21, 0x00, 0x21, 0xd5, 0xe7, 0x70, 0xbd, + 0xf8, 0xb5, 0x85, 0x7a, 0x0f, 0xf2, 0x38, 0x14, 0xdf, 0xf8, 0xc0, 0x76, + 0x2e, 0x5d, 0x35, 0x18, 0x4f, 0xf0, 0x00, 0x0e, 0xed, 0x7a, 0x2c, 0x5d, + 0x04, 0xeb, 0xc6, 0x05, 0xed, 0xb2, 0x07, 0xeb, 0x85, 0x04, 0x24, 0x6b, + 0x04, 0xf1, 0x20, 0x0c, 0xcc, 0xf8, 0x00, 0x10, 0xcc, 0xf8, 0x0c, 0xe0, + 0x8c, 0xf8, 0x11, 0x30, 0x9c, 0xf8, 0x10, 0x10, 0x91, 0x43, 0x8c, 0xf8, + 0x10, 0x10, 0x9c, 0xf8, 0x10, 0x10, 0x09, 0x07, 0x0a, 0xd4, 0x39, 0x79, + 0x9c, 0xf8, 0x16, 0x20, 0x11, 0x43, 0x39, 0x71, 0xf1, 0x19, 0x9c, 0xf8, + 0x15, 0x30, 0x0a, 0x7b, 0x1a, 0x43, 0x0a, 0x73, 0x01, 0x46, 0x20, 0x46, + 0x00, 0xf0, 0x26, 0xf8, 0x28, 0x46, 0xf2, 0xbd, 0x10, 0xb5, 0xdf, 0xf8, + 0x60, 0x16, 0x0a, 0x6a, 0x42, 0xf8, 0x1c, 0x0f, 0x13, 0x7e, 0x52, 0x7e, + 0x1b, 0x18, 0xdc, 0x7a, 0x22, 0x43, 0xda, 0x72, 0x0b, 0x6a, 0x82, 0x7a, + 0x93, 0xf8, 0x36, 0x30, 0x1a, 0x43, 0x82, 0x72, 0x08, 0x6a, 0x10, 0xf8, + 0x34, 0x2f, 0x44, 0x78, 0x52, 0x18, 0x13, 0x7b, 0xa3, 0x43, 0x13, 0x73, + 0x04, 0xd1, 0x0a, 0x79, 0x80, 0x78, 0x22, 0xea, 0x00, 0x00, 0x08, 0x71, + 0x10, 0xbd, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x10, 0xb5, 0x10, 0xf8, + 0x34, 0x2f, 0x44, 0x78, 0x52, 0x18, 0xd3, 0x7a, 0xa3, 0x43, 0xd3, 0x72, + 0x04, 0xd1, 0x8a, 0x7a, 0x80, 0x78, 0x22, 0xea, 0x00, 0x00, 0x88, 0x72, + 0x10, 0xbd, 0x00, 0x21, 0x81, 0x72, 0x0b, 0x30, 0x04, 0x21, 0x01, 0xf0, + 0x2f, 0xb8, 0x00, 0x29, 0x18, 0xbf, 0x01, 0xf0, 0x2b, 0xb8, 0x70, 0x47, + 0x38, 0xb5, 0x05, 0xf0, 0x81, 0xfd, 0xdf, 0xf8, 0xe0, 0x55, 0x69, 0x78, + 0x04, 0x46, 0x28, 0x78, 0x08, 0x43, 0x11, 0xd1, 0x00, 0xf0, 0x15, 0xf8, + 0xe8, 0x78, 0xaa, 0x78, 0x05, 0xeb, 0x80, 0x01, 0x90, 0x42, 0x09, 0x6b, + 0xa9, 0x62, 0x07, 0xd0, 0x88, 0x6b, 0x40, 0x1c, 0x88, 0x63, 0x28, 0x69, + 0x40, 0x1c, 0x28, 0x61, 0x05, 0xf0, 0x7f, 0xfd, 0x20, 0x46, 0xbd, 0xe8, + 0x32, 0x40, 0x05, 0xf0, 0x69, 0xbd, 0xdf, 0xf8, 0xa4, 0x05, 0x0f, 0xf2, + 0x14, 0x01, 0x02, 0x79, 0x52, 0x5c, 0x13, 0x18, 0x1b, 0x7b, 0x59, 0x5c, + 0x01, 0xeb, 0xc2, 0x01, 0xc1, 0x70, 0x70, 0x47, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x80, 0xb5, 0x05, 0xf0, 0xd3, 0xfc, 0xdf, 0xf8, 0x84, 0x14, 0xca, 0x69, + 0x52, 0x1c, 0xca, 0x61, 0x80, 0xf3, 0x11, 0x88, 0x05, 0xf0, 0x60, 0xfc, + 0xf3, 0xe7, 0x2d, 0xe9, 0xf8, 0x43, 0x04, 0x46, 0x0f, 0x46, 0x91, 0x46, + 0x98, 0x46, 0x05, 0xf0, 0xc1, 0xfc, 0xdf, 0xf8, 0x60, 0x54, 0x6e, 0x6a, + 0x00, 0x2e, 0x58, 0xd0, 0x71, 0x69, 0x69, 0x62, 0x80, 0xf3, 0x11, 0x88, + 0x37, 0x60, 0x00, 0x20, 0x06, 0xf1, 0x30, 0x07, 0xbc, 0x70, 0x38, 0x70, + 0x78, 0x70, 0xf0, 0x62, 0x01, 0x22, 0x09, 0x98, 0x70, 0x60, 0x04, 0xf0, + 0x07, 0x01, 0x08, 0x98, 0xf0, 0x60, 0xc6, 0xf8, 0x08, 0x90, 0x0a, 0x98, + 0x30, 0x82, 0xa6, 0xf8, 0x12, 0x80, 0x00, 0x20, 0xf8, 0x71, 0xf9, 0x70, + 0xe0, 0x08, 0x38, 0x71, 0x02, 0xfa, 0x00, 0xf0, 0xb8, 0x71, 0x02, 0xfa, + 0x01, 0xf0, 0x78, 0x71, 0x00, 0x20, 0xf0, 0x61, 0x70, 0x62, 0x30, 0x62, + 0xb8, 0x60, 0x38, 0x61, 0xf8, 0x60, 0x78, 0x61, 0xb8, 0x61, 0x4d, 0xa0, + 0xf8, 0x61, 0x00, 0x20, 0x38, 0x62, 0x30, 0x46, 0x05, 0xf0, 0x5f, 0xfc, + 0x05, 0xf0, 0x86, 0xfc, 0x05, 0xeb, 0x84, 0x01, 0x0e, 0x63, 0x80, 0xf3, + 0x11, 0x88, 0x30, 0x46, 0x05, 0xf0, 0x10, 0xfc, 0x05, 0xf0, 0x7c, 0xfc, + 0xe9, 0x6a, 0x71, 0x61, 0x00, 0x21, 0xb1, 0x61, 0xe9, 0x6a, 0x01, 0xb1, + 0x8e, 0x61, 0xee, 0x62, 0x29, 0x79, 0xba, 0x79, 0x11, 0x43, 0x29, 0x71, + 0x39, 0x79, 0x7b, 0x79, 0x49, 0x19, 0x0a, 0x7b, 0x1a, 0x43, 0x0a, 0x73, + 0xa9, 0x79, 0x49, 0x1c, 0xa9, 0x71, 0x80, 0xf3, 0x11, 0x88, 0x00, 0x20, + 0x02, 0xe0, 0x80, 0xf3, 0x11, 0x88, 0x42, 0x20, 0xbd, 0xe8, 0xf2, 0x83, + 0x00, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, 0x05, 0x46, 0x88, 0x46, + 0x28, 0x78, 0x05, 0x28, 0x17, 0x46, 0x1c, 0x46, 0x02, 0xd0, 0x00, 0xf0, + 0x7c, 0xfa, 0x36, 0xe0, 0x38, 0x06, 0x46, 0xbf, 0x07, 0xf0, 0x7f, 0x07, + 0x01, 0x26, 0x00, 0x26, 0x00, 0x20, 0x20, 0x70, 0x05, 0xf0, 0x46, 0xfc, + 0x03, 0x2f, 0x24, 0xd8, 0xdf, 0xe8, 0x07, 0xf0, 0x15, 0x1b, 0x02, 0x0c, + 0x29, 0x89, 0x08, 0xea, 0x01, 0x07, 0x47, 0x45, 0x08, 0xd0, 0x70, 0x21, + 0x21, 0x70, 0x80, 0xf3, 0x11, 0x88, 0x1b, 0xe0, 0x29, 0x89, 0x18, 0xea, + 0x01, 0x07, 0xf6, 0xd0, 0x00, 0x2e, 0xf6, 0xd0, 0xb9, 0x43, 0x29, 0x81, + 0xf3, 0xe7, 0x29, 0x89, 0x28, 0xea, 0x01, 0x07, 0x47, 0x45, 0xec, 0xd1, + 0x03, 0xe0, 0x29, 0x89, 0x38, 0xea, 0x01, 0x07, 0xe7, 0xd0, 0x00, 0x2e, + 0xe7, 0xd0, 0x39, 0x43, 0xef, 0xe7, 0x80, 0xf3, 0x11, 0x88, 0x6f, 0x20, + 0x00, 0x27, 0x20, 0x70, 0x38, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0xf8, 0xb5, + 0xdf, 0xf8, 0x08, 0x73, 0x06, 0x46, 0x38, 0x78, 0x0c, 0x46, 0x10, 0xb1, + 0x10, 0x20, 0x00, 0xf0, 0xb2, 0xbd, 0x05, 0xf0, 0x0b, 0xfc, 0xb9, 0x69, + 0x0d, 0x00, 0x0c, 0xd0, 0x49, 0x68, 0xb9, 0x61, 0x05, 0x21, 0x29, 0x70, + 0x2e, 0x81, 0x00, 0x21, 0x69, 0x60, 0x06, 0xa1, 0xe9, 0x60, 0x80, 0xf3, + 0x11, 0x88, 0x00, 0x20, 0x02, 0xe0, 0x80, 0xf3, 0x11, 0x88, 0x72, 0x20, + 0xff, 0xe7, 0x20, 0x70, 0x28, 0x46, 0xf2, 0xbd, 0x3f, 0x00, 0x00, 0x00, + 0x2d, 0xe9, 0xf8, 0x4f, 0x86, 0xb0, 0xdf, 0xf8, 0x3c, 0x65, 0x10, 0x9d, + 0x04, 0x46, 0x30, 0x78, 0x8a, 0x46, 0x93, 0x46, 0x08, 0xb1, 0x02, 0x20, + 0x7a, 0xe0, 0x70, 0x78, 0x08, 0xb1, 0x0d, 0x20, 0x76, 0xe0, 0x20, 0x78, + 0x05, 0x28, 0x18, 0xbf, 0x01, 0x20, 0x71, 0xd1, 0x5f, 0xea, 0x0b, 0x60, + 0x46, 0xbf, 0x0b, 0xf0, 0x7f, 0x0b, 0x4f, 0xf0, 0x01, 0x08, 0x4f, 0xf0, + 0x00, 0x08, 0x05, 0xf0, 0xd1, 0xfb, 0xbb, 0xf1, 0x03, 0x0f, 0x81, 0x46, + 0x5f, 0xd8, 0xdf, 0xe8, 0x0b, 0xf0, 0x33, 0x39, 0x02, 0x2a, 0x20, 0x89, + 0x0a, 0xea, 0x00, 0x07, 0x57, 0x45, 0x26, 0xd0, 0x06, 0x98, 0x00, 0x90, + 0x5b, 0x46, 0x52, 0x46, 0x01, 0xa9, 0x20, 0x46, 0x00, 0xf0, 0xae, 0xf8, + 0x00, 0xf0, 0x30, 0xf9, 0xff, 0xf7, 0x34, 0xfe, 0x05, 0xf0, 0xb6, 0xfb, + 0x81, 0x46, 0x30, 0x6a, 0x28, 0x30, 0x47, 0x7a, 0x57, 0xb3, 0x00, 0x21, + 0x41, 0x72, 0x01, 0xa8, 0x00, 0xf0, 0x0b, 0xf9, 0x31, 0x6a, 0x00, 0x20, + 0x81, 0xf8, 0x30, 0x00, 0x00, 0xf0, 0x1c, 0xf9, 0x02, 0x2f, 0x14, 0xbf, + 0x0a, 0x20, 0x0e, 0x20, 0x36, 0xe0, 0x20, 0x89, 0x1a, 0xea, 0x00, 0x07, + 0xd8, 0xd0, 0xb8, 0xf1, 0x00, 0x0f, 0x10, 0xd0, 0xb8, 0x43, 0x0d, 0xe0, + 0x20, 0x89, 0x2a, 0xea, 0x00, 0x07, 0x57, 0x45, 0xce, 0xd1, 0x03, 0xe0, + 0x20, 0x89, 0x3a, 0xea, 0x00, 0x07, 0xc9, 0xd0, 0xb8, 0xf1, 0x00, 0x0f, + 0x01, 0xd0, 0x38, 0x43, 0x20, 0x81, 0x30, 0x6a, 0x07, 0x85, 0x0d, 0xe0, + 0x07, 0x88, 0xb8, 0xf1, 0x00, 0x0f, 0x09, 0xd0, 0xbb, 0xf1, 0x01, 0x0f, + 0x0e, 0xd9, 0xab, 0xf1, 0x02, 0x00, 0x01, 0x28, 0x0d, 0xd8, 0x20, 0x89, + 0xb8, 0x43, 0x20, 0x81, 0x00, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x28, 0x70, + 0x38, 0x46, 0x07, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x20, 0x89, 0x38, 0x43, + 0xf3, 0xe7, 0x00, 0xf0, 0xe1, 0xf8, 0x6f, 0x20, 0x28, 0x70, 0x00, 0x20, + 0xf3, 0xe7, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, 0x04, 0x46, 0x0f, 0x46, + 0x20, 0x78, 0x05, 0x28, 0x16, 0x46, 0x1d, 0x46, 0x18, 0xbf, 0x01, 0x20, + 0x3a, 0xd1, 0x05, 0xf0, 0x59, 0xfb, 0x80, 0x46, 0x16, 0xb1, 0x01, 0x2e, + 0x06, 0xd0, 0x08, 0xe0, 0x20, 0x89, 0xb8, 0x43, 0x20, 0x81, 0x00, 0x27, + 0x66, 0x68, 0x13, 0xe0, 0x20, 0x89, 0x38, 0x43, 0xf8, 0xe7, 0x80, 0xf3, + 0x11, 0x88, 0x71, 0x20, 0x26, 0xe0, 0x30, 0x8a, 0x21, 0x89, 0x01, 0x40, + 0x81, 0x42, 0x06, 0xd1, 0x00, 0x22, 0x30, 0x46, 0x00, 0xf0, 0x7f, 0xf8, + 0x01, 0x28, 0x08, 0xbf, 0x01, 0x27, 0x36, 0x68, 0xde, 0xb1, 0xb0, 0x7c, + 0x03, 0x28, 0x12, 0xd8, 0xdf, 0xe8, 0x00, 0xf0, 0x08, 0x0d, 0x02, 0x03, + 0xe9, 0xe7, 0x20, 0x89, 0x31, 0x8a, 0x01, 0x40, 0xf1, 0xd0, 0xe9, 0xe7, + 0x30, 0x8a, 0x21, 0x89, 0x20, 0xea, 0x01, 0x01, 0xe2, 0xe7, 0x20, 0x89, + 0x31, 0x8a, 0x81, 0x43, 0xf4, 0xe7, 0x00, 0xf0, 0x4e, 0xfa, 0x6f, 0x20, + 0x28, 0x70, 0x00, 0x20, 0x0c, 0xe0, 0x00, 0xf0, 0x48, 0xfa, 0x0f, 0xb1, + 0xff, 0xf7, 0x94, 0xfd, 0x05, 0xf0, 0x16, 0xfb, 0x24, 0x89, 0x80, 0xf3, + 0x11, 0x88, 0x00, 0x20, 0x28, 0x70, 0x20, 0x46, 0xbd, 0xe8, 0xf0, 0x81, + 0x70, 0xb5, 0xdf, 0xf8, 0x78, 0x43, 0x25, 0x6a, 0x95, 0xf8, 0x30, 0x60, + 0x46, 0xf0, 0x20, 0x06, 0x85, 0xf8, 0x30, 0x60, 0x00, 0x25, 0x26, 0x6a, + 0x86, 0xf8, 0x31, 0x50, 0x25, 0x6a, 0x04, 0x9e, 0xee, 0x62, 0x69, 0x62, + 0x0a, 0x82, 0x8b, 0x74, 0x22, 0x6a, 0x8a, 0x60, 0x43, 0x68, 0x0b, 0x60, + 0xc8, 0x60, 0x00, 0x23, 0x4b, 0x60, 0x43, 0x68, 0x03, 0xb1, 0x59, 0x60, + 0x41, 0x60, 0x02, 0xf1, 0x34, 0x00, 0x01, 0x78, 0x43, 0x78, 0x09, 0x19, + 0x0a, 0x7b, 0x9a, 0x43, 0x0a, 0x73, 0x04, 0xd1, 0x21, 0x79, 0x80, 0x78, + 0x21, 0xea, 0x00, 0x00, 0x20, 0x71, 0x70, 0xbd, 0x70, 0xb5, 0x27, 0x4c, + 0x04, 0xf5, 0xea, 0x75, 0x4f, 0xf4, 0xa0, 0x71, 0x28, 0x46, 0xff, 0xf7, + 0x4e, 0xfd, 0x00, 0x20, 0x23, 0xa1, 0x00, 0x26, 0x04, 0xeb, 0x00, 0x12, + 0x02, 0xf5, 0xea, 0x73, 0x40, 0x1c, 0x02, 0xf5, 0xf2, 0x72, 0x13, 0x28, + 0x1e, 0x70, 0x5a, 0x60, 0xd9, 0x60, 0xf3, 0xd3, 0x04, 0xeb, 0x00, 0x10, + 0x00, 0xf5, 0xea, 0x70, 0x06, 0x70, 0x46, 0x60, 0xc1, 0x60, 0xa5, 0x61, + 0x70, 0xbd, 0x10, 0xb5, 0x83, 0x68, 0x28, 0x33, 0x00, 0x24, 0x19, 0x80, + 0x5c, 0x60, 0x5a, 0x72, 0x19, 0x7a, 0x01, 0xf0, 0xdf, 0x01, 0x19, 0x72, + 0x19, 0x7a, 0x61, 0xb9, 0xdf, 0xf8, 0xc0, 0x12, 0x9c, 0x7b, 0x0a, 0x79, + 0x22, 0x43, 0x0a, 0x71, 0x01, 0x24, 0x1a, 0x7b, 0x5b, 0x7b, 0x51, 0x18, + 0x0a, 0x7b, 0x1a, 0x43, 0x0a, 0x73, 0x00, 0xf0, 0x02, 0xf8, 0x20, 0x46, + 0x10, 0xbd, 0x41, 0x68, 0x02, 0x68, 0x21, 0xb9, 0xc1, 0x68, 0x4a, 0x60, + 0x22, 0xb1, 0x00, 0x21, 0x01, 0xe0, 0x0a, 0x60, 0x02, 0xb1, 0x51, 0x60, + 0x80, 0x68, 0x00, 0x21, 0x41, 0x62, 0x70, 0x47, 0x90, 0xf3, 0x00, 0x20, + 0x20, 0xbd, 0x00, 0x20, 0x3f, 0x00, 0x00, 0x00, 0x68, 0x7a, 0x00, 0x20, + 0x48, 0x46, 0x05, 0xf0, 0x8d, 0xba, 0x2d, 0xe9, 0xf0, 0x41, 0xdf, 0xf8, + 0x68, 0x62, 0x04, 0x46, 0x30, 0x78, 0x88, 0x46, 0x08, 0xb1, 0x00, 0x20, + 0x2e, 0xe0, 0x05, 0xf0, 0x7b, 0xfa, 0x71, 0x69, 0x0f, 0x00, 0x1c, 0xbf, + 0x49, 0x68, 0x71, 0x61, 0x05, 0xf0, 0x7a, 0xfa, 0x1f, 0xb3, 0x05, 0xf0, + 0x71, 0xfa, 0xdf, 0xf8, 0xb4, 0x15, 0x0a, 0x68, 0x15, 0x00, 0x16, 0xd0, + 0x12, 0x68, 0x0a, 0x60, 0x80, 0xf3, 0x11, 0x88, 0x6c, 0x60, 0x04, 0xeb, + 0x88, 0x00, 0xa8, 0x60, 0xec, 0x60, 0x2c, 0x61, 0xa5, 0xf8, 0x14, 0x80, + 0x00, 0x20, 0xe8, 0x82, 0x02, 0x20, 0x38, 0x70, 0x00, 0x20, 0x38, 0x81, + 0x7d, 0x60, 0x38, 0x46, 0xff, 0xf7, 0xc7, 0xfc, 0x05, 0xe0, 0x71, 0x69, + 0x79, 0x60, 0x77, 0x61, 0x80, 0xf3, 0x11, 0x88, 0x00, 0x27, 0x38, 0x46, + 0xbd, 0xe8, 0xf0, 0x81, 0x10, 0xb5, 0x04, 0x46, 0x05, 0xf0, 0x48, 0xfa, + 0x61, 0x68, 0x4a, 0x68, 0xca, 0x60, 0x4a, 0x68, 0x0a, 0x61, 0x00, 0x22, + 0xca, 0x82, 0x80, 0xf3, 0x11, 0x88, 0x00, 0x20, 0x10, 0xbd, 0x2d, 0xe9, + 0xf0, 0x41, 0x07, 0x46, 0x0e, 0x46, 0x38, 0x78, 0x02, 0x28, 0x14, 0x46, + 0x18, 0xbf, 0x01, 0x20, 0x07, 0xd1, 0x71, 0x4d, 0x28, 0x78, 0x08, 0xb1, + 0x02, 0x20, 0x02, 0xe0, 0x68, 0x78, 0x18, 0xb1, 0x0d, 0x20, 0x20, 0x70, + 0x00, 0x20, 0x50, 0xe0, 0x05, 0xf0, 0x26, 0xfa, 0x80, 0x46, 0x78, 0x68, + 0xc1, 0x8a, 0x89, 0xb1, 0x02, 0x69, 0x12, 0x1d, 0x02, 0x61, 0x49, 0x1e, + 0x52, 0xf8, 0x04, 0x7d, 0x82, 0x68, 0xc1, 0x82, 0x01, 0x69, 0x91, 0x42, + 0x04, 0xbf, 0x41, 0x68, 0x01, 0x61, 0x00, 0xf0, 0x40, 0xf9, 0x00, 0x20, + 0x20, 0x70, 0x37, 0xe0, 0x28, 0x6a, 0x90, 0xf8, 0x30, 0x10, 0x41, 0xf0, + 0x04, 0x01, 0x80, 0xf8, 0x30, 0x10, 0x00, 0x20, 0x29, 0x6a, 0x81, 0xf8, + 0x31, 0x00, 0x28, 0x6a, 0xc6, 0x62, 0x38, 0x46, 0xff, 0xf7, 0x3e, 0xfc, + 0x00, 0xf0, 0x2b, 0xf9, 0xff, 0xf7, 0x78, 0xfc, 0x05, 0xf0, 0xfa, 0xf9, + 0x06, 0x46, 0x28, 0x6a, 0x00, 0xf1, 0x20, 0x01, 0x4a, 0x7c, 0x12, 0xb1, + 0x02, 0x2a, 0x03, 0xd0, 0x05, 0xe0, 0x0f, 0x68, 0x00, 0x20, 0x07, 0xe0, + 0x00, 0x27, 0x0e, 0x20, 0x04, 0xe0, 0x39, 0x46, 0xff, 0xf7, 0x4a, 0xfc, + 0x00, 0x27, 0x0a, 0x20, 0x20, 0x70, 0x00, 0x20, 0x29, 0x6a, 0x81, 0xf8, + 0x30, 0x00, 0x29, 0x6a, 0x81, 0xf8, 0x31, 0x00, 0x00, 0x21, 0x28, 0x6a, + 0xc1, 0x61, 0x01, 0x62, 0x00, 0xf0, 0x69, 0xf8, 0x38, 0x46, 0xbd, 0xe8, + 0xf0, 0x81, 0x01, 0x20, 0x20, 0x70, 0x00, 0x20, 0x70, 0x47, 0x70, 0xb5, + 0x06, 0x46, 0x0c, 0x46, 0x30, 0x78, 0x02, 0x28, 0x01, 0xd0, 0x01, 0x20, + 0x70, 0xbd, 0x05, 0xf0, 0xc7, 0xf9, 0x05, 0x46, 0xb0, 0x7a, 0x30, 0xb1, + 0x00, 0xf0, 0x46, 0xf8, 0x00, 0xf0, 0x4e, 0xf8, 0xff, 0xf7, 0x3a, 0xfc, + 0x14, 0xe0, 0x70, 0x68, 0xc1, 0x8a, 0x82, 0x8a, 0x91, 0x42, 0x00, 0xd3, + 0x40, 0xe0, 0xc2, 0x68, 0x12, 0x1d, 0xc2, 0x60, 0x49, 0x1c, 0x42, 0xf8, + 0x04, 0x4d, 0xc1, 0x82, 0x82, 0x68, 0xc1, 0x68, 0x91, 0x42, 0x04, 0xbf, + 0x41, 0x68, 0xc1, 0x60, 0x00, 0xf0, 0x36, 0xf8, 0x00, 0x20, 0x70, 0xbd, + 0x70, 0xb5, 0x06, 0x46, 0x0c, 0x46, 0x30, 0x78, 0x02, 0x28, 0x01, 0xd0, + 0x01, 0x20, 0x70, 0xbd, 0x05, 0xf0, 0x9c, 0xf9, 0x05, 0x46, 0xb0, 0x7a, + 0x30, 0xb1, 0x00, 0xf0, 0x1b, 0xf8, 0x00, 0xf0, 0x23, 0xf8, 0xff, 0xf7, + 0x0f, 0xfc, 0x13, 0xe0, 0x70, 0x68, 0xc1, 0x8a, 0x82, 0x8a, 0x91, 0x42, + 0x00, 0xd3, 0x15, 0xe0, 0x02, 0x69, 0x43, 0x68, 0x9a, 0x42, 0x04, 0xbf, + 0x82, 0x68, 0x02, 0x61, 0x02, 0x69, 0x12, 0x1f, 0x02, 0x61, 0x14, 0x60, + 0x49, 0x1c, 0xc1, 0x82, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x20, 0x70, 0xbd, + 0x00, 0x23, 0x04, 0x22, 0x21, 0x46, 0x30, 0x46, 0xff, 0xf7, 0x80, 0xbb, + 0x00, 0xf0, 0x02, 0xf8, 0x1e, 0x20, 0x70, 0xbd, 0x28, 0x46, 0x05, 0xf0, + 0x75, 0xb9, 0x30, 0x46, 0x05, 0xf0, 0x72, 0xb9, 0x10, 0xb5, 0xdf, 0xf8, + 0x60, 0x46, 0x4f, 0xf4, 0x90, 0x71, 0x20, 0x46, 0xff, 0xf7, 0xdb, 0xfb, + 0x00, 0x20, 0x18, 0x21, 0x01, 0xfb, 0x00, 0xf2, 0x13, 0x19, 0x18, 0x33, + 0x40, 0x1c, 0x13, 0x51, 0x0b, 0x28, 0xf7, 0xd3, 0x01, 0xfb, 0x00, 0x40, + 0x00, 0x22, 0x02, 0x60, 0xdf, 0xf8, 0x7c, 0x03, 0x04, 0x60, 0x10, 0xbd, + 0x00, 0x00, 0x00, 0x00, 0x20, 0xbd, 0x00, 0x20, 0x70, 0xb5, 0x00, 0xf0, + 0x17, 0xf8, 0x08, 0xb1, 0x00, 0x20, 0x70, 0xbd, 0x05, 0xf0, 0x46, 0xf9, + 0x69, 0x69, 0x0e, 0x00, 0x1c, 0xbf, 0x49, 0x68, 0x69, 0x61, 0x05, 0xf0, + 0x45, 0xf9, 0x3e, 0xb1, 0x03, 0x20, 0x30, 0x70, 0x34, 0x81, 0x00, 0x20, + 0x70, 0x60, 0x30, 0x46, 0xff, 0xf7, 0xa7, 0xfb, 0x30, 0x46, 0x70, 0xbd, + 0xdf, 0xf8, 0x20, 0x57, 0x04, 0x46, 0x28, 0x78, 0x70, 0x47, 0xdf, 0xf8, + 0x84, 0x77, 0x38, 0x78, 0x70, 0x47, 0x01, 0x22, 0x00, 0x21, 0x20, 0x46, + 0xff, 0xf7, 0x30, 0xbb, 0x2d, 0xe9, 0xf0, 0x41, 0x00, 0xf0, 0x52, 0xf8, + 0x18, 0xbf, 0x01, 0x20, 0x12, 0xd1, 0xff, 0xf7, 0xee, 0xff, 0x08, 0xb1, + 0x02, 0x20, 0x0d, 0xe0, 0x78, 0x78, 0x08, 0xb1, 0x0d, 0x20, 0x09, 0xe0, + 0x05, 0xf0, 0x14, 0xf9, 0x80, 0x46, 0x28, 0x89, 0x30, 0xb1, 0x40, 0x1e, + 0x28, 0x81, 0x00, 0xf0, 0x3a, 0xf8, 0x00, 0x20, 0x20, 0x70, 0x34, 0xe0, + 0x38, 0x6a, 0x90, 0xf8, 0x30, 0x10, 0x41, 0xf0, 0x01, 0x01, 0x80, 0xf8, + 0x30, 0x10, 0x00, 0x20, 0x39, 0x6a, 0x81, 0xf8, 0x31, 0x00, 0x38, 0x6a, + 0xc6, 0x62, 0x28, 0x46, 0xff, 0xf7, 0x38, 0xfb, 0x00, 0xf0, 0x25, 0xf8, + 0xff, 0xf7, 0x72, 0xfb, 0x05, 0xf0, 0xf4, 0xf8, 0x06, 0x46, 0x38, 0x6a, + 0x90, 0xf8, 0x31, 0x10, 0x11, 0xb1, 0x02, 0x29, 0x02, 0xd0, 0x03, 0xe0, + 0x00, 0x20, 0x05, 0xe0, 0x0e, 0x20, 0x03, 0xe0, 0x29, 0x46, 0xff, 0xf7, + 0x47, 0xfb, 0x0a, 0x20, 0x20, 0x70, 0x00, 0x20, 0x39, 0x6a, 0x81, 0xf8, + 0x30, 0x00, 0x39, 0x6a, 0x81, 0xf8, 0x31, 0x00, 0x39, 0x6a, 0xc8, 0x61, + 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x41, 0x05, 0xf0, 0xdb, 0xb8, 0xbd, 0xe8, + 0xf0, 0x81, 0x40, 0x46, 0x05, 0xf0, 0xd6, 0xb8, 0x05, 0x46, 0x0e, 0x46, + 0x28, 0x78, 0x03, 0x28, 0x14, 0x46, 0x70, 0x47, 0x38, 0xb5, 0x04, 0x46, + 0x20, 0x78, 0x03, 0x28, 0x01, 0xd0, 0x01, 0x20, 0x32, 0xbd, 0x05, 0xf0, + 0xc1, 0xf8, 0x05, 0x46, 0xa0, 0x7a, 0x38, 0xb1, 0x00, 0x23, 0xff, 0xf7, + 0x90, 0xff, 0xff, 0xf7, 0x47, 0xff, 0xff, 0xf7, 0x33, 0xfb, 0x08, 0xe0, + 0x20, 0x89, 0x4f, 0xf6, 0xff, 0x71, 0x88, 0x42, 0x05, 0xd0, 0x40, 0x1c, + 0x20, 0x81, 0xff, 0xf7, 0x3b, 0xff, 0x00, 0x20, 0x32, 0xbd, 0xff, 0xf7, + 0x37, 0xff, 0x33, 0x20, 0x32, 0xbd, 0x2d, 0xe9, 0xf1, 0x4f, 0x84, 0xb0, + 0x8b, 0x46, 0x90, 0x46, 0x99, 0x46, 0x05, 0xf0, 0x9f, 0xf8, 0xdf, 0xf8, + 0x64, 0x56, 0x29, 0x78, 0x19, 0xb1, 0x80, 0xf3, 0x11, 0x88, 0x3c, 0x20, + 0x33, 0xe0, 0x05, 0xeb, 0x89, 0x06, 0x31, 0x6b, 0x61, 0xbb, 0x01, 0x21, + 0x31, 0x63, 0x80, 0xf3, 0x11, 0x88, 0xdd, 0xf8, 0x3c, 0xa0, 0x10, 0x9f, + 0x12, 0x9c, 0x22, 0x46, 0x39, 0x46, 0x50, 0x46, 0x00, 0xf0, 0xc6, 0xf8, + 0x04, 0x98, 0x23, 0x46, 0x42, 0x46, 0x59, 0x46, 0x05, 0xf0, 0x1a, 0xf8, + 0x01, 0x46, 0x11, 0x98, 0x02, 0x94, 0x01, 0x90, 0x00, 0x97, 0x52, 0x46, + 0x0e, 0x9b, 0x48, 0x46, 0xff, 0xf7, 0xad, 0xfb, 0x04, 0x00, 0x05, 0xd1, + 0x68, 0x79, 0x01, 0x28, 0x08, 0xd1, 0xff, 0xf7, 0xeb, 0xfa, 0x05, 0xe0, + 0x05, 0xf0, 0x6c, 0xf8, 0x00, 0x21, 0x31, 0x63, 0x80, 0xf3, 0x11, 0x88, + 0x20, 0x46, 0x02, 0xe0, 0x80, 0xf3, 0x11, 0x88, 0x28, 0x20, 0x05, 0xb0, + 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xf0, 0x41, 0xdf, 0xf8, 0x74, 0x45, + 0x06, 0x46, 0x20, 0x78, 0x08, 0xb1, 0x40, 0x20, 0x64, 0xe0, 0x18, 0x2e, + 0x08, 0xbf, 0x3e, 0x20, 0x60, 0xd0, 0x05, 0xf0, 0x51, 0xf8, 0x80, 0x46, + 0xff, 0x2e, 0x04, 0xbf, 0x20, 0x6a, 0x90, 0xf8, 0x32, 0x60, 0x04, 0xeb, + 0x86, 0x05, 0x2e, 0x6b, 0x1e, 0xb9, 0xff, 0xf7, 0x72, 0xff, 0x43, 0x20, + 0x50, 0xe0, 0x01, 0x2e, 0x03, 0xd1, 0xff, 0xf7, 0x6c, 0xff, 0x3d, 0x20, + 0x4a, 0xe0, 0x06, 0xf1, 0x30, 0x07, 0x38, 0x79, 0x7a, 0x79, 0x00, 0x19, + 0x01, 0x7b, 0x91, 0x43, 0x01, 0x73, 0x38, 0x79, 0x00, 0x19, 0x00, 0x7b, + 0x18, 0xb9, 0x20, 0x79, 0xb9, 0x79, 0x88, 0x43, 0x20, 0x71, 0xf1, 0x69, + 0x11, 0xb1, 0x30, 0x46, 0xff, 0xf7, 0x8a, 0xfa, 0x70, 0x6a, 0x08, 0xb1, + 0xff, 0xf7, 0x83, 0xfd, 0x00, 0x20, 0xf0, 0x62, 0x38, 0x70, 0x78, 0x70, + 0x60, 0x78, 0xff, 0x28, 0x1c, 0xbf, 0x40, 0x1c, 0x60, 0x70, 0xff, 0xf7, + 0x46, 0xff, 0x05, 0xf0, 0x17, 0xf8, 0x80, 0x46, 0x60, 0x78, 0x08, 0xb1, + 0x40, 0x1e, 0x60, 0x70, 0x30, 0x46, 0x04, 0xf0, 0xa3, 0xff, 0xa0, 0x79, + 0x40, 0x1e, 0xa0, 0x71, 0x00, 0x20, 0x28, 0x63, 0xb1, 0x69, 0x70, 0x69, + 0x19, 0xb9, 0x81, 0x61, 0x70, 0x69, 0xe0, 0x62, 0x03, 0xe0, 0x48, 0x61, + 0x71, 0x69, 0xb0, 0x69, 0x88, 0x61, 0x60, 0x6a, 0x70, 0x61, 0x66, 0x62, + 0x1c, 0xa0, 0xf8, 0x61, 0xff, 0xf7, 0x25, 0xff, 0x60, 0x79, 0x01, 0x28, + 0x08, 0xbf, 0xff, 0xf7, 0x6f, 0xfa, 0x00, 0x20, 0xbd, 0xe8, 0xf0, 0x81, + 0xf8, 0xb5, 0xdf, 0xf8, 0x04, 0x75, 0x05, 0x46, 0x38, 0x78, 0x0e, 0x46, + 0x14, 0x46, 0x08, 0xb1, 0x12, 0x20, 0x15, 0xe0, 0x04, 0xf0, 0xe4, 0xff, + 0xff, 0x2d, 0x04, 0xbf, 0x39, 0x6a, 0x91, 0xf8, 0x32, 0x50, 0x07, 0xeb, + 0x85, 0x01, 0x09, 0x6b, 0x00, 0x29, 0x18, 0xbf, 0x01, 0x29, 0x03, 0xd1, + 0x04, 0xf0, 0xdc, 0xff, 0x43, 0x20, 0x03, 0xe0, 0xce, 0x64, 0x80, 0xf3, + 0x11, 0x88, 0x00, 0x20, 0x20, 0x70, 0xf1, 0xbd, 0x80, 0xb5, 0xdf, 0xf8, + 0xc0, 0x04, 0x00, 0x6a, 0x04, 0xf0, 0x60, 0xff, 0xbd, 0xe8, 0x02, 0x40, + 0xff, 0x20, 0x63, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x02, 0xf0, 0x03, 0x02, 0x03, 0x2a, 0x04, 0xd1, 0x00, 0x29, 0x1c, 0xbf, + 0x89, 0x00, 0x05, 0xf0, 0x09, 0xb8, 0x70, 0x47, 0x70, 0xb5, 0xff, 0xf7, + 0x7f, 0xfe, 0x00, 0x28, 0x04, 0xbf, 0x68, 0x78, 0x00, 0x28, 0x16, 0xd1, + 0xac, 0xb1, 0x04, 0xf0, 0xab, 0xff, 0x29, 0x6a, 0x2c, 0x31, 0x0a, 0x7a, + 0x4e, 0x7a, 0x52, 0x19, 0x13, 0x7b, 0xb3, 0x43, 0x13, 0x73, 0x03, 0xd1, + 0x2a, 0x79, 0x8b, 0x7a, 0x9a, 0x43, 0x2a, 0x71, 0x0c, 0x60, 0x80, 0xf3, + 0x11, 0x88, 0xbd, 0xe8, 0x70, 0x40, 0xff, 0xf7, 0x13, 0xba, 0x70, 0xbd, + 0x8c, 0xf3, 0x00, 0x20, 0x10, 0xb5, 0x04, 0xf0, 0x91, 0xff, 0xdf, 0xf8, + 0x50, 0x14, 0x0c, 0x68, 0x80, 0xf3, 0x11, 0x88, 0x20, 0x46, 0x10, 0xbd, + 0xbd, 0xe8, 0x10, 0x40, 0x04, 0xf0, 0x8c, 0xbf, 0x2d, 0xe9, 0xf8, 0x43, + 0x06, 0x46, 0xdf, 0xf8, 0xc0, 0x03, 0x0a, 0x9c, 0x00, 0x78, 0x0f, 0x46, + 0x90, 0x46, 0x99, 0x46, 0x08, 0xb1, 0x8b, 0x20, 0x08, 0xe0, 0xff, 0xf7, + 0xfb, 0xf8, 0xdf, 0xf8, 0x20, 0x04, 0x05, 0x69, 0x2d, 0xb9, 0xff, 0xf7, + 0x0a, 0xf9, 0x86, 0x20, 0x20, 0x70, 0x00, 0x20, 0x20, 0xe0, 0xe9, 0x68, + 0x01, 0x61, 0x00, 0x21, 0xe9, 0x60, 0x29, 0x61, 0x41, 0x88, 0x49, 0x1c, + 0x41, 0x80, 0x01, 0x88, 0x49, 0x1e, 0x01, 0x80, 0x05, 0xf1, 0x24, 0x00, + 0x01, 0x21, 0x41, 0x70, 0x29, 0x1d, 0x4e, 0x61, 0x8f, 0x61, 0x80, 0xf8, + 0x00, 0x80, 0xc1, 0xf8, 0x00, 0x90, 0x08, 0x98, 0x48, 0x60, 0x09, 0x98, + 0x00, 0xb9, 0x8b, 0xa0, 0xc8, 0x61, 0xff, 0xf7, 0xe8, 0xf8, 0x00, 0x20, + 0x20, 0x70, 0x28, 0x46, 0xbd, 0xe8, 0xf2, 0x83, 0x00, 0x00, 0x00, 0x00, + 0x38, 0xb5, 0x00, 0xf0, 0x74, 0xf8, 0x18, 0xbf, 0x89, 0x20, 0x1c, 0xd1, + 0x00, 0xf0, 0x6c, 0xf8, 0x08, 0xb1, 0x8b, 0x20, 0x17, 0xe0, 0xff, 0xf7, + 0xbf, 0xf8, 0x95, 0xf8, 0x25, 0x00, 0x03, 0x28, 0x0e, 0xd8, 0xdf, 0xe8, + 0x00, 0xf0, 0x09, 0x05, 0x05, 0x02, 0x28, 0x46, 0x00, 0xf0, 0x6c, 0xf9, + 0x28, 0x46, 0x00, 0xf0, 0xd9, 0xf8, 0x84, 0xe0, 0xff, 0xf7, 0xc3, 0xf8, + 0x87, 0x20, 0x02, 0xe0, 0xff, 0xf7, 0xbf, 0xf8, 0x8d, 0x20, 0x20, 0x70, + 0x00, 0x20, 0x32, 0xbd, 0x70, 0xb5, 0x00, 0xf0, 0x4e, 0xf8, 0x18, 0xbf, + 0x89, 0x20, 0x2c, 0xd1, 0x00, 0xf0, 0x46, 0xf8, 0x08, 0xb1, 0x8b, 0x20, + 0x27, 0xe0, 0xff, 0xf7, 0x99, 0xf8, 0x05, 0xf1, 0x24, 0x00, 0x41, 0x78, + 0x03, 0x29, 0x1d, 0xd8, 0xdf, 0xe8, 0x01, 0xf0, 0x18, 0x07, 0x13, 0x02, + 0xd2, 0x49, 0x68, 0x69, 0x49, 0x68, 0x46, 0x1a, 0x05, 0xe0, 0x00, 0x78, + 0xae, 0x69, 0x02, 0x28, 0x04, 0xbf, 0x00, 0x2e, 0xee, 0x69, 0xff, 0xf7, + 0x98, 0xf8, 0x00, 0x20, 0x20, 0x70, 0x30, 0x46, 0x70, 0xbd, 0xff, 0xf7, + 0x92, 0xf8, 0x00, 0x20, 0x20, 0x70, 0x70, 0xbd, 0xff, 0xf7, 0x8d, 0xf8, + 0x87, 0x20, 0x02, 0xe0, 0xff, 0xf7, 0x89, 0xf8, 0x8d, 0x20, 0x20, 0x70, + 0x00, 0x20, 0x70, 0xbd, 0x38, 0xb5, 0x00, 0xf0, 0x18, 0xf8, 0x18, 0xbf, + 0x89, 0x20, 0x03, 0xd1, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xb1, 0x8b, 0x20, + 0xbb, 0xe7, 0xff, 0xf7, 0x63, 0xf8, 0x95, 0xf8, 0x25, 0x50, 0x03, 0x2d, + 0x94, 0xbf, 0x00, 0x20, 0x8d, 0x20, 0x20, 0x70, 0xff, 0xf7, 0x6f, 0xf8, + 0x28, 0x46, 0x32, 0xbd, 0xb3, 0x48, 0x00, 0x78, 0x70, 0x47, 0x05, 0x46, + 0x0c, 0x46, 0x28, 0x78, 0x64, 0x28, 0x70, 0x47, 0x38, 0xb5, 0xff, 0xf7, + 0xf8, 0xff, 0x18, 0xbf, 0x89, 0x20, 0x1d, 0xd1, 0xff, 0xf7, 0xf0, 0xff, + 0x08, 0xb1, 0x8b, 0x20, 0x18, 0xe0, 0xff, 0xf7, 0x43, 0xf8, 0x95, 0xf8, + 0x25, 0x00, 0x03, 0x28, 0x0f, 0xd8, 0xdf, 0xe8, 0x00, 0xf0, 0x0a, 0x05, + 0x05, 0x02, 0x28, 0x46, 0x00, 0xf0, 0xf0, 0xf8, 0x00, 0x21, 0x28, 0x46, + 0x00, 0xf0, 0xca, 0xf8, 0x07, 0xe0, 0xff, 0xf7, 0x46, 0xf8, 0x87, 0x20, + 0x02, 0xe0, 0xff, 0xf7, 0x42, 0xf8, 0x8d, 0x20, 0x81, 0xe7, 0xff, 0xf7, + 0x3e, 0xf8, 0x00, 0x20, 0x20, 0x70, 0x01, 0x20, 0x32, 0xbd, 0x00, 0x00, + 0xf8, 0xb5, 0x05, 0x46, 0x0f, 0x46, 0x28, 0x78, 0x64, 0x28, 0x16, 0x46, + 0x1c, 0x46, 0x18, 0xbf, 0x89, 0x20, 0x3a, 0xd1, 0xff, 0xf7, 0xc0, 0xff, + 0x08, 0xb1, 0x8b, 0x20, 0x35, 0xe0, 0xff, 0xf7, 0x13, 0xf8, 0x95, 0xf8, + 0x25, 0x00, 0x03, 0x28, 0x2c, 0xd8, 0xdf, 0xe8, 0x00, 0xf0, 0x27, 0x21, + 0x21, 0x02, 0x28, 0x46, 0x00, 0xf0, 0xc0, 0xf8, 0x00, 0x20, 0x20, 0x70, + 0xaf, 0xb1, 0x03, 0x2f, 0x02, 0xd0, 0x04, 0x2f, 0x06, 0xd0, 0x0e, 0xe0, + 0x6a, 0x68, 0x10, 0x00, 0x18, 0xbf, 0xa9, 0x68, 0x04, 0xd1, 0x06, 0xe0, + 0x6a, 0x68, 0x10, 0x00, 0x03, 0xd0, 0x31, 0x46, 0x28, 0x46, 0x90, 0x47, + 0x03, 0xe0, 0x8f, 0x20, 0x00, 0xe0, 0x84, 0x20, 0x20, 0x70, 0xff, 0xf7, + 0x02, 0xf8, 0x03, 0xe0, 0xfe, 0xf7, 0xff, 0xff, 0x8e, 0x20, 0x20, 0x70, + 0x01, 0x20, 0xf2, 0xbd, 0xfe, 0xf7, 0xf9, 0xff, 0x87, 0x20, 0x02, 0xe0, + 0xfe, 0xf7, 0xf5, 0xff, 0x8d, 0x20, 0x20, 0x70, 0x00, 0x20, 0xf2, 0xbd, + 0x78, 0x48, 0xc0, 0x68, 0xff, 0xf7, 0x8a, 0xbd, 0x00, 0xf1, 0x24, 0x01, + 0x00, 0x22, 0x4a, 0x70, 0x0a, 0x70, 0x09, 0xa1, 0x01, 0x62, 0xc2, 0x61, + 0x42, 0x61, 0x42, 0x60, 0x82, 0x60, 0x02, 0x61, 0x70, 0x49, 0x0a, 0x69, + 0xc2, 0x60, 0x08, 0x61, 0x48, 0x88, 0x40, 0x1e, 0x48, 0x80, 0x08, 0x88, + 0x40, 0x1c, 0x08, 0x80, 0x70, 0x47, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x74, 0xec, 0x00, 0x20, 0x70, 0xb5, 0x68, 0x4c, 0x86, 0xb0, 0x4f, 0xf4, + 0x70, 0x71, 0x04, 0xf1, 0x54, 0x00, 0xff, 0xf7, 0xa6, 0xf8, 0x40, 0x21, + 0x04, 0xf1, 0x14, 0x00, 0xff, 0xf7, 0xa1, 0xf8, 0x00, 0x20, 0x5f, 0xa1, + 0x28, 0x22, 0x02, 0xfb, 0x00, 0x43, 0x03, 0xf1, 0x54, 0x05, 0x64, 0x26, + 0x2e, 0x70, 0x40, 0x1c, 0x00, 0x26, 0x7c, 0x33, 0x17, 0x28, 0x85, 0xf8, + 0x25, 0x60, 0xeb, 0x60, 0x29, 0x62, 0xf0, 0xd3, 0x02, 0xfb, 0x00, 0x40, + 0x64, 0x22, 0x00, 0xf8, 0x54, 0x2f, 0x80, 0xf8, 0x25, 0x60, 0xc6, 0x60, + 0x01, 0x62, 0x18, 0x20, 0x20, 0x80, 0x66, 0x60, 0x04, 0xf1, 0x54, 0x00, + 0x20, 0x61, 0x66, 0x80, 0x01, 0x20, 0xff, 0xf7, 0xb7, 0xfc, 0xa0, 0x60, + 0x00, 0x20, 0xff, 0xf7, 0xb3, 0xfc, 0x03, 0x21, 0x04, 0x91, 0xe0, 0x60, + 0x80, 0x21, 0x02, 0x91, 0x4f, 0xf6, 0xfd, 0x71, 0x4a, 0x48, 0x01, 0x90, + 0x00, 0x91, 0x00, 0xf5, 0xfe, 0x72, 0x03, 0x96, 0x02, 0x23, 0x00, 0x21, + 0x0f, 0xf2, 0xa1, 0x00, 0xff, 0xf7, 0x47, 0xfd, 0x05, 0xaa, 0x0f, 0xf2, + 0x14, 0x11, 0x02, 0x20, 0xff, 0xf7, 0xf8, 0xfd, 0x06, 0xb0, 0x70, 0xbd, + 0x10, 0xb5, 0x03, 0x22, 0x80, 0xf8, 0x25, 0x20, 0x01, 0x29, 0x3d, 0x4a, + 0x53, 0x68, 0x1a, 0xbf, 0x81, 0x69, 0x00, 0x29, 0xc1, 0x69, 0x59, 0x18, + 0x41, 0x61, 0x01, 0x7d, 0x01, 0xf0, 0x07, 0x01, 0x02, 0xeb, 0xc1, 0x01, + 0x14, 0x31, 0x8a, 0x88, 0x0b, 0x68, 0x1b, 0xb9, 0x00, 0x22, 0xc2, 0x60, + 0x01, 0x22, 0x02, 0xe0, 0xc3, 0x60, 0x18, 0x61, 0x52, 0x1c, 0x8a, 0x80, + 0x08, 0x60, 0x00, 0x21, 0x01, 0x61, 0x10, 0xbd, 0x10, 0xb5, 0x00, 0xf1, + 0x0c, 0x01, 0x2d, 0x4a, 0x0b, 0x7a, 0x03, 0xf0, 0x07, 0x03, 0x02, 0xeb, + 0xc3, 0x02, 0x52, 0xf8, 0x14, 0x4f, 0x0b, 0x68, 0x84, 0x42, 0x05, 0xd1, + 0x18, 0x00, 0x10, 0x60, 0x06, 0xd0, 0x00, 0x23, 0x03, 0x61, 0x03, 0xe0, + 0x48, 0x68, 0xc3, 0x60, 0x03, 0xb1, 0x18, 0x61, 0x01, 0x20, 0x48, 0x76, + 0x00, 0x20, 0x08, 0x60, 0x48, 0x60, 0x90, 0x88, 0x40, 0x1e, 0x90, 0x80, + 0x10, 0xbd, 0x00, 0x00, 0x20, 0xbd, 0x00, 0x20, 0xf8, 0xb5, 0x1c, 0x4c, + 0x01, 0xe0, 0xfe, 0xf7, 0x34, 0xff, 0xe0, 0x68, 0x6a, 0x46, 0x00, 0x21, + 0xff, 0xf7, 0x70, 0xfc, 0xfe, 0xf7, 0x18, 0xff, 0x60, 0x68, 0x40, 0x1c, + 0x60, 0x60, 0x00, 0xf0, 0x07, 0x00, 0x04, 0xeb, 0xc0, 0x00, 0x45, 0x69, + 0x00, 0x2d, 0x08, 0xe0, 0x02, 0x21, 0x41, 0x70, 0x32, 0x68, 0x10, 0x00, + 0x02, 0xd0, 0x71, 0x68, 0x28, 0x46, 0x90, 0x47, 0x3d, 0x00, 0xe2, 0xd0, + 0x2e, 0x1d, 0x60, 0x68, 0x31, 0x69, 0xb7, 0x68, 0x88, 0x42, 0xf7, 0xd1, + 0x28, 0x46, 0xff, 0xf7, 0xb3, 0xff, 0x05, 0xf1, 0x24, 0x00, 0x01, 0x78, + 0x02, 0x29, 0xe7, 0xd1, 0x01, 0x21, 0x28, 0x46, 0xff, 0xf7, 0x88, 0xff, + 0xe4, 0xe7, 0x00, 0x00, 0x20, 0xbd, 0x00, 0x20, 0x3f, 0x00, 0x00, 0x00, + 0x90, 0xf3, 0x00, 0x20, 0x68, 0xdb, 0x00, 0x20, 0x68, 0x78, 0x00, 0x20, + 0x75, 0x43, 0x2f, 0x4f, 0x53, 0x2d, 0x49, 0x49, 0x20, 0x54, 0x6d, 0x72, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x04, 0xf0, 0xb1, 0xbd, 0xf0, 0xb4, + 0x01, 0x68, 0x44, 0x68, 0x83, 0x68, 0x09, 0x18, 0x01, 0xeb, 0x54, 0x02, + 0xe4, 0x07, 0x48, 0xbf, 0x4b, 0x44, 0x0c, 0x30, 0x91, 0x42, 0x2b, 0xd0, + 0x11, 0xf8, 0x01, 0x4b, 0x14, 0xf0, 0x03, 0x05, 0x04, 0xbf, 0x11, 0xf8, + 0x01, 0x5b, 0xed, 0x1c, 0x26, 0x09, 0x0f, 0x2e, 0x07, 0xd1, 0x11, 0xf8, + 0x01, 0x6b, 0x0f, 0x36, 0x03, 0xe0, 0x11, 0xf8, 0x01, 0x7b, 0x03, 0xf8, + 0x01, 0x7b, 0x6d, 0x1e, 0xf9, 0xd1, 0x00, 0x2e, 0xe6, 0xd0, 0xa4, 0x08, + 0x11, 0xf8, 0x01, 0x5b, 0x04, 0xf0, 0x03, 0x04, 0x03, 0x2c, 0x08, 0xbf, + 0x11, 0xf8, 0x01, 0x4b, 0x05, 0xeb, 0x04, 0x24, 0x1c, 0x1b, 0xb5, 0x1c, + 0xd8, 0xd0, 0x14, 0xf8, 0x01, 0x6b, 0x03, 0xf8, 0x01, 0x6b, 0x6d, 0x1e, + 0xf9, 0xd1, 0xd1, 0xe7, 0xf0, 0xbc, 0x70, 0x47, 0x10, 0xb5, 0xef, 0xf3, + 0x10, 0x82, 0x72, 0xb6, 0x66, 0x4b, 0x4f, 0xf6, 0xfe, 0x64, 0x00, 0xf1, + 0x8c, 0x40, 0x44, 0xe0, 0x30, 0xb5, 0x00, 0xf1, 0x8c, 0x40, 0xef, 0xf3, + 0x10, 0x83, 0x72, 0xb6, 0x60, 0x4c, 0x4f, 0xf6, 0xfe, 0x65, 0x25, 0x60, + 0x05, 0x78, 0x8d, 0x43, 0x11, 0x40, 0x29, 0x43, 0x01, 0x70, 0x00, 0x20, + 0x20, 0x60, 0x83, 0xf3, 0x10, 0x88, 0x30, 0xbd, 0xf0, 0xb5, 0x00, 0xf0, + 0x23, 0xf8, 0x0b, 0xe0, 0x72, 0xb6, 0x4f, 0xf6, 0xfe, 0x66, 0x2e, 0x60, + 0x30, 0xf8, 0x14, 0x70, 0x66, 0x5c, 0x07, 0xf1, 0x8c, 0x47, 0x3e, 0x70, + 0x00, 0xf0, 0x10, 0xf8, 0x94, 0x42, 0xf1, 0xd3, 0xf0, 0xbd, 0x10, 0xb5, + 0x00, 0x23, 0x06, 0xe0, 0x30, 0xf8, 0x13, 0x40, 0x04, 0xf1, 0x8c, 0x44, + 0x24, 0x78, 0x5c, 0x54, 0x5b, 0x1c, 0x93, 0x42, 0xf6, 0xd3, 0x10, 0xbd, + 0x00, 0x26, 0x2e, 0x60, 0x83, 0xf3, 0x10, 0x88, 0x64, 0x1c, 0x70, 0x47, + 0xef, 0xf3, 0x10, 0x83, 0x00, 0x24, 0x45, 0x4d, 0x70, 0x47, 0x10, 0xb5, + 0x00, 0xf0, 0x0a, 0xf8, 0x1c, 0x60, 0x01, 0x60, 0x01, 0xe0, 0x1c, 0x60, + 0x01, 0x70, 0x00, 0x20, 0x18, 0x60, 0x82, 0xf3, 0x10, 0x88, 0x10, 0xbd, + 0xef, 0xf3, 0x10, 0x82, 0x72, 0xb6, 0x3c, 0x4b, 0x3c, 0x4c, 0x70, 0x47, + 0x3c, 0x49, 0x09, 0x78, 0x01, 0xf0, 0x07, 0x02, 0x06, 0x2a, 0x02, 0xbf, + 0xc1, 0xf3, 0xc2, 0x01, 0x01, 0x40, 0x81, 0x42, 0x0c, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0x70, 0x47, 0x35, 0x49, 0x09, 0x78, 0x01, 0xf0, 0x07, 0x02, + 0x06, 0x2a, 0x03, 0xbf, 0x00, 0xea, 0x91, 0x11, 0x81, 0x42, 0x01, 0x20, + 0x00, 0x20, 0x70, 0x47, 0x1c, 0xb5, 0x0f, 0xf2, 0xcc, 0x02, 0x18, 0xca, + 0x69, 0x46, 0x03, 0x28, 0x18, 0xc1, 0x01, 0xd3, 0x00, 0x20, 0x16, 0xbd, + 0x00, 0xf0, 0x03, 0x00, 0x3d, 0xf8, 0x10, 0x00, 0x00, 0xf1, 0x8c, 0x41, + 0x00, 0x22, 0x08, 0x78, 0x01, 0xe0, 0x00, 0x22, 0x18, 0x46, 0x0b, 0x78, + 0x83, 0x42, 0xfa, 0xd1, 0x52, 0x1c, 0x05, 0x2a, 0xf9, 0xd3, 0x16, 0xbd, + 0x38, 0xb5, 0x04, 0x46, 0x00, 0x22, 0x04, 0x21, 0x40, 0xf2, 0x16, 0x50, + 0xff, 0xf7, 0x70, 0xff, 0x1e, 0x4d, 0x0c, 0xb9, 0x28, 0x78, 0x32, 0xbd, + 0x01, 0x2c, 0x01, 0xd1, 0x28, 0x79, 0x32, 0xbd, 0xa0, 0x1e, 0xc2, 0x00, + 0xd2, 0xb2, 0x18, 0x21, 0x40, 0xf2, 0x17, 0x50, 0xff, 0xf7, 0x60, 0xff, + 0x28, 0x7a, 0x32, 0xbd, 0x80, 0xb5, 0xff, 0xf7, 0xe3, 0xff, 0x0f, 0xf2, + 0x64, 0x01, 0x40, 0x56, 0x02, 0xbd, 0x38, 0xb5, 0x02, 0x00, 0x0c, 0x46, + 0x10, 0x4d, 0x40, 0xf2, 0x16, 0x50, 0x07, 0xd1, 0x0c, 0x22, 0x1c, 0x21, + 0xff, 0xf7, 0x4c, 0xff, 0x00, 0xf0, 0x1a, 0xf8, 0x28, 0x78, 0x0a, 0xe0, + 0x01, 0x2a, 0x07, 0xd1, 0x14, 0x22, 0x1c, 0x21, 0xff, 0xf7, 0x42, 0xff, + 0x00, 0xf0, 0x10, 0xf8, 0x28, 0x79, 0x00, 0xe0, 0x00, 0x20, 0x0f, 0xf2, + 0x28, 0x01, 0x40, 0x56, 0x32, 0xbd, 0x00, 0x00, 0x48, 0x00, 0x00, 0x50, + 0x00, 0x00, 0xab, 0xab, 0xb3, 0x01, 0x00, 0x46, 0x0b, 0x05, 0x00, 0x46, + 0x21, 0x46, 0x4f, 0xf4, 0xa0, 0x60, 0x21, 0xe7, 0xb0, 0x04, 0xb3, 0x04, + 0xb6, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, + 0xfa, 0xfa, 0xf9, 0xf9, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf7, 0xf6, + 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, + 0xee, 0xed, 0xeb, 0xea, 0xe8, 0xe5, 0xe2, 0xdc, 0x10, 0xb5, 0x01, 0x20, + 0x04, 0xf0, 0x13, 0xfe, 0x79, 0x4c, 0x18, 0x21, 0x04, 0xf1, 0x14, 0x00, + 0xff, 0xf7, 0xb6, 0xfe, 0x01, 0x22, 0x02, 0x21, 0x20, 0x1d, 0x04, 0xf0, + 0x61, 0xfc, 0xa0, 0x1c, 0x00, 0x21, 0x01, 0x80, 0x0e, 0x20, 0x04, 0xf0, + 0x56, 0xfe, 0x00, 0x22, 0x80, 0x21, 0x40, 0xf6, 0x6e, 0x10, 0xff, 0xf7, + 0xed, 0xfe, 0x6f, 0x48, 0x4f, 0xf0, 0x40, 0x71, 0xc1, 0x62, 0x01, 0x60, + 0x0e, 0x20, 0x06, 0x21, 0x04, 0xf0, 0x53, 0xfe, 0x0e, 0x20, 0x04, 0xf0, + 0x35, 0xfe, 0xbd, 0xe8, 0x10, 0x40, 0x19, 0xe0, 0x03, 0x28, 0x00, 0xdb, + 0x70, 0x47, 0x30, 0xb5, 0x02, 0x29, 0x0b, 0xda, 0x63, 0x4c, 0x01, 0xeb, + 0x41, 0x05, 0x2d, 0x19, 0x45, 0x19, 0x2a, 0x72, 0x0c, 0x22, 0x02, 0xfb, + 0x01, 0x41, 0x01, 0xeb, 0x80, 0x00, 0x43, 0x61, 0x30, 0xbd, 0x00, 0x23, + 0x00, 0x22, 0xe9, 0xe7, 0x0e, 0x20, 0x04, 0xf0, 0x28, 0xbe, 0x00, 0xbf, + 0x0e, 0x20, 0x04, 0xf0, 0x1b, 0xbe, 0x70, 0xb5, 0x04, 0x46, 0x57, 0x4d, + 0x66, 0x19, 0xb0, 0x78, 0x70, 0xb9, 0x01, 0x20, 0xa0, 0x40, 0xff, 0xf7, + 0x17, 0xff, 0x48, 0xb1, 0x05, 0xeb, 0x44, 0x00, 0x00, 0xf1, 0x10, 0x01, + 0x32, 0x46, 0x20, 0x46, 0x04, 0xf0, 0x84, 0xf8, 0x01, 0x20, 0xb0, 0x70, + 0x70, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0xff, 0xf7, 0xe6, 0xff, 0x4b, 0x48, + 0x00, 0xeb, 0x44, 0x00, 0x00, 0x8a, 0x10, 0xbd, 0x10, 0xb5, 0x04, 0x46, + 0xff, 0xf7, 0xdd, 0xff, 0x46, 0x48, 0x20, 0x5c, 0x10, 0xbd, 0x2d, 0xe9, + 0xf8, 0x4f, 0x00, 0x20, 0x00, 0x90, 0x00, 0x27, 0x42, 0x4c, 0xe8, 0x46, + 0x0d, 0xf1, 0x02, 0x06, 0x00, 0xe0, 0x0f, 0xb9, 0x1b, 0x20, 0x00, 0xe0, + 0x1c, 0x20, 0x04, 0xf0, 0x5e, 0xfe, 0x0f, 0xf2, 0x04, 0x10, 0x3e, 0x49, + 0x50, 0xf8, 0x27, 0x00, 0x08, 0x60, 0x01, 0x20, 0xb8, 0x40, 0xff, 0xf7, + 0xe1, 0xfe, 0x10, 0xb3, 0x04, 0xeb, 0x47, 0x0a, 0x17, 0xf8, 0x04, 0x90, + 0xba, 0xf8, 0x10, 0xb0, 0x3d, 0x19, 0x2a, 0x46, 0x0a, 0xf1, 0x10, 0x01, + 0x38, 0x46, 0x04, 0xf0, 0x49, 0xf8, 0xa8, 0x78, 0x10, 0xb9, 0x01, 0x20, + 0xb8, 0x55, 0x09, 0xe0, 0xba, 0xf8, 0x10, 0x00, 0x58, 0x45, 0x14, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0xb8, 0x55, 0x38, 0x5d, 0x48, 0x45, 0x01, 0xd0, + 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x07, 0xf8, 0x08, 0x00, 0x01, 0x20, + 0xa8, 0x70, 0x7f, 0x1c, 0x02, 0x2f, 0xc8, 0xd3, 0x00, 0x27, 0x38, 0x19, + 0x00, 0x79, 0x00, 0xb3, 0x00, 0x25, 0x17, 0xf8, 0x08, 0x00, 0x48, 0xb9, + 0xb8, 0x5d, 0xb8, 0xb1, 0x04, 0xf1, 0x08, 0x00, 0x07, 0xeb, 0x47, 0x01, + 0x08, 0x18, 0x28, 0x5c, 0x01, 0x28, 0x0f, 0xd1, 0x04, 0xf1, 0x14, 0x00, + 0x0c, 0x21, 0x01, 0xfb, 0x07, 0x00, 0x50, 0xf8, 0x25, 0x30, 0x18, 0x00, + 0x06, 0xd0, 0x04, 0xf1, 0x10, 0x00, 0x30, 0xf8, 0x17, 0x10, 0x3a, 0x5d, + 0xf8, 0xb2, 0x98, 0x47, 0x6d, 0x1c, 0x03, 0x2d, 0xdf, 0xd3, 0x7f, 0x1c, + 0x02, 0x2f, 0xd8, 0xd3, 0xbd, 0xe8, 0xf1, 0x8f, 0x12, 0x48, 0x4f, 0xf4, + 0x40, 0x51, 0x01, 0x60, 0xc1, 0x68, 0x41, 0xf4, 0x40, 0x51, 0xc1, 0x60, + 0x70, 0x47, 0x00, 0x28, 0x0c, 0xbf, 0x4f, 0xf4, 0x00, 0x50, 0x4f, 0xf4, + 0x80, 0x50, 0x0b, 0x4a, 0x01, 0x29, 0x0c, 0xbf, 0x11, 0x68, 0x51, 0x68, + 0x08, 0x40, 0x70, 0x47, 0x00, 0x28, 0x07, 0x49, 0x0c, 0xbf, 0x4f, 0xf4, + 0x00, 0x50, 0x4f, 0xf4, 0x80, 0x50, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, + 0x3c, 0xee, 0x00, 0x20, 0x14, 0x00, 0x00, 0x50, 0x40, 0x00, 0x00, 0x50, + 0x40, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0xd2, 0xb2, 0x20, 0x3a, 0x22, 0xbf, 0x21, 0xfa, 0x02, 0xf0, 0x00, 0x21, + 0x70, 0x47, 0x20, 0x32, 0xd1, 0x41, 0xd0, 0x40, 0x48, 0x40, 0x91, 0x40, + 0xd1, 0x40, 0x48, 0x40, 0x70, 0x47, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, + 0x10, 0xb5, 0x04, 0x46, 0x18, 0x22, 0x63, 0x00, 0x01, 0x20, 0x00, 0x21, + 0x9a, 0x40, 0x03, 0xf0, 0x17, 0xff, 0x02, 0x46, 0x04, 0xf1, 0x18, 0x00, + 0x0b, 0x46, 0x40, 0x00, 0x04, 0xf0, 0x52, 0xfe, 0xc0, 0xb2, 0x10, 0xbd, + 0x38, 0xb5, 0xdf, 0xf8, 0x00, 0x4d, 0x25, 0x68, 0x00, 0xf0, 0x6b, 0xfb, + 0x05, 0x28, 0x04, 0xbf, 0x28, 0x0c, 0x60, 0xf3, 0x82, 0x05, 0x00, 0xf0, + 0x78, 0xfb, 0x06, 0x28, 0x04, 0xbf, 0x68, 0x0c, 0x60, 0xf3, 0xc3, 0x05, + 0x65, 0x60, 0x31, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x00, 0x14, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x04, 0xf0, 0xd3, 0xfc, 0x68, 0x68, 0x00, 0xf0, + 0xc5, 0xfa, 0xdf, 0xf8, 0x30, 0x0d, 0x00, 0xeb, 0x84, 0x00, 0x45, 0x60, + 0xfe, 0xf7, 0x50, 0xfc, 0x01, 0x21, 0x28, 0x46, 0x00, 0xf0, 0x38, 0xfe, + 0x88, 0xe1, 0xf0, 0xb5, 0x83, 0xb0, 0x0c, 0x46, 0xef, 0xf3, 0x05, 0x80, + 0x08, 0xb1, 0x00, 0xf0, 0xbb, 0xfe, 0x00, 0xf0, 0xaf, 0xfe, 0x06, 0x46, + 0x00, 0xf0, 0x64, 0xfa, 0x05, 0x00, 0x14, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0x04, 0xf0, 0xb1, 0xfc, 0x05, 0xf1, 0x1c, 0x07, 0x30, 0x02, 0x40, 0xf0, + 0x02, 0x00, 0x38, 0x60, 0x07, 0x20, 0x04, 0xf0, 0x6c, 0xfd, 0x68, 0x68, + 0xdf, 0xf8, 0xdc, 0x6c, 0x01, 0xab, 0x00, 0x22, 0x17, 0x21, 0xfe, 0xf7, + 0x3d, 0xff, 0x30, 0x68, 0x39, 0x46, 0xff, 0xf7, 0xce, 0xf8, 0x8d, 0xf8, + 0x04, 0x00, 0x40, 0x1e, 0x00, 0xf0, 0x45, 0xfc, 0x0d, 0xf1, 0x05, 0x00, + 0x00, 0x90, 0x23, 0x46, 0x68, 0x68, 0x82, 0x22, 0x02, 0x21, 0xfe, 0xf7, + 0x9f, 0xfe, 0x9d, 0xf8, 0x05, 0x10, 0x00, 0xf0, 0x37, 0xfc, 0x02, 0x20, + 0x04, 0xf0, 0x54, 0xfe, 0xef, 0xf3, 0x11, 0x84, 0x60, 0x20, 0x80, 0xf3, + 0x11, 0x88, 0xdf, 0xf8, 0xa8, 0x7c, 0xdf, 0xf8, 0xa8, 0x1c, 0x3d, 0x68, + 0x4f, 0xf0, 0x00, 0x40, 0x08, 0x60, 0x04, 0xf0, 0xd9, 0xfe, 0x03, 0x28, + 0x04, 0xbf, 0x96, 0xf8, 0x54, 0x03, 0x03, 0x28, 0x03, 0xd1, 0xdf, 0xf8, + 0xbc, 0x1c, 0x01, 0x20, 0x08, 0x70, 0x05, 0xf0, 0x00, 0x40, 0x38, 0x60, + 0x84, 0xf3, 0x11, 0x88, 0x00, 0x20, 0xfe, 0xbd, 0x38, 0xb5, 0xef, 0xf3, + 0x05, 0x80, 0x08, 0xb1, 0x00, 0xf0, 0x60, 0xfe, 0x00, 0xf0, 0x54, 0xfe, + 0x00, 0xf0, 0x09, 0xfa, 0x05, 0x00, 0x14, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0x04, 0xf0, 0x57, 0xfc, 0x20, 0x02, 0x40, 0xf0, 0x03, 0x00, 0x45, 0xf8, + 0x1c, 0x0f, 0x00, 0x21, 0x08, 0x20, 0x04, 0xf0, 0x22, 0xfd, 0xdf, 0xf8, + 0x2c, 0x0c, 0x00, 0x68, 0x29, 0x46, 0xff, 0xf7, 0x7a, 0xf8, 0x40, 0x1e, + 0x00, 0xf0, 0xf3, 0xfb, 0x00, 0x20, 0x32, 0xbd, 0x70, 0xb5, 0x0c, 0x46, + 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0x00, 0xf0, 0x3b, 0xfe, 0x00, 0xf0, + 0x2f, 0xfe, 0x05, 0x46, 0x00, 0xf0, 0xe4, 0xf9, 0x06, 0x00, 0x14, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x04, 0xf0, 0x31, 0xfc, 0x06, 0xf1, 0x1c, 0x01, + 0x44, 0xea, 0x05, 0x20, 0x08, 0x60, 0xdf, 0xf8, 0xe8, 0x0b, 0x00, 0x68, + 0xff, 0xf7, 0x59, 0xf8, 0x40, 0x1e, 0x00, 0xf0, 0xd2, 0xfb, 0x00, 0x20, + 0x70, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0x03, 0x20, 0x04, 0xf0, 0xe1, 0xfc, + 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x04, 0x21, 0xd4, 0xe7, 0x10, 0xb5, + 0x04, 0x46, 0x20, 0x68, 0xc0, 0xb2, 0x81, 0x42, 0x0c, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0x04, 0xf0, 0x0e, 0xfc, 0xdf, 0xf8, 0xac, 0x0b, 0x00, 0x68, + 0x21, 0x46, 0xff, 0xf7, 0x65, 0xf8, 0x40, 0x1e, 0x00, 0xf0, 0xb3, 0xfb, + 0x00, 0x20, 0x10, 0xbd, 0xdf, 0xf8, 0x94, 0x1b, 0x91, 0xf8, 0x60, 0x23, + 0x0a, 0xb1, 0x00, 0x20, 0x70, 0x47, 0x01, 0x22, 0x81, 0xf8, 0x60, 0x23, + 0x00, 0x21, 0xde, 0xe7, 0x01, 0x21, 0xdc, 0xe7, 0x10, 0xb5, 0x04, 0x46, + 0x17, 0x20, 0x04, 0xf0, 0xb4, 0xfc, 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, + 0x08, 0x21, 0xd2, 0xe7, 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x82, 0xb0, + 0x21, 0x46, 0x09, 0x20, 0x04, 0xf0, 0xc6, 0xfc, 0x01, 0x21, 0x08, 0x20, + 0x04, 0xf0, 0xb3, 0xfc, 0xe0, 0xb2, 0x00, 0xf0, 0xcb, 0xfd, 0x06, 0x46, + 0x03, 0x20, 0x30, 0x76, 0x0c, 0xb1, 0xc5, 0xf3, 0x02, 0x10, 0xdf, 0xf8, + 0x3c, 0x5b, 0x85, 0xf8, 0x54, 0x03, 0x02, 0x20, 0x04, 0xf0, 0x7e, 0xfd, + 0x70, 0x68, 0x6b, 0x46, 0x01, 0x22, 0x02, 0x21, 0xfe, 0xf7, 0x66, 0xfe, + 0x05, 0xf1, 0x4c, 0x00, 0x01, 0x21, 0x81, 0x72, 0x04, 0x80, 0x00, 0x21, + 0xc1, 0x72, 0x00, 0xf0, 0x6b, 0xfb, 0x00, 0x20, 0x76, 0xbd, 0x70, 0xb5, + 0x04, 0x46, 0xdf, 0xf8, 0x08, 0x5b, 0x60, 0x88, 0x1c, 0x21, 0x01, 0xfb, + 0x00, 0x50, 0x00, 0x2c, 0x90, 0xf8, 0x40, 0x61, 0x14, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0x04, 0xf0, 0xae, 0xfb, 0x00, 0x20, 0x20, 0x63, 0x00, 0x2e, + 0x0c, 0xbf, 0x05, 0xf5, 0x4b, 0x70, 0x05, 0xf5, 0x4c, 0x70, 0x01, 0x68, + 0x11, 0xb9, 0x04, 0x60, 0x70, 0xbd, 0x01, 0x46, 0x08, 0x6b, 0x00, 0x28, + 0xfb, 0xd1, 0x0c, 0x63, 0x70, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0xfe, 0xf7, + 0x1f, 0xfb, 0xdf, 0xf8, 0xc0, 0x0a, 0x00, 0xf5, 0x4b, 0x71, 0x00, 0x2c, + 0x0c, 0xbf, 0x09, 0x68, 0x49, 0x68, 0x71, 0xb1, 0x89, 0x78, 0x1c, 0x22, + 0x02, 0xfb, 0x01, 0x04, 0x94, 0xf8, 0x30, 0x01, 0x03, 0x28, 0x06, 0xd1, + 0x84, 0xf8, 0x30, 0x01, 0xfe, 0xf7, 0x1f, 0xfb, 0x04, 0xf5, 0x98, 0x70, + 0x10, 0xbd, 0xc9, 0xe0, 0x70, 0xb5, 0x04, 0x00, 0x14, 0xbf, 0x01, 0x26, + 0x00, 0x26, 0x30, 0x46, 0x04, 0xf0, 0x77, 0xfb, 0x30, 0x46, 0x04, 0xf0, + 0x74, 0xfb, 0x61, 0x88, 0xdf, 0xf8, 0x74, 0x0a, 0x1c, 0x22, 0x02, 0xfb, + 0x01, 0x01, 0x91, 0xf8, 0x40, 0x11, 0x00, 0x29, 0x0c, 0xbf, 0x00, 0xf5, + 0x4b, 0x70, 0x00, 0xf5, 0x4c, 0x70, 0x01, 0x68, 0xa1, 0x42, 0x06, 0xd1, + 0x09, 0x6b, 0x01, 0x60, 0x00, 0x20, 0x20, 0x63, 0x70, 0xbd, 0x0d, 0x46, + 0x09, 0x6b, 0x00, 0x29, 0x18, 0xbf, 0xa1, 0x42, 0xf9, 0xd1, 0xa1, 0x42, + 0x03, 0xd1, 0x08, 0x6b, 0x28, 0x63, 0x00, 0x20, 0x08, 0x63, 0x70, 0xbd, + 0x38, 0xb5, 0xdf, 0xf8, 0x30, 0x1a, 0x1c, 0x22, 0x02, 0xfb, 0x00, 0x11, + 0x01, 0xf5, 0x98, 0x74, 0x00, 0xf0, 0xf4, 0xf8, 0x05, 0x46, 0xfe, 0xf7, + 0xcb, 0xfa, 0x20, 0x78, 0x01, 0x28, 0x1c, 0xbf, 0x03, 0x28, 0x02, 0x28, + 0x02, 0xd1, 0x28, 0x46, 0xff, 0xf7, 0xbc, 0xff, 0xbd, 0xe8, 0x31, 0x40, + 0xfe, 0xf7, 0xd3, 0xba, 0x10, 0xb5, 0x82, 0xb0, 0x04, 0x46, 0xfe, 0xf7, + 0xb9, 0xfa, 0x00, 0xf0, 0xa4, 0xf8, 0x0c, 0xbf, 0x4c, 0x68, 0x8c, 0x68, + 0xac, 0xb1, 0xa2, 0x78, 0x1c, 0x23, 0x03, 0xfb, 0x02, 0x00, 0x90, 0xf8, + 0x30, 0x21, 0x03, 0x2a, 0x00, 0xd0, 0x8c, 0xe0, 0x4f, 0xf0, 0xff, 0x32, + 0x0a, 0x60, 0x04, 0x21, 0x80, 0xf8, 0x30, 0x11, 0x20, 0x46, 0xff, 0xf7, + 0x9b, 0xff, 0x00, 0xf0, 0x86, 0xf8, 0x00, 0xf0, 0xc1, 0xfa, 0xfe, 0xf7, + 0xb0, 0xfa, 0x00, 0x20, 0x16, 0xbd, 0x2d, 0xe9, 0xf0, 0x43, 0x83, 0xb0, + 0x88, 0x46, 0x14, 0x46, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0x00, 0xf0, + 0x07, 0xfd, 0xfe, 0xf7, 0x8d, 0xfa, 0x00, 0xf0, 0xf9, 0xfc, 0xc7, 0xb2, + 0x38, 0x46, 0x00, 0xf0, 0xef, 0xfc, 0x05, 0x46, 0xdf, 0xf8, 0x8c, 0x99, + 0x1c, 0x20, 0x00, 0xfb, 0x07, 0x90, 0x00, 0xf5, 0x98, 0x76, 0x01, 0x20, + 0x30, 0x70, 0x39, 0x46, 0x0a, 0x20, 0x04, 0xf0, 0xd5, 0xfb, 0x28, 0x46, + 0xff, 0xf7, 0x31, 0xff, 0x38, 0x02, 0x40, 0xf0, 0x07, 0x00, 0x70, 0x61, + 0x06, 0xf1, 0x14, 0x01, 0xdf, 0xf8, 0x98, 0x0c, 0x00, 0x68, 0xfe, 0xf7, + 0x16, 0xff, 0x40, 0x1e, 0x00, 0xf0, 0x8f, 0xfa, 0xfe, 0xf7, 0x7b, 0xfa, + 0x01, 0xa8, 0x00, 0x90, 0x43, 0x46, 0x68, 0x68, 0x83, 0x22, 0x10, 0x21, + 0xfe, 0xf7, 0xe8, 0xfc, 0x9d, 0xf8, 0x04, 0x10, 0x00, 0xf0, 0x80, 0xfa, + 0x03, 0x20, 0x04, 0xf0, 0x9d, 0xfc, 0x09, 0xf6, 0x6c, 0x40, 0x20, 0x60, + 0x00, 0x20, 0xbd, 0xe8, 0xfe, 0x83, 0x10, 0xb5, 0xef, 0xf3, 0x05, 0x80, + 0x08, 0xb1, 0x00, 0xf0, 0xc3, 0xfc, 0xfe, 0xf7, 0x49, 0xfa, 0x00, 0xf0, + 0xb5, 0xfc, 0x00, 0xf0, 0x6a, 0xf8, 0xdf, 0xf8, 0x0c, 0x19, 0xe4, 0xb2, + 0x1c, 0x22, 0x02, 0xfb, 0x04, 0x11, 0x00, 0x20, 0x81, 0xf8, 0x30, 0x01, + 0xfe, 0xf7, 0x4f, 0xfa, 0x00, 0x20, 0x10, 0xbd, 0x10, 0xb5, 0x82, 0xb0, + 0x04, 0x46, 0xfe, 0xf7, 0x33, 0xfa, 0x00, 0xf0, 0x1e, 0xf8, 0x0c, 0xbf, + 0x4c, 0x68, 0x8c, 0x68, 0x7c, 0xb1, 0xa2, 0x78, 0x0a, 0x60, 0x1c, 0x23, + 0x03, 0xfb, 0x02, 0x00, 0x02, 0x21, 0x80, 0xf8, 0x30, 0x11, 0x03, 0x20, + 0x04, 0xf0, 0x4a, 0xfc, 0x00, 0xf0, 0x07, 0xf8, 0x00, 0xf0, 0x42, 0xfa, + 0x7f, 0xe7, 0xfe, 0xf7, 0x30, 0xfa, 0x01, 0x20, 0x16, 0xbd, 0x60, 0x68, + 0x6b, 0x46, 0x01, 0x22, 0x10, 0x21, 0xfe, 0xf7, 0x29, 0xbd, 0xdf, 0xf8, + 0xa8, 0x08, 0x00, 0xf5, 0x4a, 0x71, 0x00, 0x2c, 0x70, 0x47, 0x2d, 0xe9, + 0xfc, 0x41, 0x04, 0x46, 0x88, 0x46, 0x16, 0x46, 0xef, 0xf3, 0x05, 0x80, + 0x08, 0xb1, 0x00, 0xf0, 0x7b, 0xfc, 0xfe, 0xf7, 0x01, 0xfa, 0x00, 0xf0, + 0x6d, 0xfc, 0x05, 0x46, 0x00, 0xf0, 0x22, 0xf8, 0x07, 0x46, 0xdf, 0xf8, + 0x78, 0x08, 0xed, 0xb2, 0x1c, 0x21, 0x01, 0xfb, 0x05, 0x01, 0x01, 0xf5, + 0x98, 0x71, 0x03, 0x22, 0x00, 0xf6, 0x6c, 0x40, 0x0a, 0x70, 0x48, 0x60, + 0xce, 0x60, 0x0c, 0x74, 0xfe, 0xf7, 0xff, 0xf9, 0x01, 0xa8, 0x00, 0x90, + 0x43, 0x46, 0x78, 0x68, 0x83, 0x22, 0x10, 0x21, 0xfe, 0xf7, 0x6c, 0xfc, + 0x9d, 0xf8, 0x04, 0x10, 0x00, 0xf0, 0x04, 0xfa, 0x00, 0x20, 0xbd, 0xe8, + 0xf6, 0x81, 0x04, 0x46, 0xc0, 0xb2, 0x00, 0xf0, 0x3f, 0xbc, 0x30, 0xb5, + 0xdf, 0xf8, 0x2c, 0x48, 0x87, 0xb0, 0x14, 0x21, 0x04, 0xf2, 0x84, 0x40, + 0xfe, 0xf7, 0xc3, 0xfd, 0x20, 0x60, 0x00, 0xf0, 0x39, 0xf8, 0x03, 0x21, + 0x04, 0x91, 0x00, 0x21, 0x03, 0x91, 0x80, 0x21, 0x02, 0x91, 0x03, 0x21, + 0xdf, 0xf8, 0x68, 0x0c, 0x01, 0x90, 0x00, 0x91, 0x00, 0xf5, 0xfe, 0x72, + 0x03, 0x23, 0x00, 0x21, 0x0f, 0xf6, 0xa9, 0x10, 0xfe, 0xf7, 0x8d, 0xff, + 0x40, 0x1e, 0x00, 0xf0, 0xdc, 0xf9, 0x05, 0xaa, 0x0f, 0xf2, 0x38, 0x01, + 0x03, 0x20, 0xff, 0xf7, 0x3b, 0xf8, 0x04, 0xf1, 0x4c, 0x00, 0x00, 0x21, + 0x01, 0x81, 0x04, 0xf5, 0x51, 0x75, 0x4f, 0xf6, 0xff, 0x71, 0x01, 0x80, + 0x4f, 0xf0, 0xff, 0x31, 0x29, 0x60, 0x69, 0x60, 0x00, 0x21, 0x81, 0x72, + 0x04, 0xf5, 0x59, 0x70, 0xe8, 0x60, 0x00, 0xf0, 0x44, 0xf8, 0x00, 0x20, + 0x28, 0x72, 0x28, 0x77, 0x07, 0xb0, 0x30, 0xbd, 0x43, 0x74, 0x72, 0x6c, + 0x54, 0x73, 0x6b, 0x00, 0x00, 0xb1, 0x01, 0x20, 0x04, 0xf0, 0x07, 0xba, + 0xf8, 0xb5, 0x00, 0x25, 0x00, 0x21, 0xdf, 0xf8, 0x98, 0x67, 0x20, 0xfa, + 0x01, 0xf2, 0xd2, 0x07, 0x03, 0xd5, 0x06, 0xeb, 0x81, 0x02, 0xd4, 0x6f, + 0x34, 0xb9, 0x49, 0x1c, 0x07, 0x29, 0xf4, 0xd3, 0x28, 0x46, 0xf2, 0xbd, + 0x00, 0x25, 0x14, 0x46, 0xe2, 0x6a, 0x00, 0x2a, 0xf5, 0xd0, 0x63, 0x7b, + 0xa5, 0x7b, 0x2b, 0x42, 0xf6, 0xd0, 0x01, 0x21, 0x20, 0x46, 0x00, 0xf0, + 0x7d, 0xfb, 0x20, 0x7b, 0x01, 0x25, 0x07, 0x46, 0x07, 0x28, 0xb4, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x04, 0xf0, 0xdf, 0xf9, 0x00, 0x20, 0xe0, 0x62, + 0x06, 0xeb, 0x87, 0x00, 0xc1, 0x6f, 0xc4, 0x67, 0x00, 0x29, 0xdf, 0xd0, + 0xe1, 0x62, 0xdd, 0xe7, 0xdf, 0xf8, 0x38, 0x07, 0x90, 0xf8, 0x54, 0x03, + 0x70, 0x47, 0xdf, 0xf8, 0xfc, 0x0b, 0x40, 0x89, 0x00, 0xf0, 0x03, 0x01, + 0xc0, 0xf3, 0x01, 0x10, 0x03, 0x28, 0x04, 0xd1, 0x03, 0x29, 0x0c, 0xd1, + 0x01, 0x20, 0x02, 0x21, 0x1f, 0xe0, 0x01, 0x28, 0x18, 0xbf, 0x02, 0x28, + 0x0d, 0xd1, 0x03, 0x29, 0x09, 0xd1, 0x01, 0x28, 0x13, 0xd1, 0x03, 0x20, + 0x14, 0xe0, 0x01, 0x29, 0x18, 0xbf, 0x02, 0x29, 0x0f, 0xd1, 0x08, 0x46, + 0x0f, 0xe0, 0x01, 0x28, 0x01, 0xd0, 0x02, 0x28, 0x09, 0xd1, 0x01, 0x29, + 0x18, 0xbf, 0x02, 0x29, 0x05, 0xd1, 0x01, 0x28, 0x01, 0xd1, 0x08, 0x46, + 0x02, 0xe0, 0x00, 0x20, 0x01, 0xe0, 0x00, 0x20, 0x00, 0x21, 0x40, 0xea, + 0x81, 0x00, 0xdf, 0xf8, 0xd0, 0x16, 0x81, 0xf8, 0xb8, 0x03, 0x70, 0x47, + 0xdf, 0xf8, 0xc4, 0x26, 0x92, 0xf8, 0xb8, 0x23, 0x01, 0x23, 0x03, 0xfa, + 0x00, 0xf0, 0x00, 0x21, 0x00, 0xea, 0x02, 0x03, 0x13, 0xf0, 0x03, 0x0f, + 0x18, 0xbf, 0x01, 0x21, 0x05, 0xd1, 0x00, 0xea, 0x92, 0x00, 0x10, 0xf0, + 0x03, 0x0f, 0x18, 0xbf, 0x02, 0x21, 0xdf, 0xf8, 0x68, 0x0b, 0x40, 0x89, + 0x01, 0xea, 0x10, 0x10, 0x40, 0x1e, 0x40, 0xb2, 0x70, 0x47, 0xdf, 0xf8, + 0x8c, 0x06, 0xd0, 0xf8, 0x64, 0x13, 0xca, 0x03, 0x05, 0xd5, 0x90, 0xf8, + 0xba, 0x23, 0x05, 0x2a, 0x01, 0xd1, 0x05, 0x20, 0x70, 0x47, 0x49, 0x07, + 0x03, 0xd5, 0x90, 0xf8, 0xba, 0x03, 0x01, 0x28, 0x00, 0xd0, 0xff, 0x20, + 0x70, 0x47, 0xdf, 0xf8, 0x64, 0x06, 0xd0, 0xf8, 0x64, 0x13, 0x8a, 0x03, + 0x05, 0xd5, 0x90, 0xf8, 0xbb, 0x23, 0x06, 0x2a, 0x01, 0xd1, 0x06, 0x20, + 0x70, 0x47, 0x09, 0x07, 0x03, 0xd5, 0x90, 0xf8, 0xbb, 0x03, 0x02, 0x28, + 0x00, 0xd0, 0xff, 0x20, 0x70, 0x47, 0x10, 0xb5, 0x04, 0x46, 0x00, 0xf0, + 0x47, 0xfb, 0x84, 0x42, 0x0c, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x10, 0xbd, + 0x2d, 0xe9, 0xf1, 0x4f, 0x0c, 0x46, 0xdf, 0xf8, 0x24, 0x86, 0xdf, 0xf8, + 0xf0, 0xaa, 0x15, 0x46, 0x01, 0x26, 0x04, 0xf0, 0x04, 0x0b, 0x08, 0xf2, + 0xb9, 0x39, 0x00, 0x98, 0xf0, 0x40, 0xc0, 0x07, 0x6d, 0xd5, 0x08, 0xeb, + 0x86, 0x00, 0xc7, 0x6f, 0x23, 0xe0, 0x38, 0x78, 0x05, 0x28, 0x09, 0xd1, + 0xff, 0xf7, 0xb5, 0xff, 0x85, 0x42, 0x66, 0xd0, 0x03, 0x2d, 0x03, 0xd1, + 0x99, 0xf8, 0x03, 0x00, 0x00, 0x28, 0x60, 0xd1, 0x38, 0x78, 0x06, 0x28, + 0x09, 0xd1, 0xff, 0xf7, 0xbc, 0xff, 0x85, 0x42, 0x59, 0xd0, 0x03, 0x2d, + 0x03, 0xd1, 0x99, 0xf8, 0x03, 0x00, 0x00, 0x28, 0x53, 0xd1, 0x38, 0x78, + 0x01, 0x28, 0x01, 0xd1, 0xe1, 0x07, 0x4e, 0xd4, 0x02, 0x28, 0x01, 0xd1, + 0xa0, 0x07, 0x4a, 0xd4, 0xff, 0x6a, 0x00, 0x2f, 0x43, 0xd0, 0x78, 0x7b, + 0x00, 0x28, 0xf9, 0xd0, 0x79, 0x88, 0xd8, 0xf8, 0x48, 0x03, 0x11, 0xf8, + 0x0a, 0x10, 0xc8, 0x40, 0xc0, 0x07, 0xf1, 0xd5, 0x38, 0x7b, 0x01, 0x28, + 0x18, 0xbf, 0x04, 0x28, 0x25, 0xd0, 0x05, 0x28, 0xc7, 0xd0, 0x02, 0x28, + 0x1f, 0xd1, 0x39, 0x78, 0x99, 0xf8, 0x00, 0x00, 0x03, 0x29, 0x0c, 0xd1, + 0xbb, 0xf1, 0x00, 0x0f, 0xe0, 0xd0, 0x03, 0x2d, 0x29, 0xd0, 0x01, 0x2d, + 0x02, 0xd1, 0xc0, 0x07, 0xda, 0xd5, 0x24, 0xe0, 0x02, 0x2d, 0xd7, 0xd1, + 0x0b, 0xe0, 0x04, 0x29, 0xd4, 0xd1, 0x21, 0x07, 0xd2, 0xd5, 0x03, 0x2d, + 0x1b, 0xd0, 0x02, 0x2d, 0x01, 0xd1, 0x00, 0x07, 0xf0, 0xe7, 0x01, 0x2d, + 0xca, 0xd1, 0x80, 0x07, 0xec, 0xe7, 0x03, 0x28, 0xc6, 0xd1, 0x39, 0x78, + 0x03, 0x29, 0x03, 0xd1, 0xbb, 0xf1, 0x00, 0x0f, 0x04, 0xd1, 0xbf, 0xe7, + 0x04, 0x29, 0xbd, 0xd1, 0x20, 0x07, 0xbb, 0xd5, 0x03, 0x2d, 0xb9, 0xd1, + 0x03, 0xe0, 0x76, 0x1c, 0x07, 0x2e, 0x8a, 0xdb, 0x00, 0x27, 0x38, 0x46, + 0xbd, 0xe8, 0xf2, 0x8f, 0x2d, 0xe9, 0xf0, 0x41, 0xdf, 0xf8, 0xec, 0x59, + 0x80, 0x46, 0x95, 0xf8, 0x4c, 0x00, 0xc0, 0x07, 0x0e, 0x46, 0x04, 0xd5, + 0x28, 0x7a, 0x01, 0x28, 0x08, 0xbf, 0x00, 0x20, 0x2d, 0xd0, 0x2c, 0x6d, + 0xc6, 0xf3, 0x02, 0x17, 0x4c, 0xb1, 0x20, 0x46, 0xff, 0xf7, 0xaa, 0xfe, + 0x28, 0xb1, 0x3a, 0x46, 0x31, 0x46, 0x20, 0x46, 0xff, 0xf7, 0x5e, 0xff, + 0x20, 0xb9, 0x3a, 0x46, 0x31, 0x46, 0x7f, 0x20, 0xff, 0xf7, 0x58, 0xff, + 0x00, 0x28, 0xa9, 0x7a, 0x14, 0xbf, 0x07, 0x7b, 0x00, 0x27, 0x79, 0xb1, + 0x2e, 0x88, 0xf0, 0xb2, 0x00, 0xf0, 0x8a, 0xfa, 0xb8, 0xf1, 0x00, 0x0f, + 0x04, 0xbf, 0x00, 0x7b, 0xb8, 0x42, 0x0c, 0xd0, 0xe8, 0x7a, 0x50, 0xb9, + 0xf0, 0xb2, 0x00, 0xf0, 0x07, 0xf9, 0x06, 0xe0, 0x00, 0x2e, 0x04, 0xd4, + 0x18, 0xb1, 0x40, 0x88, 0x31, 0x46, 0xff, 0xf7, 0x9d, 0xfc, 0x00, 0x20, + 0xbd, 0xe8, 0xf0, 0x81, 0x70, 0xb5, 0x04, 0x00, 0x14, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0x04, 0xf0, 0x7e, 0xf8, 0x20, 0x68, 0x0f, 0x28, 0x00, 0xf0, + 0x28, 0xf8, 0x25, 0x68, 0xdf, 0xf8, 0x80, 0x24, 0xd2, 0xf8, 0xbc, 0x60, + 0x28, 0x46, 0x41, 0x08, 0x02, 0xeb, 0xc1, 0x01, 0x01, 0xf1, 0xc0, 0x03, + 0xf8, 0x31, 0xc6, 0x40, 0xf6, 0x07, 0x04, 0xd5, 0xbd, 0xe8, 0x70, 0x40, + 0x01, 0x21, 0x04, 0xf0, 0xa7, 0xb9, 0x1d, 0x60, 0x01, 0x25, 0x64, 0x68, + 0x5c, 0x60, 0x05, 0xfa, 0x00, 0xf0, 0xd2, 0xf8, 0xbc, 0x40, 0x20, 0x43, + 0xc2, 0xf8, 0xbc, 0x00, 0x0d, 0x60, 0x4b, 0x60, 0x08, 0x46, 0xbd, 0xe8, + 0x70, 0x40, 0x5d, 0xe4, 0x9d, 0xf8, 0x00, 0x10, 0x48, 0x1e, 0x80, 0x41, + 0xc0, 0x0f, 0x04, 0xf0, 0x4e, 0xb8, 0xf8, 0xb5, 0x06, 0x46, 0x37, 0x68, + 0x0e, 0x2f, 0x20, 0xd2, 0x00, 0x21, 0x38, 0x46, 0xdf, 0xf8, 0x1c, 0x44, + 0x04, 0xf0, 0x6e, 0xf9, 0x04, 0xf1, 0x54, 0x05, 0xf8, 0xb2, 0x29, 0x78, + 0x05, 0xf0, 0x56, 0xfb, 0x00, 0x28, 0x40, 0xf0, 0xa6, 0x80, 0x6f, 0xb1, + 0x02, 0x2f, 0x10, 0xd0, 0x04, 0x2f, 0x19, 0xd0, 0x06, 0x2f, 0x5f, 0xd0, + 0x08, 0x2f, 0x4f, 0xd0, 0x0a, 0x2f, 0x69, 0xd0, 0x0c, 0x2f, 0x00, 0xf0, + 0x80, 0x80, 0x93, 0xe0, 0x70, 0x68, 0x00, 0xf0, 0x8f, 0xfb, 0x00, 0x20, + 0xf2, 0xbd, 0x74, 0x68, 0x0e, 0x20, 0x04, 0xf0, 0xe6, 0xf8, 0x01, 0x20, + 0x28, 0x70, 0x00, 0x21, 0x20, 0x46, 0x05, 0xf0, 0xbd, 0xfb, 0xf2, 0xe7, + 0x10, 0x20, 0x04, 0xf0, 0xdc, 0xf8, 0x04, 0xf0, 0x0c, 0xfe, 0x01, 0x00, + 0x06, 0xd0, 0x04, 0x20, 0x04, 0xf0, 0x52, 0xf9, 0x04, 0x20, 0x00, 0xf0, + 0x62, 0xfb, 0xe4, 0xe7, 0x04, 0x20, 0x28, 0x70, 0x1c, 0x21, 0x00, 0x20, + 0xa8, 0x64, 0x04, 0xf1, 0xa0, 0x00, 0x03, 0xf0, 0x59, 0xfe, 0x00, 0xf0, + 0xfd, 0xfb, 0x48, 0xb1, 0x4f, 0xf0, 0x7f, 0x42, 0x40, 0xf6, 0xff, 0x73, + 0x00, 0x20, 0x00, 0xf0, 0x0d, 0xf9, 0x68, 0x46, 0x05, 0xf0, 0x7d, 0xfb, + 0xff, 0xf7, 0x06, 0xfb, 0x07, 0x22, 0x00, 0x23, 0x03, 0x20, 0x00, 0xf0, + 0x03, 0xf9, 0x04, 0x20, 0x00, 0xf0, 0x41, 0xfb, 0x00, 0x25, 0x6c, 0x20, + 0x00, 0xfb, 0x05, 0x40, 0x00, 0xf2, 0x14, 0x50, 0x05, 0xf0, 0x32, 0xfc, + 0x6d, 0x1c, 0x12, 0x2d, 0xf5, 0xd3, 0xb8, 0xe7, 0x74, 0x68, 0x12, 0x20, + 0x04, 0xf0, 0xa1, 0xf8, 0x21, 0x46, 0x00, 0x20, 0x05, 0xf0, 0x2a, 0xfc, + 0x01, 0x46, 0x08, 0x20, 0x04, 0xf0, 0x16, 0xf9, 0x08, 0x20, 0xc2, 0xe7, + 0x74, 0x68, 0x11, 0x20, 0x04, 0xf0, 0x93, 0xf8, 0x21, 0x46, 0x01, 0x20, + 0x05, 0xf0, 0x1c, 0xfc, 0x01, 0x46, 0x06, 0x20, 0x04, 0xf0, 0x08, 0xf9, + 0x06, 0x20, 0xb4, 0xe7, 0x74, 0x68, 0x14, 0x20, 0x04, 0xf0, 0x85, 0xf8, + 0x29, 0x78, 0xe0, 0xb2, 0x05, 0xf0, 0xc6, 0xfa, 0x48, 0xb9, 0xc4, 0xf3, + 0x42, 0x10, 0x03, 0x28, 0x04, 0xd1, 0x01, 0x21, 0x20, 0x46, 0x00, 0xf0, + 0xf9, 0xfb, 0x00, 0xe0, 0x04, 0x20, 0x01, 0x46, 0x0a, 0x20, 0x04, 0xf0, + 0xef, 0xf8, 0x0a, 0x20, 0x9b, 0xe7, 0x74, 0x68, 0x20, 0x06, 0x45, 0x0f, + 0x13, 0x20, 0x04, 0xf0, 0x6a, 0xf8, 0x03, 0x2d, 0x18, 0xbf, 0x02, 0x2d, + 0x11, 0xbf, 0x04, 0x20, 0x00, 0x21, 0x20, 0x46, 0x00, 0xf0, 0xe2, 0xfb, + 0x01, 0x46, 0x0c, 0x20, 0x04, 0xf0, 0xda, 0xf8, 0x0c, 0x20, 0x86, 0xe7, + 0x03, 0xf0, 0x95, 0xff, 0x6b, 0xe7, 0x80, 0x28, 0x03, 0xd1, 0x38, 0x46, + 0x00, 0xf0, 0xe3, 0xfa, 0x65, 0xe7, 0x01, 0x46, 0x38, 0x46, 0x04, 0xf0, + 0xcb, 0xf8, 0xf6, 0xe7, 0x10, 0xb5, 0x82, 0xb0, 0x00, 0xf0, 0x74, 0xf9, + 0x04, 0x46, 0x20, 0x7e, 0x05, 0x28, 0x1c, 0xbf, 0x04, 0x20, 0x20, 0x76, + 0x02, 0x20, 0x04, 0xf0, 0x2b, 0xf9, 0x60, 0x68, 0x6b, 0x46, 0x01, 0x22, + 0x01, 0x21, 0xfe, 0xf7, 0x13, 0xfa, 0xff, 0xf7, 0x1f, 0xff, 0xdf, 0xf8, + 0x70, 0x1b, 0x01, 0x20, 0x81, 0xf8, 0x57, 0x00, 0x06, 0x20, 0x04, 0xf0, + 0x30, 0xf8, 0x00, 0x20, 0x16, 0xbd, 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0xff, 0xf7, 0x12, 0xfd, 0x06, 0x46, 0xb0, 0x7b, 0x28, 0xb1, 0xe0, 0xb2, + 0x00, 0xf0, 0xb2, 0xf8, 0x05, 0x20, 0x04, 0xf0, 0x20, 0xf8, 0x00, 0x20, + 0x70, 0x73, 0xb0, 0x73, 0x01, 0x21, 0x30, 0x46, 0x00, 0xf0, 0xea, 0xf8, + 0xe0, 0xb2, 0x05, 0xf0, 0x57, 0xfb, 0xdf, 0xf8, 0x2c, 0x1b, 0x01, 0xeb, + 0x84, 0x01, 0x00, 0x20, 0x48, 0x60, 0x30, 0x69, 0xff, 0xf7, 0x3e, 0xfd, + 0x70, 0x6a, 0x33, 0x69, 0x00, 0x22, 0x29, 0x46, 0x98, 0x47, 0x00, 0x20, + 0x70, 0xbd, 0xf0, 0xb5, 0x83, 0xb0, 0x07, 0x46, 0x00, 0xf0, 0x2c, 0xf9, + 0x04, 0x46, 0x02, 0x20, 0x04, 0xf0, 0x06, 0xf9, 0x20, 0x7e, 0xdf, 0xf8, + 0xf8, 0x5a, 0x05, 0x28, 0x05, 0xf1, 0x4c, 0x06, 0x11, 0xd1, 0x01, 0x21, + 0x38, 0x46, 0xff, 0xf7, 0xc4, 0xff, 0x30, 0x7a, 0x05, 0x28, 0x0a, 0xd1, + 0x03, 0x20, 0x30, 0x72, 0x04, 0xf0, 0x13, 0xfc, 0x00, 0xf0, 0x35, 0xf8, + 0x04, 0xf0, 0x1e, 0xf9, 0x00, 0x20, 0x00, 0xf0, 0x74, 0xfa, 0x00, 0x20, + 0x60, 0x73, 0x02, 0x20, 0x20, 0x76, 0x4f, 0xf6, 0xff, 0x70, 0x30, 0x80, + 0x00, 0x20, 0x70, 0x81, 0x00, 0x2f, 0x04, 0xbf, 0x30, 0x7a, 0x05, 0x28, + 0x0a, 0xd1, 0x08, 0x20, 0x00, 0x90, 0x4f, 0xf0, 0xff, 0x30, 0x01, 0x90, + 0x68, 0x46, 0x00, 0xf0, 0x20, 0xf8, 0x00, 0x20, 0x00, 0xf0, 0x5b, 0xfa, + 0x20, 0x7b, 0x05, 0xeb, 0x80, 0x01, 0x01, 0x22, 0xc9, 0x6f, 0x04, 0xe0, + 0x4b, 0x7b, 0x01, 0x2b, 0x08, 0xbf, 0x00, 0x22, 0xc9, 0x6a, 0x00, 0x29, + 0xf8, 0xd1, 0x32, 0xb1, 0xf1, 0x6c, 0x01, 0x22, 0x02, 0xfa, 0x00, 0xf0, + 0x21, 0xea, 0x00, 0x00, 0xf0, 0x64, 0x00, 0x20, 0xfe, 0xbd, 0x07, 0x22, + 0x00, 0x23, 0x02, 0x20, 0x00, 0x21, 0x04, 0xf0, 0x39, 0xb8, 0xf8, 0xb5, + 0x06, 0x46, 0x00, 0x20, 0x00, 0xf0, 0xd4, 0xf8, 0xdf, 0xf8, 0x50, 0x5a, + 0xd5, 0xf8, 0xc8, 0x70, 0x05, 0xf1, 0x54, 0x04, 0xa0, 0x6e, 0x80, 0x08, + 0x00, 0xf0, 0x01, 0x00, 0x03, 0xf0, 0xd9, 0xfe, 0x02, 0x2f, 0x0c, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, 0xd3, 0xfe, 0x71, 0x68, 0xc9, 0xb2, + 0x38, 0x46, 0x04, 0xf0, 0x0f, 0xf8, 0x38, 0x46, 0x00, 0xf0, 0x1f, 0xfa, + 0x70, 0x68, 0x70, 0xb9, 0x05, 0xf0, 0x93, 0xfc, 0x48, 0xb1, 0x03, 0x20, + 0x20, 0x70, 0x01, 0x20, 0x85, 0xf8, 0x4c, 0x03, 0x04, 0xf0, 0xab, 0xfb, + 0xff, 0xf7, 0xcd, 0xff, 0x08, 0xe0, 0x02, 0x20, 0x05, 0xe0, 0x95, 0xf8, + 0x4c, 0x03, 0x00, 0x28, 0x14, 0xbf, 0x03, 0x20, 0x02, 0x20, 0x20, 0x70, + 0x01, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x45, 0xff, 0x00, 0x20, 0xf2, 0xbd, + 0x80, 0xb5, 0x00, 0xf0, 0x99, 0xf8, 0x00, 0x21, 0x81, 0x73, 0x02, 0x7b, + 0xdf, 0xf8, 0xd4, 0x19, 0x01, 0xeb, 0x82, 0x02, 0xd2, 0xf8, 0xa0, 0x30, + 0x5b, 0x1e, 0xc2, 0xf8, 0xa0, 0x30, 0x00, 0x7b, 0x01, 0xeb, 0x80, 0x02, + 0xd2, 0xf8, 0xa0, 0x20, 0x42, 0xb9, 0xd1, 0xf8, 0x9c, 0x20, 0x01, 0x23, + 0x03, 0xfa, 0x00, 0xf0, 0x22, 0xea, 0x00, 0x00, 0xc1, 0xf8, 0x9c, 0x00, + 0x00, 0x20, 0x02, 0xbd, 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x20, 0x7b, + 0x06, 0x46, 0x07, 0x28, 0xb4, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, + 0x82, 0xfe, 0x00, 0x20, 0xe0, 0x62, 0x00, 0x2d, 0x23, 0x48, 0x0c, 0xbf, + 0x60, 0x30, 0x7c, 0x30, 0x50, 0xf8, 0x26, 0x10, 0x19, 0xb9, 0x40, 0xf8, + 0x26, 0x40, 0x04, 0xe0, 0x01, 0x46, 0xc8, 0x6a, 0x00, 0x28, 0xfb, 0xd1, + 0xcc, 0x62, 0x00, 0x20, 0x70, 0xbd, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x20, + 0xf8, 0xb5, 0x06, 0x46, 0x0f, 0x46, 0x30, 0x7b, 0x04, 0x46, 0x07, 0x28, + 0xb4, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, 0x60, 0xfe, 0xdf, 0xf8, + 0x48, 0x19, 0x00, 0x2f, 0x0c, 0xbf, 0x01, 0xf1, 0x60, 0x02, 0x01, 0xf1, + 0x7c, 0x02, 0x52, 0xf8, 0x24, 0x00, 0xb0, 0x42, 0x11, 0xd1, 0xc3, 0x6a, + 0x42, 0xf8, 0x24, 0x30, 0x3b, 0xb9, 0x04, 0x7b, 0xd1, 0xf8, 0x98, 0x20, + 0x01, 0x23, 0xa3, 0x40, 0x9a, 0x43, 0xc1, 0xf8, 0x98, 0x20, 0x00, 0x21, + 0xc1, 0x62, 0x00, 0x20, 0xf2, 0xbd, 0x05, 0x46, 0xc0, 0x6a, 0x00, 0x28, + 0x18, 0xbf, 0xb0, 0x42, 0xf9, 0xd1, 0xb0, 0x42, 0x02, 0xd1, 0xc1, 0x6a, + 0xe9, 0x62, 0xf0, 0xe7, 0x01, 0x20, 0xf2, 0xbd, 0xb8, 0x04, 0x00, 0x20, + 0xdf, 0xf8, 0xf0, 0x18, 0xdf, 0xf8, 0xc4, 0x24, 0xd1, 0xf8, 0x50, 0x13, + 0x80, 0x5c, 0x1d, 0xe0, 0x00, 0xe1, 0x00, 0xe0, 0x80, 0xe1, 0x00, 0xe0, + 0x10, 0xb5, 0x04, 0x46, 0x04, 0x2c, 0xb4, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0x03, 0xf0, 0x21, 0xfe, 0xdf, 0xf8, 0xc8, 0x08, 0x00, 0xeb, 0x84, 0x00, + 0xd0, 0xf8, 0xa8, 0x43, 0x04, 0xf0, 0x4a, 0xf8, 0xa0, 0x42, 0x34, 0xbf, + 0x20, 0x1a, 0x00, 0x20, 0x10, 0xbd, 0x00, 0x00, 0x65, 0x2c, 0x00, 0x20, + 0xdf, 0xf8, 0xa8, 0x18, 0x01, 0xeb, 0x80, 0x00, 0x40, 0x68, 0x70, 0x47, + 0x80, 0xb5, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0x00, 0xf0, 0x04, 0xf8, + 0xdf, 0xf8, 0x94, 0x08, 0x00, 0x68, 0x02, 0xbd, 0x00, 0x20, 0x03, 0xf0, + 0xfe, 0xbd, 0x80, 0xb5, 0xff, 0xf7, 0xf0, 0xff, 0xdf, 0xf8, 0x54, 0x14, + 0x40, 0x5c, 0x02, 0xbd, 0x10, 0xb5, 0xdf, 0xf8, 0x78, 0x48, 0x20, 0x68, + 0x10, 0xf1, 0x01, 0x0f, 0x14, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, + 0xec, 0xfd, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0xff, 0xf7, 0xe6, 0xff, + 0x20, 0x68, 0xc0, 0xb2, 0xff, 0xf7, 0xd2, 0xff, 0x04, 0x00, 0x14, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, 0xdd, 0xfd, 0x60, 0x68, 0x10, 0xbd, + 0xf8, 0xb5, 0x00, 0xf0, 0x56, 0xf8, 0x0e, 0x46, 0x14, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0x03, 0xf0, 0xd2, 0xfd, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, + 0xff, 0xf7, 0xcc, 0xff, 0x67, 0x00, 0x01, 0x20, 0x00, 0x21, 0x07, 0xf1, + 0x18, 0x02, 0x02, 0xf0, 0xe5, 0xff, 0x04, 0x46, 0x0d, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x07, 0xf1, 0x19, 0x02, 0x02, 0xf0, 0xdd, 0xff, 0x03, 0x2e, + 0x14, 0xd8, 0xdf, 0xe8, 0x06, 0xf0, 0x02, 0x07, 0x0a, 0x0d, 0x22, 0x46, + 0x2b, 0x46, 0x20, 0x46, 0x29, 0x46, 0x09, 0xe0, 0x22, 0x46, 0x2b, 0x46, + 0x04, 0xe0, 0x02, 0x46, 0x0b, 0x46, 0x03, 0xe0, 0x02, 0x46, 0x0b, 0x46, + 0x00, 0x20, 0x00, 0x21, 0x03, 0xf0, 0xf6, 0xfe, 0x00, 0x20, 0xf2, 0xbd, + 0x10, 0xb5, 0x82, 0xb0, 0xff, 0xf7, 0x96, 0xff, 0xc0, 0xb2, 0xff, 0xf7, + 0x8d, 0xff, 0x00, 0xf0, 0x1a, 0xf8, 0x14, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0x03, 0xf0, 0x97, 0xfd, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0xff, 0xf7, + 0x91, 0xff, 0x60, 0x68, 0x6b, 0x46, 0x00, 0x22, 0x08, 0x21, 0xfe, 0xf7, + 0x29, 0xf8, 0xff, 0xf7, 0x35, 0xfd, 0xa0, 0x6a, 0x69, 0x46, 0xfe, 0xf7, + 0xbd, 0xfc, 0xff, 0xf7, 0x2f, 0xfd, 0x00, 0x20, 0x16, 0xbd, 0x04, 0x46, + 0xdf, 0xf8, 0x8c, 0x07, 0x00, 0x68, 0x10, 0xf1, 0x01, 0x0f, 0x70, 0x47, + 0x00, 0xb5, 0xdf, 0xf8, 0x80, 0x07, 0x83, 0xb0, 0x00, 0x68, 0x10, 0xf1, + 0x01, 0x0f, 0x14, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, 0x6f, 0xfd, + 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0xff, 0xf7, 0x69, 0xff, 0xff, 0xf7, + 0x71, 0xff, 0x01, 0xa9, 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, 0x08, 0x21, + 0xfd, 0xf7, 0x72, 0xff, 0x00, 0x20, 0x0e, 0xbd, 0x2d, 0xe9, 0xf0, 0x47, + 0x82, 0xb0, 0x04, 0xf0, 0xa8, 0xf8, 0xdf, 0xf8, 0x44, 0x07, 0xdf, 0xf8, + 0x38, 0x47, 0x03, 0xf0, 0x5b, 0xfe, 0x04, 0xf1, 0x54, 0x05, 0x02, 0x20, + 0x28, 0x70, 0x01, 0x26, 0x00, 0x20, 0xc0, 0x46, 0x07, 0x22, 0x00, 0x23, + 0x01, 0x20, 0xff, 0xf7, 0x5b, 0xfe, 0x03, 0xf0, 0x9d, 0xff, 0x20, 0x65, + 0x09, 0xe0, 0x40, 0x46, 0xff, 0xf7, 0x57, 0xfe, 0x21, 0x6d, 0x48, 0x46, + 0xff, 0xf7, 0x76, 0xfc, 0x01, 0x20, 0x03, 0xf0, 0x07, 0xff, 0x20, 0x68, + 0x6a, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xfb, 0xf8, 0x80, 0x46, 0x01, 0x20, + 0xd8, 0xf8, 0x00, 0xa0, 0x03, 0xf0, 0xde, 0xfe, 0x5f, 0xfa, 0x8a, 0xf0, + 0x0a, 0x28, 0x4f, 0xea, 0x1a, 0x27, 0x4f, 0xf0, 0x00, 0x09, 0xe5, 0xd8, + 0xdf, 0xe8, 0x00, 0xf0, 0x08, 0x13, 0x37, 0x46, 0x4a, 0x06, 0x06, 0x06, + 0x07, 0x56, 0x69, 0x00, 0xdc, 0xe7, 0xd8, 0xe7, 0x84, 0xf8, 0x60, 0x93, + 0x03, 0xf0, 0x70, 0xff, 0x01, 0x46, 0x21, 0x65, 0x02, 0x20, 0x03, 0xf0, + 0xf7, 0xfd, 0xb1, 0x46, 0xd0, 0xe7, 0xb4, 0xf8, 0xc0, 0x03, 0xd8, 0xf8, + 0x04, 0x30, 0x04, 0xeb, 0xc0, 0x00, 0x00, 0xf5, 0x71, 0x72, 0xd3, 0xe9, + 0x00, 0x01, 0xc2, 0xe9, 0x00, 0x01, 0xd8, 0xf8, 0x04, 0x00, 0xff, 0xf7, + 0xb4, 0xfc, 0xb4, 0xf8, 0xc0, 0x03, 0xdf, 0xf8, 0x94, 0x16, 0x09, 0x68, + 0x04, 0xeb, 0x80, 0x00, 0xc0, 0xf8, 0x44, 0x14, 0xb4, 0xf8, 0xc0, 0x03, + 0x40, 0x1c, 0xa4, 0xf8, 0xc0, 0x03, 0x80, 0xb2, 0x10, 0x28, 0xaf, 0xdb, + 0xa4, 0xf8, 0xc0, 0x93, 0xac, 0xe7, 0x28, 0x78, 0x05, 0x28, 0xa9, 0xd0, + 0xf8, 0xb2, 0xff, 0xf7, 0xd7, 0xfe, 0x02, 0x7b, 0x69, 0x6c, 0x06, 0xfa, + 0x02, 0xf2, 0x11, 0x43, 0x69, 0x64, 0x06, 0x76, 0x46, 0x73, 0x9d, 0xe7, + 0xf8, 0xb2, 0xff, 0xf7, 0x9a, 0xfd, 0x99, 0xe7, 0xf8, 0xb2, 0xff, 0xf7, + 0xc7, 0xfe, 0x07, 0x46, 0x01, 0x21, 0xff, 0xf7, 0x69, 0xfe, 0x01, 0x21, + 0x38, 0x46, 0xff, 0xf7, 0x43, 0xfe, 0x8d, 0xe7, 0xf8, 0xb2, 0xff, 0xf7, + 0xbb, 0xfe, 0x02, 0x7b, 0xa9, 0x6c, 0x06, 0xfa, 0x02, 0xf2, 0x11, 0x43, + 0xa9, 0x64, 0x01, 0x7b, 0x04, 0xeb, 0x81, 0x01, 0xd1, 0xf8, 0xa0, 0x20, + 0x52, 0x1c, 0xc1, 0xf8, 0xa0, 0x20, 0x86, 0x73, 0x7a, 0xe7, 0xf8, 0xb2, + 0xff, 0xf7, 0x0c, 0xfe, 0x76, 0xe7, 0xdf, 0xf8, 0x08, 0x06, 0xdf, 0xf8, + 0xf8, 0x25, 0x00, 0x68, 0x41, 0x68, 0x11, 0x60, 0x90, 0xf8, 0x32, 0x10, + 0x01, 0x20, 0x03, 0xf0, 0x8f, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0x72, 0xb6, + 0x03, 0xf0, 0xc1, 0xfd, 0xdf, 0xf8, 0xd4, 0x05, 0xd0, 0xf8, 0xbc, 0x10, + 0x01, 0x22, 0xa2, 0x40, 0x91, 0x43, 0xc0, 0xf8, 0xbc, 0x10, 0x62, 0xb6, + 0x10, 0xbd, 0x00, 0x00, 0x88, 0xf2, 0x00, 0x20, 0xfe, 0xb5, 0x0f, 0x20, + 0xdf, 0xf8, 0xb4, 0x55, 0x03, 0xf0, 0x57, 0xfd, 0x05, 0xf1, 0x4c, 0x04, + 0x20, 0x7a, 0x01, 0x28, 0x10, 0xd1, 0xa0, 0x7a, 0x28, 0xb1, 0x05, 0x20, + 0x20, 0x72, 0x00, 0x20, 0xff, 0xf7, 0xfe, 0xfc, 0x3f, 0xe0, 0x08, 0x20, + 0x01, 0x90, 0x4f, 0xf0, 0xff, 0x30, 0x02, 0x90, 0x01, 0xa8, 0xff, 0xf7, + 0x94, 0xfd, 0x33, 0xe0, 0x68, 0x46, 0x05, 0xf0, 0x25, 0xfb, 0x68, 0x46, + 0x05, 0xf0, 0xf5, 0xfa, 0x05, 0x20, 0x20, 0x72, 0x01, 0x26, 0x04, 0xf0, + 0x54, 0xf9, 0x05, 0xeb, 0x86, 0x00, 0x47, 0x68, 0x8f, 0xb1, 0x78, 0x88, + 0x22, 0x88, 0xc1, 0xb2, 0x91, 0x42, 0x08, 0xd1, 0x39, 0x7e, 0x05, 0x29, + 0x05, 0xd0, 0xc0, 0xb2, 0xff, 0xf7, 0xda, 0xfc, 0x05, 0x20, 0x38, 0x76, + 0x03, 0xe0, 0x01, 0x21, 0xc0, 0xb2, 0xff, 0xf7, 0xf2, 0xfc, 0x76, 0x1c, + 0x12, 0x2e, 0xe6, 0xdb, 0x20, 0x88, 0x4f, 0xf6, 0xff, 0x71, 0x88, 0x42, + 0x0d, 0xd1, 0x05, 0xf0, 0x1e, 0xfa, 0x50, 0xb1, 0x03, 0x20, 0x20, 0x72, + 0x04, 0xf0, 0x39, 0xf9, 0xff, 0xf7, 0x5b, 0xfd, 0x03, 0xf0, 0x44, 0xfe, + 0x00, 0x20, 0xff, 0xf7, 0x9a, 0xff, 0x00, 0x20, 0xfe, 0xbd, 0x10, 0xb5, + 0x82, 0xb0, 0xef, 0xf3, 0x05, 0x80, 0x08, 0xb1, 0xff, 0xf7, 0x3c, 0xfe, + 0xff, 0xf7, 0x30, 0xfe, 0xff, 0xf7, 0x42, 0xfe, 0x04, 0x00, 0x14, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x03, 0xf0, 0x33, 0xfc, 0x6b, 0x46, 0x02, 0x22, + 0x01, 0x21, 0x20, 0x46, 0xfd, 0xf7, 0xd4, 0xfd, 0x00, 0xf0, 0x01, 0x00, + 0x16, 0xbd, 0x10, 0xb5, 0x00, 0x24, 0xc0, 0xf3, 0x47, 0x12, 0x00, 0x2a, + 0x18, 0xbf, 0x01, 0x2a, 0x00, 0xf0, 0x1f, 0x00, 0x14, 0xd1, 0x02, 0x29, + 0x10, 0xd2, 0x0c, 0x23, 0x58, 0x43, 0x00, 0x2a, 0x0c, 0xbf, 0xdf, 0xf8, + 0xd0, 0x24, 0xdf, 0xf8, 0xd0, 0x24, 0x80, 0x18, 0x82, 0x68, 0x50, 0xf8, + 0x21, 0x10, 0xdf, 0xf8, 0xc8, 0x04, 0x05, 0xf0, 0x1d, 0xfb, 0x02, 0xe0, + 0x05, 0x24, 0x00, 0xe0, 0x04, 0x24, 0x20, 0x46, 0x10, 0xbd, 0x00, 0x00, + 0x68, 0x76, 0x00, 0x20, 0xf8, 0xb5, 0xdf, 0xf8, 0x90, 0x04, 0xd0, 0xf8, + 0x50, 0x03, 0x05, 0x68, 0x16, 0x48, 0x44, 0x89, 0x04, 0xf0, 0x03, 0x00, + 0xc4, 0xf3, 0x83, 0x01, 0x41, 0xea, 0x00, 0x11, 0x41, 0xea, 0x80, 0x11, + 0x41, 0xea, 0x00, 0x21, 0x41, 0xea, 0x80, 0x21, 0x41, 0xea, 0x00, 0x30, + 0x00, 0xea, 0x05, 0x06, 0xff, 0xf7, 0x6d, 0xfa, 0x05, 0x28, 0x0c, 0xbf, + 0x01, 0x27, 0x00, 0x27, 0xff, 0xf7, 0x7b, 0xfa, 0x06, 0x28, 0x0c, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x47, 0xea, 0x40, 0x00, 0x15, 0xea, 0x00, 0x40, + 0x07, 0xd0, 0x00, 0x90, 0x00, 0x98, 0x80, 0x0b, 0x00, 0xea, 0x94, 0x00, + 0x00, 0xf0, 0x0c, 0x00, 0x06, 0x43, 0x30, 0x46, 0xf2, 0xbd, 0x00, 0x00, + 0x78, 0x29, 0x00, 0x20, 0xf4, 0x1e, 0x00, 0x20, 0x04, 0x05, 0x00, 0x20, + 0xdf, 0xf8, 0x1c, 0x14, 0xd1, 0xf8, 0x64, 0x13, 0xc1, 0x40, 0x01, 0xf0, + 0x01, 0x00, 0x70, 0x47, 0x10, 0xb5, 0x04, 0x46, 0xff, 0xf7, 0xba, 0xff, + 0xe0, 0x40, 0x00, 0xf0, 0x01, 0x00, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x43, + 0x00, 0x24, 0x85, 0xb0, 0x03, 0x46, 0xde, 0xb2, 0x0f, 0x46, 0x18, 0x0a, + 0x40, 0x2e, 0x4f, 0xea, 0x13, 0x4c, 0x00, 0xf0, 0x0f, 0x01, 0xdf, 0xf8, + 0xe4, 0x83, 0xdf, 0xf8, 0xfc, 0x53, 0x18, 0xbf, 0x41, 0x2e, 0x0c, 0xf0, + 0x01, 0x0e, 0x00, 0xf0, 0x03, 0x00, 0xc3, 0xf3, 0x07, 0x22, 0x08, 0xf5, + 0x51, 0x79, 0x2b, 0xd0, 0x42, 0x2e, 0x2e, 0xd0, 0x43, 0x2e, 0x32, 0xd0, + 0x44, 0x2e, 0x25, 0xd0, 0x60, 0x2e, 0x35, 0xd0, 0x61, 0x2e, 0x00, 0xf0, + 0x73, 0x81, 0x62, 0x2e, 0x68, 0xd0, 0x63, 0x2e, 0x00, 0xf0, 0x4d, 0x81, + 0x64, 0x2e, 0x00, 0xf0, 0x7b, 0x81, 0x65, 0x2e, 0x00, 0xf0, 0x80, 0x80, + 0x66, 0x2e, 0x00, 0xf0, 0x9c, 0x80, 0x67, 0x2e, 0x00, 0xf0, 0x1f, 0x81, + 0x69, 0x2e, 0x00, 0xf0, 0x39, 0x81, 0x6a, 0x2e, 0x00, 0xf0, 0x7a, 0x81, + 0x6b, 0x2e, 0x00, 0xf0, 0x7f, 0x81, 0x6c, 0x2e, 0x03, 0xd0, 0x6d, 0x2e, + 0x00, 0xf0, 0x3e, 0x81, 0x7d, 0xe1, 0x00, 0x2f, 0x00, 0xf0, 0x7a, 0x81, + 0x05, 0xf0, 0x17, 0xfb, 0x77, 0xe1, 0xc3, 0xf3, 0x07, 0x41, 0x10, 0x46, + 0xff, 0xf7, 0x3f, 0xff, 0x3f, 0xe1, 0x14, 0x22, 0xdf, 0xf8, 0x74, 0x13, + 0x28, 0x46, 0x05, 0xf0, 0x71, 0xfa, 0x6a, 0xe1, 0x16, 0x46, 0xe0, 0x46, + 0x30, 0x46, 0x05, 0xf0, 0x15, 0xfb, 0x00, 0x28, 0x00, 0xf0, 0xfb, 0x80, + 0x00, 0x2f, 0x30, 0x46, 0x11, 0xd0, 0x05, 0xf0, 0x6b, 0xfb, 0x18, 0xb9, + 0x08, 0xf0, 0x1f, 0x01, 0x00, 0x22, 0x06, 0xe0, 0x4f, 0xea, 0x08, 0x62, + 0x10, 0x0f, 0x08, 0xf0, 0x0f, 0x01, 0x00, 0xf0, 0x01, 0x02, 0x30, 0x46, + 0x05, 0xf0, 0x37, 0xfb, 0x4d, 0xe1, 0x05, 0xf0, 0x20, 0xfb, 0x07, 0x46, + 0x30, 0x46, 0x05, 0xf0, 0x4b, 0xfb, 0x80, 0x46, 0x30, 0x46, 0x05, 0xf0, + 0x51, 0xfb, 0x3f, 0x02, 0x18, 0xb9, 0x08, 0xf0, 0x1f, 0x00, 0x38, 0x43, + 0x36, 0xe1, 0xb8, 0xf1, 0x13, 0x0f, 0x08, 0xbf, 0x2f, 0x60, 0xe9, 0xd0, + 0x08, 0xf0, 0x0f, 0x00, 0x38, 0x43, 0x40, 0xf0, 0x10, 0x00, 0x2b, 0xe1, + 0x00, 0x2f, 0x40, 0xf0, 0x2f, 0x81, 0x00, 0x20, 0xfe, 0xf7, 0x69, 0xfd, + 0x06, 0x46, 0x00, 0x20, 0xfe, 0xf7, 0x6e, 0xfd, 0x46, 0xea, 0x00, 0x40, + 0x04, 0x90, 0x01, 0x20, 0xfe, 0xf7, 0x5f, 0xfd, 0x06, 0x46, 0x01, 0x20, + 0xfe, 0xf7, 0x64, 0xfd, 0x46, 0xea, 0x00, 0x40, 0x03, 0x90, 0x04, 0x22, + 0x04, 0xa9, 0x28, 0x46, 0x05, 0xf0, 0x1c, 0xfa, 0x04, 0x22, 0x03, 0xa9, + 0x28, 0x1d, 0x02, 0xe1, 0xd9, 0xf8, 0x00, 0x00, 0x00, 0x2f, 0xda, 0xd0, + 0x0f, 0x29, 0x03, 0xd1, 0x28, 0x68, 0xc9, 0xf8, 0x00, 0x00, 0x11, 0xe0, + 0xc3, 0xf3, 0x00, 0x32, 0x02, 0xeb, 0x41, 0x01, 0x14, 0x29, 0x28, 0xbf, + 0x04, 0x24, 0x01, 0x22, 0x02, 0xfa, 0x01, 0xf1, 0x9a, 0x04, 0x4c, 0xbf, + 0x08, 0x43, 0x88, 0x43, 0x00, 0x2c, 0xc9, 0xf8, 0x00, 0x00, 0x01, 0xd1, + 0xfe, 0xf7, 0xfc, 0xfd, 0xf3, 0xe0, 0x56, 0x1e, 0x07, 0x2e, 0xc3, 0xf3, + 0x01, 0x41, 0xbc, 0xd8, 0xdf, 0xe8, 0x06, 0xf0, 0x04, 0x20, 0x57, 0x62, + 0x4c, 0x4c, 0x6c, 0x12, 0x00, 0x2f, 0x67, 0xd0, 0x5f, 0xfa, 0x8c, 0xf1, + 0x01, 0xf0, 0x03, 0x00, 0x49, 0x07, 0x02, 0xd5, 0xfc, 0xf7, 0x9c, 0xff, + 0xdd, 0xe0, 0xfc, 0xf7, 0x8b, 0xff, 0xda, 0xe0, 0x00, 0x2f, 0x76, 0x46, + 0x58, 0xd0, 0x29, 0x46, 0x30, 0x46, 0x03, 0xf0, 0x34, 0xf8, 0x00, 0x28, + 0x52, 0xd0, 0x29, 0x46, 0x30, 0x46, 0x02, 0xf0, 0xe4, 0xff, 0xcc, 0xe0, + 0xc3, 0xf3, 0x83, 0x46, 0x00, 0x2f, 0x18, 0xbf, 0x00, 0x2e, 0x0d, 0x46, + 0x46, 0xd0, 0x00, 0x27, 0x25, 0xfa, 0x07, 0xf0, 0xc0, 0x07, 0x1b, 0xd5, + 0x00, 0x2f, 0x14, 0xbf, 0x09, 0x20, 0x08, 0x20, 0x98, 0xf8, 0x54, 0x10, + 0x03, 0x29, 0x04, 0xd0, 0xd9, 0xf8, 0x20, 0x10, 0xc1, 0x40, 0xc8, 0x07, + 0x04, 0xd4, 0x31, 0x46, 0x38, 0x46, 0x05, 0xf0, 0xe5, 0xfd, 0x09, 0xe0, + 0x38, 0x46, 0x05, 0xf0, 0xc4, 0xfd, 0x08, 0xb1, 0x01, 0x24, 0xa8, 0xe0, + 0x31, 0x46, 0x38, 0x46, 0x05, 0xf0, 0xc7, 0xfd, 0x7f, 0x1c, 0x02, 0x2f, + 0xdc, 0xd3, 0xa0, 0xe0, 0x00, 0x2f, 0x1f, 0xd0, 0x05, 0x2a, 0x0c, 0xbf, + 0x00, 0x20, 0x01, 0x20, 0x0f, 0xfa, 0x8c, 0xf1, 0x06, 0xf0, 0x6e, 0xfb, + 0x95, 0xe0, 0x00, 0x2f, 0x14, 0xd0, 0x0d, 0x46, 0x28, 0x46, 0x07, 0xf0, + 0x6f, 0xff, 0x29, 0x46, 0x00, 0x20, 0x05, 0xf0, 0x56, 0xfd, 0x8a, 0xe0, + 0x00, 0x2f, 0x09, 0xd0, 0x0d, 0x46, 0x01, 0x20, 0x05, 0xf0, 0x4f, 0xfd, + 0x28, 0x46, 0x07, 0xf0, 0x73, 0xff, 0x80, 0xe0, 0x00, 0x2f, 0x0c, 0x46, + 0x7c, 0xd0, 0x98, 0xf8, 0x54, 0x00, 0x03, 0x28, 0x78, 0xd1, 0x00, 0x25, + 0x24, 0xfa, 0x05, 0xf0, 0xc0, 0x07, 0x44, 0xbf, 0x28, 0x46, 0x05, 0xf0, + 0x9c, 0xfd, 0x6d, 0x1c, 0x02, 0x2d, 0xf5, 0xd3, 0x6c, 0xe0, 0x0e, 0xeb, + 0x41, 0x00, 0xc0, 0xb2, 0x06, 0x46, 0x13, 0x2e, 0x01, 0xdb, 0x05, 0x24, + 0x65, 0xe0, 0x7f, 0xb1, 0xfe, 0xf7, 0x58, 0xfd, 0x00, 0x28, 0x60, 0xd1, + 0x56, 0x48, 0x30, 0x5c, 0x08, 0xeb, 0x80, 0x00, 0x02, 0xab, 0x40, 0x68, + 0x40, 0x68, 0x01, 0x22, 0x28, 0x21, 0xfd, 0xf7, 0xe9, 0xfc, 0x54, 0xe0, + 0xfe, 0xf7, 0x48, 0xfd, 0x28, 0x70, 0x50, 0xe0, 0x00, 0x2f, 0x4d, 0xd0, + 0xff, 0xf7, 0x42, 0xfc, 0x4b, 0xe0, 0x27, 0xb1, 0xd5, 0xe9, 0x00, 0x23, + 0x04, 0xf0, 0xa2, 0xfc, 0x13, 0xe0, 0x07, 0xf0, 0xcd, 0xff, 0xc5, 0xe9, + 0x00, 0x01, 0x40, 0xe0, 0x4f, 0xea, 0x8c, 0x56, 0x18, 0x0b, 0xb6, 0x0d, + 0x00, 0xf0, 0x03, 0x00, 0x4f, 0xb1, 0x02, 0x28, 0xa8, 0xbf, 0x07, 0x24, + 0x35, 0xda, 0x0a, 0x46, 0x31, 0x46, 0x08, 0xf0, 0x58, 0xfc, 0x04, 0x46, + 0x2f, 0xe0, 0xea, 0x1c, 0x29, 0x46, 0x08, 0xf0, 0x7a, 0xfc, 0x2a, 0xe0, + 0x7f, 0xb9, 0x03, 0xf0, 0x7f, 0xfc, 0x06, 0x46, 0x04, 0x2e, 0x05, 0xd1, + 0x04, 0xf0, 0x3d, 0xfc, 0x46, 0xea, 0x00, 0x10, 0x00, 0x90, 0x00, 0xe0, + 0x00, 0x96, 0x04, 0x22, 0x69, 0x46, 0x09, 0xe0, 0x0f, 0xb1, 0x02, 0x24, + 0x17, 0xe0, 0x03, 0xf0, 0x63, 0xfc, 0x00, 0xf0, 0x0f, 0x00, 0x01, 0x90, + 0x04, 0x22, 0x01, 0xa9, 0x28, 0x46, 0x05, 0xf0, 0x13, 0xf9, 0x0c, 0xe0, + 0x17, 0xb1, 0x04, 0xf0, 0x20, 0xfc, 0x08, 0xe0, 0x04, 0xf0, 0x21, 0xfc, + 0x28, 0x60, 0x04, 0xe0, 0x17, 0xb1, 0x08, 0xf0, 0x3f, 0xff, 0x00, 0xe0, + 0x03, 0x24, 0xe0, 0xb2, 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x83, 0x38, 0xb5, + 0x04, 0x46, 0x1a, 0x48, 0x90, 0xf8, 0xb8, 0x03, 0x0d, 0x46, 0x00, 0xf0, + 0x03, 0x01, 0x03, 0x29, 0xc0, 0xf3, 0x81, 0x00, 0x01, 0xd1, 0xb0, 0xb9, + 0x03, 0xe0, 0x00, 0x29, 0x08, 0xbf, 0x03, 0x28, 0x11, 0xd1, 0x0b, 0x20, + 0x05, 0xf0, 0xea, 0xf9, 0x13, 0x28, 0x01, 0xd1, 0x01, 0x20, 0x32, 0xbd, + 0x1c, 0xb9, 0x0b, 0x20, 0x05, 0xf0, 0x9c, 0xf9, 0x02, 0xe0, 0x0b, 0x20, + 0x05, 0xf0, 0x8f, 0xf9, 0x28, 0x46, 0x01, 0xf0, 0xf9, 0xfe, 0x00, 0x20, + 0x32, 0xbd, 0x08, 0x48, 0xd0, 0xf8, 0xa8, 0x03, 0x70, 0x47, 0x06, 0x48, + 0xd0, 0xf8, 0xb4, 0x03, 0x70, 0x47, 0x04, 0x48, 0xd0, 0xf8, 0xac, 0x03, + 0x70, 0x47, 0x02, 0x48, 0x90, 0xf8, 0x54, 0x00, 0x70, 0x47, 0x00, 0x00, + 0xb8, 0x04, 0x00, 0x20, 0x60, 0xf3, 0x00, 0x20, 0x49, 0x3d, 0x00, 0x01, + 0x08, 0x00, 0x00, 0x49, 0x48, 0xbd, 0x00, 0x20, 0x98, 0x68, 0x01, 0x01, + 0xa8, 0x6f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x20, 0xe8, 0xf2, 0x00, 0x20, + 0xc8, 0x20, 0x00, 0x20, 0xdf, 0xf8, 0x84, 0x07, 0x00, 0x68, 0x70, 0x47, + 0x28, 0x21, 0x42, 0xf6, 0x2c, 0x40, 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x00, 0x22, 0x00, 0xf0, 0x44, 0xf8, 0x40, 0xf2, 0xc9, 0x66, 0x80, 0x21, + 0x30, 0x46, 0xfe, 0xf7, 0x7b, 0xfa, 0x00, 0x21, 0x30, 0x46, 0xfe, 0xf7, + 0x77, 0xfa, 0xdf, 0xf8, 0x5c, 0x07, 0xdf, 0xf8, 0x5c, 0x17, 0x40, 0x6b, + 0x46, 0x00, 0x30, 0x46, 0x00, 0x27, 0x01, 0xe0, 0x40, 0x08, 0x7f, 0x1c, + 0x88, 0x42, 0xfb, 0xd2, 0x06, 0x2f, 0xb4, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0x03, 0xf0, 0x7d, 0xf9, 0x7a, 0x01, 0xd2, 0xb2, 0xe0, 0x21, 0x00, 0xf0, + 0x23, 0xf8, 0xdf, 0xf8, 0x28, 0x07, 0xfe, 0x40, 0x06, 0x60, 0x04, 0x22, + 0x00, 0xf0, 0x1b, 0xf8, 0xdf, 0xf8, 0x24, 0x07, 0xdf, 0xf8, 0x24, 0x17, + 0xdf, 0xf8, 0x24, 0x27, 0x04, 0x80, 0x45, 0x80, 0x30, 0x20, 0x08, 0x80, + 0xdf, 0xf8, 0x1c, 0x17, 0x08, 0x80, 0x0f, 0x21, 0xdf, 0xf8, 0x18, 0x07, + 0x01, 0x80, 0x30, 0x21, 0x11, 0x80, 0x01, 0x80, 0x70, 0x21, 0x01, 0x80, + 0xb0, 0x21, 0x01, 0x80, 0xf0, 0x21, 0x01, 0x80, 0xf1, 0xbd, 0x04, 0x21, + 0x4f, 0xf4, 0x8c, 0x70, 0xfe, 0xf7, 0x42, 0xba, 0x2d, 0xe9, 0xf8, 0x4f, + 0xdf, 0xf8, 0xf4, 0x66, 0xdf, 0xf8, 0xf4, 0x16, 0xdf, 0xf8, 0xd0, 0x26, + 0x18, 0xb9, 0xd2, 0xe9, 0x06, 0x5b, 0xc8, 0x6a, 0x03, 0xe0, 0xd2, 0xe9, + 0x08, 0x5b, 0x08, 0x6c, 0x50, 0x36, 0x30, 0x21, 0xb0, 0xfb, 0xf1, 0xf9, + 0x50, 0x21, 0x30, 0x46, 0x02, 0xf0, 0x8e, 0xff, 0x01, 0x27, 0x09, 0xfb, + 0x07, 0xf0, 0x00, 0x21, 0x15, 0xeb, 0x00, 0x08, 0x4b, 0xeb, 0x01, 0x0a, + 0x28, 0x1a, 0x6b, 0xeb, 0x01, 0x01, 0x08, 0xf0, 0x83, 0xff, 0x01, 0x21, + 0x00, 0x28, 0x01, 0xfa, 0x07, 0xf4, 0x03, 0xd5, 0xb0, 0x6c, 0x20, 0x43, + 0xb0, 0x64, 0x04, 0xe0, 0x06, 0xeb, 0x80, 0x00, 0x41, 0x6a, 0x21, 0x43, + 0x41, 0x62, 0x40, 0x46, 0x51, 0x46, 0x08, 0xf0, 0x71, 0xff, 0x00, 0x28, + 0x03, 0xd5, 0xf0, 0x6c, 0x20, 0x43, 0xf0, 0x64, 0x04, 0xe0, 0x56, 0xf8, + 0x20, 0x10, 0x21, 0x43, 0x46, 0xf8, 0x20, 0x10, 0x7f, 0x1c, 0x18, 0x2f, + 0xd3, 0xd3, 0xbd, 0xe8, 0xf1, 0x8f, 0x2d, 0xe9, 0xf8, 0x4f, 0x89, 0x46, + 0x17, 0x46, 0xdf, 0xf8, 0x48, 0x16, 0xdf, 0xf8, 0x64, 0x26, 0x15, 0x68, + 0x00, 0x28, 0x07, 0xbf, 0xd0, 0x6a, 0xd1, 0xe9, 0x00, 0x48, 0x10, 0x6c, + 0xd1, 0xe9, 0x02, 0x48, 0x01, 0x09, 0x00, 0x07, 0x2a, 0x46, 0x00, 0x23, + 0x02, 0xf0, 0x08, 0xfc, 0x30, 0x22, 0x00, 0x23, 0x02, 0xf0, 0x04, 0xfc, + 0x06, 0x46, 0x8a, 0x46, 0xdf, 0xb1, 0x07, 0xf1, 0x18, 0x00, 0x31, 0x28, + 0x17, 0xd2, 0xfa, 0x17, 0xa6, 0xfb, 0x07, 0x01, 0x06, 0xfb, 0x02, 0x11, + 0x0a, 0xfb, 0x07, 0x11, 0x27, 0x1a, 0x28, 0x46, 0x68, 0xeb, 0x01, 0x0b, + 0xa0, 0xfb, 0x07, 0x23, 0x00, 0xfb, 0x0b, 0x33, 0x12, 0x0f, 0x42, 0xea, + 0x03, 0x10, 0x19, 0x0f, 0x08, 0xf0, 0x2a, 0xff, 0x05, 0x46, 0x00, 0x2d, + 0x01, 0xd5, 0x00, 0x20, 0x20, 0xe0, 0x3a, 0x46, 0x5b, 0x46, 0x48, 0x46, + 0x08, 0xf0, 0x78, 0xfe, 0x2a, 0x46, 0x20, 0x46, 0x41, 0x46, 0x08, 0xf0, + 0x38, 0xfe, 0x04, 0x46, 0x0f, 0x46, 0x2a, 0x46, 0x30, 0x46, 0x51, 0x46, + 0x08, 0xf0, 0x31, 0xfe, 0x06, 0x46, 0xdf, 0xf8, 0xd8, 0x25, 0x24, 0x09, + 0x00, 0x0f, 0x44, 0xea, 0x07, 0x74, 0x40, 0xea, 0x01, 0x10, 0x14, 0x60, + 0x40, 0xf4, 0x00, 0x40, 0x10, 0x81, 0x30, 0x01, 0x50, 0x60, 0x01, 0x20, + 0xbd, 0xe8, 0xf2, 0x8f, 0xdf, 0xf8, 0xb8, 0x15, 0x08, 0x80, 0x70, 0x47, + 0x4f, 0xf0, 0x82, 0x41, 0x02, 0x68, 0x0a, 0x60, 0x42, 0x68, 0x4a, 0x60, + 0x02, 0x89, 0x0a, 0x81, 0x42, 0x89, 0x4a, 0x81, 0x82, 0x89, 0x8a, 0x81, + 0xc2, 0x89, 0xca, 0x87, 0xdf, 0xf8, 0x98, 0x15, 0x02, 0x8a, 0x0a, 0x80, + 0x40, 0x8a, 0x48, 0x80, 0x00, 0x21, 0xdf, 0xf8, 0x90, 0x05, 0x41, 0x80, + 0x81, 0x82, 0xc1, 0x82, 0x1f, 0x21, 0x01, 0x80, 0x00, 0x21, 0x81, 0x80, + 0xc1, 0x80, 0x70, 0x47, 0x38, 0xb5, 0x0c, 0x46, 0x01, 0xf0, 0x8a, 0xfe, + 0xdf, 0xf8, 0x74, 0x15, 0x02, 0xf0, 0x24, 0xf8, 0x05, 0x46, 0x20, 0x46, + 0x01, 0xf0, 0x82, 0xfe, 0x29, 0x46, 0x02, 0xf0, 0x1d, 0xf8, 0xdf, 0xf8, + 0x64, 0x15, 0x01, 0xf0, 0x8b, 0xfe, 0x08, 0xf0, 0x17, 0xff, 0x04, 0x46, + 0x03, 0xf0, 0xab, 0xf8, 0x20, 0x28, 0x28, 0xbf, 0x1f, 0x20, 0x01, 0x21, + 0x01, 0xfa, 0x00, 0xf2, 0x43, 0x1e, 0xa2, 0x1a, 0x99, 0x40, 0x8a, 0x42, + 0x28, 0xbf, 0x40, 0xf0, 0x20, 0x00, 0x80, 0xb2, 0x32, 0xbd, 0x00, 0xf0, + 0x1f, 0x01, 0x01, 0x22, 0x8a, 0x40, 0xc0, 0xf3, 0x40, 0x10, 0x49, 0x1e, + 0x88, 0x40, 0x80, 0x18, 0x70, 0x47, 0xdf, 0xf8, 0x24, 0x25, 0x4f, 0xf6, + 0xff, 0x73, 0x13, 0x81, 0x01, 0xb1, 0x04, 0x21, 0x00, 0xf0, 0x03, 0x00, + 0x08, 0x18, 0x00, 0x02, 0x40, 0xf4, 0x10, 0x40, 0x10, 0x80, 0x70, 0x47, + 0xdf, 0xf8, 0x04, 0x05, 0x01, 0x88, 0x01, 0xf4, 0x73, 0x61, 0x41, 0xf0, + 0x80, 0x01, 0x01, 0x80, 0x70, 0x47, 0xf0, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x83, 0xb0, 0x00, 0xf0, 0x0c, 0xf9, 0xdf, 0xf8, 0xec, 0x64, 0xdf, 0xf8, + 0xec, 0x74, 0xff, 0xf7, 0x3b, 0xfa, 0x30, 0x60, 0x06, 0x21, 0x03, 0x20, + 0x03, 0xf0, 0x8d, 0xf8, 0x4f, 0xf6, 0xff, 0x70, 0xb8, 0x80, 0x4f, 0xf6, + 0xf5, 0x30, 0xb8, 0x81, 0x03, 0x20, 0x03, 0xf0, 0x69, 0xf8, 0x03, 0x20, + 0x03, 0xf0, 0x6c, 0xf8, 0x30, 0x68, 0x00, 0xf0, 0xed, 0xf8, 0x29, 0x46, + 0xe0, 0xb2, 0xff, 0xf7, 0xc4, 0xff, 0x01, 0xa8, 0x00, 0x90, 0x41, 0xf2, + 0x88, 0x33, 0x30, 0x68, 0x03, 0x22, 0x05, 0x21, 0xfd, 0xf7, 0x22, 0xfa, + 0x39, 0x88, 0xc0, 0x07, 0x04, 0xd5, 0x2f, 0x20, 0x03, 0xf0, 0xcf, 0xf8, + 0x01, 0x24, 0x0d, 0xe0, 0x40, 0xf2, 0x0a, 0x40, 0x08, 0x40, 0x02, 0x28, + 0x04, 0xd1, 0x30, 0x20, 0x03, 0xf0, 0xc5, 0xf8, 0x00, 0x24, 0x03, 0xe0, + 0x31, 0x20, 0x03, 0xf0, 0xc0, 0xf8, 0x03, 0x24, 0x00, 0xf0, 0x68, 0xf8, + 0x03, 0x20, 0x03, 0xf0, 0x4a, 0xf8, 0x00, 0x21, 0x00, 0xf0, 0xc8, 0xf8, + 0x20, 0x46, 0xfe, 0xbd, 0x00, 0x28, 0x08, 0xd5, 0xdf, 0xf8, 0x60, 0x34, + 0x40, 0x42, 0x53, 0xf8, 0x20, 0x30, 0x13, 0x60, 0xdf, 0xf8, 0x58, 0x24, + 0x06, 0xe0, 0xdf, 0xf8, 0x58, 0x34, 0x53, 0xf8, 0x20, 0x30, 0x13, 0x60, + 0xdf, 0xf8, 0x50, 0x24, 0x52, 0xf8, 0x20, 0x00, 0x08, 0x60, 0x70, 0x47, + 0xdf, 0xf8, 0x48, 0x14, 0xdf, 0xf8, 0x48, 0x34, 0x08, 0x22, 0x0a, 0x80, + 0x00, 0x22, 0x4a, 0x83, 0x8a, 0x83, 0x00, 0x21, 0xdf, 0xf8, 0x3c, 0x24, + 0x11, 0x80, 0x30, 0xf8, 0x11, 0x20, 0x23, 0xf8, 0x11, 0x20, 0x49, 0x1c, + 0x18, 0x29, 0xf8, 0xd3, 0xdf, 0xf8, 0x2c, 0x14, 0x42, 0x8e, 0x0a, 0x80, + 0xc2, 0x8e, 0x4a, 0x82, 0x02, 0x8f, 0x8a, 0x82, 0x42, 0x8f, 0xca, 0x82, + 0x82, 0x8f, 0x0a, 0x83, 0xc2, 0x8f, 0x4a, 0x83, 0xb0, 0xf8, 0x40, 0x00, + 0x88, 0x83, 0x00, 0x20, 0x48, 0x80, 0x88, 0x80, 0x70, 0x47, 0x10, 0xb5, + 0x01, 0xb1, 0x04, 0x21, 0x00, 0xf0, 0x03, 0x00, 0x08, 0x18, 0xdf, 0xf8, + 0xd0, 0x13, 0xdf, 0xf8, 0xc0, 0x33, 0x00, 0x02, 0x08, 0x80, 0x40, 0xf4, + 0x30, 0x40, 0x94, 0x8e, 0x5c, 0x82, 0x40, 0xf0, 0x40, 0x00, 0x4f, 0xf6, + 0xff, 0x74, 0x0c, 0x81, 0x9c, 0x8a, 0x44, 0xf4, 0x7f, 0x44, 0x9c, 0x82, + 0x1c, 0x8b, 0x44, 0xf4, 0x00, 0x44, 0x1c, 0x83, 0x12, 0x8e, 0x1a, 0x80, + 0x08, 0x80, 0x10, 0xbd, 0xdf, 0xf8, 0x98, 0x03, 0x01, 0x88, 0x01, 0xf4, + 0x73, 0x61, 0x41, 0xf4, 0x03, 0x51, 0x01, 0x80, 0x70, 0x47, 0x2d, 0xe9, + 0xfc, 0x41, 0x06, 0x46, 0x0f, 0x46, 0x90, 0x46, 0x00, 0xf0, 0x55, 0xf8, + 0xdf, 0xf8, 0x7c, 0x43, 0xdf, 0xf8, 0x7c, 0x53, 0xff, 0xf7, 0x84, 0xf9, + 0x20, 0x60, 0x06, 0x21, 0x03, 0x20, 0x02, 0xf0, 0xd6, 0xff, 0x4f, 0xf6, + 0xff, 0x70, 0xa8, 0x80, 0x4f, 0xf6, 0x35, 0x30, 0xa8, 0x81, 0x03, 0x20, + 0x02, 0xf0, 0xb2, 0xff, 0x03, 0x20, 0x02, 0xf0, 0xb5, 0xff, 0x42, 0x46, + 0x39, 0x46, 0x30, 0x46, 0xff, 0xf7, 0xb3, 0xff, 0x01, 0xa8, 0x00, 0x90, + 0x41, 0xf2, 0x88, 0x33, 0x20, 0x68, 0x03, 0x22, 0x05, 0x21, 0xfd, 0xf7, + 0x6d, 0xf9, 0x02, 0x46, 0x28, 0x88, 0xd2, 0x07, 0x04, 0xd5, 0x2f, 0x20, + 0x03, 0xf0, 0x19, 0xf8, 0x01, 0x25, 0x13, 0xe0, 0x4f, 0xf4, 0x99, 0x62, + 0x10, 0x42, 0x04, 0xd0, 0x31, 0x20, 0x03, 0xf0, 0x10, 0xf8, 0x02, 0x25, + 0x0a, 0xe0, 0x80, 0x07, 0x04, 0xd5, 0x30, 0x20, 0x03, 0xf0, 0x09, 0xf8, + 0x00, 0x25, 0x03, 0xe0, 0x31, 0x20, 0x03, 0xf0, 0x04, 0xf8, 0x03, 0x25, + 0xff, 0xf7, 0xac, 0xff, 0x03, 0x20, 0x02, 0xf0, 0x8e, 0xff, 0x20, 0x68, + 0x00, 0xf0, 0x06, 0xf8, 0x00, 0x21, 0x00, 0xf0, 0x09, 0xf8, 0x28, 0x46, + 0xbd, 0xe8, 0xf6, 0x81, 0x01, 0xab, 0x00, 0x22, 0x04, 0x21, 0xfd, 0xf7, + 0xc9, 0xb9, 0x01, 0x21, 0x2d, 0x20, 0x02, 0xf0, 0xfc, 0xbf, 0x00, 0xf5, + 0x4a, 0x70, 0x00, 0x23, 0x03, 0x60, 0x01, 0x71, 0x42, 0x71, 0x70, 0x47, + 0x30, 0xb5, 0x00, 0x24, 0x00, 0x23, 0x50, 0xf8, 0x24, 0x20, 0x01, 0xeb, + 0xc4, 0x05, 0x64, 0x1c, 0xc5, 0xe9, 0x00, 0x23, 0x18, 0x2c, 0xf6, 0xd3, + 0x30, 0xbd, 0x30, 0xb5, 0x00, 0x24, 0x50, 0xf8, 0x24, 0x20, 0x01, 0xeb, + 0xc4, 0x05, 0xd3, 0x17, 0xc5, 0xe9, 0x00, 0x23, 0x64, 0x1c, 0x18, 0x2c, + 0xf5, 0xd3, 0x30, 0xbd, 0x70, 0xb5, 0x02, 0x46, 0x0b, 0x46, 0x00, 0x26, + 0x03, 0xeb, 0xc6, 0x00, 0x00, 0x21, 0xd0, 0xe9, 0x00, 0x45, 0x52, 0xf8, + 0x26, 0x00, 0x00, 0xf0, 0x11, 0xf8, 0xf5, 0xd3, 0x70, 0xbd, 0x70, 0xb5, + 0x02, 0x46, 0x0b, 0x46, 0x00, 0x26, 0x03, 0xeb, 0xc6, 0x00, 0xd0, 0xe9, + 0x00, 0x45, 0x52, 0xf8, 0x26, 0x00, 0xc1, 0x17, 0x00, 0xf0, 0x02, 0xf8, + 0xf5, 0xd3, 0x70, 0xbd, 0x20, 0x18, 0x03, 0xeb, 0xc6, 0x04, 0x69, 0x41, + 0xc4, 0xe9, 0x00, 0x01, 0x76, 0x1c, 0x18, 0x2e, 0x70, 0x47, 0x2d, 0xe9, + 0xf0, 0x47, 0x04, 0x46, 0x04, 0xf5, 0x16, 0x75, 0xd4, 0xf8, 0x28, 0x13, + 0xdf, 0xf8, 0x3c, 0x82, 0xdf, 0xf8, 0x3c, 0x92, 0xdf, 0xf8, 0x2c, 0xa2, + 0xdf, 0xf8, 0x2c, 0x02, 0x00, 0x29, 0x04, 0xf5, 0xc8, 0x76, 0x04, 0xf1, + 0xc8, 0x07, 0x21, 0x46, 0x11, 0xd0, 0xff, 0xf7, 0xc1, 0xff, 0x39, 0x46, + 0x50, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x31, 0x46, 0x48, 0x46, 0xff, 0xf7, + 0xc8, 0xff, 0x29, 0x46, 0x40, 0x46, 0xff, 0xf7, 0xc4, 0xff, 0xd4, 0xf8, + 0x28, 0x03, 0x40, 0x1c, 0x0e, 0xe0, 0xff, 0xf7, 0x95, 0xff, 0x39, 0x46, + 0x50, 0x46, 0xff, 0xf7, 0x91, 0xff, 0x31, 0x46, 0x48, 0x46, 0xff, 0xf7, + 0x9a, 0xff, 0x29, 0x46, 0x40, 0x46, 0xff, 0xf7, 0x96, 0xff, 0x01, 0x20, + 0xc4, 0xf8, 0x28, 0x03, 0xbd, 0xe8, 0xf0, 0x87, 0xc1, 0xb2, 0x01, 0xeb, + 0x10, 0x20, 0x70, 0x47, 0xf0, 0xb5, 0x4b, 0x6e, 0x03, 0x66, 0x01, 0x22, + 0x00, 0x24, 0x00, 0x25, 0x00, 0x23, 0x17, 0x26, 0x02, 0x27, 0x0a, 0xe0, + 0x01, 0xeb, 0x83, 0x0c, 0xdc, 0xf8, 0x04, 0xc0, 0xa4, 0x45, 0xd8, 0xbf, + 0x64, 0x46, 0x65, 0x45, 0xb8, 0xbf, 0x65, 0x46, 0x5b, 0x1c, 0x9e, 0x42, + 0xf2, 0xd2, 0x19, 0x23, 0x2f, 0x26, 0x7f, 0x1e, 0xf9, 0xd1, 0x23, 0x46, + 0x2c, 0x46, 0x6f, 0xf3, 0x0b, 0x04, 0xb4, 0xf1, 0x00, 0x6f, 0x6f, 0xf3, + 0x0b, 0x03, 0x04, 0xdc, 0x13, 0xf1, 0x00, 0x6f, 0x04, 0xdb, 0x00, 0x24, + 0x17, 0xe0, 0xb4, 0xf1, 0x80, 0x5f, 0x05, 0xda, 0x13, 0xf1, 0x80, 0x5f, + 0x05, 0xdb, 0x01, 0x24, 0x01, 0x25, 0x13, 0xe0, 0xb4, 0xf1, 0x00, 0x5f, + 0x04, 0xda, 0x13, 0xf1, 0x00, 0x5f, 0x04, 0xdb, 0x02, 0x24, 0x06, 0xe0, + 0xb4, 0xf1, 0x80, 0x4f, 0x05, 0xda, 0x13, 0xf1, 0x80, 0x4f, 0x02, 0xdb, + 0x03, 0x24, 0x25, 0x46, 0x02, 0xe0, 0x03, 0x24, 0x03, 0x25, 0x00, 0x22, + 0x00, 0x23, 0x17, 0x26, 0x02, 0x27, 0x08, 0xe0, 0x01, 0xeb, 0x83, 0x0c, + 0xdc, 0xf8, 0x04, 0xc0, 0x4c, 0xfa, 0x05, 0xfc, 0x40, 0xf8, 0x23, 0xc0, + 0x5b, 0x1c, 0x9e, 0x42, 0xf4, 0xd2, 0x19, 0x23, 0x2f, 0x26, 0x7f, 0x1e, + 0xf9, 0xd1, 0x44, 0xf0, 0x30, 0x03, 0x20, 0xf8, 0xc0, 0x3f, 0x09, 0x68, + 0x41, 0x60, 0x10, 0x46, 0xf0, 0xbd, 0x3e, 0xb5, 0x0f, 0xf2, 0x34, 0x12, + 0x38, 0xca, 0x69, 0x46, 0x03, 0x28, 0x38, 0xc1, 0x34, 0xbf, 0x5d, 0xf8, + 0x20, 0x00, 0x00, 0x20, 0x3e, 0xbd, 0x70, 0xb5, 0x0f, 0xf2, 0x10, 0x13, + 0x84, 0xb0, 0x70, 0xcb, 0x6a, 0x46, 0x03, 0x28, 0x70, 0xc2, 0x11, 0xd2, + 0x5d, 0xf8, 0x20, 0x00, 0x01, 0xfa, 0x00, 0xf2, 0x03, 0x23, 0x03, 0xfa, + 0x00, 0xf0, 0x19, 0x42, 0x40, 0xf0, 0xc0, 0x00, 0x06, 0xd0, 0x81, 0xb2, + 0x92, 0xb2, 0x24, 0x48, 0x00, 0xf0, 0xaf, 0xf8, 0x01, 0x20, 0x00, 0xe0, + 0x00, 0x20, 0x04, 0xb0, 0x70, 0xbd, 0x20, 0x49, 0x09, 0x88, 0x01, 0x80, + 0x32, 0x49, 0x09, 0x88, 0x41, 0x80, 0x70, 0x47, 0x10, 0xb5, 0x04, 0x46, + 0x1b, 0x48, 0x21, 0x88, 0x00, 0xf0, 0xfa, 0xf8, 0x61, 0x88, 0x2d, 0x48, + 0xbd, 0xe8, 0x10, 0x40, 0x00, 0xf0, 0xf4, 0xb8, 0x10, 0xb5, 0x00, 0x03, + 0x0c, 0x46, 0x00, 0xf4, 0x40, 0x52, 0x4f, 0xf4, 0x40, 0x51, 0x13, 0x48, + 0x00, 0xf0, 0xfa, 0xf8, 0x04, 0xf0, 0x3c, 0x01, 0xbd, 0xe8, 0x10, 0x40, + 0xff, 0xe7, 0x23, 0x48, 0x00, 0xf0, 0xe2, 0xb8, 0x80, 0xb5, 0x22, 0x49, + 0x4f, 0xf6, 0xff, 0x70, 0x08, 0x80, 0x6b, 0x46, 0x14, 0x48, 0x00, 0x68, + 0x01, 0x22, 0x04, 0x21, 0xfd, 0xf7, 0x82, 0xf8, 0x01, 0xbd, 0x00, 0x00, + 0x80, 0xf3, 0x00, 0x20, 0x00, 0xf2, 0x00, 0x20, 0x01, 0xd0, 0x12, 0x13, + 0xfc, 0x01, 0x00, 0x41, 0xc0, 0x02, 0x00, 0x41, 0xc0, 0x06, 0x00, 0x41, + 0xc0, 0x04, 0x00, 0x41, 0x02, 0x08, 0x00, 0x41, 0x08, 0xef, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0x40, 0x00, 0x00, 0x41, 0x0c, 0x00, 0x00, 0x41, + 0x58, 0x00, 0x00, 0x41, 0xb0, 0x00, 0x00, 0x41, 0xbd, 0x37, 0x86, 0x35, + 0x00, 0x00, 0x40, 0x42, 0x00, 0x08, 0x00, 0x41, 0x7c, 0xf3, 0x00, 0x20, + 0x08, 0x08, 0x00, 0x41, 0x00, 0x16, 0x00, 0x41, 0x80, 0x16, 0x00, 0x41, + 0x00, 0x17, 0x00, 0x41, 0x80, 0x17, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x41, + 0x80, 0x00, 0x00, 0x41, 0x04, 0x08, 0x00, 0x41, 0xb2, 0x00, 0x00, 0x41, + 0xfe, 0x01, 0x00, 0x41, 0x14, 0x08, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x41, + 0x00, 0x04, 0x00, 0x41, 0x00, 0x06, 0x00, 0x41, 0xdf, 0xf8, 0x10, 0x14, + 0x28, 0x22, 0x02, 0xfb, 0x00, 0x10, 0x81, 0x7f, 0xc2, 0x7f, 0x90, 0xf8, + 0x20, 0x00, 0x41, 0xea, 0x02, 0x21, 0x41, 0xea, 0x00, 0x40, 0x70, 0x47, + 0xdf, 0xf8, 0xf4, 0x13, 0x28, 0x22, 0x02, 0xfb, 0x00, 0x10, 0x10, 0xf8, + 0x21, 0x1f, 0x40, 0x78, 0x00, 0xf0, 0x07, 0x00, 0x41, 0xea, 0x00, 0x20, + 0x70, 0x47, 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, + 0xdf, 0xf8, 0xd4, 0x13, 0xdf, 0xf8, 0xd4, 0x33, 0x09, 0x68, 0x4f, 0xf0, + 0x00, 0x42, 0x1a, 0x60, 0x70, 0x47, 0xdf, 0xf8, 0xc4, 0x33, 0x01, 0xf0, + 0x00, 0x42, 0x1a, 0x60, 0x80, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x70, 0xb5, + 0x00, 0xf0, 0x56, 0xf8, 0x00, 0xf0, 0x79, 0xf8, 0xbd, 0xe8, 0x70, 0x40, + 0xef, 0xe7, 0x2d, 0xe9, 0xf0, 0x41, 0x06, 0x46, 0x88, 0x46, 0xff, 0xf7, + 0xdc, 0xff, 0x00, 0xf0, 0x36, 0xf8, 0x20, 0xb1, 0x41, 0x46, 0x30, 0x46, + 0xfd, 0xf7, 0x3e, 0xfe, 0x01, 0x27, 0x20, 0x46, 0x29, 0x46, 0xff, 0xf7, + 0xde, 0xff, 0x38, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0xf8, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x16, 0x46, 0x01, 0x20, 0x00, 0x27, 0x00, 0xe0, 0x7f, 0x1c, + 0xb7, 0x42, 0x06, 0xd2, 0x79, 0x5d, 0x34, 0xf8, 0x17, 0x00, 0xff, 0xf7, + 0xdc, 0xff, 0x00, 0x28, 0xf5, 0xd1, 0xf2, 0xbd, 0x2d, 0xe9, 0xf8, 0x43, + 0x06, 0x46, 0x89, 0x46, 0x90, 0x46, 0xff, 0xf7, 0xb4, 0xff, 0x00, 0xf0, + 0x0e, 0xf8, 0x28, 0xb1, 0x42, 0x46, 0x49, 0x46, 0x30, 0x46, 0xfd, 0xf7, + 0x1f, 0xfe, 0x01, 0x27, 0x20, 0x46, 0x29, 0x46, 0xff, 0xf7, 0xb5, 0xff, + 0x38, 0x46, 0xbd, 0xe8, 0xf2, 0x83, 0x04, 0x46, 0xdf, 0xf8, 0x2c, 0x03, + 0x00, 0x78, 0x00, 0x27, 0x0d, 0x46, 0x70, 0x47, 0x70, 0xb5, 0x00, 0xf0, + 0x06, 0xf8, 0x00, 0xf0, 0x17, 0xf8, 0x0a, 0xb1, 0x25, 0x70, 0x01, 0x26, + 0x0e, 0xe0, 0x04, 0x46, 0x0d, 0x46, 0x90, 0xe7, 0x04, 0x46, 0x0d, 0x46, + 0x16, 0x46, 0x8c, 0xe7, 0x70, 0xb5, 0xff, 0xf7, 0xf6, 0xff, 0x00, 0xf0, + 0x07, 0xf8, 0x0a, 0xb1, 0x25, 0x80, 0x01, 0x26, 0xff, 0xf7, 0x91, 0xff, + 0x30, 0x46, 0x70, 0xbd, 0xba, 0x4a, 0x12, 0x78, 0x00, 0x26, 0x70, 0x47, + 0xf8, 0xb5, 0xff, 0xf7, 0xe9, 0xff, 0x00, 0xf0, 0x08, 0xf8, 0x12, 0xb1, + 0x00, 0xf0, 0x09, 0xf8, 0x01, 0x27, 0xff, 0xf7, 0x80, 0xff, 0x38, 0x46, + 0xf2, 0xbd, 0xb2, 0x4a, 0x12, 0x78, 0x00, 0x27, 0x70, 0x47, 0x22, 0x88, + 0xaa, 0x43, 0x05, 0xea, 0x06, 0x03, 0x1a, 0x43, 0x22, 0x80, 0x70, 0x47, + 0x70, 0xb5, 0xff, 0xf7, 0xce, 0xff, 0xff, 0xf7, 0xdf, 0xff, 0x0a, 0xb1, + 0x25, 0x60, 0x01, 0x26, 0xd6, 0xe7, 0x10, 0xb5, 0x04, 0x46, 0x04, 0x22, + 0x21, 0x46, 0x0f, 0xf2, 0xb4, 0x20, 0xfd, 0xf7, 0xee, 0xfd, 0x01, 0x22, + 0x21, 0x1d, 0x0f, 0xf2, 0xb0, 0x20, 0xfd, 0xf7, 0xe8, 0xfd, 0xa2, 0x48, + 0x00, 0x68, 0xa0, 0x60, 0x10, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x04, 0x22, 0x21, 0x46, 0x0f, 0xf2, 0x8c, 0x20, 0xff, 0xf7, 0x74, 0xff, + 0x55, 0xb9, 0xa0, 0x68, 0x9a, 0x49, 0x08, 0x60, 0x21, 0x1d, 0xbd, 0xe8, + 0x38, 0x40, 0x01, 0x22, 0x0f, 0xf2, 0x7c, 0x20, 0xfd, 0xf7, 0xbc, 0xbd, + 0x31, 0xbd, 0x38, 0xb5, 0x20, 0xb9, 0x01, 0x24, 0x40, 0xf6, 0x12, 0x05, + 0x80, 0x21, 0x03, 0xe0, 0x02, 0x24, 0x40, 0xf6, 0x13, 0x05, 0x40, 0x21, + 0x00, 0x22, 0x40, 0xf6, 0x14, 0x00, 0xff, 0xf7, 0x69, 0xff, 0x00, 0x22, + 0xc0, 0x21, 0x28, 0x46, 0xff, 0xf7, 0x64, 0xff, 0x21, 0x46, 0x4f, 0xf4, + 0x82, 0x70, 0xff, 0xf7, 0x38, 0xff, 0xbd, 0xe8, 0x38, 0x40, 0x00, 0x22, + 0x33, 0x21, 0x4f, 0xf4, 0xa9, 0x60, 0x57, 0xe7, 0x80, 0xb5, 0x85, 0x48, + 0x01, 0x6d, 0x03, 0x20, 0x01, 0xf0, 0x0e, 0xfa, 0x03, 0x20, 0x01, 0xf0, + 0x23, 0xfa, 0x18, 0xb9, 0xff, 0xf7, 0x45, 0xf8, 0x00, 0x28, 0xf7, 0xd0, + 0xbd, 0xe8, 0x02, 0x40, 0x03, 0x20, 0x01, 0xf0, 0x91, 0xb9, 0x77, 0x48, + 0x90, 0xf8, 0x43, 0x20, 0x04, 0xe0, 0x75, 0x48, 0x90, 0xf8, 0x6b, 0x00, + 0x40, 0xf0, 0x20, 0x02, 0x3f, 0x21, 0x40, 0xf6, 0x15, 0x00, 0x37, 0xe7, + 0x2d, 0xe9, 0xf1, 0x4f, 0x84, 0xb0, 0x07, 0xf0, 0x0c, 0xfd, 0x01, 0x20, + 0xff, 0xf7, 0xde, 0xfe, 0x04, 0x46, 0x01, 0x20, 0xff, 0xf7, 0xcc, 0xfe, + 0x82, 0x46, 0x03, 0x20, 0xff, 0xf7, 0xd6, 0xfe, 0x05, 0x46, 0x03, 0x20, + 0xff, 0xf7, 0xc4, 0xfe, 0x06, 0x46, 0x6c, 0x48, 0x6c, 0x4a, 0x41, 0x78, + 0x00, 0x78, 0x13, 0x78, 0x40, 0xea, 0x01, 0x20, 0x40, 0x05, 0x40, 0x0d, + 0x01, 0x21, 0x03, 0xf0, 0x03, 0x07, 0x02, 0x2f, 0x4f, 0xf0, 0x00, 0x0b, + 0x08, 0xbf, 0x02, 0x21, 0x02, 0xd0, 0x03, 0x2f, 0x08, 0xbf, 0x04, 0x21, + 0xdf, 0x06, 0x48, 0xbf, 0x49, 0x00, 0x9b, 0x06, 0x48, 0xbf, 0x49, 0x00, + 0x52, 0x78, 0x52, 0x07, 0x4c, 0xbf, 0x01, 0xeb, 0x81, 0x01, 0x89, 0x00, + 0x00, 0x91, 0x02, 0x27, 0x54, 0x49, 0x91, 0xf8, 0x89, 0x20, 0x91, 0xf8, + 0x39, 0x10, 0x8b, 0x1a, 0x01, 0x2b, 0x03, 0xdb, 0x07, 0xfa, 0x01, 0xf1, + 0x01, 0x27, 0x08, 0xe0, 0x00, 0x2b, 0x03, 0xd5, 0x59, 0x42, 0x8c, 0x40, + 0x0a, 0xfa, 0x01, 0xfa, 0x07, 0xfa, 0x02, 0xf1, 0x00, 0x27, 0x05, 0xfa, + 0x07, 0xf2, 0xa2, 0x1a, 0x50, 0x4b, 0x03, 0xfb, 0x02, 0xa2, 0x01, 0x92, + 0x48, 0x43, 0x01, 0x9b, 0x00, 0x9a, 0xc1, 0x17, 0x06, 0xfa, 0x07, 0xf4, + 0xcd, 0xe9, 0x02, 0x01, 0x1b, 0x1b, 0x83, 0xfb, 0x02, 0x89, 0x00, 0x25, + 0x07, 0xe0, 0xae, 0x19, 0x01, 0x99, 0x00, 0x98, 0x06, 0xfa, 0x07, 0xf2, + 0x89, 0x1a, 0x81, 0xfb, 0x00, 0x89, 0xdd, 0xe9, 0x02, 0x23, 0x40, 0x46, + 0x49, 0x46, 0x01, 0xf0, 0xf9, 0xfe, 0xdd, 0xe9, 0x02, 0x23, 0x04, 0x46, + 0x8a, 0x46, 0xa2, 0xfb, 0x04, 0x01, 0x02, 0xfb, 0x0a, 0x11, 0x03, 0xfb, + 0x04, 0x11, 0xb8, 0xeb, 0x00, 0x00, 0x79, 0xeb, 0x01, 0x01, 0x08, 0xbf, + 0x00, 0x28, 0x08, 0xd0, 0x00, 0x2d, 0xde, 0xd1, 0x38, 0x48, 0x86, 0x42, + 0xac, 0xbf, 0x4f, 0xf0, 0xff, 0x35, 0x01, 0x25, 0xd7, 0xe7, 0xb5, 0xb1, + 0x30, 0x02, 0x01, 0x0e, 0x40, 0xf2, 0x45, 0x30, 0xff, 0xf7, 0x81, 0xfe, + 0x30, 0x04, 0x01, 0x0e, 0x4f, 0xf4, 0x51, 0x70, 0xff, 0xf7, 0x7b, 0xfe, + 0xf1, 0xb2, 0x40, 0xf2, 0x43, 0x30, 0xff, 0xf7, 0x76, 0xfe, 0x00, 0x22, + 0x00, 0x21, 0x40, 0xf2, 0x41, 0x30, 0xff, 0xf7, 0x97, 0xfe, 0x60, 0x42, + 0x00, 0x02, 0x23, 0x4e, 0x00, 0x0a, 0x40, 0xf0, 0x40, 0x70, 0x30, 0x60, + 0x20, 0x22, 0x4f, 0xf4, 0x80, 0x50, 0x70, 0x60, 0x20, 0x21, 0x40, 0xf6, + 0x15, 0x00, 0xff, 0xf7, 0x87, 0xfe, 0x00, 0x22, 0x01, 0x21, 0x4f, 0xf4, + 0x60, 0x70, 0xfd, 0xf7, 0xaf, 0xfc, 0x04, 0x98, 0x01, 0x28, 0x23, 0xdb, + 0x30, 0x68, 0x04, 0x99, 0x20, 0xf0, 0xf0, 0x40, 0x40, 0xea, 0xc1, 0x60, + 0x40, 0xf0, 0x80, 0x60, 0x30, 0x60, 0x4f, 0xf4, 0x7a, 0x71, 0x03, 0x20, + 0x01, 0xf0, 0x2c, 0xf9, 0x30, 0x68, 0x40, 0x01, 0x07, 0xd5, 0x03, 0x20, + 0x01, 0xf0, 0x3e, 0xf9, 0x18, 0xb9, 0xfe, 0xf7, 0x60, 0xff, 0x00, 0x28, + 0xf4, 0xd0, 0x30, 0x68, 0x40, 0x01, 0x04, 0xd5, 0xfe, 0xf7, 0x59, 0xff, + 0x08, 0xb9, 0x4f, 0xf0, 0x01, 0x0b, 0x03, 0x20, 0x01, 0xf0, 0xa6, 0xf8, + 0x58, 0x46, 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x68, 0xee, 0x00, 0x20, + 0x00, 0xe1, 0x00, 0xe0, 0x80, 0xe1, 0x00, 0xe0, 0x65, 0x2c, 0x00, 0x20, + 0x10, 0x00, 0x00, 0x45, 0x4c, 0x1f, 0x00, 0x20, 0x41, 0x01, 0x00, 0x46, + 0x01, 0x01, 0x00, 0x46, 0x00, 0xf8, 0x7f, 0x00, 0x01, 0xfc, 0x3f, 0x00, + 0x48, 0x05, 0x12, 0x08, 0x13, 0x08, 0x14, 0x08, 0x80, 0x03, 0x00, 0x00, + 0x10, 0xb5, 0x00, 0x24, 0x00, 0x21, 0xe0, 0xb2, 0x00, 0xf0, 0xad, 0xf8, + 0x01, 0x21, 0xe0, 0xb2, 0x00, 0xf0, 0xe1, 0xf8, 0x64, 0x1c, 0x02, 0x2c, + 0xf4, 0xd3, 0x10, 0xbd, 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0xff, 0xf7, + 0xe4, 0xfe, 0x00, 0x2c, 0x0c, 0xbf, 0x01, 0x21, 0x10, 0x21, 0x40, 0xf2, + 0x49, 0x50, 0xfd, 0xf7, 0x45, 0xfc, 0x2e, 0x00, 0x18, 0xbf, 0x01, 0x2d, + 0x04, 0xd1, 0x7e, 0x21, 0x40, 0xf2, 0x0b, 0x20, 0xfd, 0xf7, 0x3c, 0xfc, + 0x00, 0x2c, 0x0c, 0xbf, 0x00, 0x20, 0x04, 0x20, 0x05, 0xf0, 0x03, 0x01, + 0x01, 0xfa, 0x00, 0xf2, 0x03, 0x21, 0x81, 0x40, 0xd2, 0xb2, 0xc9, 0xb2, + 0x4f, 0xf4, 0xa9, 0x60, 0xff, 0xf7, 0x08, 0xfe, 0x01, 0x2d, 0x18, 0xbf, + 0x02, 0x2d, 0x10, 0xd1, 0x00, 0x2c, 0x07, 0xbf, 0x08, 0x24, 0x40, 0xf2, + 0x42, 0x50, 0x10, 0x24, 0x40, 0xf2, 0x43, 0x50, 0x00, 0x22, 0xc0, 0x21, + 0xff, 0xf7, 0xf8, 0xfd, 0x21, 0x46, 0x4f, 0xf4, 0x82, 0x70, 0xff, 0xf7, + 0xcc, 0xfd, 0x01, 0x20, 0x70, 0xbd, 0xff, 0xf7, 0x97, 0xbe, 0x00, 0xb1, + 0x04, 0x20, 0x41, 0x49, 0x09, 0x78, 0xc1, 0x40, 0x01, 0xf0, 0x03, 0x00, + 0x70, 0x47, 0x10, 0xb5, 0x02, 0x46, 0x00, 0x21, 0x53, 0x68, 0x18, 0x46, + 0x01, 0xf0, 0xca, 0xfb, 0x08, 0xd2, 0x10, 0x68, 0x3a, 0x4c, 0x19, 0x46, + 0x01, 0xf0, 0x2e, 0xf9, 0x20, 0x60, 0x00, 0x20, 0xc4, 0xe9, 0x02, 0x00, + 0x10, 0xbd, 0x38, 0xb5, 0x36, 0x4a, 0x35, 0x4d, 0xd2, 0xe9, 0x08, 0x01, + 0xd5, 0xe9, 0x02, 0x23, 0x99, 0x42, 0x08, 0xbf, 0x90, 0x42, 0x3f, 0xd0, + 0xc5, 0xe9, 0x02, 0x01, 0x31, 0x4a, 0x00, 0x23, 0x01, 0xf0, 0x16, 0xfe, + 0x00, 0x24, 0x80, 0xb2, 0xb0, 0xf5, 0x95, 0x7f, 0xb8, 0xbf, 0xff, 0x24, + 0x1a, 0xdb, 0xb0, 0xf5, 0xd5, 0x6f, 0x17, 0xdc, 0x40, 0xf2, 0x29, 0x11, + 0x40, 0x1a, 0x00, 0xb2, 0x41, 0x11, 0x00, 0xeb, 0x91, 0x61, 0x89, 0x02, + 0x09, 0x0c, 0x0f, 0xf2, 0x74, 0x12, 0x8b, 0x5c, 0xa0, 0xeb, 0x81, 0x10, + 0x89, 0x18, 0x00, 0xb2, 0x49, 0x78, 0x59, 0x1a, 0x48, 0x43, 0x41, 0x11, + 0x00, 0xeb, 0x91, 0x60, 0xa3, 0xeb, 0xa0, 0x14, 0xe0, 0xb2, 0x01, 0xf0, + 0xe3, 0xf8, 0x29, 0x68, 0x01, 0xf0, 0x7e, 0xfa, 0x01, 0xf0, 0xe8, 0xfa, + 0x84, 0xb2, 0xff, 0x2c, 0xc8, 0xbf, 0xff, 0x24, 0xe1, 0xb2, 0x40, 0xf2, + 0x44, 0x50, 0xfd, 0xf7, 0xb5, 0xfb, 0xe1, 0xb2, 0xbd, 0xe8, 0x34, 0x40, + 0x40, 0xf2, 0x45, 0x50, 0xfd, 0xf7, 0xae, 0xbb, 0x31, 0xbd, 0x00, 0x28, + 0x0c, 0xbf, 0x40, 0xf2, 0x46, 0x50, 0x40, 0xf2, 0x47, 0x50, 0x01, 0xf0, + 0x03, 0x02, 0x03, 0x21, 0xfd, 0xf7, 0xac, 0xbb, 0x70, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x08, 0xf0, 0x6d, 0xf9, 0x2f, 0x26, 0x03, 0x28, 0x08, 0xd1, + 0x00, 0x21, 0x8d, 0x42, 0x08, 0x48, 0x03, 0xd8, 0x84, 0x42, 0x38, 0xbf, + 0x2d, 0x26, 0x00, 0xd3, 0x2e, 0x26, 0x30, 0x46, 0x70, 0xbd, 0x00, 0x00, + 0x48, 0x05, 0x00, 0x46, 0x08, 0xf3, 0x00, 0x20, 0x00, 0xf2, 0x00, 0x20, + 0x40, 0x42, 0x0f, 0x00, 0x00, 0x28, 0x6b, 0xee, 0x00, 0x28, 0x0c, 0xbf, + 0x40, 0xf2, 0x5e, 0x40, 0x40, 0xf2, 0x5f, 0x40, 0xfd, 0xf7, 0x7c, 0xbb, + 0x00, 0xf0, 0x0f, 0x02, 0x0f, 0x21, 0x4f, 0xf4, 0xc1, 0x70, 0xfd, 0xf7, + 0x7f, 0xbb, 0x00, 0x28, 0x0c, 0xbf, 0x40, 0xf2, 0x46, 0x50, 0x40, 0xf2, + 0x47, 0x50, 0x89, 0x00, 0x01, 0xf0, 0x0c, 0x02, 0x0c, 0x21, 0xfd, 0xf7, + 0x73, 0xbb, 0x00, 0x28, 0x0c, 0xbf, 0x4f, 0xf4, 0xa8, 0x60, 0x40, 0xf2, + 0x41, 0x50, 0x8a, 0x01, 0xd2, 0xb2, 0xc0, 0x21, 0xfd, 0xf7, 0x68, 0xbb, + 0x00, 0x28, 0x0c, 0xbf, 0x4f, 0xf4, 0xa8, 0x60, 0x40, 0xf2, 0x41, 0x50, + 0x01, 0xf0, 0x3f, 0x02, 0x3f, 0x21, 0xfd, 0xf7, 0x5d, 0xbb, 0x10, 0xb5, + 0x00, 0xf0, 0x17, 0xf8, 0xfd, 0xf7, 0x7f, 0xfb, 0x21, 0x46, 0xbd, 0xe8, + 0x10, 0x40, 0x05, 0x22, 0x0f, 0xf2, 0x48, 0x00, 0xfd, 0xf7, 0x77, 0xbb, + 0x10, 0xb5, 0x00, 0xf0, 0x0a, 0xf8, 0xff, 0xf7, 0x0b, 0xfd, 0x21, 0x46, + 0xbd, 0xe8, 0x10, 0x40, 0x05, 0x22, 0x0f, 0xf2, 0x30, 0x00, 0xfd, 0xf7, + 0x57, 0xbb, 0x04, 0x46, 0x03, 0x22, 0x61, 0x1d, 0x0f, 0xf2, 0x2c, 0x00, + 0x70, 0x47, 0x00, 0xb1, 0x04, 0x20, 0x01, 0xf0, 0x01, 0x01, 0x01, 0xfa, + 0x00, 0xf2, 0x01, 0x21, 0x81, 0x40, 0xd2, 0xb2, 0xc9, 0xb2, 0x4f, 0xf4, + 0xaa, 0x60, 0xfd, 0xf7, 0x2f, 0xbb, 0x00, 0x00, 0x40, 0x05, 0x41, 0x05, + 0x50, 0x05, 0x49, 0x05, 0x0b, 0x02, 0x00, 0x00, 0x48, 0x05, 0x42, 0x05, + 0x43, 0x05, 0x00, 0x00, 0xff, 0xc1, 0x97, 0x7a, 0x65, 0x57, 0x4b, 0x42, + 0x3a, 0x33, 0x2d, 0x27, 0x22, 0x1d, 0x1a, 0x16, 0x13, 0x10, 0x0d, 0x0a, + 0x06, 0x03, 0x00, 0x00, 0x70, 0xb5, 0x04, 0x46, 0x00, 0x25, 0x0f, 0xf2, + 0x60, 0x66, 0x36, 0xf9, 0x15, 0x20, 0xe9, 0xb2, 0x20, 0x46, 0x00, 0xf0, + 0x29, 0xf8, 0x6d, 0x1c, 0x04, 0x2d, 0xf6, 0xd3, 0x70, 0xbd, 0x10, 0xb5, + 0x08, 0x22, 0x08, 0x21, 0x4f, 0xf4, 0x8c, 0x70, 0xfd, 0xf7, 0x02, 0xfb, + 0x00, 0x24, 0x20, 0x46, 0xff, 0xf7, 0xe6, 0xff, 0x64, 0x1c, 0x02, 0x2c, + 0xf9, 0xd3, 0xdf, 0xf8, 0xac, 0x05, 0x4f, 0xf4, 0x80, 0x71, 0x81, 0x61, + 0x42, 0x6a, 0x42, 0xf4, 0x80, 0x72, 0x42, 0x62, 0x01, 0x60, 0x13, 0x20, + 0x06, 0x21, 0x02, 0xf0, 0x5c, 0xfa, 0x13, 0x20, 0x02, 0xf0, 0x3e, 0xfa, + 0xbd, 0xe8, 0x10, 0x40, 0x13, 0x20, 0x02, 0xf0, 0x3f, 0xba, 0x00, 0x00, + 0x2d, 0xe9, 0xf8, 0x43, 0x14, 0x46, 0x05, 0x46, 0x27, 0x12, 0x01, 0x20, + 0x03, 0x29, 0x00, 0xfa, 0x05, 0xf6, 0x40, 0xf6, 0x1c, 0x28, 0x3b, 0xd8, + 0xdf, 0xe8, 0x01, 0xf0, 0x02, 0x1a, 0x21, 0x27, 0x0f, 0xf2, 0xcc, 0x56, + 0xa0, 0x05, 0x01, 0x0e, 0x36, 0xf8, 0x25, 0x00, 0xfd, 0xf7, 0xc2, 0xfa, + 0x06, 0xeb, 0x85, 0x00, 0x04, 0xf0, 0x03, 0x04, 0x45, 0x88, 0x44, 0xf0, + 0x80, 0x01, 0x28, 0x46, 0xfd, 0xf7, 0xb8, 0xfa, 0x00, 0xbf, 0x00, 0xbf, + 0x00, 0xbf, 0x21, 0x46, 0x28, 0x46, 0x1b, 0xe0, 0x0f, 0xf2, 0xa4, 0x59, + 0x00, 0xf0, 0x1e, 0xf8, 0x07, 0xf0, 0x3f, 0x01, 0x0a, 0xe0, 0x0f, 0xf2, + 0xa8, 0x50, 0x30, 0xf8, 0x15, 0x00, 0xe1, 0xb2, 0x0e, 0xe0, 0x0f, 0xf2, + 0xa0, 0x59, 0x00, 0xf0, 0x11, 0xf8, 0xf9, 0xb2, 0x09, 0xeb, 0x85, 0x00, + 0x40, 0x88, 0xfd, 0xf7, 0x9b, 0xfa, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xbf, + 0xf1, 0xb2, 0x40, 0x46, 0xbd, 0xe8, 0xf4, 0x43, 0xfd, 0xf7, 0x92, 0xba, + 0xbd, 0xe8, 0xf1, 0x83, 0x39, 0xf8, 0x25, 0x00, 0xe1, 0xb2, 0xfd, 0xf7, + 0x8b, 0xba, 0x10, 0xb5, 0x82, 0xb0, 0xdf, 0xf8, 0xe0, 0x44, 0xfe, 0xf7, + 0xa7, 0xfb, 0x20, 0x60, 0x01, 0x21, 0x2e, 0x20, 0x02, 0xf0, 0x6d, 0xfa, + 0x20, 0x68, 0x6b, 0x46, 0x00, 0x22, 0x04, 0x21, 0xfc, 0xf7, 0x30, 0xfc, + 0x4f, 0xf0, 0x8a, 0x40, 0x01, 0x68, 0x61, 0x60, 0x41, 0x68, 0x01, 0xf4, + 0xa0, 0x71, 0x41, 0xf0, 0x11, 0x01, 0x41, 0x60, 0x13, 0xbd, 0x30, 0xb5, + 0x83, 0xb0, 0xfe, 0xf7, 0x8d, 0xfb, 0xdf, 0xf8, 0xa4, 0x14, 0x08, 0x60, + 0x01, 0xa9, 0x00, 0x91, 0x41, 0xf2, 0x88, 0x33, 0x03, 0x22, 0x05, 0x21, + 0xfc, 0xf7, 0x8a, 0xfb, 0xc0, 0x07, 0x4f, 0xf0, 0x8a, 0x44, 0x04, 0xd5, + 0x2f, 0x20, 0x02, 0xf0, 0x36, 0xfa, 0x01, 0x25, 0x0b, 0xe0, 0xa0, 0x68, + 0xc0, 0x07, 0x04, 0xd5, 0x30, 0x20, 0x02, 0xf0, 0x2e, 0xfa, 0x00, 0x25, + 0x03, 0xe0, 0x31, 0x20, 0x02, 0xf0, 0x29, 0xfa, 0x02, 0x25, 0xa0, 0x68, + 0xc0, 0x07, 0x07, 0xd4, 0x20, 0x68, 0x20, 0xf0, 0x7e, 0x50, 0x20, 0x60, + 0x60, 0x68, 0x40, 0xf0, 0x01, 0x00, 0x60, 0x60, 0x00, 0x21, 0x2e, 0x20, + 0x02, 0xf0, 0x29, 0xfa, 0x28, 0x46, 0x3e, 0xbd, 0xdf, 0xf8, 0x44, 0x04, + 0x01, 0x68, 0x41, 0xf0, 0x02, 0x01, 0x01, 0x60, 0x70, 0x47, 0x4f, 0xf0, + 0x8a, 0x41, 0x08, 0x60, 0x70, 0x47, 0x02, 0x68, 0x22, 0xf0, 0x7e, 0x52, + 0x42, 0xea, 0xc1, 0x51, 0x01, 0x60, 0x70, 0x47, 0x01, 0x21, 0x00, 0xf0, + 0x1f, 0x02, 0x91, 0x40, 0xc0, 0xf3, 0x41, 0x10, 0x48, 0x43, 0x01, 0xeb, + 0x90, 0x00, 0x70, 0x47, 0x10, 0xb5, 0x04, 0x46, 0x02, 0xf0, 0x6f, 0xf9, + 0x01, 0x21, 0x81, 0x40, 0x62, 0x1a, 0x89, 0x08, 0xb2, 0xfb, 0xf1, 0xf1, + 0x40, 0xea, 0x41, 0x10, 0xc0, 0xb2, 0x10, 0xbd, 0xdf, 0xf8, 0xf4, 0x13, + 0x0a, 0x68, 0x22, 0xf0, 0xf2, 0x02, 0x00, 0xf0, 0x0f, 0x00, 0x42, 0xea, + 0x00, 0x10, 0x40, 0xf0, 0x04, 0x00, 0x08, 0x60, 0x70, 0x47, 0xdf, 0xf8, + 0xdc, 0x03, 0x01, 0x68, 0x21, 0xf0, 0x04, 0x01, 0xc5, 0xe7, 0x10, 0xb5, + 0xd3, 0x07, 0x12, 0xd5, 0x0f, 0xf2, 0x2c, 0x43, 0x33, 0xf8, 0x20, 0x40, + 0x04, 0xf1, 0x8c, 0x44, 0x03, 0xeb, 0x80, 0x03, 0x24, 0x78, 0xa4, 0x00, + 0x0c, 0x80, 0x5b, 0x88, 0x03, 0xf1, 0x8c, 0x43, 0x1b, 0x78, 0x03, 0xf0, + 0x03, 0x03, 0x23, 0x43, 0x0b, 0x80, 0x92, 0x07, 0x17, 0xd5, 0x0f, 0xf2, + 0x0c, 0x42, 0x32, 0xf8, 0x20, 0x30, 0x03, 0xf1, 0x8c, 0x43, 0x02, 0xeb, + 0x80, 0x00, 0x1b, 0x78, 0x4b, 0x80, 0x40, 0x88, 0x00, 0xf1, 0x8c, 0x40, + 0x00, 0x78, 0x00, 0xf0, 0x3f, 0x00, 0x43, 0xea, 0x00, 0x20, 0x82, 0x04, + 0x48, 0x80, 0x02, 0xd5, 0xde, 0x4a, 0x10, 0x43, 0x48, 0x80, 0x10, 0xbd, + 0x00, 0x21, 0xdd, 0x4a, 0x52, 0xf8, 0x21, 0x20, 0x40, 0xf8, 0x21, 0x20, + 0x49, 0x1c, 0x38, 0x29, 0xf7, 0xd3, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x47, + 0x0d, 0x46, 0xd8, 0x49, 0x49, 0x69, 0x92, 0x46, 0xd7, 0x4a, 0x12, 0x78, + 0x04, 0x46, 0x01, 0x20, 0x13, 0x07, 0x48, 0xbf, 0x04, 0x20, 0x02, 0xd4, + 0x52, 0x07, 0x48, 0xbf, 0x02, 0x20, 0x48, 0x43, 0xd2, 0x49, 0x88, 0x42, + 0x2c, 0xbf, 0x0f, 0xf2, 0xc4, 0x38, 0x0f, 0xf2, 0xb4, 0x38, 0x00, 0x27, + 0x05, 0xeb, 0xc7, 0x00, 0x00, 0xf1, 0x60, 0x06, 0xd6, 0xe9, 0x00, 0x01, + 0x00, 0xf0, 0x84, 0xfe, 0x00, 0xf0, 0xdf, 0xf8, 0xe1, 0x68, 0x00, 0xf0, + 0xbd, 0xff, 0xe0, 0x60, 0xd6, 0xe9, 0x06, 0x01, 0x00, 0xf0, 0x7a, 0xfe, + 0x00, 0xf0, 0xd5, 0xf8, 0x21, 0x69, 0x00, 0xf0, 0xb3, 0xff, 0x20, 0x61, + 0xd6, 0xe9, 0x0c, 0x01, 0x00, 0xf0, 0x70, 0xfe, 0x00, 0xf0, 0xcb, 0xf8, + 0x61, 0x69, 0x00, 0xf0, 0xa9, 0xff, 0x60, 0x61, 0xd6, 0xe9, 0x12, 0x01, + 0x00, 0xf0, 0x66, 0xfe, 0x00, 0xf0, 0xc1, 0xf8, 0xa1, 0x69, 0x00, 0xf0, + 0x9f, 0xff, 0x7f, 0x1c, 0x03, 0x2f, 0xa0, 0x61, 0xd0, 0xd3, 0x00, 0x27, + 0x00, 0xf0, 0xbb, 0xf8, 0x00, 0xf0, 0xb2, 0xf8, 0x21, 0x68, 0x00, 0xf0, + 0x93, 0xff, 0x00, 0xf0, 0xbd, 0xf8, 0x00, 0xf0, 0xab, 0xf8, 0x61, 0x68, + 0x00, 0xf0, 0x8c, 0xff, 0x60, 0x60, 0xd9, 0xe9, 0x06, 0x01, 0x00, 0xf0, + 0x49, 0xfe, 0x00, 0xf0, 0xa1, 0xf8, 0xa1, 0x68, 0x00, 0xf0, 0x82, 0xff, + 0x02, 0x2f, 0xa0, 0x60, 0xe4, 0xd3, 0x01, 0x27, 0x00, 0xf0, 0x9f, 0xf8, + 0x00, 0xf0, 0x96, 0xf8, 0x21, 0x68, 0x00, 0xf0, 0x77, 0xff, 0x00, 0xf0, + 0xa1, 0xf8, 0x00, 0xf0, 0x8f, 0xf8, 0x61, 0x68, 0x00, 0xf0, 0x70, 0xff, + 0x60, 0x60, 0xd9, 0xe9, 0x0c, 0x01, 0x00, 0xf0, 0x2d, 0xfe, 0x00, 0xf0, + 0x85, 0xf8, 0xa1, 0x68, 0x00, 0xf0, 0x66, 0xff, 0x02, 0x2f, 0xa0, 0x60, + 0xe4, 0xd3, 0xc0, 0x35, 0xd5, 0xe9, 0x00, 0x01, 0x00, 0xf0, 0x20, 0xfe, + 0xe1, 0x69, 0x00, 0xf0, 0x5b, 0xff, 0xe0, 0x61, 0xd5, 0xe9, 0x02, 0x01, + 0x00, 0xf0, 0x18, 0xfe, 0x21, 0x6a, 0x00, 0xf0, 0x53, 0xff, 0x20, 0x62, + 0xd5, 0xe9, 0x04, 0x01, 0x00, 0xf0, 0x10, 0xfe, 0x61, 0x6a, 0x00, 0xf0, + 0x4b, 0xff, 0x60, 0x62, 0xd5, 0xe9, 0x06, 0x01, 0x00, 0xf0, 0x08, 0xfe, + 0xa1, 0x6a, 0x00, 0xf0, 0x43, 0xff, 0xa0, 0x62, 0x50, 0x46, 0x00, 0xf0, + 0x3d, 0xfe, 0xe1, 0x6a, 0x00, 0xf0, 0x3c, 0xff, 0xe1, 0x69, 0x05, 0x46, + 0xe5, 0x62, 0x08, 0x46, 0x00, 0xf0, 0xd2, 0xff, 0x29, 0x46, 0x00, 0xf0, + 0x41, 0xfe, 0x01, 0x46, 0x20, 0x68, 0x00, 0xf0, 0xbb, 0xfe, 0x60, 0x63, + 0x25, 0x6a, 0x28, 0x46, 0x29, 0x46, 0x00, 0xf0, 0xc5, 0xff, 0x00, 0xf0, + 0x3c, 0xf8, 0x01, 0x46, 0x60, 0x68, 0x00, 0xf0, 0xaf, 0xfe, 0xa0, 0x63, + 0x29, 0x46, 0xe0, 0x69, 0x00, 0xf0, 0xba, 0xff, 0x00, 0xf0, 0x31, 0xf8, + 0x01, 0x46, 0xa0, 0x68, 0x00, 0xf0, 0xa4, 0xfe, 0xe0, 0x63, 0x66, 0x6a, + 0x00, 0xf0, 0x2c, 0xf8, 0x00, 0xf0, 0x27, 0xf8, 0x01, 0x46, 0xe0, 0x68, + 0x00, 0xf0, 0x9a, 0xfe, 0x20, 0x64, 0x29, 0x46, 0x30, 0x46, 0x00, 0xf0, + 0xa5, 0xff, 0x00, 0xf0, 0x1c, 0xf8, 0x01, 0x46, 0x60, 0x69, 0x00, 0xf0, + 0x8f, 0xfe, 0xa0, 0x64, 0xa6, 0x6a, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, + 0x12, 0xf8, 0x01, 0x46, 0x20, 0x69, 0x00, 0xf0, 0x85, 0xfe, 0x60, 0x64, + 0x29, 0x46, 0x30, 0x46, 0x00, 0xf0, 0x90, 0xff, 0x00, 0xf0, 0x07, 0xf8, + 0x01, 0x46, 0xa0, 0x69, 0x00, 0xf0, 0x7a, 0xfe, 0xe0, 0x64, 0xbd, 0xe8, + 0xf0, 0x87, 0xe1, 0x6a, 0x00, 0xf0, 0xf6, 0xbd, 0xe0, 0x69, 0x31, 0x46, + 0x00, 0xf0, 0x80, 0xbf, 0x71, 0x68, 0x00, 0xf0, 0x7d, 0xbf, 0x58, 0xf8, + 0x27, 0x10, 0x00, 0xf0, 0x79, 0xbf, 0x78, 0x42, 0x05, 0xeb, 0xc7, 0x09, + 0x08, 0xeb, 0x80, 0x06, 0xd9, 0xe9, 0x00, 0x01, 0x00, 0xf0, 0x96, 0xbd, + 0x20, 0x60, 0x7f, 0x1c, 0xd9, 0xe9, 0x12, 0x01, 0x00, 0xf0, 0x90, 0xbd, + 0x30, 0xb5, 0xb9, 0xb0, 0x04, 0x46, 0x0d, 0x46, 0x68, 0x46, 0xff, 0xf7, + 0xd9, 0xfe, 0x2a, 0x46, 0x69, 0x46, 0x20, 0x46, 0xff, 0xf7, 0xde, 0xfe, + 0x39, 0xb0, 0x30, 0xbd, 0x2d, 0xe9, 0xf8, 0x43, 0x04, 0x46, 0x04, 0xf1, + 0xc0, 0x07, 0x0d, 0x46, 0xd7, 0xe9, 0x02, 0x01, 0x90, 0x46, 0x00, 0xf0, + 0x77, 0xfd, 0x06, 0x46, 0xd7, 0xe9, 0x00, 0x01, 0x00, 0xf0, 0x72, 0xfd, + 0x07, 0x46, 0x40, 0x46, 0x00, 0xf0, 0xaa, 0xfd, 0x80, 0x46, 0xd4, 0xe9, + 0x00, 0x01, 0x00, 0xf0, 0x69, 0xfd, 0x81, 0x46, 0x38, 0x46, 0x39, 0x46, + 0x00, 0xf0, 0x3e, 0xff, 0x41, 0x46, 0x00, 0xf0, 0xad, 0xfd, 0x01, 0x46, + 0x48, 0x46, 0x00, 0xf0, 0x27, 0xfe, 0x07, 0x46, 0xd4, 0xe9, 0x12, 0x01, + 0x00, 0xf0, 0x58, 0xfd, 0x04, 0x46, 0x30, 0x46, 0xff, 0xf7, 0xab, 0xff, + 0x41, 0x46, 0x00, 0xf0, 0x9d, 0xfd, 0x01, 0x46, 0x20, 0x46, 0x00, 0xf0, + 0x17, 0xfe, 0x39, 0x46, 0x00, 0xf0, 0x88, 0xfe, 0x41, 0x46, 0x00, 0xf0, + 0x93, 0xfd, 0x29, 0x46, 0x01, 0xf0, 0x26, 0xf8, 0x94, 0xbf, 0x01, 0x20, + 0x00, 0x20, 0xbd, 0xe8, 0xf2, 0x83, 0x10, 0xb5, 0x28, 0x49, 0x20, 0x4c, + 0x82, 0xb0, 0x4f, 0xf4, 0x80, 0x70, 0x08, 0x60, 0x6b, 0x46, 0x20, 0x68, + 0x01, 0x22, 0x04, 0x21, 0xfc, 0xf7, 0x04, 0xfa, 0x60, 0x68, 0x4f, 0xf0, + 0x8a, 0x41, 0x08, 0x60, 0x13, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x28, 0x46, 0xff, 0xf7, 0xf0, 0xfc, 0x05, 0xf1, 0x08, 0x00, 0xff, 0xf7, + 0x42, 0xf9, 0x01, 0x21, 0xe0, 0xb2, 0xff, 0xf7, 0xe9, 0xfb, 0x1a, 0x4a, + 0xd2, 0xe9, 0x08, 0x01, 0xff, 0xf7, 0x94, 0xfc, 0x01, 0x46, 0xe0, 0xb2, + 0xff, 0xf7, 0xae, 0xfc, 0x00, 0x20, 0xff, 0xf7, 0xb3, 0xfc, 0x03, 0x21, + 0xe0, 0xb2, 0xff, 0xf7, 0xc2, 0xfc, 0x3f, 0x21, 0xe0, 0xb2, 0xff, 0xf7, + 0xc9, 0xfc, 0xff, 0xf7, 0x2c, 0xfc, 0xff, 0xf7, 0x0e, 0xfc, 0x00, 0x2c, + 0x0c, 0xbf, 0x02, 0x20, 0x03, 0x20, 0xbd, 0xe8, 0x34, 0x40, 0x28, 0x21, + 0xff, 0xf7, 0x30, 0xb9, 0x28, 0x00, 0x00, 0x50, 0x58, 0xf3, 0x00, 0x20, + 0x04, 0x00, 0x00, 0x45, 0x04, 0x00, 0x00, 0x51, 0x00, 0xc0, 0xff, 0xff, + 0x00, 0x01, 0x00, 0x45, 0x78, 0x29, 0x00, 0x20, 0x10, 0x09, 0x00, 0x46, + 0x01, 0x1c, 0x4e, 0x0e, 0x40, 0x00, 0x00, 0x50, 0x00, 0xf2, 0x00, 0x20, + 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x07, 0xf0, 0x53, 0xfe, 0x28, 0x60, + 0x29, 0x1d, 0x20, 0x46, 0xbd, 0xe8, 0x34, 0x40, 0xaf, 0xe7, 0x10, 0xb5, + 0x04, 0x46, 0x04, 0xf1, 0x08, 0x00, 0xff, 0xf7, 0xfd, 0xf8, 0x20, 0x46, + 0xbd, 0xe8, 0x10, 0x40, 0xff, 0xf7, 0xa8, 0xbc, 0x38, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x28, 0x1d, 0xff, 0xf7, 0xef, 0xff, 0x29, 0x68, 0x20, 0x46, + 0xbd, 0xe8, 0x34, 0x40, 0x07, 0xf0, 0x3e, 0xbe, 0x00, 0x07, 0x01, 0x07, + 0x02, 0x07, 0x03, 0x07, 0x12, 0x0a, 0x13, 0x0a, 0x1f, 0x0a, 0x20, 0x0a, + 0xee, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x09, 0xab, 0x09, + 0x10, 0x0a, 0x11, 0x0a, 0x1d, 0x0a, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x7b, 0x72, 0x3e, + 0x99, 0xbb, 0x06, 0x3f, 0xb3, 0x7b, 0x72, 0x3e, 0x0f, 0x4a, 0x80, 0x04, + 0x80, 0x0c, 0x10, 0x60, 0x88, 0x04, 0x80, 0x0c, 0x50, 0x60, 0x70, 0x47, + 0x0c, 0x4a, 0x10, 0x60, 0x51, 0x60, 0x70, 0x47, 0x4f, 0xf0, 0xa2, 0x41, + 0x0a, 0x68, 0x22, 0xf0, 0x80, 0x42, 0x42, 0xea, 0x80, 0x70, 0x08, 0x60, + 0x48, 0x68, 0x40, 0xf0, 0x08, 0x00, 0x48, 0x60, 0x70, 0x47, 0x05, 0x48, + 0x01, 0x68, 0x21, 0xf0, 0x08, 0x01, 0x01, 0x60, 0x70, 0x47, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x51, 0x20, 0x00, 0x00, 0x51, 0x04, 0x00, 0x00, 0x51, + 0x38, 0xb5, 0xdf, 0xf8, 0x90, 0x46, 0xa8, 0x21, 0x20, 0x46, 0x01, 0xf0, + 0x05, 0xfd, 0x00, 0x25, 0xfc, 0xf7, 0x1c, 0xfd, 0x54, 0x21, 0x01, 0xfb, + 0x05, 0x41, 0x6d, 0x1c, 0x02, 0x2d, 0x08, 0x64, 0xf6, 0xd3, 0x0f, 0xf2, + 0xd8, 0x61, 0xdf, 0xf8, 0x70, 0x06, 0x1c, 0xc9, 0x1c, 0xc0, 0x31, 0xbd, + 0x2d, 0xe9, 0xf0, 0x47, 0xdf, 0xf8, 0x64, 0x06, 0x84, 0xb0, 0x80, 0x7a, + 0x0c, 0x46, 0x00, 0xf0, 0x03, 0x09, 0xff, 0xf7, 0xdd, 0xff, 0x00, 0x27, + 0x00, 0x26, 0x0d, 0xf1, 0x04, 0x0a, 0x29, 0xfa, 0x06, 0xf0, 0xc0, 0x07, + 0x4f, 0xd5, 0xdf, 0xf8, 0x40, 0x06, 0x26, 0x60, 0x00, 0xf1, 0x40, 0x01, + 0x61, 0x60, 0x54, 0x22, 0x00, 0xf1, 0x0c, 0x01, 0xa1, 0x60, 0x01, 0x25, + 0xdf, 0xf8, 0x24, 0x16, 0x02, 0xfb, 0x06, 0x18, 0x06, 0x21, 0x01, 0xfb, + 0x06, 0x00, 0x6c, 0x30, 0xe0, 0x61, 0xc4, 0xf8, 0x0c, 0x80, 0x20, 0x46, + 0x00, 0xf0, 0x18, 0xfb, 0x29, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x8c, 0xfa, + 0x07, 0x00, 0x19, 0xd1, 0xe1, 0x69, 0x60, 0x68, 0x01, 0xeb, 0x45, 0x01, + 0x00, 0x91, 0x14, 0x21, 0x01, 0xfb, 0x05, 0x01, 0x0b, 0x1d, 0xb0, 0xf9, + 0x02, 0x20, 0x01, 0x88, 0x20, 0x68, 0x01, 0xf0, 0x5a, 0xfb, 0x00, 0xb1, + 0x05, 0x20, 0x4a, 0xf8, 0x25, 0x00, 0x20, 0xb9, 0xe0, 0x69, 0x10, 0xf8, + 0x15, 0x00, 0x5a, 0x28, 0x00, 0xda, 0x05, 0x27, 0x29, 0x46, 0x20, 0x46, + 0x00, 0xf0, 0xa6, 0xfa, 0xc7, 0xb9, 0xe1, 0x69, 0x11, 0xf8, 0x15, 0x20, + 0x08, 0xeb, 0x85, 0x00, 0x48, 0x30, 0x01, 0xeb, 0x45, 0x01, 0x42, 0x80, + 0x6d, 0x1e, 0x49, 0x78, 0x01, 0x80, 0xcd, 0xd5, 0xe0, 0x68, 0x50, 0x30, + 0x01, 0x21, 0x41, 0x80, 0x01, 0x80, 0x76, 0x1c, 0x02, 0x2e, 0xa8, 0xd3, + 0x38, 0x46, 0x04, 0xb0, 0xbd, 0xe8, 0xf0, 0x87, 0xe0, 0x68, 0x50, 0x30, + 0x00, 0x21, 0x41, 0x80, 0x01, 0x80, 0xf5, 0xe7, 0x70, 0x47, 0x2d, 0xe9, + 0xf0, 0x4f, 0x0c, 0x46, 0x8b, 0xb0, 0xdf, 0xf8, 0x7c, 0x15, 0x20, 0x60, + 0x01, 0xf1, 0x40, 0x02, 0x62, 0x60, 0x54, 0x23, 0x01, 0xf1, 0x0c, 0x02, + 0xa2, 0x60, 0x4f, 0xf4, 0x84, 0x5a, 0xdf, 0xf8, 0x60, 0x25, 0x03, 0xfb, + 0x00, 0x22, 0xe2, 0x60, 0x06, 0x22, 0x02, 0xfb, 0x00, 0x10, 0x6c, 0x30, + 0xe0, 0x61, 0xfb, 0xf7, 0x99, 0xfd, 0xe0, 0x68, 0x01, 0x6c, 0x41, 0x64, + 0xfc, 0xf7, 0x7c, 0xfc, 0x01, 0x46, 0xe0, 0x68, 0x01, 0x64, 0x52, 0x46, + 0xc1, 0x6b, 0x49, 0x1c, 0xc1, 0x63, 0x08, 0x21, 0x07, 0xf0, 0x72, 0xfe, + 0xe0, 0x68, 0xe1, 0x69, 0xb0, 0xf8, 0x4a, 0x00, 0x08, 0x70, 0xe0, 0x68, + 0xe1, 0x69, 0xb0, 0xf8, 0x48, 0x00, 0x48, 0x70, 0xe0, 0x68, 0xe1, 0x69, + 0xb0, 0xf8, 0x4e, 0x00, 0x88, 0x70, 0xe0, 0x68, 0xe1, 0x69, 0xb0, 0xf8, + 0x4c, 0x00, 0xc8, 0x70, 0xfb, 0xf7, 0x89, 0xfd, 0x20, 0x46, 0x00, 0xf0, + 0x8f, 0xfa, 0xe0, 0x68, 0xb0, 0xf8, 0x50, 0x00, 0x10, 0xb9, 0x4f, 0xf0, + 0x05, 0x09, 0x65, 0xe0, 0x01, 0x26, 0x49, 0xf2, 0xb2, 0x27, 0x32, 0x46, + 0x69, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x67, 0xf8, 0x5f, 0xea, 0x00, 0x09, + 0x5a, 0xd1, 0x01, 0x2e, 0x05, 0xd1, 0xe0, 0x68, 0x3a, 0x46, 0x00, 0x21, + 0x07, 0xf0, 0x40, 0xfe, 0xba, 0x46, 0x76, 0x1e, 0xed, 0xd5, 0xfb, 0xf7, + 0x53, 0xfd, 0x00, 0x26, 0xdf, 0xf8, 0xc4, 0xa4, 0xdf, 0xf8, 0xc4, 0x84, + 0x68, 0x46, 0x14, 0x21, 0x01, 0xfb, 0x06, 0x05, 0x01, 0x21, 0x28, 0x68, + 0x07, 0xf0, 0x6e, 0xfe, 0xe7, 0x68, 0x0c, 0x21, 0x01, 0xfb, 0x06, 0x7b, + 0x41, 0x46, 0x00, 0xf0, 0x5d, 0xfd, 0x51, 0x46, 0x00, 0xf0, 0x5a, 0xfd, + 0x00, 0xf0, 0xc4, 0xfd, 0xcb, 0xf8, 0x14, 0x00, 0x51, 0x46, 0x68, 0x68, + 0x00, 0xf0, 0x52, 0xfd, 0x00, 0xf0, 0xbc, 0xfd, 0xcb, 0xf8, 0x18, 0x00, + 0x51, 0x46, 0xa8, 0x68, 0x00, 0xf0, 0x4a, 0xfd, 0x00, 0xf0, 0xb4, 0xfd, + 0xcb, 0xf8, 0x1c, 0x00, 0x01, 0x21, 0xe8, 0x68, 0x07, 0xf0, 0x4c, 0xfe, + 0x01, 0x46, 0x40, 0x46, 0x00, 0xf0, 0x3e, 0xfd, 0x51, 0x46, 0x00, 0xf0, + 0x3b, 0xfd, 0x07, 0xeb, 0xc6, 0x07, 0x00, 0xf0, 0xa3, 0xfd, 0xf8, 0x62, + 0x01, 0x21, 0x28, 0x69, 0x07, 0xf0, 0x3c, 0xfe, 0x41, 0x46, 0x00, 0xf0, + 0x2f, 0xfd, 0x51, 0x46, 0x00, 0xf0, 0x2c, 0xfd, 0x00, 0xf0, 0x96, 0xfd, + 0x76, 0x1c, 0x02, 0x2e, 0x38, 0x63, 0xb9, 0xdb, 0xfb, 0xf7, 0x1b, 0xfd, + 0x49, 0xf6, 0xe4, 0x2a, 0xe0, 0x68, 0x52, 0x46, 0x49, 0x46, 0x07, 0xf0, + 0xe7, 0xfd, 0x48, 0x46, 0x0b, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, + 0xf7, 0x4f, 0x92, 0xb0, 0x00, 0x24, 0x12, 0x98, 0x03, 0x94, 0x02, 0x94, + 0xa0, 0x46, 0x00, 0x68, 0x14, 0x99, 0x01, 0x90, 0x12, 0x98, 0x00, 0xf0, + 0x83, 0xf9, 0x00, 0x90, 0x10, 0xb1, 0x00, 0xf0, 0xe7, 0xf8, 0xd7, 0xe0, + 0x12, 0x98, 0xc0, 0x69, 0x14, 0x99, 0x10, 0xf8, 0x11, 0x10, 0x01, 0x98, + 0x03, 0xf0, 0x91, 0xfe, 0xa3, 0x46, 0x77, 0xe0, 0x00, 0x26, 0x04, 0xaa, + 0x04, 0xa8, 0x32, 0xf9, 0x26, 0x20, 0x00, 0xeb, 0x86, 0x0a, 0xd3, 0x17, + 0xa2, 0xfb, 0x02, 0x57, 0xba, 0xf9, 0x02, 0x00, 0x02, 0xfb, 0x03, 0x77, + 0x03, 0xfb, 0x02, 0x77, 0xc1, 0x17, 0xa0, 0xfb, 0x00, 0x23, 0x00, 0xfb, + 0x01, 0x33, 0x01, 0xfb, 0x00, 0x33, 0x39, 0x46, 0xa8, 0x18, 0x59, 0x41, + 0x00, 0xf0, 0x06, 0xfb, 0x03, 0x99, 0x00, 0xf0, 0x41, 0xfc, 0x03, 0x90, + 0x0b, 0xa8, 0x00, 0xeb, 0x86, 0x09, 0x30, 0xf9, 0x26, 0x00, 0xc1, 0x17, + 0xa0, 0xfb, 0x00, 0x23, 0xb9, 0xf9, 0x02, 0x50, 0x00, 0xfb, 0x01, 0x33, + 0x01, 0xfb, 0x00, 0x33, 0xef, 0x17, 0xa5, 0xfb, 0x05, 0x01, 0x05, 0xfb, + 0x07, 0x11, 0x07, 0xfb, 0x05, 0x11, 0x10, 0x18, 0x59, 0x41, 0x00, 0xf0, + 0xe9, 0xfa, 0x21, 0x46, 0x00, 0xf0, 0x24, 0xfc, 0x04, 0x46, 0x0b, 0xa8, + 0xb9, 0xf9, 0x02, 0x50, 0x30, 0xf9, 0x26, 0x90, 0xba, 0xf9, 0x02, 0x20, + 0x04, 0xa8, 0xef, 0x17, 0x30, 0xf9, 0x26, 0xc0, 0xa2, 0xfb, 0x05, 0x01, + 0xd3, 0x17, 0x02, 0xfb, 0x07, 0x11, 0x03, 0xfb, 0x05, 0x11, 0xcc, 0xfb, + 0x09, 0x01, 0x00, 0xf0, 0xcf, 0xfa, 0x02, 0x99, 0x00, 0xf0, 0x0a, 0xfc, + 0x02, 0x90, 0x2a, 0x46, 0x04, 0xa8, 0x3b, 0x46, 0x30, 0xf9, 0x26, 0x00, + 0xa0, 0xfb, 0x02, 0x57, 0xc1, 0x17, 0x00, 0xfb, 0x03, 0x77, 0x0b, 0xa8, + 0x01, 0xfb, 0x02, 0x77, 0x30, 0xf9, 0x26, 0x00, 0xba, 0xf9, 0x02, 0x10, + 0x81, 0xfb, 0x00, 0x01, 0x28, 0x1a, 0x67, 0xeb, 0x01, 0x01, 0x00, 0xf0, + 0xb3, 0xfa, 0x41, 0x46, 0x00, 0xf0, 0xee, 0xfb, 0x76, 0x1c, 0x07, 0x2e, + 0x80, 0x46, 0x8a, 0xd3, 0x0b, 0xf1, 0x01, 0x0b, 0x00, 0xf0, 0x5b, 0xf8, + 0x83, 0x45, 0x19, 0xd2, 0x01, 0x98, 0x07, 0x23, 0x04, 0xaa, 0x0b, 0xa9, + 0x03, 0xf0, 0x4e, 0xfe, 0xfe, 0xf7, 0x8f, 0xf8, 0x00, 0x28, 0x3f, 0xf4, + 0x79, 0xaf, 0x12, 0x99, 0xc9, 0x68, 0x06, 0x20, 0x08, 0x60, 0xab, 0xf1, + 0x01, 0x0b, 0x00, 0xf0, 0x4d, 0xf8, 0x14, 0x99, 0x12, 0x98, 0x00, 0xf0, + 0xe1, 0xf8, 0x00, 0x28, 0x00, 0x90, 0xdf, 0xd0, 0x00, 0xf0, 0x44, 0xf8, + 0x00, 0x98, 0x00, 0x28, 0x32, 0xd1, 0x13, 0x98, 0x14, 0x99, 0x14, 0x22, + 0x02, 0xfb, 0x01, 0x06, 0x00, 0xf0, 0x33, 0xf8, 0xc0, 0xeb, 0xc0, 0x00, + 0x00, 0xf0, 0xae, 0xfa, 0x05, 0x46, 0x20, 0x46, 0x29, 0x46, 0x00, 0xf0, + 0xc3, 0xfa, 0x00, 0xf0, 0xf5, 0xfb, 0x00, 0xf0, 0x23, 0xf8, 0xf0, 0x60, + 0x29, 0x46, 0x03, 0x98, 0x00, 0xf0, 0xba, 0xfa, 0x00, 0xf0, 0xec, 0xfb, + 0x00, 0xf0, 0x1a, 0xf8, 0x30, 0x61, 0xf1, 0x68, 0x00, 0xf0, 0xb2, 0xfa, + 0x30, 0x60, 0x21, 0x46, 0x9a, 0x48, 0x00, 0xf0, 0x3b, 0xfc, 0x00, 0xf0, + 0x0f, 0xf8, 0x04, 0x46, 0x02, 0x98, 0x21, 0x46, 0x00, 0xf0, 0xa6, 0xfa, + 0x70, 0x60, 0x21, 0x46, 0x40, 0x46, 0x00, 0xf0, 0xa1, 0xfa, 0xb0, 0x60, + 0x00, 0x98, 0x15, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x90, 0x49, 0x00, 0xf0, + 0x99, 0xba, 0x12, 0x98, 0x01, 0x99, 0x80, 0x68, 0x00, 0xeb, 0x41, 0x00, + 0x80, 0x8a, 0x70, 0x47, 0x14, 0x99, 0x12, 0x98, 0xce, 0xe0, 0x10, 0xb5, + 0x04, 0x46, 0x21, 0x46, 0x08, 0x29, 0xb1, 0xbf, 0x4f, 0xf4, 0x30, 0x60, + 0x40, 0xf6, 0x01, 0x30, 0x08, 0x39, 0x89, 0xb2, 0x00, 0xf1, 0x8c, 0x42, + 0x01, 0x23, 0x12, 0x78, 0x03, 0xfa, 0x01, 0xf1, 0x8a, 0x43, 0x11, 0x43, + 0xc9, 0xb2, 0xfc, 0xf7, 0x49, 0xfd, 0x04, 0x2c, 0x40, 0xf6, 0x06, 0x30, + 0x7e, 0x49, 0x05, 0xda, 0x09, 0x78, 0x01, 0xf0, 0xf0, 0x01, 0x41, 0xf0, + 0x03, 0x01, 0x0e, 0xe0, 0x08, 0x2c, 0x05, 0xda, 0x09, 0x78, 0x01, 0xf0, + 0x0f, 0x01, 0x41, 0xf0, 0x30, 0x01, 0x06, 0xe0, 0x48, 0x78, 0x00, 0xf0, + 0xf0, 0x00, 0x40, 0xf0, 0x03, 0x01, 0x40, 0xf6, 0x07, 0x30, 0xbd, 0xe8, + 0x10, 0x40, 0xfc, 0xf7, 0x2b, 0xbd, 0x10, 0xb5, 0x08, 0x28, 0xb2, 0xbf, + 0x40, 0xf6, 0x02, 0x32, 0x40, 0xf6, 0x03, 0x32, 0x08, 0x38, 0x02, 0xf1, + 0x8c, 0x43, 0x01, 0x24, 0x1b, 0x78, 0x84, 0x40, 0x23, 0xea, 0x04, 0x00, + 0x01, 0xb1, 0x20, 0x43, 0xbd, 0xe8, 0x10, 0x40, 0xc1, 0xb2, 0x10, 0x46, + 0xfc, 0xf7, 0x14, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0xa0, 0x68, 0x22, 0x68, + 0x00, 0xeb, 0x42, 0x00, 0x01, 0x29, 0x02, 0x89, 0x80, 0x88, 0x02, 0xd1, + 0x52, 0x1e, 0x92, 0x41, 0xd2, 0x0f, 0x11, 0x46, 0xff, 0xf7, 0xd9, 0xff, + 0x5e, 0x48, 0x58, 0x4d, 0x00, 0x68, 0x21, 0x68, 0x05, 0xeb, 0x81, 0x01, + 0x08, 0x63, 0xfc, 0xf7, 0x83, 0xfa, 0x21, 0x68, 0x05, 0xeb, 0x81, 0x01, + 0x88, 0x63, 0x00, 0x21, 0x20, 0x68, 0x05, 0xeb, 0x80, 0x00, 0xbd, 0xe8, + 0x34, 0x40, 0x00, 0x1d, 0xfe, 0xf7, 0x20, 0xbf, 0xf8, 0xb5, 0x04, 0x46, + 0x53, 0x4d, 0x4c, 0x4e, 0x51, 0x48, 0x07, 0x68, 0xfc, 0xf7, 0x6e, 0xfa, + 0x06, 0xf1, 0x38, 0x02, 0x06, 0xf1, 0x30, 0x01, 0x52, 0xf8, 0x24, 0x20, + 0x51, 0xf8, 0x24, 0x10, 0x80, 0x1a, 0x2a, 0x6c, 0xc9, 0x1b, 0x02, 0xfb, + 0x00, 0x10, 0x06, 0xeb, 0x84, 0x01, 0x49, 0x68, 0x49, 0xb9, 0x06, 0xf1, + 0x28, 0x01, 0x51, 0xf8, 0x24, 0x10, 0x88, 0x42, 0x03, 0xd2, 0xfd, 0xf7, + 0xa2, 0xff, 0x00, 0x28, 0xe0, 0xd0, 0xf1, 0xbd, 0x70, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x00, 0x21, 0x00, 0x20, 0xfc, 0xf7, 0x18, 0xff, 0x01, 0x2d, + 0x03, 0xd1, 0x01, 0x21, 0x20, 0x46, 0xff, 0xf7, 0xa9, 0xff, 0x20, 0x68, + 0x04, 0xf1, 0x10, 0x01, 0x03, 0xf0, 0xf5, 0xfd, 0x06, 0x00, 0x09, 0xd1, + 0xe0, 0x69, 0x00, 0xeb, 0x45, 0x01, 0x20, 0x68, 0x03, 0xf0, 0x48, 0xfe, + 0x20, 0x68, 0x03, 0xf0, 0x2a, 0xfe, 0x06, 0x46, 0x01, 0x2e, 0x0b, 0xd0, + 0x02, 0x2e, 0x0b, 0xd0, 0x0c, 0x2e, 0x0b, 0xd0, 0x11, 0x2e, 0x0b, 0xd0, + 0x13, 0x2e, 0x0b, 0xd0, 0x14, 0x2e, 0x08, 0xbf, 0x0a, 0x26, 0x08, 0xe0, + 0x02, 0x26, 0x06, 0xe0, 0x01, 0x26, 0x04, 0xe0, 0x0b, 0x26, 0x02, 0xe0, + 0x03, 0x26, 0x00, 0xe0, 0x09, 0x26, 0x20, 0x68, 0xff, 0xf7, 0xa4, 0xff, + 0x30, 0x46, 0x70, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0xfd, 0xf7, + 0xcf, 0xf9, 0x03, 0x28, 0x06, 0xd1, 0x07, 0xf0, 0xd5, 0xfe, 0x00, 0x21, + 0x04, 0xf1, 0x10, 0x00, 0xfe, 0xf7, 0xcf, 0xfe, 0x01, 0x2d, 0x03, 0xd1, + 0x00, 0x21, 0x20, 0x46, 0xff, 0xf7, 0x68, 0xff, 0xbd, 0xe8, 0x32, 0x40, + 0x00, 0x20, 0xfc, 0xf7, 0x29, 0xbf, 0x70, 0xb5, 0x11, 0x4b, 0x03, 0xeb, + 0x40, 0x01, 0x00, 0x22, 0x0d, 0x7c, 0x8c, 0x8a, 0x08, 0x2d, 0x02, 0xdb, + 0x08, 0x3d, 0xed, 0xb2, 0x01, 0x22, 0x01, 0x26, 0x06, 0xfa, 0x05, 0xf5, + 0xd6, 0x5c, 0xae, 0x43, 0xd6, 0x54, 0x04, 0xb9, 0x00, 0x25, 0xd2, 0x18, + 0x03, 0xeb, 0x80, 0x00, 0x94, 0x78, 0x2c, 0x43, 0x94, 0x70, 0x01, 0x22, + 0x42, 0x60, 0x0b, 0x4a, 0x09, 0x8b, 0xd2, 0x6b, 0x51, 0x43, 0x81, 0x62, + 0x70, 0xbd, 0x00, 0x00, 0x94, 0xed, 0x00, 0x20, 0xec, 0x2b, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0x00, 0x00, 0xc8, 0x42, 0x00, 0x00, 0xa0, 0x41, + 0xf4, 0xfd, 0xb4, 0x47, 0x06, 0x0b, 0x00, 0x46, 0x18, 0xe0, 0x00, 0xe0, + 0x00, 0xf2, 0x00, 0x20, 0x10, 0xb5, 0x04, 0x46, 0xe0, 0x69, 0x80, 0x88, + 0xd0, 0xb9, 0xa0, 0x68, 0x21, 0x68, 0x00, 0xeb, 0x41, 0x00, 0x00, 0x8a, + 0x20, 0x28, 0x09, 0xda, 0xff, 0xf7, 0xd5, 0xfe, 0xa0, 0x68, 0x22, 0x68, + 0x00, 0xeb, 0x42, 0x00, 0x01, 0x21, 0x00, 0x8a, 0xff, 0xf7, 0x01, 0xff, + 0xa0, 0x68, 0x21, 0x68, 0x00, 0xeb, 0x41, 0x00, 0x80, 0x88, 0xff, 0xf7, + 0xc6, 0xfe, 0xe1, 0x69, 0x01, 0x20, 0x88, 0x80, 0x10, 0xbd, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x38, 0xb5, 0x75, 0x4d, 0x04, 0x46, 0x15, 0xf8, 0x34, 0x10, 0x48, 0x1e, + 0x80, 0x41, 0xc0, 0x0f, 0x01, 0xf0, 0x29, 0xfb, 0x01, 0x20, 0x3f, 0xe0, + 0xf8, 0xb5, 0x06, 0x46, 0x6e, 0x4d, 0x34, 0x46, 0x15, 0xf8, 0x34, 0x00, + 0x01, 0x28, 0x0f, 0x46, 0x18, 0xbf, 0x00, 0x20, 0x01, 0xf0, 0x1b, 0xfb, + 0x6a, 0x48, 0x87, 0x42, 0x28, 0xbf, 0x6a, 0x4f, 0x28, 0x6b, 0x47, 0x43, + 0x30, 0x46, 0x00, 0xf0, 0x4f, 0xf8, 0x30, 0x46, 0x00, 0xf0, 0x53, 0xf8, + 0x05, 0xeb, 0xc4, 0x00, 0x02, 0x21, 0x40, 0x68, 0x07, 0x60, 0xc1, 0x60, + 0x00, 0x21, 0x81, 0x60, 0xf0, 0x21, 0x81, 0x60, 0x02, 0x20, 0x05, 0xf8, + 0x34, 0x00, 0xf1, 0xbd, 0x10, 0xb5, 0x5c, 0x4a, 0x02, 0xeb, 0xc0, 0x01, + 0x4b, 0x68, 0x59, 0x68, 0x14, 0x6b, 0xb1, 0xfb, 0xf4, 0xf1, 0x00, 0x24, + 0x9c, 0x60, 0x01, 0x23, 0x02, 0xf8, 0x30, 0x30, 0x08, 0x46, 0x10, 0xbd, + 0x38, 0xb5, 0x54, 0x4d, 0x04, 0x46, 0x15, 0xf8, 0x34, 0x10, 0x01, 0x29, + 0x18, 0xbf, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20, 0x05, 0xf8, 0x34, 0x00, + 0x31, 0xbd, 0x51, 0x49, 0x0a, 0x68, 0x90, 0x42, 0x09, 0xd3, 0x49, 0x68, + 0x80, 0x1a, 0xb0, 0xfb, 0xf1, 0xf0, 0x00, 0x21, 0x01, 0xe0, 0x00, 0xbf, + 0x49, 0x1c, 0x81, 0x42, 0xfb, 0xd3, 0x70, 0x47, 0x10, 0xb4, 0x46, 0x4b, + 0x1b, 0x6b, 0x03, 0xfb, 0x00, 0xf3, 0x06, 0x24, 0xb3, 0xfb, 0xf4, 0xf3, + 0x19, 0x00, 0x00, 0x23, 0x1a, 0x00, 0x8a, 0x42, 0x02, 0xd2, 0x00, 0xbf, + 0x52, 0x1c, 0xfa, 0xe7, 0x10, 0xbc, 0x70, 0x47, 0x3d, 0x49, 0x01, 0xeb, + 0xc0, 0x00, 0x90, 0xf9, 0x01, 0x00, 0x01, 0xf0, 0x01, 0xbb, 0x10, 0xb5, + 0x39, 0x49, 0x01, 0xeb, 0xc0, 0x00, 0x90, 0xf9, 0x01, 0x40, 0x20, 0x46, + 0x01, 0xf0, 0xf8, 0xfa, 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x01, 0xf0, + 0xf9, 0xba, 0x33, 0x49, 0x01, 0xeb, 0xc0, 0x00, 0x90, 0xf9, 0x01, 0x00, + 0x01, 0xf0, 0xfb, 0xba, 0x80, 0xb5, 0x06, 0x21, 0x05, 0x20, 0x01, 0xf0, + 0x02, 0xfb, 0x06, 0x21, 0x06, 0x20, 0x01, 0xf0, 0xfe, 0xfa, 0x06, 0x21, + 0x07, 0x20, 0x01, 0xf0, 0xfa, 0xfa, 0x06, 0x21, 0x08, 0x20, 0x01, 0xf0, + 0xf6, 0xfa, 0x06, 0x21, 0x2f, 0x20, 0x01, 0xf0, 0xf2, 0xfa, 0x06, 0x21, + 0x30, 0x20, 0x01, 0xf0, 0xee, 0xfa, 0x06, 0x21, 0x31, 0x20, 0x01, 0xf0, + 0xea, 0xfa, 0x06, 0x21, 0x32, 0x20, 0x01, 0xf0, 0xe6, 0xfa, 0x23, 0x48, + 0x1e, 0x49, 0xc0, 0x6b, 0x08, 0x63, 0x01, 0xbd, 0x38, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0xff, 0xf7, 0x49, 0xff, 0x1b, 0x48, 0x85, 0x42, 0x19, 0x48, + 0x28, 0xbf, 0x1a, 0x4d, 0x01, 0x6b, 0x00, 0xeb, 0xc4, 0x00, 0x69, 0x43, + 0x40, 0x68, 0x01, 0x60, 0x02, 0x21, 0xc1, 0x60, 0x00, 0x21, 0xc1, 0x60, + 0x81, 0x60, 0xf0, 0x21, 0x81, 0x60, 0x31, 0xbd, 0x10, 0x49, 0x01, 0xeb, + 0xc0, 0x00, 0x40, 0x68, 0x40, 0x69, 0x70, 0x47, 0x80, 0xb5, 0x00, 0x20, + 0xff, 0xf7, 0xb1, 0xff, 0x00, 0xf0, 0x12, 0xf8, 0x08, 0x70, 0x01, 0xbd, + 0x80, 0xb5, 0x01, 0x20, 0xff, 0xf7, 0xa9, 0xff, 0x00, 0xf0, 0x0a, 0xf8, + 0x08, 0x72, 0x01, 0xbd, 0x80, 0xb5, 0x02, 0x20, 0xff, 0xf7, 0xa1, 0xff, + 0x00, 0xf0, 0x02, 0xf8, 0x08, 0x74, 0x01, 0xbd, 0x01, 0x49, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x20, 0xc1, 0xe1, 0xe4, 0x00, + 0xc0, 0xe1, 0xe4, 0x00, 0xac, 0x2a, 0x00, 0x20, 0x00, 0xf2, 0x00, 0x20, + 0x80, 0xb5, 0x03, 0x20, 0xff, 0xf7, 0x8b, 0xff, 0xff, 0xf7, 0xec, 0xff, + 0x08, 0x76, 0x01, 0xbd, 0x00, 0x29, 0x40, 0xf1, 0x0b, 0x80, 0xf4, 0x46, + 0x49, 0x42, 0x40, 0x42, 0x71, 0xf1, 0x00, 0x01, 0x00, 0xf0, 0x0a, 0xf8, + 0x50, 0xf0, 0x00, 0x40, 0x60, 0x47, 0x00, 0x00, 0x50, 0xea, 0x01, 0x02, + 0x00, 0xf0, 0x0e, 0x80, 0x09, 0x42, 0x00, 0xbf, 0x0b, 0xd1, 0xb0, 0xfa, + 0x80, 0xf1, 0x88, 0x40, 0xc1, 0xf1, 0x9d, 0x01, 0xc9, 0x05, 0x02, 0x06, + 0x72, 0xf1, 0x00, 0x42, 0x41, 0xeb, 0x10, 0x20, 0x70, 0x47, 0xb1, 0xfa, + 0x81, 0xf2, 0x41, 0x40, 0x90, 0x40, 0xc2, 0xf1, 0x20, 0x02, 0x61, 0xfa, + 0x02, 0xf1, 0x81, 0xea, 0x00, 0x00, 0x18, 0xbf, 0x40, 0xf0, 0x01, 0x00, + 0x02, 0xf1, 0x9d, 0x01, 0xe8, 0xe7, 0x00, 0x00, 0x00, 0x28, 0x40, 0xf1, + 0x09, 0x80, 0xf4, 0x46, 0x40, 0x42, 0x00, 0xf0, 0x05, 0xf8, 0x50, 0xf0, + 0x00, 0x40, 0x60, 0x47, 0x00, 0x28, 0x00, 0xbf, 0x0a, 0xd0, 0xb0, 0xfa, + 0x80, 0xf1, 0x88, 0x40, 0xd1, 0xf1, 0x9d, 0x01, 0xc9, 0x05, 0x02, 0x06, + 0x72, 0xf1, 0x00, 0x42, 0x41, 0xeb, 0x10, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x10, 0xb5, 0xff, 0x23, 0x13, 0xea, 0xd0, 0x54, 0x1d, 0xbf, 0x13, 0xea, + 0xd1, 0x52, 0x9c, 0x42, 0x9a, 0x42, 0x39, 0xe0, 0xa4, 0x1a, 0xda, 0x07, + 0x80, 0xea, 0x01, 0x03, 0x13, 0x40, 0x42, 0xea, 0x01, 0x21, 0x42, 0xea, + 0x00, 0x20, 0x42, 0x1a, 0x3c, 0xbf, 0x64, 0x1e, 0x01, 0xeb, 0x42, 0x02, + 0x09, 0x0a, 0xb2, 0xfb, 0xf1, 0xfe, 0x01, 0xfb, 0x1e, 0x22, 0x12, 0x02, + 0xb2, 0xfb, 0xf1, 0xf0, 0x01, 0xfb, 0x10, 0x22, 0x6e, 0xf3, 0x0f, 0x20, + 0x12, 0x02, 0xb2, 0xfb, 0xf1, 0xfe, 0x4e, 0xea, 0x00, 0x20, 0x7f, 0x34, + 0x06, 0xdd, 0xfe, 0x2c, 0x24, 0xda, 0x53, 0xea, 0x50, 0x00, 0x50, 0xeb, + 0xc4, 0x50, 0x10, 0xbd, 0xd4, 0xf1, 0x02, 0x04, 0x01, 0xfb, 0x1e, 0x22, + 0x40, 0xf0, 0x80, 0x71, 0x19, 0x2c, 0x1d, 0xdc, 0x21, 0xfa, 0x04, 0xf0, + 0xc4, 0xf1, 0x20, 0x04, 0xa1, 0x40, 0x11, 0x43, 0x71, 0xf1, 0x00, 0x42, + 0x58, 0x41, 0x10, 0xbd, 0x9c, 0x42, 0x1a, 0xbf, 0x03, 0xea, 0xd1, 0x52, + 0x9a, 0x42, 0x0f, 0xe0, 0x80, 0xea, 0x01, 0x0e, 0x0e, 0xf0, 0x00, 0x43, + 0x40, 0x00, 0x04, 0xd0, 0x49, 0x00, 0x16, 0xd1, 0x43, 0xf0, 0xff, 0x40, + 0x10, 0xbd, 0x49, 0x00, 0x08, 0xbf, 0xd3, 0x43, 0x18, 0x00, 0x10, 0xbd, + 0x9c, 0x42, 0x05, 0xd1, 0xd2, 0x1a, 0xf7, 0xd0, 0x01, 0xf0, 0x00, 0x41, + 0x48, 0x40, 0x10, 0xbd, 0x4a, 0x02, 0x12, 0xbf, 0x08, 0x46, 0x48, 0x40, + 0x00, 0xf0, 0x00, 0x40, 0x10, 0xbd, 0x4a, 0xb9, 0x09, 0x02, 0xb1, 0xfa, + 0x81, 0xf2, 0x91, 0x40, 0x44, 0xb1, 0xa4, 0x18, 0xc0, 0x01, 0x40, 0xf0, + 0x00, 0x40, 0x9e, 0xe7, 0xc9, 0x01, 0x41, 0xf0, 0x00, 0x41, 0x52, 0x42, + 0x00, 0x02, 0xb0, 0xfa, 0x80, 0xf4, 0xa0, 0x40, 0x14, 0x1b, 0x94, 0xe7, + 0x90, 0xea, 0x01, 0x0f, 0x44, 0xbf, 0x81, 0xf0, 0x00, 0x41, 0x00, 0xf0, + 0x75, 0xb8, 0x00, 0xbf, 0x43, 0x1a, 0x4f, 0xf0, 0x00, 0x42, 0x3e, 0xbf, + 0x53, 0x40, 0xc0, 0x1a, 0xc9, 0x18, 0x00, 0xbf, 0xd3, 0x09, 0x5f, 0xea, + 0xd0, 0x5c, 0x13, 0xeb, 0x40, 0x0f, 0x34, 0xbf, 0xb3, 0xeb, 0x41, 0x0f, + 0x40, 0xe0, 0x7c, 0xeb, 0xd1, 0x53, 0x0c, 0xd3, 0x42, 0xea, 0x01, 0x21, + 0x22, 0xd8, 0xd1, 0xeb, 0x40, 0x20, 0x09, 0xd3, 0x40, 0x0a, 0x28, 0xbf, + 0x5f, 0xea, 0x50, 0x01, 0x40, 0xeb, 0xcc, 0x50, 0x70, 0x47, 0x40, 0x1a, + 0x15, 0xd0, 0x40, 0x02, 0xb0, 0xfa, 0x80, 0xf2, 0x52, 0x1c, 0x90, 0x40, + 0x40, 0x0a, 0x4f, 0xea, 0x3c, 0x23, 0xb3, 0xeb, 0x02, 0x63, 0x84, 0xbf, + 0x00, 0xeb, 0x73, 0x00, 0x07, 0xe0, 0x40, 0xf4, 0x00, 0x00, 0x1a, 0x16, + 0xdb, 0x07, 0xc2, 0xf1, 0x01, 0x02, 0xd0, 0x40, 0x18, 0x43, 0x70, 0x47, + 0x18, 0x2b, 0xfc, 0xdc, 0x31, 0xfa, 0x03, 0xf2, 0x02, 0xfa, 0x03, 0xf3, + 0x59, 0x1a, 0x38, 0xbf, 0x42, 0xf0, 0x01, 0x02, 0xd2, 0xeb, 0x40, 0x20, + 0x3c, 0xbf, 0x40, 0x00, 0xac, 0xf1, 0x01, 0x0c, 0x5f, 0xea, 0xcc, 0x5c, + 0xc2, 0x05, 0x72, 0xf1, 0x00, 0x41, 0x4c, 0xeb, 0x50, 0x20, 0x70, 0x47, + 0x13, 0xeb, 0x40, 0x0f, 0x0f, 0xd2, 0x4b, 0x00, 0x09, 0xd0, 0xac, 0xeb, + 0xd1, 0x53, 0x02, 0x2b, 0x03, 0xdb, 0x49, 0x02, 0x17, 0x2b, 0xdd, 0xdd, + 0x70, 0x47, 0x91, 0x43, 0x40, 0x1a, 0x43, 0x00, 0xd5, 0xd1, 0x00, 0x20, + 0x70, 0x47, 0x13, 0xeb, 0x41, 0x0f, 0xd0, 0xd3, 0x6f, 0xf0, 0x00, 0x00, + 0x70, 0x47, 0x00, 0x00, 0x90, 0xea, 0x01, 0x0f, 0x44, 0xbf, 0x81, 0xf0, + 0x00, 0x41, 0xff, 0xf7, 0x8d, 0xbf, 0x00, 0xbf, 0x42, 0x1a, 0x3c, 0xbf, + 0x80, 0x1a, 0x89, 0x18, 0x4f, 0xf0, 0x00, 0x4c, 0xc0, 0xf3, 0xc7, 0x52, + 0xff, 0x2a, 0x24, 0xd0, 0xc1, 0xf3, 0xc7, 0x53, 0x13, 0xb3, 0xd2, 0x1a, + 0xd2, 0xf1, 0x19, 0x03, 0x27, 0xdd, 0x4c, 0xea, 0x01, 0x21, 0x4c, 0xfa, + 0x03, 0xf3, 0x21, 0xea, 0x03, 0x03, 0xd1, 0x40, 0xc2, 0x0d, 0x4c, 0xea, + 0x00, 0x20, 0x40, 0x18, 0x34, 0xbf, 0x20, 0xea, 0x0c, 0x00, 0x4c, 0xea, + 0x50, 0x00, 0xd2, 0x05, 0x53, 0xea, 0x00, 0x63, 0x73, 0xeb, 0x0c, 0x0c, + 0x52, 0xeb, 0x10, 0x20, 0x42, 0x00, 0x12, 0xf1, 0x80, 0x7f, 0x38, 0xbf, + 0x70, 0x47, 0xc0, 0x0d, 0xc0, 0x05, 0x70, 0x47, 0x49, 0x02, 0x12, 0xbf, + 0x9a, 0x42, 0x00, 0xeb, 0x51, 0x20, 0xf8, 0xe7, 0xd2, 0xf1, 0x17, 0x03, + 0xd9, 0xd5, 0x70, 0x47, 0x4f, 0xf4, 0x00, 0x02, 0xc1, 0x0d, 0x23, 0xd0, + 0xff, 0x29, 0x29, 0xd2, 0x30, 0xea, 0xc1, 0x50, 0x10, 0x43, 0x7d, 0x31, + 0x49, 0x08, 0x28, 0xbf, 0x00, 0x18, 0x80, 0x00, 0x4f, 0xf0, 0xc0, 0x73, + 0xb0, 0xf1, 0x90, 0x60, 0x06, 0xd4, 0x52, 0x08, 0x0e, 0xd2, 0xc0, 0x1a, + 0x9b, 0x18, 0xd2, 0xeb, 0x40, 0x00, 0xf8, 0xd5, 0x52, 0x08, 0x06, 0xd2, + 0xc0, 0x18, 0x9b, 0x1a, 0xd2, 0xeb, 0x40, 0x00, 0xf1, 0xd5, 0x52, 0x08, + 0xf8, 0xd3, 0x5b, 0x1e, 0x58, 0x08, 0x50, 0xeb, 0xc1, 0x50, 0x70, 0x47, + 0xb0, 0xfa, 0x80, 0xf1, 0x08, 0x39, 0x88, 0x40, 0xf9, 0xd0, 0xd1, 0xf1, + 0x01, 0x01, 0xd8, 0xe7, 0xff, 0x29, 0xf4, 0xd0, 0xd0, 0x42, 0xf2, 0xd8, + 0x40, 0x00, 0xf0, 0xd0, 0xc8, 0x43, 0x07, 0xf0, 0xd1, 0xbf, 0x00, 0x00, + 0x40, 0xea, 0x01, 0x0c, 0x5f, 0xea, 0x4c, 0x0c, 0x07, 0xd0, 0x88, 0x42, + 0x05, 0xd1, 0x4f, 0xea, 0x40, 0x0c, 0x1c, 0xf1, 0x80, 0x7f, 0x98, 0xbf, + 0x80, 0x42, 0x70, 0x47, 0x4f, 0xf0, 0x80, 0x7c, 0x1c, 0xeb, 0x40, 0x0f, + 0x94, 0xbf, 0x1c, 0xeb, 0x41, 0x0f, 0x05, 0xe0, 0x40, 0xea, 0x01, 0x0c, + 0x5f, 0xea, 0x4c, 0x0c, 0x01, 0xd2, 0x88, 0x42, 0x70, 0x47, 0x18, 0xbf, + 0x81, 0x42, 0x70, 0x47, 0xff, 0x22, 0x12, 0xea, 0xd0, 0x5c, 0x1d, 0xbf, + 0x12, 0xea, 0xd1, 0x53, 0x94, 0x45, 0x93, 0x42, 0x2b, 0xe0, 0x9c, 0x44, + 0xd3, 0x07, 0x80, 0xea, 0x01, 0x02, 0x1a, 0x40, 0x43, 0xea, 0x00, 0x20, + 0x43, 0xea, 0x01, 0x21, 0xa1, 0xfb, 0x00, 0x30, 0x41, 0x00, 0x38, 0xbf, + 0x40, 0x00, 0x7c, 0xf1, 0x7f, 0x01, 0x0b, 0xdb, 0xfe, 0x29, 0x4a, 0xda, + 0x5b, 0x08, 0x42, 0xea, 0xc1, 0x51, 0x53, 0xea, 0x00, 0x63, 0x73, 0xf1, + 0x00, 0x4c, 0x51, 0xeb, 0x10, 0x20, 0x70, 0x47, 0xd1, 0xf1, 0x08, 0x0c, + 0xdc, 0xf1, 0x20, 0x01, 0x2f, 0xdb, 0x5b, 0x08, 0x10, 0xfa, 0x01, 0xf1, + 0x0b, 0x43, 0x73, 0xf1, 0x00, 0x41, 0x20, 0xfa, 0x0c, 0xf0, 0x50, 0x41, + 0x70, 0x47, 0x94, 0x45, 0x1c, 0xbf, 0x02, 0xea, 0xd1, 0x53, 0x93, 0x42, + 0x80, 0xea, 0x01, 0x02, 0x02, 0xf0, 0x00, 0x42, 0x1d, 0xd0, 0x40, 0x00, + 0x19, 0xd0, 0x49, 0x00, 0x17, 0xd0, 0x5b, 0xb9, 0x63, 0x45, 0x14, 0xd0, + 0x09, 0x02, 0xb1, 0xfa, 0x81, 0xf3, 0x99, 0x40, 0xbc, 0xeb, 0x03, 0x0c, + 0xc0, 0x01, 0x40, 0xf0, 0x00, 0x40, 0xc1, 0xe7, 0x00, 0x02, 0xb0, 0xfa, + 0x80, 0xfc, 0x10, 0xfa, 0x0c, 0xf0, 0xb3, 0xeb, 0x0c, 0x0c, 0xc9, 0x01, + 0x41, 0xf0, 0x00, 0x41, 0xb6, 0xe7, 0x10, 0x00, 0x70, 0x47, 0x40, 0x00, + 0x0a, 0xd0, 0x49, 0x00, 0x08, 0xd0, 0x10, 0xf1, 0x80, 0x7f, 0x94, 0xbf, + 0x11, 0xf1, 0x80, 0x7f, 0x02, 0xe0, 0x42, 0xf0, 0xff, 0x40, 0x70, 0x47, + 0xd0, 0x43, 0x70, 0x47, 0x41, 0x00, 0x09, 0x0e, 0x7f, 0x39, 0x15, 0xd4, + 0xd1, 0xf1, 0x1f, 0x01, 0x14, 0xd4, 0x40, 0x00, 0x07, 0xd2, 0xc0, 0x01, + 0x40, 0xf0, 0x00, 0x40, 0xc8, 0x40, 0x48, 0xbf, 0x6f, 0xf0, 0x00, 0x40, + 0x70, 0x47, 0xc0, 0x01, 0x40, 0xf0, 0x00, 0x40, 0xc8, 0x40, 0x4c, 0xbf, + 0x4f, 0xf0, 0x00, 0x40, 0x40, 0x42, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, + 0x00, 0x42, 0x4f, 0xf0, 0x00, 0x40, 0x58, 0xbf, 0xc0, 0x43, 0x70, 0x47, + 0xc0, 0xf3, 0xc7, 0x52, 0x7e, 0x3a, 0x09, 0xdd, 0x18, 0x2a, 0x0c, 0xda, + 0x6f, 0xf0, 0x7f, 0x41, 0xd1, 0x40, 0x20, 0xea, 0x51, 0x00, 0x40, 0x18, + 0x88, 0x43, 0x70, 0x47, 0x00, 0xf0, 0x00, 0x40, 0x08, 0xbf, 0x40, 0xf0, + 0x7e, 0x50, 0x70, 0x47, 0x38, 0xb5, 0x0b, 0x46, 0xc3, 0xf3, 0xc7, 0x51, + 0xff, 0x29, 0x02, 0x46, 0x09, 0xd0, 0x11, 0xb1, 0x4f, 0xf0, 0xff, 0x34, + 0x09, 0xe0, 0x58, 0x02, 0x0c, 0xbf, 0x00, 0x24, 0x6f, 0xf0, 0x01, 0x04, + 0x03, 0xe0, 0x58, 0x02, 0x14, 0xbf, 0x02, 0x24, 0x01, 0x24, 0xc2, 0xf3, + 0xc7, 0x51, 0xff, 0x29, 0x08, 0xd0, 0x11, 0xb1, 0x4f, 0xf0, 0xff, 0x31, + 0x08, 0xe0, 0x50, 0x02, 0x06, 0xd0, 0x6f, 0xf0, 0x01, 0x01, 0x03, 0xe0, + 0x50, 0x02, 0x14, 0xbf, 0x02, 0x21, 0x01, 0x21, 0x01, 0x2c, 0xb8, 0xbf, + 0x01, 0x29, 0x1c, 0xda, 0x00, 0x2a, 0x46, 0xbf, 0x82, 0xf0, 0x00, 0x42, + 0x08, 0x25, 0x00, 0x25, 0x00, 0x2b, 0x44, 0xbf, 0x83, 0xf0, 0x00, 0x43, + 0x85, 0xf0, 0x06, 0x05, 0x18, 0x46, 0x11, 0x46, 0xff, 0xf7, 0x12, 0xff, + 0x02, 0xd2, 0xff, 0xf7, 0x93, 0xfd, 0x1f, 0xe0, 0x00, 0x2c, 0x04, 0xd5, + 0x10, 0x46, 0x19, 0x46, 0xff, 0xf7, 0x8c, 0xfd, 0x1a, 0xe0, 0x00, 0x20, + 0x18, 0xe0, 0x02, 0x29, 0x01, 0xd1, 0x10, 0x46, 0x32, 0xbd, 0x02, 0x2c, + 0x01, 0xd1, 0x18, 0x46, 0x32, 0xbd, 0x8c, 0x42, 0x0c, 0xbf, 0x4f, 0xf0, + 0x7e, 0x50, 0x00, 0x20, 0x00, 0x2a, 0x4c, 0xbf, 0x08, 0x25, 0x00, 0x25, + 0x00, 0x2b, 0x48, 0xbf, 0x85, 0xf0, 0x06, 0x05, 0x01, 0x29, 0x01, 0xd1, + 0x85, 0xf0, 0x02, 0x05, 0x29, 0x46, 0xbd, 0xe8, 0x34, 0x40, 0x07, 0xf0, + 0xaf, 0xbe, 0x00, 0x00, 0x4f, 0xf0, 0x80, 0x7c, 0x1c, 0xeb, 0x40, 0x0f, + 0x94, 0xbf, 0x1c, 0xeb, 0x41, 0x0f, 0x05, 0xe0, 0x40, 0xea, 0x01, 0x0c, + 0x5f, 0xea, 0x4c, 0x0c, 0x01, 0xd2, 0x81, 0x42, 0x70, 0x47, 0x18, 0xbf, + 0x88, 0x42, 0x70, 0x47, 0x2d, 0xe9, 0xf1, 0x4d, 0x83, 0xb0, 0x0c, 0x46, + 0x03, 0x98, 0x01, 0x94, 0xc0, 0xf3, 0xc7, 0x50, 0xff, 0x28, 0x15, 0x46, + 0x08, 0xd1, 0x03, 0x98, 0x00, 0x27, 0x40, 0x02, 0x0c, 0xbf, 0x4f, 0xf0, + 0x01, 0x08, 0x4f, 0xf0, 0x02, 0x08, 0x13, 0xe0, 0x01, 0x28, 0x07, 0xda, + 0x03, 0xa8, 0x07, 0xf0, 0xfd, 0xfe, 0x01, 0x28, 0x02, 0xdb, 0x00, 0x27, + 0xb8, 0x46, 0x09, 0xe0, 0x03, 0x99, 0x21, 0xf0, 0xff, 0x41, 0x41, 0xf0, + 0x7c, 0x51, 0x03, 0x91, 0xa0, 0xf1, 0x7e, 0x07, 0x4f, 0xf0, 0xff, 0x38, + 0x00, 0x21, 0x01, 0xa8, 0x07, 0xf0, 0xfd, 0xfe, 0x06, 0x46, 0x0d, 0xb1, + 0x00, 0x20, 0x28, 0x80, 0x26, 0xb9, 0x20, 0x46, 0x00, 0x21, 0xff, 0xf7, + 0x91, 0xfe, 0x12, 0xd0, 0xb8, 0xf1, 0x00, 0x0f, 0x12, 0xd5, 0x3f, 0xb2, + 0x01, 0x2f, 0x14, 0xd1, 0x03, 0x98, 0x4f, 0xf0, 0x7c, 0x51, 0xff, 0xf7, + 0x85, 0xfe, 0x06, 0xd0, 0x01, 0x2e, 0x0c, 0xd1, 0x4f, 0xf0, 0x3f, 0x41, + 0xff, 0xf7, 0x7e, 0xfe, 0x2e, 0xd1, 0x4f, 0xf0, 0x7e, 0x50, 0x0d, 0xe1, + 0xb8, 0xf1, 0x02, 0x0f, 0x03, 0xd1, 0x03, 0x98, 0x08, 0xe1, 0x01, 0x2e, + 0x53, 0xdb, 0x02, 0x2e, 0x08, 0xbf, 0x20, 0x46, 0x00, 0xf0, 0x02, 0x81, + 0xb8, 0xf1, 0x01, 0x0f, 0x1a, 0xd1, 0x03, 0x98, 0x00, 0x28, 0x02, 0xd4, + 0x00, 0x2c, 0x43, 0xd5, 0x2f, 0xe0, 0x00, 0x2c, 0x09, 0xd4, 0x00, 0x2e, + 0x3e, 0xd1, 0x4f, 0xf0, 0xff, 0x31, 0x01, 0xa8, 0x07, 0xf0, 0xbf, 0xfe, + 0x00, 0x28, 0x37, 0xd5, 0x34, 0xe0, 0x16, 0xbb, 0x4f, 0xf0, 0xff, 0x31, + 0x01, 0xa8, 0x07, 0xf0, 0xb6, 0xfe, 0x00, 0x28, 0x1b, 0xd5, 0x17, 0xe0, + 0x01, 0x2e, 0x08, 0xd1, 0x00, 0x2c, 0x3f, 0xb2, 0x02, 0xd4, 0x01, 0x2f, + 0x26, 0xda, 0x12, 0xe0, 0x01, 0x2f, 0x10, 0xda, 0x22, 0xe0, 0x00, 0x2c, + 0x0f, 0xd4, 0x66, 0xb9, 0x4f, 0xf0, 0xff, 0x31, 0x01, 0xa8, 0x07, 0xf0, + 0xa0, 0xfe, 0x00, 0x28, 0x44, 0xbf, 0x03, 0x98, 0x00, 0x28, 0x02, 0xd5, + 0x4f, 0xf0, 0x00, 0x40, 0xc8, 0xe0, 0x00, 0x20, 0xc6, 0xe0, 0x07, 0xf0, + 0xbb, 0xfe, 0x22, 0x21, 0x01, 0x60, 0x5e, 0xb9, 0x4f, 0xf0, 0xff, 0x31, + 0x01, 0xa8, 0x07, 0xf0, 0x8c, 0xfe, 0x00, 0x28, 0x44, 0xbf, 0x03, 0x98, + 0x00, 0x28, 0x01, 0xd5, 0x4f, 0x48, 0xb5, 0xe0, 0x4f, 0xf0, 0xff, 0x40, + 0xb2, 0xe0, 0x03, 0x98, 0x00, 0x28, 0x48, 0xbf, 0x00, 0x2e, 0x06, 0xd5, + 0x07, 0xf0, 0xa2, 0xfe, 0x21, 0x21, 0x01, 0x60, 0x6f, 0xf0, 0x00, 0x40, + 0xa6, 0xe0, 0x00, 0x21, 0xff, 0xf7, 0x38, 0xff, 0x38, 0xbf, 0x00, 0x26, + 0x08, 0xd3, 0x80, 0xf0, 0x00, 0x40, 0x03, 0x90, 0x4f, 0xf0, 0xff, 0x31, + 0x01, 0xa8, 0x07, 0xf0, 0x68, 0xfe, 0x06, 0x46, 0x03, 0x98, 0x40, 0x49, + 0xff, 0xf7, 0x0e, 0xfe, 0x06, 0xd2, 0x01, 0x46, 0x4f, 0xf0, 0x80, 0x40, + 0xff, 0xf7, 0x1a, 0xfe, 0x03, 0x90, 0x7f, 0x1e, 0x03, 0x99, 0x3b, 0x48, + 0xff, 0xf7, 0x78, 0xfd, 0x83, 0x46, 0x03, 0x99, 0x4f, 0xf0, 0x7e, 0x50, + 0xff, 0xf7, 0x72, 0xfd, 0x01, 0x46, 0x58, 0x46, 0xff, 0xf7, 0x7c, 0xfc, + 0x80, 0x46, 0x41, 0x46, 0xff, 0xf7, 0x06, 0xfe, 0x82, 0x46, 0xcd, 0xf8, + 0x0c, 0xb0, 0x06, 0xf0, 0xcb, 0xff, 0x51, 0x46, 0xff, 0xf7, 0xfe, 0xfd, + 0x03, 0x99, 0xff, 0xf7, 0xeb, 0xfc, 0x41, 0x46, 0xff, 0xf7, 0xf8, 0xfd, + 0x01, 0x46, 0x03, 0x98, 0xff, 0xf7, 0x58, 0xfd, 0x80, 0x46, 0x38, 0xb2, + 0xff, 0xf7, 0x48, 0xfc, 0x07, 0x46, 0x40, 0x46, 0x27, 0x49, 0xff, 0xf7, + 0x5d, 0xfc, 0x39, 0x46, 0xff, 0xf7, 0x4c, 0xfd, 0x01, 0x90, 0x21, 0x46, + 0xff, 0xf7, 0xe4, 0xfd, 0x00, 0x90, 0x4f, 0xf0, 0x47, 0x41, 0xff, 0xf7, + 0xcd, 0xfd, 0x43, 0xd3, 0x20, 0x49, 0xff, 0xf7, 0xe3, 0xfe, 0x41, 0xd9, + 0x00, 0x21, 0xff, 0xf7, 0xc5, 0xfd, 0x01, 0x46, 0x34, 0xbf, 0x4f, 0xf0, + 0x3f, 0x40, 0x4f, 0xf0, 0x7c, 0x50, 0xff, 0xf7, 0x33, 0xfd, 0xff, 0xf7, + 0x39, 0xfe, 0x82, 0x46, 0x38, 0x46, 0x21, 0x46, 0xff, 0xf7, 0xc8, 0xfd, + 0x07, 0x46, 0x50, 0x46, 0xff, 0xf7, 0x1c, 0xfc, 0x01, 0x46, 0x38, 0x46, + 0xff, 0xf7, 0xb0, 0xfc, 0x10, 0x49, 0xff, 0xf7, 0xbd, 0xfd, 0x07, 0x46, + 0x40, 0x46, 0x21, 0x46, 0xff, 0xf7, 0xb8, 0xfd, 0x39, 0x46, 0xff, 0xf7, + 0x19, 0xfd, 0x00, 0x90, 0x1d, 0xb1, 0xa5, 0xf8, 0x00, 0xa0, 0x4f, 0xf0, + 0x00, 0x0a, 0x52, 0x46, 0x4f, 0xf0, 0x7e, 0x51, 0x68, 0x46, 0x07, 0xf0, + 0x19, 0xfe, 0x68, 0xb1, 0x01, 0x28, 0x0d, 0xd0, 0x13, 0xe0, 0x00, 0xbf, + 0x00, 0x00, 0x80, 0xff, 0xf3, 0x04, 0x35, 0x3f, 0x00, 0x00, 0x80, 0xbf, + 0x18, 0x72, 0x31, 0x3f, 0x01, 0x00, 0x00, 0x47, 0x00, 0x20, 0x01, 0xe0, + 0x4f, 0xf0, 0xff, 0x40, 0x00, 0x90, 0x07, 0xf0, 0xfd, 0xfd, 0x22, 0x21, + 0x01, 0x60, 0x00, 0x2e, 0x00, 0x98, 0x18, 0xbf, 0x80, 0xf0, 0x00, 0x40, + 0x04, 0xb0, 0xbd, 0xe8, 0xf0, 0x8d, 0x00, 0x22, 0xa0, 0xe6, 0x00, 0x00, + 0xd2, 0xb2, 0x20, 0x3a, 0x22, 0xbf, 0x00, 0xfa, 0x02, 0xf1, 0x00, 0x20, + 0x70, 0x47, 0x52, 0x42, 0xd0, 0x41, 0xd2, 0xf1, 0x20, 0x02, 0x91, 0x40, + 0x41, 0x40, 0xd0, 0x40, 0x90, 0x40, 0x41, 0x40, 0x70, 0x47, 0x00, 0x00, + 0x38, 0xb5, 0x05, 0x46, 0x0d, 0x48, 0x0c, 0x46, 0x41, 0x78, 0x21, 0x70, + 0x6a, 0x46, 0x00, 0x78, 0x60, 0x70, 0xa1, 0x1d, 0x28, 0x46, 0x00, 0xf0, + 0x89, 0xf8, 0x0f, 0xf2, 0x50, 0x10, 0x30, 0xf8, 0x25, 0x10, 0x01, 0xf1, + 0x8c, 0x41, 0x00, 0xeb, 0x85, 0x00, 0x09, 0x78, 0xe1, 0x70, 0x40, 0x88, + 0x00, 0xf1, 0x8c, 0x40, 0x00, 0x78, 0x20, 0x71, 0x31, 0xbd, 0x00, 0x00, + 0x6d, 0x09, 0x00, 0x46, 0x38, 0xb5, 0x0d, 0x46, 0x2a, 0x79, 0xe9, 0x78, + 0x04, 0x46, 0x00, 0xf0, 0x47, 0xf8, 0xe9, 0x88, 0x20, 0x46, 0x00, 0xf0, + 0x59, 0xf8, 0x29, 0x78, 0x40, 0xf6, 0x6e, 0x10, 0xfb, 0xf7, 0x86, 0xfe, + 0x69, 0x78, 0xbd, 0xe8, 0x34, 0x40, 0x40, 0xf6, 0x6d, 0x10, 0xfb, 0xf7, + 0x7f, 0xbe, 0x70, 0xb5, 0x55, 0x1c, 0x0e, 0x46, 0x03, 0x2e, 0x04, 0x46, + 0x1d, 0xd0, 0x10, 0x78, 0x00, 0xf0, 0x9f, 0x00, 0x10, 0x70, 0x02, 0x2e, + 0x28, 0x78, 0x00, 0xf0, 0xe0, 0x00, 0x28, 0x70, 0x08, 0xd1, 0x90, 0x78, + 0x13, 0x78, 0x43, 0xea, 0x40, 0x13, 0x13, 0x70, 0x2b, 0x78, 0x43, 0xea, + 0x40, 0x10, 0x28, 0x70, 0x00, 0x2c, 0x10, 0x78, 0x07, 0xbf, 0x00, 0xf0, + 0xfc, 0x00, 0x08, 0x43, 0x00, 0xf0, 0xf3, 0x00, 0x40, 0xea, 0x81, 0x00, + 0x10, 0x70, 0x40, 0xf6, 0x6e, 0x10, 0x11, 0x78, 0xfb, 0xf7, 0x56, 0xfe, + 0x29, 0x78, 0x40, 0xf6, 0x6d, 0x10, 0xfb, 0xf7, 0x51, 0xfe, 0x02, 0x2e, + 0x05, 0xd1, 0x20, 0x46, 0xbd, 0xe8, 0x70, 0x40, 0x00, 0x22, 0x00, 0x21, + 0x00, 0xe0, 0x70, 0xbd, 0x70, 0xb5, 0x39, 0x2a, 0x0f, 0xf2, 0x88, 0x06, + 0x04, 0x46, 0xac, 0xbf, 0x42, 0xf0, 0x40, 0x05, 0x02, 0xf0, 0xbf, 0x05, + 0x36, 0xf8, 0x24, 0x00, 0xfb, 0xf7, 0x3a, 0xfe, 0x29, 0x46, 0x06, 0xeb, + 0x84, 0x00, 0xbd, 0xe8, 0x70, 0x40, 0x40, 0x88, 0xfb, 0xf7, 0x32, 0xbe, + 0x70, 0xb5, 0x04, 0x46, 0x0f, 0xf2, 0x64, 0x06, 0x06, 0xeb, 0x84, 0x00, + 0x0d, 0x46, 0x40, 0x88, 0x29, 0x0a, 0xfb, 0xf7, 0x27, 0xfe, 0x36, 0xf8, + 0x24, 0x00, 0xe9, 0xb2, 0xbd, 0xe8, 0x70, 0x40, 0xfb, 0xf7, 0x20, 0xbe, + 0x2d, 0xe9, 0xf0, 0x41, 0x06, 0x46, 0x0f, 0xf2, 0x48, 0x08, 0x08, 0xeb, + 0x86, 0x00, 0x0c, 0x46, 0x47, 0x88, 0x15, 0x46, 0x00, 0x21, 0x38, 0x46, + 0xfb, 0xf7, 0x12, 0xfe, 0x07, 0xf1, 0x8c, 0x40, 0x00, 0x78, 0x38, 0xf8, + 0x26, 0x10, 0x01, 0xf1, 0x8c, 0x41, 0x09, 0x78, 0x41, 0xea, 0x00, 0x20, + 0x81, 0x0a, 0x80, 0x05, 0x29, 0x70, 0x80, 0x0d, 0x20, 0x80, 0xbd, 0xe8, + 0xf0, 0x81, 0x00, 0x00, 0x67, 0x09, 0x68, 0x09, 0x6a, 0x09, 0x6b, 0x09, + 0x60, 0x09, 0x61, 0x09, 0x62, 0x09, 0x63, 0x09, 0x40, 0x09, 0x41, 0x09, + 0x42, 0x09, 0x43, 0x09, 0x13, 0xf0, 0x00, 0x4c, 0x03, 0xd5, 0x5b, 0x42, + 0x52, 0x42, 0x63, 0xf1, 0x00, 0x03, 0x9c, 0xea, 0x21, 0x0c, 0x00, 0xf0, + 0x17, 0x80, 0x10, 0xb5, 0x64, 0x46, 0x03, 0xd3, 0x49, 0x42, 0x40, 0x42, + 0x61, 0xf1, 0x00, 0x01, 0x00, 0xf0, 0x0e, 0xf8, 0x64, 0x00, 0x04, 0xd3, + 0x49, 0x42, 0x40, 0x42, 0x61, 0xf1, 0x00, 0x01, 0x24, 0x42, 0x03, 0xd5, + 0x5b, 0x42, 0x52, 0x42, 0x63, 0xf1, 0x00, 0x03, 0x10, 0xbd, 0x00, 0x00, + 0x1b, 0x42, 0x13, 0xd1, 0x09, 0x42, 0x36, 0xd1, 0x2a, 0xb1, 0x84, 0x46, + 0xb0, 0xfb, 0xf2, 0xf0, 0x02, 0xfb, 0x10, 0xc2, 0x70, 0x47, 0x07, 0xf0, + 0xff, 0xbd, 0xfc, 0xd3, 0x00, 0x22, 0x00, 0x23, 0x70, 0x47, 0x0b, 0x00, + 0x02, 0x00, 0x00, 0x21, 0x00, 0x20, 0x70, 0x47, 0x90, 0x42, 0x71, 0xeb, + 0x03, 0x0c, 0xf6, 0xd3, 0x70, 0xb5, 0xb1, 0xfa, 0x81, 0xf4, 0xb3, 0xfa, + 0x83, 0xf5, 0x2c, 0x1b, 0xa3, 0x40, 0xc4, 0xf1, 0x20, 0x05, 0x32, 0xfa, + 0x05, 0xf6, 0x33, 0x43, 0xa2, 0x40, 0x5f, 0xf0, 0x00, 0x46, 0xe6, 0x40, + 0x02, 0xe0, 0x5b, 0x08, 0x5f, 0xea, 0x32, 0x02, 0x84, 0x1a, 0x71, 0xeb, + 0x03, 0x05, 0x24, 0xbf, 0x20, 0x46, 0x29, 0x46, 0x76, 0x41, 0xf4, 0xd3, + 0x02, 0x00, 0x0b, 0x00, 0x30, 0x00, 0x00, 0x21, 0x70, 0xbd, 0x01, 0x2a, + 0xcf, 0xd9, 0x70, 0xb5, 0x14, 0x0c, 0x20, 0xd0, 0xb1, 0xfa, 0x81, 0xf4, + 0xb2, 0xfa, 0x82, 0xf5, 0xc4, 0xf1, 0x20, 0x04, 0x64, 0x19, 0xb4, 0xf1, + 0x20, 0x06, 0xd6, 0xd3, 0xb2, 0x40, 0x5f, 0xf0, 0x00, 0x44, 0xf4, 0x40, + 0x00, 0x25, 0x02, 0xe0, 0x52, 0x08, 0x5f, 0xea, 0x33, 0x03, 0xc6, 0x1a, + 0x71, 0xeb, 0x02, 0x0e, 0x24, 0xbf, 0x30, 0x46, 0x71, 0x46, 0x64, 0x41, + 0x6d, 0x41, 0xf3, 0xd3, 0x02, 0x00, 0x0b, 0x00, 0x20, 0x00, 0x29, 0x00, + 0x70, 0xbd, 0x0c, 0x46, 0xb1, 0xfb, 0xf2, 0xf1, 0x02, 0xfb, 0x11, 0x45, + 0x2d, 0x04, 0x45, 0xea, 0x10, 0x45, 0xb5, 0xfb, 0xf2, 0xf4, 0x02, 0xfb, + 0x14, 0x55, 0x80, 0xb2, 0x40, 0xea, 0x05, 0x45, 0xb5, 0xfb, 0xf2, 0xf0, + 0x02, 0xfb, 0x10, 0x52, 0x40, 0xea, 0x04, 0x40, 0x70, 0xbd, 0x00, 0x00, + 0x10, 0xb5, 0xda, 0x48, 0x01, 0x1d, 0x00, 0x22, 0x00, 0x23, 0x0c, 0xc1, + 0x00, 0x21, 0x00, 0x24, 0x1e, 0xc0, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x43, + 0xd5, 0x48, 0x87, 0xb0, 0x80, 0x7a, 0x00, 0xf0, 0x03, 0x08, 0x40, 0x46, + 0xfb, 0xf7, 0xb0, 0xfd, 0x00, 0x24, 0x08, 0xb9, 0x02, 0x20, 0x55, 0xe0, + 0x00, 0x26, 0xdf, 0xf8, 0x38, 0x93, 0xcf, 0x4d, 0x28, 0xfa, 0x06, 0xf0, + 0xc0, 0x07, 0x49, 0xd5, 0x00, 0x27, 0x28, 0x78, 0x01, 0x21, 0xb9, 0x40, + 0x08, 0x42, 0x3f, 0xd0, 0x00, 0x21, 0x00, 0x20, 0xfb, 0xf7, 0x85, 0xff, + 0x01, 0x2f, 0x06, 0xd1, 0x03, 0xa9, 0x30, 0x46, 0xfe, 0xf7, 0x26, 0xfd, + 0x05, 0xf1, 0x18, 0x01, 0x11, 0xe0, 0x68, 0x46, 0xfd, 0xf7, 0x27, 0xfe, + 0x01, 0xa8, 0xfe, 0xf7, 0xce, 0xf9, 0x01, 0x21, 0xf0, 0xb2, 0xfe, 0xf7, + 0xcb, 0xf8, 0xfe, 0xf7, 0x06, 0xf9, 0xb0, 0x1c, 0x28, 0x21, 0x80, 0xb2, + 0xfd, 0xf7, 0x2c, 0xfe, 0x29, 0x1d, 0x09, 0xf1, 0x04, 0x00, 0x00, 0xeb, + 0x86, 0x00, 0x00, 0xeb, 0x47, 0x02, 0x30, 0x46, 0x00, 0xf0, 0x6e, 0xf8, + 0x04, 0x46, 0x40, 0x1e, 0x80, 0x41, 0x09, 0xeb, 0x46, 0x01, 0xc0, 0x0f, + 0x78, 0x54, 0x01, 0x2f, 0x04, 0xd1, 0x03, 0xa9, 0x30, 0x46, 0xfe, 0xf7, + 0x11, 0xfd, 0x05, 0xe0, 0x68, 0x46, 0xfd, 0xf7, 0x05, 0xfe, 0x01, 0xa8, + 0xfe, 0xf7, 0xb2, 0xf9, 0x00, 0x20, 0xfb, 0xf7, 0xa7, 0xff, 0x14, 0xb9, + 0x7f, 0x1c, 0x02, 0x2f, 0xb7, 0xd3, 0x14, 0xb9, 0x76, 0x1c, 0x02, 0x2e, + 0xae, 0xd3, 0x20, 0x46, 0x07, 0xb0, 0xbd, 0xe8, 0xf0, 0x83, 0xa2, 0x4a, + 0x02, 0xeb, 0x41, 0x01, 0x40, 0x5c, 0x70, 0x47, 0x9f, 0x4a, 0x02, 0xeb, + 0x81, 0x01, 0x01, 0xeb, 0x40, 0x00, 0x00, 0x1d, 0x70, 0x47, 0x80, 0xb5, + 0xfe, 0xf7, 0x4f, 0xfa, 0xfe, 0xf7, 0x69, 0xfa, 0x02, 0x28, 0x01, 0xd1, + 0x03, 0x20, 0x02, 0xbd, 0x01, 0x28, 0x0c, 0xbf, 0x04, 0x20, 0x00, 0x20, + 0x02, 0xbd, 0xf0, 0xb5, 0x05, 0x46, 0x0c, 0x46, 0x96, 0x48, 0x00, 0xeb, + 0xc4, 0x02, 0xd2, 0xe9, 0x00, 0x01, 0x95, 0x4a, 0x02, 0xeb, 0xc4, 0x06, + 0xd6, 0xe9, 0x00, 0x23, 0x80, 0x18, 0x59, 0x41, 0x2a, 0x46, 0x07, 0xf0, + 0xf9, 0xfc, 0xa0, 0xfb, 0x00, 0x67, 0x00, 0xfb, 0x01, 0x77, 0x01, 0xfb, + 0x00, 0x77, 0x8e, 0x48, 0x00, 0xeb, 0xc4, 0x02, 0xd2, 0xe9, 0x00, 0x01, + 0x8c, 0x4a, 0x02, 0xeb, 0xc4, 0x04, 0xd4, 0xe9, 0x00, 0x23, 0x80, 0x1a, + 0x99, 0x41, 0x2a, 0x46, 0x07, 0xf0, 0xe4, 0xfc, 0xa0, 0xfb, 0x00, 0x23, + 0x00, 0xfb, 0x01, 0x33, 0x01, 0xfb, 0x00, 0x33, 0xb0, 0x18, 0x47, 0xeb, + 0x03, 0x01, 0xf0, 0xbd, 0x2d, 0xe9, 0xf5, 0x4f, 0x0e, 0x46, 0x81, 0xb0, + 0xb6, 0xf9, 0x08, 0x10, 0xb6, 0xf9, 0x06, 0x00, 0xfe, 0xf7, 0xd0, 0xfc, + 0x31, 0x69, 0xf0, 0x68, 0xfe, 0xf7, 0xd4, 0xfc, 0x01, 0x98, 0xfe, 0xf7, + 0xd5, 0xfc, 0x4f, 0xf0, 0x00, 0x0a, 0xd0, 0x46, 0xf0, 0x78, 0x00, 0x27, + 0xc1, 0x46, 0x18, 0xb1, 0xfe, 0xf7, 0x81, 0xfa, 0xc3, 0x46, 0x04, 0xe0, + 0x08, 0x20, 0xfe, 0xf7, 0x6f, 0xfa, 0x4f, 0xf0, 0x08, 0x0b, 0xb6, 0xf9, + 0x06, 0x00, 0x00, 0x28, 0x48, 0xbf, 0x40, 0x42, 0xb6, 0xf9, 0x08, 0x40, + 0x00, 0x2c, 0x48, 0xbf, 0x64, 0x42, 0x84, 0x42, 0x38, 0xbf, 0x04, 0x46, + 0x20, 0x46, 0x00, 0xf0, 0xb7, 0xfb, 0x11, 0x28, 0x04, 0xd2, 0x20, 0x46, + 0x00, 0xf0, 0xb2, 0xfb, 0x11, 0x30, 0x00, 0xe0, 0x22, 0x20, 0xb1, 0x78, + 0x08, 0x18, 0x1d, 0x28, 0x26, 0xbf, 0x1c, 0x38, 0x00, 0x90, 0xcd, 0xf8, + 0x00, 0x80, 0x34, 0x78, 0x10, 0xe0, 0x00, 0x25, 0x00, 0x98, 0x29, 0x46, + 0xff, 0xf7, 0x87, 0xff, 0x89, 0x45, 0x05, 0xdc, 0x01, 0xdb, 0x80, 0x45, + 0x02, 0xd2, 0x2f, 0x19, 0x80, 0x46, 0x89, 0x46, 0x6d, 0x1c, 0x03, 0x2d, + 0xf0, 0xd3, 0xe4, 0x1c, 0x70, 0x78, 0x80, 0x1e, 0xa0, 0x42, 0x08, 0xd3, + 0x01, 0x98, 0x21, 0x04, 0x00, 0xf0, 0x43, 0xf8, 0xff, 0xf7, 0x63, 0xff, + 0x5f, 0xea, 0x00, 0x0a, 0xe1, 0xd0, 0x00, 0xf0, 0x36, 0xf8, 0xf0, 0x78, + 0x00, 0x28, 0x2b, 0xd1, 0x02, 0x99, 0x09, 0x78, 0x01, 0x98, 0x49, 0x1e, + 0x09, 0x04, 0x00, 0xf0, 0x32, 0xf8, 0x00, 0x24, 0x01, 0xe0, 0x08, 0x2c, + 0x1b, 0xd0, 0x20, 0x46, 0xfe, 0xf7, 0x1a, 0xfa, 0xff, 0xf7, 0x4b, 0xff, + 0x5f, 0xea, 0x00, 0x0a, 0x16, 0xd1, 0x00, 0x25, 0x00, 0x98, 0x29, 0x46, + 0xff, 0xf7, 0x51, 0xff, 0x89, 0x45, 0x09, 0xdc, 0x01, 0xdb, 0x80, 0x45, + 0x06, 0xd2, 0x02, 0x9a, 0x12, 0x78, 0xaa, 0x18, 0x57, 0x1e, 0xa3, 0x46, + 0x80, 0x46, 0x89, 0x46, 0x6d, 0x1c, 0x03, 0x2d, 0xec, 0xd3, 0x64, 0x1c, + 0x10, 0x2c, 0xde, 0xd3, 0x00, 0xf0, 0x07, 0xf8, 0xfe, 0xf7, 0x5f, 0xfc, + 0xfe, 0xf7, 0x05, 0xfa, 0x50, 0x46, 0xbd, 0xe8, 0xfe, 0x8f, 0x02, 0x98, + 0x07, 0x70, 0x02, 0x98, 0x80, 0xf8, 0x01, 0xb0, 0x70, 0x47, 0x01, 0xf4, + 0xfe, 0x01, 0x41, 0xea, 0x80, 0x70, 0xb1, 0x78, 0xc9, 0x05, 0x01, 0xf0, + 0x7e, 0x51, 0x08, 0x43, 0x31, 0x79, 0xc9, 0x03, 0x01, 0xf4, 0x00, 0x41, + 0x08, 0x43, 0x40, 0xf0, 0x00, 0x40, 0x40, 0xf4, 0x80, 0x40, 0xfe, 0xf7, + 0xb8, 0xb9, 0x70, 0xb5, 0x04, 0x9c, 0x0e, 0x46, 0x15, 0x46, 0x19, 0x46, + 0x22, 0x46, 0xff, 0xf7, 0x45, 0xff, 0xc8, 0xb9, 0x21, 0x78, 0x71, 0x18, + 0x21, 0x70, 0xad, 0xb1, 0xea, 0x10, 0x05, 0xeb, 0x12, 0x72, 0x12, 0x11, + 0xc9, 0xb2, 0x51, 0x18, 0x63, 0x78, 0xa5, 0xeb, 0x02, 0x12, 0xd2, 0x18, + 0x12, 0xb2, 0x00, 0x2a, 0x02, 0xd5, 0x49, 0x1e, 0x10, 0x32, 0x03, 0xe0, + 0x10, 0x2a, 0xa4, 0xbf, 0x49, 0x1c, 0x10, 0x3a, 0x21, 0x70, 0x62, 0x70, + 0x70, 0xbd, 0x10, 0xb5, 0x00, 0x22, 0x17, 0x4b, 0x44, 0x24, 0x00, 0xf0, + 0x31, 0xf8, 0xdc, 0x63, 0x01, 0x24, 0xa3, 0xf8, 0x40, 0x40, 0x94, 0x24, + 0x13, 0x4b, 0x00, 0xf0, 0x29, 0xf8, 0x9c, 0x61, 0x01, 0x24, 0x9c, 0x83, + 0x58, 0xb1, 0x11, 0x4b, 0x54, 0x24, 0x00, 0xf0, 0x21, 0xf8, 0x9c, 0x64, + 0x01, 0xeb, 0x82, 0x04, 0xa4, 0x68, 0xdc, 0x64, 0x01, 0x24, 0xa3, 0xf8, + 0x50, 0x40, 0x52, 0x1c, 0x02, 0x2a, 0xe0, 0xd3, 0x10, 0xbd, 0x00, 0x00, + 0x78, 0xb8, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, 0x20, 0x29, 0x00, 0x20, + 0x60, 0x01, 0x00, 0x45, 0xa8, 0x01, 0x00, 0x45, 0x90, 0x01, 0x00, 0x45, + 0x78, 0x01, 0x00, 0x45, 0xa8, 0xef, 0x00, 0x20, 0x74, 0x27, 0x00, 0x20, + 0x94, 0xed, 0x00, 0x20, 0x04, 0xfb, 0x02, 0x33, 0x51, 0xf8, 0x22, 0x40, + 0x70, 0x47, 0x01, 0xb4, 0xbd, 0xf8, 0x02, 0x00, 0x5a, 0x28, 0x03, 0xdb, + 0xbd, 0xf8, 0x00, 0x00, 0x10, 0x28, 0x01, 0xdb, 0x00, 0x20, 0x00, 0xe0, + 0x01, 0x20, 0x01, 0xb0, 0x70, 0x47, 0xfe, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x00, 0x26, 0x55, 0xf8, 0x26, 0x00, 0x00, 0x90, 0xff, 0xf7, 0xe9, 0xff, + 0x07, 0x46, 0x34, 0xb1, 0x05, 0xeb, 0x86, 0x00, 0x80, 0x68, 0x00, 0x90, + 0xff, 0xf7, 0xe1, 0xff, 0x00, 0xe0, 0x01, 0x20, 0x17, 0xb1, 0x10, 0xb1, + 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0xa9, 0xc0, 0xb2, 0x41, 0xf8, + 0x26, 0x00, 0x76, 0x1c, 0x02, 0x2e, 0xe4, 0xd3, 0x01, 0x98, 0x00, 0x28, + 0x1e, 0xbf, 0x02, 0x98, 0x00, 0x28, 0x01, 0x20, 0xc0, 0xb2, 0xfe, 0xbd, + 0x35, 0x49, 0x00, 0x20, 0x08, 0x80, 0x70, 0x47, 0x07, 0xf0, 0x9d, 0xbb, + 0x07, 0xf0, 0x9c, 0xbb, 0x07, 0xf0, 0x9b, 0xbb, 0x07, 0xf0, 0x9b, 0xbb, + 0x4f, 0xf0, 0x80, 0x73, 0x42, 0xf8, 0x04, 0x39, 0x10, 0x60, 0x10, 0x1f, + 0x2d, 0x4a, 0x40, 0xf8, 0x04, 0x29, 0x4f, 0xf0, 0x12, 0x32, 0x40, 0xf8, + 0x04, 0x29, 0x4f, 0xf0, 0x03, 0x32, 0x40, 0xf8, 0x04, 0x29, 0x4f, 0xf0, + 0x02, 0x32, 0x40, 0xf8, 0x04, 0x29, 0x4f, 0xf0, 0x01, 0x32, 0x40, 0xf8, + 0x04, 0x29, 0x40, 0xf8, 0x04, 0x19, 0x4f, 0xf0, 0x11, 0x31, 0x40, 0xf8, + 0x04, 0x19, 0x4f, 0xf0, 0x10, 0x31, 0x40, 0xf8, 0x04, 0x19, 0x4f, 0xf0, + 0x09, 0x31, 0x40, 0xf8, 0x04, 0x19, 0x4f, 0xf0, 0x08, 0x31, 0x40, 0xf8, + 0x04, 0x19, 0x4f, 0xf0, 0x07, 0x31, 0x40, 0xf8, 0x04, 0x19, 0x4f, 0xf0, + 0x06, 0x31, 0x40, 0xf8, 0x04, 0x19, 0x4f, 0xf0, 0x05, 0x31, 0x40, 0xf8, + 0x04, 0x19, 0x4f, 0xf0, 0x04, 0x31, 0x01, 0x60, 0x70, 0x47, 0x07, 0xf0, + 0x5f, 0xbb, 0x07, 0xf0, 0x64, 0xbb, 0x80, 0xb5, 0x07, 0xf0, 0x62, 0xfb, + 0x0e, 0x48, 0x01, 0x88, 0x49, 0x1c, 0x01, 0x80, 0x89, 0xb2, 0x05, 0x29, + 0x05, 0xd3, 0x00, 0x21, 0x01, 0x80, 0xbd, 0xe8, 0x01, 0x40, 0xfb, 0xf7, + 0xbf, 0xb9, 0x01, 0xbd, 0x80, 0xb5, 0x00, 0xf0, 0x13, 0xf8, 0x08, 0x49, + 0x0a, 0x78, 0x52, 0x1c, 0x0a, 0x70, 0x80, 0xf3, 0x11, 0x88, 0xfa, 0xf7, + 0xcd, 0xf9, 0xbd, 0xe8, 0x01, 0x40, 0xfa, 0xf7, 0x67, 0xb9, 0x00, 0x00, + 0x9c, 0xf3, 0x00, 0x20, 0xbd, 0x2a, 0x00, 0x01, 0x20, 0xbd, 0x00, 0x20, + 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, + 0x80, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x1b, 0x48, 0xff, 0x21, 0x01, 0x70, + 0x00, 0x20, 0x80, 0xf3, 0x09, 0x88, 0x19, 0x48, 0x01, 0x21, 0x01, 0x70, + 0x18, 0x48, 0x19, 0x49, 0x01, 0x60, 0x62, 0xb6, 0xfe, 0xe7, 0x16, 0x48, + 0x16, 0x49, 0x01, 0x60, 0x70, 0x47, 0x14, 0x48, 0x14, 0x49, 0x01, 0x60, + 0x70, 0x47, 0x72, 0xb6, 0xef, 0xf3, 0x09, 0x80, 0x28, 0xb1, 0x20, 0x38, + 0x80, 0xe8, 0xf0, 0x0f, 0x10, 0x49, 0x09, 0x68, 0x08, 0x60, 0x00, 0xb5, + 0x0f, 0x48, 0x80, 0x47, 0x5d, 0xf8, 0x04, 0xeb, 0x0e, 0x48, 0x0f, 0x49, + 0x0a, 0x78, 0x02, 0x70, 0x0a, 0x48, 0x0e, 0x49, 0x0a, 0x68, 0x02, 0x60, + 0x10, 0x68, 0x90, 0xe8, 0xf0, 0x0f, 0x20, 0x30, 0x80, 0xf3, 0x09, 0x88, + 0x4e, 0xf0, 0x04, 0x0e, 0x62, 0xb6, 0x70, 0x47, 0x22, 0xed, 0x00, 0xe0, + 0x25, 0xbd, 0x00, 0x20, 0x04, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x10, + 0x40, 0xbd, 0x00, 0x20, 0x03, 0x7a, 0x00, 0x01, 0x22, 0xbd, 0x00, 0x20, + 0x23, 0xbd, 0x00, 0x20, 0x48, 0xbd, 0x00, 0x20, 0x00, 0x22, 0x07, 0xf0, + 0xeb, 0xba, 0x00, 0x00, 0x62, 0xf3, 0x0f, 0x22, 0x62, 0xf3, 0x1f, 0x42, + 0x40, 0x18, 0x10, 0xf0, 0x03, 0x03, 0x08, 0xd0, 0xc9, 0x1a, 0x1f, 0xd3, + 0xdb, 0x07, 0x48, 0xbf, 0x00, 0xf8, 0x01, 0x2d, 0x28, 0xbf, 0x20, 0xf8, + 0x02, 0x2d, 0x13, 0x00, 0x30, 0xb4, 0x14, 0x46, 0x15, 0x46, 0x10, 0x39, + 0x28, 0xbf, 0x20, 0xe9, 0x3c, 0x00, 0xfa, 0xd8, 0x49, 0x07, 0x28, 0xbf, + 0x20, 0xe9, 0x0c, 0x00, 0x48, 0xbf, 0x40, 0xf8, 0x04, 0x2d, 0x89, 0x00, + 0x28, 0xbf, 0x20, 0xf8, 0x02, 0x2d, 0x48, 0xbf, 0x00, 0xf8, 0x01, 0x2d, + 0x30, 0xbc, 0x70, 0x47, 0xc9, 0x18, 0x18, 0xbf, 0x00, 0xf8, 0x01, 0x2d, + 0xcb, 0x07, 0x28, 0xbf, 0x00, 0xf8, 0x01, 0x2d, 0x70, 0x47, 0x00, 0x00, + 0x58, 0xb5, 0x04, 0x46, 0x03, 0x2c, 0x16, 0xda, 0x04, 0xf0, 0x00, 0xff, + 0xbb, 0x4a, 0xbc, 0x4e, 0x12, 0x68, 0x09, 0x07, 0x41, 0xea, 0x10, 0x11, + 0x00, 0x07, 0x00, 0x23, 0xff, 0xf7, 0x78, 0xfc, 0x06, 0xeb, 0xc4, 0x02, + 0xc2, 0xe9, 0x00, 0x01, 0x20, 0x46, 0x04, 0xf0, 0xef, 0xfe, 0x06, 0xeb, + 0xc4, 0x02, 0xc2, 0xe9, 0x06, 0x01, 0x51, 0xbd, 0x7c, 0xb5, 0xb2, 0x49, + 0x0f, 0xf2, 0x28, 0x34, 0x09, 0x78, 0x01, 0xf0, 0x03, 0x02, 0x89, 0x08, + 0x01, 0xf0, 0x01, 0x03, 0x60, 0xcc, 0x69, 0x46, 0x01, 0x2a, 0x60, 0xc1, + 0x4f, 0xf4, 0x7a, 0x71, 0xa1, 0xfb, 0x00, 0x01, 0x04, 0xd1, 0x1b, 0xb1, + 0x49, 0x00, 0x41, 0xea, 0xd0, 0x71, 0x40, 0x00, 0x6c, 0x46, 0x04, 0xeb, + 0x83, 0x03, 0xd2, 0x5c, 0x02, 0xb0, 0xbd, 0xe8, 0x70, 0x40, 0x00, 0x23, + 0xff, 0xf7, 0x4a, 0xbc, 0xa2, 0x49, 0x09, 0x78, 0x49, 0x07, 0x46, 0xbf, + 0x05, 0x21, 0xb0, 0xfb, 0xf1, 0xf0, 0x80, 0x08, 0x70, 0x47, 0x9f, 0x49, + 0x09, 0x78, 0xc9, 0x07, 0x9e, 0x49, 0x48, 0xbf, 0x40, 0x08, 0x09, 0x78, + 0xc1, 0xf3, 0x41, 0x01, 0xc8, 0x40, 0x70, 0x47, 0x10, 0xb5, 0x95, 0x48, + 0x95, 0x4c, 0x40, 0x68, 0xff, 0xf7, 0xc4, 0xff, 0x20, 0x63, 0xff, 0xf7, + 0xe3, 0xff, 0x60, 0x63, 0xff, 0xf7, 0xe9, 0xff, 0xa0, 0x63, 0x95, 0x49, + 0xb0, 0xfb, 0xf1, 0xf0, 0x40, 0x1c, 0xe0, 0x63, 0x4f, 0xf4, 0x7a, 0x71, + 0xa0, 0x6b, 0xb0, 0xfb, 0xf1, 0xf0, 0x20, 0x64, 0x10, 0xbd, 0x4b, 0x01, + 0x19, 0x18, 0x8f, 0x48, 0x20, 0x22, 0x18, 0x18, 0x02, 0xf0, 0x10, 0xb8, + 0xf8, 0xb5, 0x8d, 0x4d, 0x8d, 0x4a, 0x29, 0x68, 0x51, 0x18, 0x00, 0x20, + 0x8c, 0x4a, 0x91, 0x42, 0x0c, 0xd2, 0x69, 0x68, 0x8b, 0x4a, 0x51, 0x18, + 0x8b, 0x4a, 0x91, 0x42, 0x06, 0xd2, 0x29, 0x7a, 0x04, 0x29, 0x03, 0xda, + 0x69, 0x89, 0xb1, 0xf5, 0x00, 0x7f, 0x00, 0xd3, 0x01, 0x20, 0xae, 0x7a, + 0x86, 0x49, 0x87, 0x4a, 0x87, 0x4b, 0x88, 0x4c, 0x03, 0x27, 0x3e, 0x42, + 0x0c, 0xd0, 0x2e, 0x7c, 0x03, 0x2e, 0x07, 0xda, 0x6e, 0x69, 0xa6, 0x19, + 0x9e, 0x42, 0x03, 0xd2, 0x6e, 0x6a, 0x00, 0xf0, 0x69, 0xf8, 0x02, 0xe0, + 0x01, 0x26, 0x00, 0xe0, 0x00, 0x26, 0x30, 0x43, 0xae, 0x7a, 0x0c, 0x27, + 0x3e, 0x42, 0x09, 0xd0, 0xee, 0x6a, 0xa6, 0x19, 0x9e, 0x42, 0x03, 0xd2, + 0xae, 0x6b, 0x00, 0xf0, 0x59, 0xf8, 0x02, 0xe0, 0x01, 0x26, 0x00, 0xe0, + 0x00, 0x26, 0x30, 0x43, 0xae, 0x7a, 0x30, 0x27, 0x3e, 0x42, 0x0b, 0xd0, + 0x2e, 0x6c, 0xa6, 0x19, 0x9e, 0x42, 0x05, 0xd2, 0xee, 0x6c, 0x73, 0x4f, + 0xbe, 0x42, 0xb6, 0x41, 0xf6, 0x0f, 0x02, 0xe0, 0x01, 0x26, 0x00, 0xe0, + 0x00, 0x26, 0x30, 0x43, 0x6e, 0x89, 0x4f, 0xf4, 0xe0, 0x77, 0x3e, 0x42, + 0x0c, 0xd0, 0x6e, 0x6d, 0xa4, 0x19, 0x9c, 0x42, 0x06, 0xd2, 0x2b, 0x6e, + 0xd2, 0x18, 0x8a, 0x42, 0x89, 0x41, 0xc9, 0x43, 0xc9, 0x0f, 0x02, 0xe0, + 0x01, 0x21, 0x00, 0xe0, 0x00, 0x21, 0x51, 0xea, 0x00, 0x04, 0x06, 0xd0, + 0x04, 0x22, 0x00, 0x23, 0x00, 0x21, 0x04, 0x20, 0x00, 0xf0, 0xe4, 0xf9, + 0x22, 0xe0, 0x4f, 0x4e, 0x64, 0x22, 0x29, 0x46, 0x30, 0x46, 0x01, 0xf0, + 0x9d, 0xff, 0x70, 0x89, 0xc0, 0xf3, 0x81, 0x00, 0x10, 0xb1, 0x00, 0x21, + 0x00, 0xf0, 0x1e, 0xf8, 0x70, 0x89, 0xc0, 0xf3, 0x01, 0x10, 0x10, 0xb1, + 0x01, 0x21, 0x00, 0xf0, 0x17, 0xf8, 0x70, 0x89, 0xc0, 0xf3, 0x82, 0x10, + 0x10, 0xb1, 0x02, 0x21, 0x00, 0xf0, 0x10, 0xf8, 0xb0, 0x7a, 0x03, 0x21, + 0x08, 0x42, 0x1c, 0xbf, 0x05, 0xf1, 0x64, 0x00, 0xff, 0xf7, 0x69, 0xff, + 0x20, 0x46, 0xf2, 0xbd, 0x96, 0x19, 0x8e, 0x42, 0xb6, 0x41, 0xf6, 0x43, + 0xf6, 0x0f, 0x70, 0x47, 0x05, 0xf1, 0x64, 0x00, 0x5d, 0xe7, 0x80, 0xb5, + 0x00, 0xf0, 0x43, 0xf8, 0x0e, 0xd0, 0x00, 0xf0, 0x35, 0xf8, 0x00, 0x21, + 0x40, 0xf2, 0x09, 0x20, 0xfb, 0xf7, 0x42, 0xf9, 0x00, 0xf0, 0x33, 0xf8, + 0x00, 0x22, 0x03, 0x21, 0x40, 0xf2, 0x0a, 0x20, 0xfb, 0xf7, 0x44, 0xf9, + 0xf8, 0x20, 0x00, 0xf0, 0x35, 0xf8, 0xbd, 0xe8, 0x02, 0x40, 0x0e, 0x20, + 0x00, 0xf0, 0xa5, 0xb8, 0x80, 0xb5, 0x05, 0x21, 0x4f, 0xf4, 0xd8, 0x70, + 0xfb, 0xf7, 0x2c, 0xf9, 0x00, 0x21, 0x4f, 0xf4, 0x82, 0x70, 0xfb, 0xf7, + 0x27, 0xf9, 0x00, 0xf0, 0x1e, 0xf8, 0x10, 0xd0, 0xff, 0x21, 0x40, 0xf2, + 0x09, 0x20, 0xfb, 0xf7, 0x1f, 0xf9, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, + 0x0e, 0xf8, 0xbd, 0xe8, 0x08, 0x40, 0x03, 0x22, 0x03, 0x21, 0x40, 0xf2, + 0x0a, 0x20, 0xfb, 0xf7, 0x1d, 0xb9, 0x01, 0xbd, 0xff, 0x21, 0x40, 0xf6, + 0x89, 0x50, 0xfb, 0xf7, 0x0d, 0xb9, 0x03, 0x22, 0x03, 0x21, 0x40, 0xf6, + 0x8a, 0x50, 0xfb, 0xf7, 0x11, 0xb9, 0x15, 0x48, 0x80, 0x7a, 0x03, 0x21, + 0x08, 0x42, 0x70, 0x47, 0x01, 0x07, 0x0a, 0xd5, 0x11, 0x49, 0x49, 0x89, + 0x01, 0xf0, 0x03, 0x02, 0x89, 0x08, 0x89, 0x01, 0x41, 0xea, 0x02, 0x11, + 0x41, 0xf0, 0x0f, 0x01, 0x08, 0x40, 0x01, 0x46, 0x4f, 0xf4, 0xd8, 0x70, + 0xfb, 0xf7, 0xf0, 0xb8, 0x00, 0x28, 0x14, 0xbf, 0x02, 0x22, 0x00, 0x22, + 0x02, 0x21, 0x4f, 0xf4, 0xd8, 0x70, 0xfb, 0xf7, 0xf1, 0xb8, 0x38, 0xb9, + 0x16, 0x49, 0x4f, 0xf0, 0x00, 0x40, 0x08, 0x60, 0x00, 0xbf, 0x00, 0xbf, + 0x00, 0xbf, 0x00, 0xbf, 0x70, 0x47, 0x00, 0x00, 0x78, 0x29, 0x00, 0x20, + 0x00, 0xf2, 0x00, 0x20, 0x19, 0x01, 0x00, 0x46, 0x02, 0x01, 0x00, 0x46, + 0x18, 0x01, 0x00, 0x46, 0x08, 0x0d, 0x00, 0x46, 0x40, 0x42, 0x0f, 0x00, + 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0xc0, 0x87, 0x82, 0xfe, + 0xc1, 0x57, 0x95, 0x11, 0x20, 0xf9, 0xa5, 0xff, 0x21, 0x79, 0x61, 0x00, + 0x81, 0x77, 0x8e, 0x06, 0x00, 0xd3, 0xce, 0xfe, 0x01, 0x70, 0x28, 0x12, + 0x00, 0xa0, 0x15, 0xff, 0x00, 0x2d, 0x31, 0x01, 0x04, 0xed, 0x00, 0xe0, + 0x10, 0xb5, 0x04, 0x46, 0x00, 0xf0, 0x07, 0xf8, 0x01, 0x21, 0x81, 0x40, + 0x49, 0x1e, 0x21, 0x42, 0x18, 0xbf, 0x40, 0x1c, 0x10, 0xbd, 0xb0, 0xfa, + 0x80, 0xf0, 0xc0, 0xf1, 0x1f, 0x00, 0x70, 0x47, 0x04, 0x06, 0x08, 0x0c, + 0x05, 0x0f, 0x0a, 0x0f, 0x01, 0x21, 0x00, 0xf0, 0x1f, 0x02, 0x91, 0x40, + 0x11, 0x4a, 0x04, 0xe0, 0x01, 0x21, 0x00, 0xf0, 0x1f, 0x02, 0x91, 0x40, + 0x0f, 0x4a, 0x40, 0x09, 0x42, 0xf8, 0x20, 0x10, 0x70, 0x47, 0x01, 0x21, + 0x00, 0xf0, 0x1f, 0x02, 0x91, 0x40, 0x0c, 0x4a, 0xf5, 0xe7, 0x01, 0x21, + 0x00, 0xf0, 0x1f, 0x02, 0x91, 0x40, 0x0a, 0x4a, 0xef, 0xe7, 0x09, 0x01, + 0x00, 0x28, 0x06, 0xd5, 0x08, 0x4a, 0x00, 0xf0, 0x0f, 0x00, 0x80, 0x18, + 0x00, 0xf8, 0x04, 0x1c, 0x70, 0x47, 0x06, 0x4a, 0x81, 0x54, 0x70, 0x47, + 0x80, 0xe2, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe0, 0x80, 0xe1, 0x00, 0xe0, + 0x00, 0xe2, 0x00, 0xe0, 0x18, 0xed, 0x00, 0xe0, 0x00, 0xe4, 0x00, 0xe0, + 0x42, 0x48, 0x00, 0xf1, 0x08, 0x01, 0x01, 0x60, 0x00, 0x21, 0xc1, 0x80, + 0x04, 0x21, 0x81, 0x80, 0x00, 0x21, 0x3f, 0x48, 0x81, 0x60, 0x6f, 0xf0, + 0x7f, 0x41, 0x01, 0x60, 0x15, 0x21, 0x81, 0x60, 0x70, 0x47, 0xef, 0xf3, + 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x37, 0x49, + 0x0a, 0x68, 0x10, 0x60, 0x01, 0xf5, 0x80, 0x50, 0x00, 0x1d, 0x82, 0x42, + 0x2c, 0xbf, 0x01, 0xf1, 0x08, 0x00, 0x10, 0x1d, 0x08, 0x60, 0xc8, 0x88, + 0xb0, 0xf5, 0x80, 0x6f, 0xbc, 0xbf, 0x40, 0x1c, 0xc8, 0x80, 0x70, 0x47, + 0x38, 0xb5, 0x04, 0x46, 0xff, 0xf7, 0xe3, 0xff, 0x05, 0x46, 0x00, 0xf0, + 0x11, 0xf8, 0x85, 0xf3, 0x11, 0x88, 0x31, 0xbd, 0x70, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0xff, 0xf7, 0xd8, 0xff, 0x06, 0x46, 0x00, 0xf0, 0x06, 0xf8, + 0x28, 0x46, 0xff, 0xf7, 0xd8, 0xff, 0x86, 0xf3, 0x11, 0x88, 0x70, 0xbd, + 0x23, 0x48, 0x01, 0x68, 0x00, 0x22, 0x42, 0x60, 0x15, 0x22, 0x42, 0x60, + 0x44, 0xea, 0xc1, 0x10, 0xcb, 0xe7, 0x10, 0xb5, 0x1f, 0x4a, 0x04, 0x46, + 0xd2, 0xe9, 0x02, 0x01, 0x22, 0x46, 0xfb, 0xf7, 0x21, 0xfa, 0xc0, 0x07, + 0x04, 0xd5, 0x44, 0xf0, 0x00, 0x40, 0xbd, 0xe8, 0x10, 0x40, 0xcf, 0xe7, + 0x10, 0xbd, 0x38, 0xb5, 0x00, 0xf0, 0x1f, 0xf8, 0xc0, 0x07, 0x08, 0xd5, + 0x05, 0xf0, 0x01, 0x00, 0x44, 0xea, 0x80, 0x10, 0xbd, 0xe8, 0x32, 0x40, + 0x40, 0xf0, 0x00, 0x40, 0xc0, 0xe7, 0x31, 0xbd, 0x38, 0xb5, 0x00, 0xf0, + 0x10, 0xf8, 0xc0, 0x07, 0x0c, 0xd5, 0x68, 0x0e, 0x00, 0xf0, 0x40, 0x00, + 0x04, 0xf0, 0x3f, 0x02, 0x69, 0x00, 0x10, 0x43, 0xbd, 0xe8, 0x34, 0x40, + 0x49, 0x08, 0x40, 0xf0, 0x00, 0x40, 0xb7, 0xe7, 0x31, 0xbd, 0x07, 0x4a, + 0x04, 0x46, 0x0d, 0x46, 0xd2, 0xe9, 0x02, 0x01, 0x22, 0x46, 0xfb, 0xf7, + 0xef, 0xb9, 0x00, 0x00, 0xb8, 0x82, 0x00, 0x20, 0x00, 0x00, 0x30, 0x59, + 0x04, 0x00, 0x30, 0x59, 0x88, 0x02, 0x00, 0x20, 0x10, 0xb5, 0x04, 0x46, + 0x00, 0xf0, 0x07, 0xf8, 0x20, 0x46, 0x07, 0xf0, 0x5b, 0xf8, 0xbd, 0xe8, + 0x10, 0x40, 0x07, 0xf0, 0x4b, 0xb8, 0x10, 0xb5, 0x30, 0x48, 0x00, 0x21, + 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x1e, 0xc0, 0x10, 0xbd, 0x10, 0xb5, + 0x00, 0xf0, 0x05, 0xf8, 0x23, 0xea, 0x00, 0x00, 0x42, 0xf8, 0x21, 0x00, + 0x10, 0xbd, 0x29, 0x4a, 0x01, 0x09, 0x52, 0xf8, 0x21, 0x30, 0x01, 0x24, + 0x40, 0x00, 0x04, 0xfa, 0x00, 0xf0, 0x70, 0x47, 0x30, 0xb5, 0x02, 0x09, + 0x23, 0x4b, 0x53, 0xf8, 0x22, 0x40, 0x40, 0x00, 0x40, 0x1c, 0x07, 0x25, + 0x85, 0x40, 0xac, 0x43, 0x43, 0xf8, 0x22, 0x40, 0x01, 0xf0, 0x07, 0x01, + 0x53, 0xf8, 0x22, 0x40, 0x01, 0xfa, 0x00, 0xf0, 0x20, 0x43, 0x43, 0xf8, + 0x22, 0x00, 0x30, 0xbd, 0x19, 0x4a, 0x03, 0x09, 0x52, 0xf8, 0x23, 0x20, + 0x43, 0x00, 0x5b, 0x1c, 0xda, 0x40, 0x02, 0xf0, 0x07, 0x02, 0x8a, 0x42, + 0x38, 0xbf, 0xff, 0xf7, 0xdd, 0xbf, 0x70, 0x47, 0xf0, 0xb5, 0xef, 0xf3, + 0x10, 0x84, 0x72, 0xb6, 0x11, 0x4d, 0xd5, 0xe9, 0x00, 0x67, 0x26, 0xea, + 0x02, 0x02, 0x27, 0xea, 0x03, 0x03, 0x10, 0x43, 0x19, 0x43, 0xc5, 0xe9, + 0x00, 0x01, 0x84, 0xf3, 0x10, 0x88, 0xf0, 0xbd, 0xd0, 0xb5, 0x04, 0x46, + 0xef, 0xf3, 0x10, 0x80, 0x72, 0xb6, 0x08, 0x49, 0xd1, 0xe9, 0x00, 0x67, + 0x80, 0xf3, 0x10, 0x88, 0x26, 0xea, 0x02, 0x00, 0x27, 0xea, 0x03, 0x01, + 0x22, 0x46, 0xbd, 0xe8, 0xd0, 0x40, 0xfb, 0xf7, 0x79, 0xb9, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x49, 0x10, 0x00, 0x00, 0x49, 0x3c, 0x48, 0x01, 0x74, + 0xc9, 0xb2, 0x03, 0x29, 0x9c, 0xbf, 0x00, 0x20, 0xff, 0xf7, 0x7f, 0xbe, + 0x70, 0x47, 0x30, 0xb5, 0x37, 0x4d, 0x85, 0xb0, 0x04, 0x46, 0x55, 0xf8, + 0x24, 0x10, 0xa1, 0xb9, 0x03, 0xa9, 0x02, 0x91, 0x00, 0x90, 0x00, 0x21, + 0x33, 0x48, 0x34, 0x4b, 0x01, 0x91, 0x01, 0x22, 0x50, 0xf8, 0x24, 0x00, + 0xfa, 0xf7, 0xe8, 0xfc, 0x45, 0xf8, 0x24, 0x00, 0x9d, 0xf8, 0x0c, 0x10, + 0x48, 0x1e, 0x80, 0x41, 0xc0, 0x0f, 0xff, 0xf7, 0x62, 0xfe, 0x05, 0xb0, + 0x30, 0xbd, 0x38, 0xb5, 0x28, 0x4d, 0x04, 0x46, 0x55, 0xf8, 0x24, 0x00, + 0x20, 0xb1, 0x69, 0x46, 0xfa, 0xf7, 0x12, 0xfd, 0x00, 0xf0, 0x1b, 0xf8, + 0x00, 0x20, 0x45, 0xf8, 0x24, 0x00, 0x31, 0xbd, 0x38, 0xb5, 0x00, 0xf0, + 0x3b, 0xf8, 0x11, 0xd1, 0x1f, 0x4d, 0x55, 0xf8, 0x24, 0x00, 0x68, 0xb1, + 0x69, 0x46, 0xfa, 0xf7, 0x5d, 0xfd, 0x01, 0x28, 0x08, 0xd1, 0x00, 0xf0, + 0x08, 0xf8, 0x55, 0xf8, 0x24, 0x00, 0x69, 0x46, 0xfa, 0xf7, 0x74, 0xfd, + 0x00, 0xf0, 0x01, 0xf8, 0x31, 0xbd, 0x9d, 0xf8, 0x00, 0x10, 0x48, 0x1e, + 0x80, 0x41, 0xc0, 0x0f, 0xff, 0xf7, 0x33, 0xbe, 0x38, 0xb5, 0x00, 0xf0, + 0x1d, 0xf8, 0x1a, 0xd1, 0x10, 0x4d, 0x55, 0xf8, 0x24, 0x00, 0xb0, 0xb1, + 0x69, 0x46, 0xfa, 0xf7, 0x3f, 0xfd, 0x03, 0x28, 0x11, 0xd1, 0xff, 0xf7, + 0xea, 0xff, 0x55, 0xf8, 0x24, 0x00, 0x69, 0x46, 0xfa, 0xf7, 0x00, 0xfd, + 0xff, 0xf7, 0xe3, 0xff, 0x55, 0xf8, 0x24, 0x00, 0x6b, 0x46, 0x00, 0x22, + 0x00, 0x21, 0xfa, 0xf7, 0x79, 0xfd, 0xff, 0xf7, 0xda, 0xff, 0x31, 0xbd, + 0x04, 0x46, 0x03, 0x48, 0x00, 0x7c, 0x01, 0x28, 0x70, 0x47, 0x00, 0x00, + 0x08, 0x1f, 0x00, 0x20, 0x1c, 0x1f, 0x00, 0x20, 0x45, 0x81, 0x00, 0x01, + 0x00, 0x20, 0x00, 0xe0, 0x01, 0x20, 0x38, 0xb5, 0xff, 0xf7, 0xee, 0xff, + 0x0b, 0xd1, 0x00, 0x25, 0x00, 0x2c, 0xe8, 0xb2, 0x02, 0xd1, 0xff, 0xf7, + 0x7c, 0xff, 0x01, 0xe0, 0xff, 0xf7, 0x97, 0xff, 0x6d, 0x1c, 0x04, 0x2d, + 0xf4, 0xd3, 0x31, 0xbd, 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, + 0x11, 0x88, 0x70, 0x47, 0x30, 0xb5, 0x00, 0xf0, 0x11, 0xf8, 0x23, 0x43, + 0x13, 0x60, 0x01, 0xeb, 0x40, 0x00, 0x01, 0x22, 0x42, 0x70, 0x30, 0xbd, + 0x30, 0xb5, 0x00, 0xf0, 0x07, 0xf8, 0xa3, 0x43, 0x13, 0x60, 0x01, 0xeb, + 0x40, 0x00, 0x00, 0x22, 0x42, 0x70, 0x30, 0xbd, 0xdf, 0xf8, 0xb0, 0x2c, + 0xdf, 0xf8, 0xd4, 0x1d, 0x13, 0x68, 0x11, 0xf9, 0x10, 0x50, 0x01, 0x24, + 0xac, 0x40, 0x70, 0x47, 0xdf, 0xf8, 0xa0, 0x0c, 0xc0, 0x6c, 0x70, 0x47, + 0xdf, 0xf8, 0x9c, 0x1c, 0xdf, 0xf8, 0x94, 0x0c, 0x89, 0x6b, 0xc0, 0x6c, + 0xdf, 0xf8, 0x94, 0x2c, 0xb1, 0xfb, 0xf2, 0xf1, 0x48, 0x43, 0xdf, 0xf8, + 0x68, 0x1d, 0x48, 0x60, 0x70, 0x47, 0x80, 0xb5, 0xdf, 0xf8, 0x3c, 0x0d, + 0x00, 0x21, 0x41, 0x71, 0x84, 0x30, 0xfb, 0xf7, 0xb1, 0xf9, 0x06, 0xf0, + 0xea, 0xf9, 0xbd, 0xe8, 0x01, 0x40, 0x06, 0xf0, 0x1a, 0xb9, 0xdf, 0xf8, + 0xc8, 0x1d, 0x02, 0x20, 0x08, 0x60, 0x70, 0x47, 0xdf, 0xf8, 0x18, 0x0d, + 0x41, 0x79, 0xd0, 0xf8, 0x80, 0x00, 0x00, 0x29, 0x18, 0xbf, 0x40, 0xf0, + 0x00, 0x40, 0x70, 0x47, 0xdf, 0xf8, 0x04, 0x0d, 0x01, 0x79, 0x00, 0x29, + 0x0e, 0xbf, 0x00, 0x20, 0xd0, 0xf8, 0x80, 0x00, 0xc0, 0xf3, 0x02, 0x10, + 0x70, 0x47, 0x10, 0xb5, 0xdf, 0xf8, 0x28, 0x4c, 0xa1, 0x7c, 0x4f, 0xf4, + 0x17, 0x60, 0xfa, 0xf7, 0x73, 0xfe, 0xe1, 0x7c, 0xbd, 0xe8, 0x10, 0x40, + 0x40, 0xf6, 0x71, 0x10, 0xfa, 0xf7, 0x6c, 0xbe, 0x2d, 0xe9, 0xf0, 0x47, + 0x06, 0x21, 0x31, 0x20, 0xff, 0xf7, 0xdf, 0xfd, 0x31, 0x20, 0xff, 0xf7, + 0xc1, 0xfd, 0x31, 0x20, 0xff, 0xf7, 0xc4, 0xfd, 0xff, 0xf7, 0xac, 0xff, + 0xdf, 0xf8, 0xb4, 0x4c, 0xdf, 0xf8, 0xd0, 0x5c, 0xdf, 0xf8, 0xd0, 0x1c, + 0xdf, 0xf8, 0xe4, 0x9b, 0x00, 0x20, 0x60, 0x71, 0x68, 0x68, 0x08, 0x60, + 0x06, 0x21, 0x10, 0x20, 0xff, 0xf7, 0xc7, 0xfd, 0x02, 0x21, 0x0c, 0x20, + 0xff, 0xf7, 0xc3, 0xfd, 0x02, 0x21, 0x0a, 0x20, 0xff, 0xf7, 0xbf, 0xfd, + 0x02, 0x21, 0x1d, 0x20, 0xff, 0xf7, 0xbb, 0xfd, 0x02, 0x21, 0x0d, 0x20, + 0xff, 0xf7, 0xb7, 0xfd, 0x02, 0x21, 0x0b, 0x20, 0xff, 0xf7, 0xb3, 0xfd, + 0x02, 0x21, 0x1e, 0x20, 0xff, 0xf7, 0xaf, 0xfd, 0x02, 0x21, 0x1f, 0x20, + 0xff, 0xf7, 0xab, 0xfd, 0xdf, 0xf8, 0xc4, 0x0d, 0x40, 0x89, 0xc0, 0xf3, + 0x81, 0x01, 0x89, 0xf8, 0x04, 0x10, 0x01, 0x23, 0x00, 0xf0, 0x03, 0x01, + 0x89, 0xf8, 0x05, 0x10, 0x00, 0x21, 0x03, 0xfa, 0x01, 0xf8, 0x08, 0xea, + 0x00, 0x06, 0x0f, 0x1d, 0x8a, 0x1c, 0x16, 0xf0, 0x03, 0x0f, 0x03, 0xfa, + 0x07, 0xf7, 0x03, 0xfa, 0x02, 0xf2, 0x03, 0xfa, 0x01, 0xfe, 0x0d, 0xd1, + 0x2e, 0x78, 0x42, 0xea, 0x0e, 0x0a, 0x47, 0xea, 0x0a, 0x0a, 0x4a, 0xea, + 0x06, 0x06, 0x2e, 0x70, 0x4e, 0xf0, 0x04, 0x0a, 0x6e, 0x78, 0x4a, 0xea, + 0x06, 0x06, 0x6e, 0x70, 0x08, 0xea, 0x90, 0x0a, 0x8e, 0x1d, 0x1a, 0xf0, + 0x03, 0x0f, 0x03, 0xfa, 0x06, 0xf6, 0x0b, 0xd1, 0x42, 0xea, 0x0e, 0x02, + 0x94, 0xf8, 0x06, 0xa0, 0x17, 0x43, 0x37, 0x43, 0x47, 0xea, 0x0a, 0x07, + 0xa7, 0x71, 0x4a, 0x19, 0x7f, 0x27, 0x97, 0x70, 0x08, 0xea, 0x10, 0x17, + 0x17, 0xf0, 0x03, 0x0f, 0x02, 0xd1, 0xe7, 0x79, 0x37, 0x43, 0xe7, 0x71, + 0x49, 0x1c, 0x02, 0x29, 0xc3, 0xdb, 0xc0, 0xf3, 0x82, 0x10, 0x20, 0xb9, + 0xe0, 0x79, 0x40, 0xf0, 0x30, 0x00, 0xe0, 0x71, 0x15, 0xe0, 0x80, 0x22, + 0x80, 0x21, 0x4f, 0xf4, 0x02, 0x60, 0xfa, 0xf7, 0xe5, 0xfd, 0xc0, 0x22, + 0xc0, 0x21, 0x40, 0xf6, 0x1f, 0x00, 0xfa, 0xf7, 0xdf, 0xfd, 0x3f, 0x21, + 0x40, 0xf6, 0x8c, 0x50, 0xfa, 0xf7, 0xd0, 0xfd, 0x03, 0x21, 0x4f, 0xf4, + 0x03, 0x70, 0xfa, 0xf7, 0xcb, 0xfd, 0xc0, 0x22, 0xc0, 0x21, 0x40, 0xf6, + 0x14, 0x00, 0xfa, 0xf7, 0xcf, 0xfd, 0xc0, 0x22, 0xc0, 0x21, 0x40, 0xf6, + 0x12, 0x00, 0xfa, 0xf7, 0xc9, 0xfd, 0xc0, 0x22, 0xc0, 0x21, 0x40, 0xf6, + 0x13, 0x00, 0xfa, 0xf7, 0xc3, 0xfd, 0xc0, 0x22, 0xc0, 0x21, 0x40, 0xf2, + 0x42, 0x50, 0xfa, 0xf7, 0xbd, 0xfd, 0xc0, 0x22, 0xc0, 0x21, 0x40, 0xf2, + 0x43, 0x50, 0xfa, 0xf7, 0xb7, 0xfd, 0x00, 0x22, 0xc0, 0x21, 0x40, 0xf2, + 0xe4, 0x60, 0xfa, 0xf7, 0xb1, 0xfd, 0x99, 0xf8, 0x04, 0x00, 0x99, 0xf8, + 0x05, 0x10, 0x40, 0xea, 0x81, 0x00, 0xc4, 0xf8, 0x80, 0x00, 0x06, 0xf0, + 0x2b, 0xf8, 0xbd, 0xe8, 0xf0, 0x47, 0x05, 0xf0, 0x6b, 0xbe, 0x80, 0xb5, + 0x4f, 0xf0, 0x92, 0x41, 0x00, 0x20, 0x08, 0x60, 0x04, 0x21, 0x01, 0x20, + 0xff, 0xf7, 0x09, 0xfd, 0x01, 0x20, 0xff, 0xf7, 0xf1, 0xfc, 0x00, 0x20, + 0x02, 0xbd, 0xf8, 0xb5, 0x0a, 0x20, 0xff, 0xf7, 0xe5, 0xfc, 0x1d, 0x20, + 0xff, 0xf7, 0xe2, 0xfc, 0x0c, 0x20, 0xff, 0xf7, 0xdf, 0xfc, 0xdf, 0xf8, + 0x78, 0x3c, 0xdf, 0xf8, 0x78, 0x5c, 0xdf, 0xf8, 0x30, 0x2a, 0xdf, 0xf8, + 0xf0, 0x4a, 0x00, 0x20, 0x98, 0x60, 0x18, 0x60, 0x28, 0x60, 0x4f, 0xf4, + 0x00, 0x21, 0x90, 0x78, 0x70, 0xb9, 0x00, 0xf0, 0xfd, 0xf9, 0x10, 0x79, + 0xc2, 0x07, 0x4c, 0xbf, 0x80, 0x22, 0x00, 0x22, 0xa2, 0x65, 0x80, 0x07, + 0x58, 0xbf, 0x00, 0x21, 0x21, 0x66, 0x03, 0x20, 0x20, 0x72, 0x45, 0xe0, + 0x03, 0xf1, 0x40, 0x00, 0x60, 0x62, 0x03, 0xf1, 0x3c, 0x00, 0xa0, 0x62, + 0x05, 0xf1, 0x40, 0x00, 0x20, 0x63, 0x05, 0xf1, 0x3c, 0x00, 0x60, 0x63, + 0x80, 0x20, 0xd8, 0x63, 0xe9, 0x63, 0x98, 0x6c, 0x40, 0xf0, 0x80, 0x00, + 0x98, 0x64, 0xd8, 0x6c, 0x40, 0xf0, 0x80, 0x00, 0xd8, 0x64, 0xa8, 0x6c, + 0x40, 0xf4, 0x00, 0x20, 0xa8, 0x64, 0xe8, 0x6c, 0x40, 0xf4, 0x00, 0x20, + 0xe8, 0x64, 0xdf, 0xf8, 0xe8, 0x0b, 0x46, 0x89, 0xc6, 0xf3, 0x81, 0x07, + 0x03, 0x2f, 0x04, 0xbf, 0x12, 0x78, 0x00, 0x2a, 0x40, 0xf2, 0x05, 0x10, + 0x05, 0xd1, 0x80, 0x21, 0x99, 0x60, 0x08, 0x22, 0x04, 0x21, 0x21, 0x72, + 0x11, 0xe0, 0x00, 0x22, 0x22, 0x72, 0xc6, 0xf3, 0x80, 0x02, 0x1a, 0xb1, + 0x80, 0x22, 0x1a, 0x60, 0x01, 0x22, 0x22, 0x72, 0xb2, 0x08, 0x92, 0x07, + 0x04, 0xd5, 0x29, 0x60, 0x21, 0x7a, 0x41, 0xf0, 0x02, 0x01, 0x21, 0x72, + 0x00, 0x22, 0x08, 0x21, 0xfa, 0xf7, 0x26, 0xfd, 0x00, 0xf0, 0xc3, 0xf9, + 0x05, 0xf0, 0xeb, 0xff, 0xd4, 0xf8, 0x80, 0x00, 0x80, 0x08, 0x80, 0x00, + 0xc4, 0xf8, 0x80, 0x00, 0x0a, 0x20, 0xff, 0xf7, 0x82, 0xfc, 0x1d, 0x20, + 0xff, 0xf7, 0x7f, 0xfc, 0xbd, 0xe8, 0xf2, 0x40, 0x0c, 0x20, 0xff, 0xf7, + 0x7a, 0xbc, 0xf8, 0xb5, 0x0d, 0x20, 0xff, 0xf7, 0x61, 0xfc, 0x0b, 0x20, + 0xff, 0xf7, 0x5e, 0xfc, 0x1e, 0x20, 0xff, 0xf7, 0x5b, 0xfc, 0xdf, 0xf8, + 0xf8, 0x5b, 0xdf, 0xf8, 0xf8, 0x6b, 0xdf, 0xf8, 0x28, 0x39, 0xdf, 0xf8, + 0xdc, 0x1c, 0xdf, 0xf8, 0xe4, 0x49, 0x00, 0x20, 0xa8, 0x60, 0x28, 0x60, + 0x30, 0x60, 0x4f, 0xf4, 0x80, 0x12, 0x98, 0x78, 0x70, 0xb9, 0x00, 0xf0, + 0x6a, 0xf9, 0x58, 0x79, 0xc3, 0x07, 0x4c, 0xbf, 0x40, 0x23, 0x00, 0x23, + 0xa3, 0x64, 0x80, 0x07, 0x58, 0xbf, 0x00, 0x22, 0x22, 0x65, 0x03, 0x20, + 0x08, 0x70, 0x43, 0xe0, 0x05, 0xf1, 0x3c, 0x00, 0xe0, 0x60, 0x05, 0xf1, + 0x38, 0x00, 0x20, 0x61, 0x06, 0xf1, 0x3c, 0x00, 0xa0, 0x61, 0x06, 0xf1, + 0x38, 0x00, 0xe0, 0x61, 0x40, 0x20, 0xa8, 0x63, 0xb2, 0x63, 0x68, 0x6c, + 0x40, 0xf0, 0x40, 0x00, 0x68, 0x64, 0xa8, 0x6c, 0x40, 0xf0, 0x40, 0x00, + 0xa8, 0x64, 0x70, 0x6c, 0x40, 0xf4, 0x80, 0x10, 0x70, 0x64, 0xb0, 0x6c, + 0x40, 0xf4, 0x80, 0x10, 0xb0, 0x64, 0xdf, 0xf8, 0xdc, 0x0a, 0x47, 0x89, + 0x07, 0xf0, 0x03, 0x0c, 0xbc, 0xf1, 0x03, 0x0f, 0x04, 0xbf, 0x5b, 0x78, + 0x00, 0x2b, 0x40, 0xf2, 0x05, 0x10, 0x04, 0xd1, 0x40, 0x22, 0xaa, 0x60, + 0x04, 0x22, 0x0a, 0x70, 0x0f, 0xe0, 0x00, 0x23, 0x0b, 0x70, 0xfb, 0x07, + 0x03, 0xd5, 0x40, 0x23, 0x2b, 0x60, 0x01, 0x23, 0x0b, 0x70, 0xbb, 0x07, + 0x04, 0xd5, 0x32, 0x60, 0x0a, 0x78, 0x42, 0xf0, 0x02, 0x02, 0x0a, 0x70, + 0x00, 0x22, 0x04, 0x21, 0xfa, 0xf7, 0xa2, 0xfc, 0x00, 0xf0, 0x6f, 0xf9, + 0xff, 0xf7, 0x19, 0xfe, 0xd4, 0xf8, 0x80, 0x00, 0x20, 0xf0, 0x0c, 0x00, + 0xc4, 0xf8, 0x80, 0x00, 0x0b, 0x20, 0xff, 0xf7, 0xfe, 0xfb, 0x1e, 0x20, + 0xff, 0xf7, 0xfb, 0xfb, 0xbd, 0xe8, 0xf2, 0x40, 0x0d, 0x20, 0xff, 0xf7, + 0xf6, 0xbb, 0x2d, 0xe9, 0xf8, 0x43, 0xdf, 0xf8, 0x38, 0x58, 0xdf, 0xf8, + 0xf0, 0x6b, 0xe8, 0x78, 0xdf, 0xf8, 0xf0, 0x48, 0x98, 0xb9, 0x00, 0xf0, + 0x12, 0xf9, 0x30, 0x60, 0x10, 0x20, 0x60, 0x64, 0xa9, 0x79, 0x48, 0x08, + 0x40, 0x00, 0x01, 0xf0, 0x01, 0x02, 0x89, 0x08, 0x00, 0xf0, 0x02, 0x00, + 0x89, 0x00, 0x10, 0x43, 0x01, 0xf0, 0x04, 0x01, 0x08, 0x43, 0xa0, 0x66, + 0x37, 0xe0, 0x00, 0x20, 0x01, 0xf0, 0x88, 0xfb, 0x80, 0x46, 0x01, 0x20, + 0x01, 0xf0, 0x84, 0xfb, 0x07, 0x46, 0x02, 0x20, 0x01, 0xf0, 0x80, 0xfb, + 0x81, 0x46, 0x03, 0x20, 0x01, 0xf0, 0x7c, 0xfb, 0xa8, 0xf1, 0x04, 0x01, + 0x04, 0x2f, 0x21, 0x67, 0x0a, 0xd2, 0x07, 0xf1, 0x0a, 0x02, 0x62, 0x67, + 0x0a, 0x30, 0xe0, 0x67, 0x09, 0xf1, 0x0a, 0x02, 0xa2, 0x67, 0xdf, 0xf8, + 0x88, 0x0b, 0x0c, 0xe0, 0x10, 0x2f, 0x09, 0xd2, 0x3a, 0x1f, 0x62, 0x67, + 0x00, 0x1f, 0xe0, 0x67, 0xa9, 0xf1, 0x04, 0x02, 0xa2, 0x67, 0x06, 0xf1, + 0x38, 0x00, 0x00, 0xe0, 0x00, 0x20, 0xe0, 0x63, 0x01, 0x20, 0x88, 0x40, + 0x06, 0xf1, 0x34, 0x01, 0x21, 0x64, 0x60, 0x64, 0x70, 0x63, 0x30, 0x60, + 0x31, 0x6c, 0x08, 0x43, 0x30, 0x64, 0x00, 0x22, 0x03, 0x21, 0x40, 0xf2, + 0x05, 0x10, 0xfa, 0xf7, 0x31, 0xfc, 0x00, 0x21, 0x4f, 0xf4, 0x82, 0x70, + 0xfa, 0xf7, 0x22, 0xfc, 0xdf, 0xf8, 0xb4, 0x0b, 0x00, 0x78, 0x60, 0x70, + 0x29, 0x7e, 0xc9, 0x07, 0x48, 0xbf, 0x40, 0xf0, 0xc0, 0x00, 0x20, 0x70, + 0x00, 0xf0, 0x10, 0xf9, 0x05, 0xf0, 0x58, 0xfd, 0xd4, 0xf8, 0x80, 0x00, + 0xdf, 0xf8, 0x98, 0x1b, 0x20, 0xf0, 0x70, 0x00, 0xc4, 0xf8, 0x80, 0x00, + 0x00, 0x20, 0x08, 0x70, 0x1f, 0x20, 0xbd, 0xe8, 0xf2, 0x43, 0xff, 0xf7, + 0x78, 0xbb, 0xdf, 0xf8, 0x84, 0x0b, 0x01, 0x79, 0x01, 0x29, 0x0c, 0xbf, + 0x02, 0x21, 0x00, 0x21, 0x01, 0x71, 0x00, 0x20, 0x70, 0x47, 0x10, 0xb5, + 0xdf, 0xf8, 0xec, 0x47, 0x20, 0x79, 0x02, 0x28, 0x6d, 0xd1, 0xdf, 0xf8, + 0x68, 0x0b, 0x01, 0x68, 0x21, 0xf0, 0xc0, 0x01, 0x01, 0x60, 0x41, 0x68, + 0x21, 0xf0, 0xc0, 0x01, 0x41, 0x60, 0xdf, 0xf8, 0x58, 0x0b, 0x01, 0x68, + 0x21, 0xf4, 0xc0, 0x11, 0x01, 0x60, 0x41, 0x68, 0x21, 0xf4, 0xc0, 0x11, + 0x41, 0x60, 0xdf, 0xf8, 0xf8, 0x16, 0xc9, 0x78, 0x01, 0x29, 0x05, 0xd1, + 0x01, 0x68, 0x23, 0x6f, 0x01, 0x22, 0x9a, 0x40, 0x91, 0x43, 0x01, 0x60, + 0x05, 0xf0, 0x07, 0xff, 0x00, 0xf0, 0x60, 0xf8, 0x00, 0x20, 0xa0, 0x65, + 0x20, 0x66, 0x0c, 0x20, 0xff, 0xf7, 0x3f, 0xfb, 0x0a, 0x20, 0xff, 0xf7, + 0x3c, 0xfb, 0x1d, 0x20, 0xff, 0xf7, 0x39, 0xfb, 0x00, 0xf0, 0x45, 0xf8, + 0x00, 0x20, 0xa0, 0x64, 0x20, 0x65, 0x0d, 0x20, 0xff, 0xf7, 0x31, 0xfb, + 0x0b, 0x20, 0xff, 0xf7, 0x2e, 0xfb, 0x1e, 0x20, 0xff, 0xf7, 0x2b, 0xfb, + 0x00, 0xf0, 0x51, 0xf8, 0xa0, 0x66, 0x1f, 0x20, 0xff, 0xf7, 0x25, 0xfb, + 0xdf, 0xf8, 0xd8, 0x1a, 0x01, 0x20, 0x08, 0x70, 0x10, 0x20, 0xff, 0xf7, + 0x18, 0xfb, 0x0a, 0x20, 0xff, 0xf7, 0x15, 0xfb, 0x1d, 0x20, 0xff, 0xf7, + 0x12, 0xfb, 0x0c, 0x20, 0xff, 0xf7, 0x0f, 0xfb, 0x0b, 0x20, 0xff, 0xf7, + 0x0c, 0xfb, 0x1e, 0x20, 0xff, 0xf7, 0x09, 0xfb, 0x0d, 0x20, 0xff, 0xf7, + 0x06, 0xfb, 0x1f, 0x20, 0xff, 0xf7, 0x03, 0xfb, 0x06, 0xf0, 0x7b, 0xfc, + 0x00, 0x20, 0xff, 0xf7, 0xa1, 0xfa, 0xff, 0xf7, 0x5d, 0xfa, 0x07, 0x22, + 0x04, 0xf1, 0x8c, 0x01, 0x0f, 0xf6, 0xfc, 0x20, 0xfa, 0xf7, 0xa6, 0xfb, + 0x04, 0xe0, 0x00, 0x20, 0xff, 0xf7, 0x94, 0xfa, 0xff, 0xf7, 0x50, 0xfa, + 0x00, 0x20, 0x20, 0x71, 0x10, 0xbd, 0x04, 0xf1, 0x48, 0x00, 0xe0, 0x60, + 0x04, 0xf1, 0x4c, 0x00, 0x20, 0x61, 0x04, 0xf1, 0x50, 0x00, 0xa0, 0x61, + 0x04, 0xf1, 0x54, 0x00, 0xe0, 0x61, 0x70, 0x47, 0x04, 0xf1, 0x58, 0x00, + 0x60, 0x62, 0x04, 0xf1, 0x5c, 0x00, 0xa0, 0x62, 0x04, 0xf1, 0x60, 0x00, + 0x20, 0x63, 0x04, 0xf1, 0x64, 0x00, 0x60, 0x63, 0x70, 0x47, 0x04, 0xf1, + 0x68, 0x00, 0xe0, 0x63, 0x04, 0xf1, 0x6c, 0x00, 0x20, 0x64, 0x00, 0x20, + 0x60, 0x67, 0x01, 0x20, 0xa0, 0x67, 0x02, 0x20, 0xe0, 0x67, 0x00, 0x20, + 0x70, 0x47, 0x38, 0xb5, 0xdf, 0xf8, 0xe0, 0x45, 0xdf, 0xf8, 0xa0, 0x16, + 0x20, 0x7b, 0x89, 0x79, 0xdf, 0xf8, 0xb8, 0x56, 0x20, 0xea, 0x01, 0x01, + 0x40, 0xf6, 0x84, 0x50, 0xfa, 0xf7, 0x48, 0xfb, 0x60, 0x7b, 0xa9, 0x78, + 0x20, 0xea, 0x01, 0x01, 0x40, 0xf6, 0x85, 0x50, 0xfa, 0xf7, 0x40, 0xfb, + 0xa0, 0x7b, 0xe9, 0x78, 0x20, 0xea, 0x01, 0x01, 0x40, 0xf6, 0x86, 0x50, + 0xfa, 0xf7, 0x38, 0xfb, 0x00, 0x21, 0x4f, 0xf4, 0x01, 0x70, 0xfa, 0xf7, + 0x33, 0xfb, 0x00, 0x21, 0x40, 0xf2, 0x05, 0x20, 0xfa, 0xf7, 0x2e, 0xfb, + 0xbd, 0xe8, 0x34, 0x40, 0x00, 0x21, 0x40, 0xf2, 0x06, 0x20, 0xfa, 0xf7, + 0x27, 0xbb, 0x38, 0xb5, 0xdf, 0xf8, 0x64, 0x46, 0xdf, 0xf8, 0xcc, 0x59, + 0x21, 0x78, 0x28, 0x7c, 0x20, 0xea, 0x01, 0x01, 0x40, 0xf6, 0x89, 0x50, + 0xfa, 0xf7, 0x1a, 0xfb, 0x68, 0x7c, 0x61, 0x78, 0x20, 0xea, 0x01, 0x01, + 0x40, 0xf6, 0x8a, 0x50, 0xfa, 0xf7, 0x12, 0xfb, 0x00, 0x21, 0x40, 0xf2, + 0x09, 0x20, 0xfa, 0xf7, 0x0d, 0xfb, 0xbd, 0xe8, 0x34, 0x40, 0x00, 0x21, + 0x40, 0xf2, 0x0a, 0x20, 0xfa, 0xf7, 0x06, 0xbb, 0x80, 0xb5, 0xdf, 0xf8, + 0x04, 0x16, 0xdf, 0xf8, 0x3c, 0x05, 0xc9, 0x79, 0x40, 0x69, 0xc9, 0x43, + 0x01, 0x40, 0xc9, 0xb2, 0x40, 0xf6, 0x87, 0x50, 0xfa, 0xf7, 0xf8, 0xfa, + 0xbd, 0xe8, 0x04, 0x40, 0x00, 0x21, 0x40, 0xf2, 0x07, 0x20, 0xfa, 0xf7, + 0xf1, 0xba, 0xf8, 0xb5, 0x00, 0x24, 0x0f, 0xf6, 0x18, 0x25, 0x0f, 0xf6, + 0x10, 0x26, 0xa0, 0x5d, 0xfb, 0xf7, 0x36, 0xfe, 0x30, 0xb1, 0x20, 0x46, + 0x01, 0xf0, 0x6d, 0xfd, 0x10, 0xb9, 0x20, 0x46, 0x05, 0xf0, 0xb3, 0xf9, + 0x60, 0x5d, 0xfb, 0xf7, 0x2b, 0xfe, 0x10, 0xb1, 0x20, 0x46, 0xfd, 0xf7, + 0x62, 0xfe, 0x64, 0x1c, 0x02, 0x2c, 0xea, 0xd3, 0x04, 0xf0, 0xa1, 0xfa, + 0x08, 0xb1, 0x04, 0xf0, 0xa2, 0xfa, 0xdf, 0xf8, 0xd8, 0x44, 0xe0, 0x78, + 0x01, 0x28, 0x43, 0xd1, 0x00, 0x20, 0x01, 0xf0, 0xef, 0xf9, 0x00, 0x1f, + 0x0c, 0x28, 0x3b, 0xd2, 0x01, 0x20, 0x01, 0xf0, 0xe9, 0xf9, 0x05, 0x46, + 0x02, 0x20, 0x01, 0xf0, 0xe5, 0xf9, 0x06, 0x46, 0x03, 0x20, 0x01, 0xf0, + 0xe1, 0xf9, 0x04, 0x2d, 0xb8, 0xbf, 0x00, 0x21, 0x07, 0xdb, 0x10, 0x2d, + 0xb8, 0xbf, 0x01, 0x21, 0x03, 0xdb, 0x13, 0x2d, 0xb4, 0xbf, 0x02, 0x21, + 0x03, 0x21, 0x04, 0x2e, 0xb8, 0xbf, 0x00, 0x22, 0x07, 0xdb, 0x10, 0x2e, + 0xb8, 0xbf, 0x01, 0x22, 0x03, 0xdb, 0x13, 0x2e, 0xb4, 0xbf, 0x02, 0x22, + 0x03, 0x22, 0x04, 0x28, 0xb8, 0xbf, 0x00, 0x23, 0x07, 0xdb, 0x10, 0x28, + 0xb8, 0xbf, 0x01, 0x23, 0x03, 0xdb, 0x13, 0x28, 0xb4, 0xbf, 0x02, 0x23, + 0x03, 0x23, 0x03, 0x29, 0x0a, 0xd2, 0x91, 0x42, 0x08, 0xbf, 0x99, 0x42, + 0x06, 0xd1, 0x02, 0x29, 0x06, 0xd1, 0x10, 0x2d, 0x04, 0xbf, 0x11, 0x2e, + 0x12, 0x28, 0x01, 0xd0, 0x04, 0x20, 0xf2, 0xbd, 0xef, 0xf3, 0x10, 0x86, + 0x72, 0xb6, 0xdf, 0xf8, 0x04, 0x55, 0x0f, 0xf6, 0xec, 0x00, 0x07, 0x22, + 0x05, 0xf1, 0x8c, 0x01, 0xfa, 0xf7, 0xad, 0xfa, 0xff, 0xf7, 0xef, 0xfc, + 0xff, 0xf7, 0x71, 0xfd, 0xff, 0xf7, 0xf3, 0xfd, 0x21, 0x7a, 0x4f, 0xf4, + 0xdb, 0x70, 0xfa, 0xf7, 0x71, 0xfa, 0x61, 0x7a, 0x40, 0xf2, 0xb7, 0x10, + 0xfa, 0xf7, 0x6c, 0xfa, 0x08, 0x20, 0xff, 0xf7, 0x67, 0xf9, 0x40, 0xf2, + 0x2f, 0x47, 0x80, 0x22, 0x80, 0x21, 0x38, 0x46, 0xfa, 0xf7, 0x6c, 0xfa, + 0x00, 0x22, 0x80, 0x21, 0x38, 0x46, 0xfa, 0xf7, 0x67, 0xfa, 0xa0, 0x78, + 0x01, 0x28, 0x18, 0xbf, 0x00, 0x20, 0xff, 0xf7, 0x67, 0xf9, 0xff, 0xf7, + 0xa3, 0xfb, 0x01, 0x20, 0x28, 0x71, 0x86, 0xf3, 0x10, 0x88, 0x10, 0x20, + 0xff, 0xf7, 0xb2, 0xf9, 0x28, 0x7a, 0x41, 0x07, 0x48, 0xbf, 0x0c, 0x20, + 0x08, 0xd4, 0xc0, 0x07, 0x44, 0xbf, 0x0a, 0x20, 0xff, 0xf7, 0xa8, 0xf9, + 0x28, 0x7a, 0x80, 0x07, 0x02, 0xd5, 0x1d, 0x20, 0xff, 0xf7, 0xa2, 0xf9, + 0xdf, 0xf8, 0x68, 0x47, 0x20, 0x78, 0x41, 0x07, 0x48, 0xbf, 0x0d, 0x20, + 0x08, 0xd4, 0xc0, 0x07, 0x44, 0xbf, 0x0b, 0x20, 0xff, 0xf7, 0x96, 0xf9, + 0x20, 0x78, 0x80, 0x07, 0x02, 0xd5, 0x1e, 0x20, 0xff, 0xf7, 0x90, 0xf9, + 0x1f, 0x20, 0xff, 0xf7, 0x8d, 0xf9, 0x06, 0xf0, 0xc5, 0xfa, 0x00, 0x20, + 0xf2, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, 0x4f, 0xf0, 0x92, 0x45, 0xdf, 0xf8, + 0x3c, 0x64, 0x28, 0x68, 0x69, 0x68, 0x6f, 0x68, 0x4f, 0xea, 0x11, 0x28, + 0x31, 0x79, 0x00, 0x24, 0x01, 0x29, 0x04, 0xbf, 0x00, 0xf0, 0x3f, 0x00, + 0x0a, 0x28, 0x63, 0xd1, 0x00, 0x21, 0xff, 0xf7, 0x53, 0xfa, 0xff, 0xb2, + 0x61, 0x2f, 0xdf, 0xf8, 0xa0, 0x07, 0x40, 0xd0, 0x64, 0x2f, 0x04, 0xbf, + 0x80, 0x78, 0x00, 0x28, 0x56, 0xd1, 0xd6, 0xf8, 0x80, 0x00, 0x08, 0xf0, + 0x0f, 0x08, 0x88, 0xea, 0x00, 0x07, 0xf8, 0x07, 0x0b, 0xd5, 0x71, 0x6a, + 0x08, 0xf0, 0x01, 0x00, 0xc0, 0x01, 0x08, 0x60, 0x01, 0x24, 0xb1, 0x6a, + 0xf0, 0x6a, 0x08, 0x60, 0x0a, 0x20, 0xff, 0xf7, 0x64, 0xf9, 0xb8, 0x07, + 0x0b, 0xd5, 0x31, 0x6b, 0x08, 0xf0, 0x02, 0x00, 0x80, 0x04, 0x08, 0x60, + 0x01, 0x24, 0x71, 0x6b, 0xb0, 0x6b, 0x08, 0x60, 0x1d, 0x20, 0xff, 0xf7, + 0x56, 0xf9, 0x78, 0x07, 0x0b, 0xd5, 0xf1, 0x68, 0x08, 0xf0, 0x04, 0x00, + 0x00, 0x01, 0x08, 0x60, 0x01, 0x24, 0x31, 0x69, 0x70, 0x69, 0x08, 0x60, + 0x0b, 0x20, 0xff, 0xf7, 0x48, 0xf9, 0x38, 0x07, 0x1c, 0xd5, 0xb1, 0x69, + 0x08, 0xf0, 0x08, 0x00, 0x40, 0x04, 0x08, 0x60, 0xf1, 0x69, 0x30, 0x6a, + 0x08, 0x60, 0x1e, 0x20, 0x0f, 0xe0, 0xc0, 0x78, 0xc0, 0xb9, 0xf1, 0x6b, + 0x08, 0xf0, 0x07, 0x00, 0x08, 0x60, 0x04, 0x28, 0x32, 0x6c, 0x71, 0x6c, + 0x11, 0x60, 0x04, 0xbf, 0xc8, 0xf3, 0x01, 0x10, 0x00, 0xf0, 0xf3, 0xfa, + 0x1f, 0x20, 0xff, 0xf7, 0x2a, 0xf9, 0x00, 0xe0, 0x5c, 0xb1, 0x00, 0x20, + 0x28, 0x60, 0x0a, 0x20, 0xbd, 0xe8, 0xf0, 0x41, 0xfb, 0xf7, 0x1b, 0xbc, + 0xbd, 0xe8, 0xf0, 0x41, 0x0f, 0x20, 0xff, 0xf7, 0x1c, 0xb9, 0xbd, 0xe8, + 0xf0, 0x81, 0x10, 0xb5, 0x05, 0xf0, 0xe8, 0xfc, 0x05, 0xf0, 0x1c, 0xfc, + 0xd8, 0x4c, 0x00, 0x20, 0xa0, 0x60, 0x02, 0x20, 0xe0, 0x60, 0x31, 0x20, + 0xff, 0xf7, 0xf8, 0xf8, 0xcb, 0x48, 0x01, 0x21, 0x41, 0x71, 0x84, 0x30, + 0xd1, 0x49, 0x49, 0x68, 0x21, 0x60, 0x70, 0x21, 0xa1, 0x60, 0xbd, 0xe8, + 0x10, 0x40, 0xfa, 0xf7, 0xa3, 0xbc, 0x70, 0xb5, 0x00, 0xf0, 0x8c, 0xf8, + 0x10, 0xd5, 0x30, 0x78, 0x40, 0xf0, 0x40, 0x00, 0x30, 0x70, 0x04, 0x20, + 0xff, 0xf7, 0xae, 0xfa, 0xd5, 0xf8, 0x80, 0x00, 0x40, 0xf0, 0x01, 0x00, + 0xc5, 0xf8, 0x80, 0x00, 0x00, 0x20, 0xc0, 0x46, 0xc0, 0x46, 0x0f, 0xe0, + 0x00, 0x20, 0xc0, 0x46, 0xc0, 0x46, 0x30, 0x78, 0x00, 0xf0, 0xbf, 0x00, + 0x30, 0x70, 0x04, 0x20, 0xff, 0xf7, 0xa4, 0xfa, 0xd5, 0xf8, 0x80, 0x00, + 0x40, 0x08, 0x40, 0x00, 0xc5, 0xf8, 0x80, 0x00, 0x62, 0xe0, 0x70, 0xb5, + 0xb1, 0x4c, 0xdf, 0xf8, 0x54, 0x56, 0x61, 0x6b, 0xdf, 0xf8, 0x50, 0x66, + 0x4f, 0xf4, 0x00, 0x20, 0x08, 0x60, 0x4f, 0xf6, 0xfe, 0x60, 0x28, 0x60, + 0x20, 0x6b, 0x00, 0x68, 0x00, 0x03, 0x10, 0xd5, 0x30, 0x78, 0x40, 0xf0, + 0x80, 0x00, 0x30, 0x70, 0x05, 0x20, 0xff, 0xf7, 0x7b, 0xfa, 0xd4, 0xf8, + 0x80, 0x00, 0x40, 0xf0, 0x02, 0x00, 0xc4, 0xf8, 0x80, 0x00, 0x01, 0x20, + 0xc0, 0x46, 0xc0, 0x46, 0x0f, 0xe0, 0x01, 0x20, 0xc0, 0x46, 0xc0, 0x46, + 0x30, 0x78, 0x00, 0xf0, 0x7f, 0x00, 0x30, 0x70, 0x05, 0x20, 0xff, 0xf7, + 0x71, 0xfa, 0xd4, 0xf8, 0x80, 0x00, 0x20, 0xf0, 0x02, 0x00, 0xc4, 0xf8, + 0x80, 0x00, 0x10, 0x20, 0xff, 0xf7, 0xa5, 0xf8, 0x00, 0x20, 0x28, 0x60, + 0x70, 0xbd, 0x70, 0xb5, 0x00, 0xf0, 0x2e, 0xf8, 0x13, 0xd5, 0x30, 0x78, + 0x40, 0xf0, 0xc0, 0x00, 0x30, 0x70, 0x04, 0x20, 0xff, 0xf7, 0x50, 0xfa, + 0x05, 0x20, 0xff, 0xf7, 0x4d, 0xfa, 0xd5, 0xf8, 0x80, 0x00, 0x40, 0xf0, + 0x03, 0x00, 0xc5, 0xf8, 0x80, 0x00, 0x02, 0x20, 0xc0, 0x46, 0xc0, 0x46, + 0x12, 0xe0, 0x02, 0x20, 0xc0, 0x46, 0xc0, 0x46, 0x30, 0x78, 0x00, 0xf0, + 0x3f, 0x00, 0x30, 0x70, 0x04, 0x20, 0xff, 0xf7, 0x43, 0xfa, 0x05, 0x20, + 0xff, 0xf7, 0x40, 0xfa, 0xd5, 0xf8, 0x80, 0x00, 0x80, 0x08, 0x80, 0x00, + 0xc5, 0xf8, 0x80, 0x00, 0x10, 0x20, 0xff, 0xf7, 0x74, 0xf8, 0x00, 0x20, + 0x20, 0x60, 0x70, 0xbd, 0xdf, 0xf8, 0x84, 0x45, 0x7c, 0x4d, 0xdf, 0xf8, + 0x84, 0x65, 0x4f, 0xf6, 0xfe, 0x60, 0x20, 0x60, 0x80, 0x20, 0xa9, 0x6a, + 0x08, 0x60, 0x68, 0x6a, 0x00, 0x68, 0x00, 0x06, 0x70, 0x47, 0x38, 0xb5, + 0x00, 0xf0, 0x75, 0xf8, 0x0c, 0xd5, 0x41, 0xf0, 0x10, 0x01, 0x01, 0x70, + 0x06, 0x20, 0xff, 0xf7, 0x11, 0xfa, 0xd5, 0xf8, 0x80, 0x00, 0x40, 0xf0, + 0x04, 0x00, 0x00, 0xf0, 0x3f, 0xf8, 0x0b, 0xe0, 0x01, 0xf0, 0xef, 0x01, + 0x01, 0x70, 0x06, 0x20, 0xff, 0xf7, 0x0e, 0xfa, 0xd5, 0xf8, 0x80, 0x00, + 0x20, 0xf0, 0x04, 0x00, 0xc5, 0xf8, 0x80, 0x00, 0x2a, 0xe0, 0x38, 0xb5, + 0xdf, 0xf8, 0x28, 0x45, 0x65, 0x4d, 0x4f, 0xf6, 0xfe, 0x60, 0x20, 0x60, + 0x4f, 0xf4, 0x80, 0x10, 0xe9, 0x69, 0x08, 0x60, 0xa9, 0x69, 0xdf, 0xf8, + 0x18, 0x05, 0x09, 0x68, 0xc9, 0x02, 0x01, 0x78, 0x0c, 0xd5, 0x41, 0xf0, + 0x20, 0x01, 0x01, 0x70, 0x07, 0x20, 0xff, 0xf7, 0xe5, 0xf9, 0xd5, 0xf8, + 0x80, 0x00, 0x40, 0xf0, 0x08, 0x00, 0x00, 0xf0, 0x13, 0xf8, 0x0b, 0xe0, + 0x01, 0xf0, 0xdf, 0x01, 0x01, 0x70, 0x07, 0x20, 0xff, 0xf7, 0xe2, 0xf9, + 0xd5, 0xf8, 0x80, 0x00, 0x20, 0xf0, 0x08, 0x00, 0xc5, 0xf8, 0x80, 0x00, + 0x10, 0x20, 0xff, 0xf7, 0x16, 0xf8, 0x00, 0x20, 0x20, 0x60, 0x31, 0xbd, + 0xc5, 0xf8, 0x80, 0x00, 0x0e, 0x20, 0xff, 0xf7, 0x0e, 0xb8, 0x38, 0xb5, + 0x00, 0xf0, 0x21, 0xf8, 0x0f, 0xd5, 0x41, 0xf0, 0x30, 0x01, 0x01, 0x70, + 0x06, 0x20, 0xff, 0xf7, 0xbd, 0xf9, 0x07, 0x20, 0xff, 0xf7, 0xba, 0xf9, + 0xd5, 0xf8, 0x80, 0x00, 0x40, 0xf0, 0x0c, 0x00, 0xff, 0xf7, 0xe8, 0xff, + 0x0e, 0xe0, 0x01, 0xf0, 0xcf, 0x01, 0x01, 0x70, 0x06, 0x20, 0xff, 0xf7, + 0xb7, 0xf9, 0x07, 0x20, 0xff, 0xf7, 0xb4, 0xf9, 0xd5, 0xf8, 0x80, 0x00, + 0x20, 0xf0, 0x0c, 0x00, 0xc5, 0xf8, 0x80, 0x00, 0xd0, 0xe7, 0xdf, 0xf8, + 0x78, 0x44, 0x39, 0x4d, 0x4f, 0xf6, 0xfe, 0x60, 0x20, 0x60, 0x40, 0x20, + 0x29, 0x69, 0x08, 0x60, 0xe9, 0x68, 0xdf, 0xf8, 0x68, 0x04, 0x09, 0x68, + 0x49, 0x06, 0x01, 0x78, 0x70, 0x47, 0x00, 0x00, 0x18, 0x00, 0x00, 0x49, + 0x4c, 0x1f, 0x00, 0x20, 0x00, 0xf2, 0x00, 0x20, 0x40, 0x42, 0x0f, 0x00, + 0xf8, 0xb5, 0x2d, 0x48, 0x02, 0x6c, 0x41, 0x6c, 0x11, 0x60, 0xd0, 0xf8, + 0x80, 0x10, 0xc1, 0xf3, 0x02, 0x14, 0xc1, 0x6b, 0x91, 0xb1, 0x09, 0x68, + 0x42, 0x6f, 0x21, 0xfa, 0x02, 0xf3, 0x82, 0x6f, 0x21, 0xfa, 0x02, 0xf5, + 0x05, 0xf0, 0x01, 0x02, 0x5b, 0x08, 0xc3, 0x6f, 0x52, 0x41, 0xd9, 0x40, + 0x01, 0xf0, 0x01, 0x01, 0x42, 0xea, 0x81, 0x05, 0xed, 0xb2, 0x04, 0xe0, + 0xdf, 0xf8, 0x10, 0x14, 0x09, 0x78, 0x01, 0xf0, 0x07, 0x05, 0xac, 0x42, + 0x35, 0xd0, 0xd0, 0xf8, 0x80, 0x10, 0xdf, 0xf8, 0xf8, 0x63, 0x21, 0xf0, + 0x70, 0x01, 0x41, 0xea, 0x05, 0x11, 0xc0, 0xf8, 0x80, 0x10, 0x10, 0x20, + 0xfe, 0xf7, 0x9f, 0xff, 0x4f, 0xf6, 0xfe, 0x60, 0x30, 0x60, 0xdf, 0xf8, + 0xd8, 0x03, 0x00, 0x7e, 0xc0, 0x07, 0x03, 0xd5, 0xdf, 0xf8, 0xb8, 0x03, + 0x00, 0xf0, 0x83, 0xf8, 0xdf, 0xf8, 0xd4, 0x73, 0x0f, 0xf2, 0x50, 0x41, + 0x38, 0x78, 0x00, 0xf0, 0xef, 0x00, 0x38, 0x70, 0x20, 0x46, 0x51, 0xf8, + 0x24, 0x10, 0x88, 0x47, 0x0f, 0xf2, 0x1c, 0x41, 0x51, 0xf8, 0x25, 0x10, + 0x28, 0x46, 0x88, 0x47, 0x38, 0x78, 0x40, 0xf0, 0x10, 0x00, 0x38, 0x70, + 0x00, 0x20, 0x30, 0x60, 0x1c, 0x20, 0xbd, 0xe8, 0xf2, 0x40, 0xfe, 0xf7, + 0x76, 0xbf, 0xf1, 0xbd, 0xd0, 0x1f, 0x00, 0x20, 0xdf, 0xf8, 0x98, 0x03, + 0xdf, 0xf8, 0x98, 0x23, 0x01, 0x78, 0x92, 0xf8, 0x6b, 0x20, 0x01, 0xf0, + 0xe0, 0x01, 0x11, 0x43, 0x41, 0xf0, 0x20, 0x01, 0x01, 0x70, 0x70, 0x47, + 0x30, 0xf3, 0x00, 0x20, 0x00, 0x00, 0x20, 0x59, 0xdf, 0xf8, 0x7c, 0x13, + 0x00, 0x20, 0x08, 0x70, 0xdf, 0xf8, 0x78, 0x13, 0x08, 0x80, 0x70, 0x47, + 0x70, 0x47, 0x10, 0xb5, 0x00, 0xf0, 0x2b, 0xf8, 0x00, 0xf0, 0x65, 0xf8, + 0xa4, 0x7c, 0x00, 0xf0, 0x69, 0xf8, 0x49, 0x7d, 0x81, 0x70, 0x01, 0x21, + 0x11, 0x70, 0xd4, 0x4a, 0x41, 0x79, 0x00, 0xf0, 0x54, 0xf8, 0x41, 0x71, + 0x01, 0x20, 0x11, 0xe0, 0xb4, 0x28, 0x00, 0x20, 0x10, 0xb5, 0x00, 0xf0, + 0x16, 0xf8, 0x00, 0xf0, 0x75, 0xf8, 0xa4, 0x7c, 0x23, 0x43, 0x03, 0x70, + 0x09, 0x78, 0x89, 0x18, 0x49, 0x7d, 0x81, 0x70, 0x01, 0x20, 0x00, 0xf0, + 0x68, 0xf8, 0x05, 0x20, 0x05, 0xf0, 0x67, 0xf9, 0x00, 0xf0, 0x1d, 0xf9, + 0x08, 0x20, 0xbd, 0xe8, 0x10, 0x40, 0xff, 0xf7, 0xe3, 0xb8, 0xc6, 0x48, + 0xc6, 0x4a, 0x01, 0x79, 0x01, 0xf0, 0x7f, 0x01, 0x01, 0x71, 0x70, 0x47, + 0x0c, 0x00, 0x00, 0x59, 0x80, 0xb5, 0x00, 0xe0, 0x80, 0xb5, 0x05, 0xf0, + 0x85, 0xf9, 0xc1, 0x48, 0x81, 0x78, 0x41, 0xf0, 0x80, 0x01, 0x81, 0x70, + 0x00, 0xf0, 0x05, 0xf8, 0x08, 0x20, 0xbd, 0xe8, 0x02, 0x40, 0xff, 0xf7, + 0xd3, 0xb8, 0x01, 0x78, 0x41, 0xf0, 0xc0, 0x01, 0x01, 0x70, 0x70, 0x47, + 0x10, 0xb5, 0x00, 0xf0, 0x49, 0xf8, 0x00, 0xf0, 0x18, 0xf8, 0x24, 0x7e, + 0x00, 0xf0, 0x1c, 0xf8, 0xc9, 0x7e, 0x81, 0x70, 0x02, 0x21, 0x11, 0x70, + 0xad, 0x4a, 0x01, 0x79, 0x00, 0xf0, 0x07, 0xf8, 0x01, 0x71, 0x02, 0x20, + 0x05, 0xf0, 0x2d, 0xf9, 0x00, 0xf0, 0x42, 0xf8, 0xc5, 0xe7, 0x92, 0xf8, + 0x43, 0x20, 0x01, 0xf0, 0xc0, 0x01, 0x11, 0x43, 0x70, 0x47, 0xab, 0x49, + 0x03, 0x78, 0x0c, 0x78, 0xa4, 0x18, 0x03, 0xf0, 0xc0, 0x03, 0x70, 0x47, + 0x23, 0x43, 0x03, 0x70, 0x09, 0x78, 0x89, 0x18, 0xa0, 0x4a, 0x70, 0x47, + 0x10, 0xb5, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0xf0, 0x13, 0xf8, 0x24, 0x7e, + 0x23, 0x43, 0x03, 0x70, 0x09, 0x78, 0x89, 0x18, 0xc9, 0x7e, 0x81, 0x70, + 0x02, 0x20, 0x00, 0xf0, 0x06, 0xf8, 0x06, 0x20, 0x05, 0xf0, 0x05, 0xf9, + 0x00, 0xf0, 0x1a, 0xf8, 0x9d, 0xe7, 0x95, 0x49, 0x08, 0x70, 0x55, 0xe7, + 0x99, 0x49, 0x03, 0x78, 0x0c, 0x78, 0xa4, 0x18, 0x03, 0xf0, 0xc0, 0x03, + 0x70, 0x47, 0x00, 0x00, 0x78, 0x29, 0x00, 0x20, 0x95, 0x48, 0x91, 0x4a, + 0xc1, 0x78, 0x01, 0xf0, 0xbf, 0x01, 0xc1, 0x70, 0x70, 0x47, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x50, 0x04, 0x00, 0x00, 0x58, 0x7c, 0x48, 0x01, 0x78, + 0x01, 0xf0, 0x3f, 0x01, 0x01, 0x70, 0x09, 0x20, 0x70, 0x47, 0x80, 0xb5, + 0x05, 0xf0, 0x12, 0xf9, 0x00, 0xf0, 0x07, 0xf8, 0x91, 0xe7, 0x80, 0xb5, + 0x05, 0xf0, 0x0c, 0xf9, 0x00, 0xf0, 0x01, 0xf8, 0x8b, 0xe7, 0x87, 0x48, + 0x41, 0x78, 0x41, 0xf0, 0x40, 0x01, 0x41, 0x70, 0x01, 0x78, 0x41, 0xf0, + 0xc0, 0x01, 0x01, 0x70, 0x09, 0x20, 0x70, 0x47, 0x10, 0xb5, 0x79, 0x49, + 0x7a, 0x4a, 0x00, 0x20, 0x08, 0x70, 0x7a, 0x49, 0x7b, 0x48, 0x13, 0x78, + 0x00, 0xf0, 0x1c, 0xf8, 0xa4, 0x7c, 0x23, 0x43, 0x13, 0x70, 0x93, 0x78, + 0x00, 0xf0, 0x16, 0xf8, 0x64, 0x7d, 0x23, 0x43, 0x93, 0x70, 0x53, 0x78, + 0x00, 0xf0, 0x10, 0xf8, 0x24, 0x7e, 0x23, 0x43, 0x53, 0x70, 0xd3, 0x78, + 0x00, 0x78, 0x40, 0x18, 0x03, 0xf0, 0xc0, 0x03, 0xc0, 0x7e, 0x18, 0x43, + 0xd0, 0x70, 0x10, 0xbd, 0x08, 0x00, 0x00, 0x50, 0x08, 0x00, 0x00, 0x58, + 0x04, 0x78, 0x64, 0x18, 0x03, 0xf0, 0xc0, 0x03, 0x70, 0x47, 0x80, 0xb5, + 0x05, 0xf0, 0xd0, 0xf8, 0x6b, 0x48, 0xff, 0xf7, 0x54, 0xff, 0x41, 0x78, + 0x41, 0xf0, 0xc0, 0x01, 0x41, 0x70, 0x63, 0x49, 0x8a, 0x78, 0x42, 0xf0, + 0xc0, 0x02, 0x8a, 0x70, 0x0a, 0x78, 0x42, 0xf0, 0xc0, 0x02, 0x0a, 0x70, + 0x4a, 0x78, 0x42, 0xf0, 0xc0, 0x02, 0x4a, 0x70, 0x81, 0x79, 0x01, 0xf0, + 0xcc, 0x01, 0x81, 0x71, 0x60, 0x48, 0x61, 0x49, 0x0a, 0x78, 0x03, 0x78, + 0x1a, 0x40, 0x83, 0x78, 0x1a, 0x43, 0x0a, 0x70, 0x4a, 0x78, 0x43, 0x78, + 0x1a, 0x40, 0xc3, 0x78, 0x1a, 0x43, 0x4a, 0x70, 0x01, 0x21, 0x41, 0x60, + 0x81, 0x60, 0x00, 0x20, 0x42, 0x49, 0x08, 0x70, 0x01, 0xbd, 0x08, 0xb1, + 0x57, 0x49, 0x08, 0x70, 0x70, 0x47, 0x56, 0x48, 0x00, 0x78, 0x70, 0x47, + 0x80, 0xb5, 0x55, 0x48, 0x53, 0x4a, 0x81, 0x79, 0x46, 0x4b, 0x01, 0xf0, + 0x7f, 0x01, 0x81, 0x71, 0x41, 0x79, 0x01, 0xf0, 0x3f, 0x01, 0x41, 0x71, + 0x12, 0x78, 0x0f, 0xf2, 0xa4, 0x11, 0x51, 0x5c, 0x4e, 0x4a, 0x11, 0x70, + 0x04, 0x22, 0x1a, 0x70, 0x01, 0x70, 0xff, 0xf7, 0xa9, 0xfe, 0x04, 0x20, + 0x05, 0xf0, 0x4f, 0xf8, 0x00, 0xf0, 0x05, 0xf8, 0x0a, 0x20, 0xbd, 0xe8, + 0x02, 0x40, 0xfe, 0xf7, 0xcb, 0xbf, 0x2c, 0x48, 0x01, 0x78, 0x01, 0xf0, + 0x3f, 0x01, 0x01, 0x70, 0x70, 0x47, 0x80, 0xb5, 0x05, 0xf0, 0x72, 0xf8, + 0x40, 0x48, 0x00, 0x21, 0x01, 0x70, 0x81, 0x79, 0x41, 0xf0, 0x80, 0x01, + 0x81, 0x71, 0x41, 0x79, 0x41, 0xf0, 0xc0, 0x01, 0x41, 0x71, 0x0a, 0x20, + 0xe7, 0xe6, 0x00, 0x00, 0x64, 0xf3, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x58, + 0x44, 0x00, 0x00, 0x50, 0x2d, 0xe9, 0xf0, 0x47, 0x04, 0x46, 0x91, 0x46, + 0x9a, 0x46, 0xfe, 0xf7, 0xa1, 0xff, 0x1c, 0x4f, 0x80, 0x46, 0x38, 0x79, + 0x01, 0x28, 0x25, 0xd1, 0x02, 0x2c, 0x21, 0xd1, 0xfe, 0xf7, 0x98, 0xff, + 0x30, 0x4e, 0x31, 0x49, 0x35, 0x68, 0x04, 0x46, 0x4f, 0xf0, 0x00, 0x40, + 0x08, 0x60, 0xd7, 0xf8, 0x80, 0x00, 0xc0, 0xf3, 0x02, 0x10, 0x03, 0x28, + 0x18, 0xbf, 0x04, 0x28, 0x09, 0xd0, 0x05, 0x28, 0x18, 0xbf, 0x06, 0x28, + 0x05, 0xd0, 0x02, 0x22, 0x48, 0x46, 0x51, 0x46, 0x03, 0xf0, 0xc4, 0xfc, + 0x00, 0xe0, 0x05, 0x20, 0x05, 0xf0, 0x00, 0x41, 0x31, 0x60, 0x84, 0xf3, + 0x11, 0x88, 0x06, 0xe0, 0x05, 0x20, 0x04, 0xe0, 0x22, 0x46, 0x48, 0x46, + 0x51, 0x46, 0x03, 0xf0, 0xb5, 0xfc, 0x88, 0xf3, 0x11, 0x88, 0xc0, 0xb2, + 0xbd, 0xe8, 0xf0, 0x87, 0x41, 0x0c, 0x00, 0x46, 0x65, 0x2c, 0x00, 0x20, + 0xd0, 0x1f, 0x00, 0x20, 0x4c, 0x00, 0x00, 0x50, 0x4c, 0x00, 0x00, 0x58, + 0x4c, 0x1f, 0x00, 0x20, 0x48, 0x00, 0x00, 0x50, 0xb0, 0x01, 0x00, 0x46, + 0x28, 0x0b, 0x00, 0x46, 0x42, 0x06, 0x00, 0x46, 0x15, 0x08, 0x00, 0x46, + 0x68, 0xee, 0x00, 0x20, 0x04, 0x01, 0x00, 0x46, 0xfe, 0x01, 0x00, 0x41, + 0x10, 0x08, 0x00, 0x46, 0x4c, 0x29, 0x00, 0x20, 0x12, 0x08, 0x00, 0x46, + 0x6c, 0x29, 0x00, 0x20, 0x6d, 0x29, 0x00, 0x20, 0x11, 0x08, 0x00, 0x46, + 0x13, 0x08, 0x00, 0x46, 0x42, 0x05, 0x00, 0x46, 0xec, 0x2b, 0x00, 0x20, + 0x02, 0x0b, 0x00, 0x46, 0x64, 0x2c, 0x00, 0x20, 0x1a, 0x08, 0x00, 0x46, + 0x0c, 0x02, 0x00, 0x46, 0x00, 0xe1, 0x00, 0xe0, 0x80, 0xe1, 0x00, 0xe0, + 0x04, 0x02, 0x84, 0x0d, 0x05, 0x02, 0x85, 0x0d, 0x06, 0x02, 0x86, 0x0d, + 0x41, 0x0c, 0x00, 0x00, 0x45, 0x90, 0x00, 0x01, 0x57, 0x90, 0x00, 0x01, + 0xf1, 0x90, 0x00, 0x01, 0xdd, 0x91, 0x00, 0x01, 0xa1, 0x92, 0x00, 0x01, + 0x81, 0x90, 0x00, 0x01, 0x45, 0x91, 0x00, 0x01, 0x45, 0x90, 0x00, 0x01, + 0x55, 0x90, 0x00, 0x01, 0xc5, 0x90, 0x00, 0x01, 0xaf, 0x91, 0x00, 0x01, + 0x33, 0x92, 0x00, 0x01, 0xef, 0x92, 0x00, 0x01, 0xc9, 0x90, 0x00, 0x01, + 0xbb, 0x91, 0x00, 0x01, 0x55, 0x90, 0x00, 0x01, 0x08, 0x09, 0x00, 0x00, + 0x0c, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0f, 0xf2, 0x2c, 0x02, + 0x00, 0xf0, 0x1f, 0x00, 0x80, 0x5c, 0x08, 0xb9, 0x03, 0x20, 0x70, 0x47, + 0x01, 0x22, 0x02, 0xfa, 0x01, 0xf1, 0x08, 0x42, 0x14, 0xbf, 0x00, 0x20, + 0x02, 0x20, 0x70, 0x47, 0x0f, 0xf2, 0x1c, 0x02, 0x06, 0x23, 0x03, 0xfb, + 0x00, 0x20, 0x08, 0x5c, 0x70, 0x47, 0x00, 0x00, 0x0c, 0x18, 0x1c, 0x1c, + 0x18, 0x3e, 0x3e, 0x18, 0x00, 0x3e, 0x1c, 0x3e, 0x3e, 0x0c, 0x00, 0x00, + 0x02, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x80, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x02, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0xb5, 0x08, 0x46, + 0x6b, 0x46, 0x40, 0x68, 0x01, 0x22, 0x08, 0x21, 0xf8, 0xf7, 0x44, 0xff, + 0x00, 0xf0, 0x01, 0xf8, 0x01, 0xbd, 0x9d, 0xf8, 0x00, 0x10, 0x48, 0x1e, + 0x80, 0x41, 0xc0, 0x0f, 0xfe, 0xf7, 0x9d, 0xbc, 0x70, 0xb5, 0x82, 0xb0, + 0x0d, 0xf1, 0x01, 0x00, 0xfa, 0xf7, 0x47, 0xfa, 0x01, 0x24, 0x67, 0x4d, + 0x58, 0x20, 0x00, 0xfb, 0x04, 0x56, 0x33, 0x69, 0x18, 0x00, 0x03, 0xd0, + 0x70, 0x6a, 0x00, 0x22, 0x00, 0x21, 0x98, 0x47, 0x69, 0x46, 0x00, 0x20, + 0xf8, 0xf7, 0x73, 0xfe, 0x70, 0x60, 0xff, 0xf7, 0xe0, 0xff, 0x64, 0x1c, + 0x11, 0x2c, 0xeb, 0xd3, 0x05, 0xf0, 0x46, 0xff, 0x0d, 0xf1, 0x01, 0x00, + 0x00, 0xf0, 0xe0, 0xfa, 0x73, 0xbd, 0xf8, 0xb5, 0xfe, 0xf7, 0x70, 0xfe, + 0x00, 0x24, 0x57, 0x4d, 0x57, 0x4e, 0xe0, 0xb2, 0xfb, 0xf7, 0xae, 0xf8, + 0x60, 0xb1, 0xa0, 0x5d, 0x58, 0x21, 0x01, 0xfb, 0x00, 0x57, 0x00, 0xf0, + 0x25, 0xf8, 0x3b, 0x69, 0x18, 0x00, 0x03, 0xd0, 0x78, 0x6a, 0x00, 0x22, + 0x02, 0x21, 0x98, 0x47, 0x64, 0x1c, 0x10, 0x2c, 0xeb, 0xd3, 0xf1, 0xbd, + 0x10, 0xb5, 0x4b, 0x4c, 0x82, 0xb0, 0x60, 0x62, 0x60, 0x68, 0x20, 0xb9, + 0x69, 0x46, 0xf8, 0xf7, 0x42, 0xfe, 0x60, 0x60, 0x03, 0xe0, 0x00, 0xf0, + 0x98, 0xf8, 0xff, 0xf7, 0xac, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x08, 0xf8, + 0x23, 0x69, 0x18, 0x00, 0x03, 0xd0, 0x60, 0x6a, 0x00, 0x22, 0x02, 0x21, + 0x98, 0x47, 0x13, 0xbd, 0x30, 0xb5, 0x04, 0x46, 0x3d, 0x48, 0x58, 0x21, + 0x87, 0xb0, 0x01, 0xfb, 0x04, 0x05, 0xfb, 0xf7, 0x37, 0xf8, 0xc4, 0xb1, + 0x3b, 0x48, 0x20, 0x5c, 0xfb, 0xf7, 0x74, 0xf8, 0x00, 0x28, 0x36, 0xd0, + 0x20, 0x46, 0xfa, 0xf7, 0xfd, 0xfd, 0x05, 0xa9, 0x02, 0x91, 0x00, 0x95, + 0x00, 0x21, 0x01, 0x91, 0x01, 0x46, 0x35, 0x4b, 0x01, 0x22, 0x00, 0x20, + 0xf9, 0xf7, 0xa4, 0xfa, 0xa8, 0x62, 0x9d, 0xf8, 0x14, 0x10, 0xff, 0xf7, + 0x80, 0xff, 0xeb, 0x6b, 0xa8, 0x6c, 0xe9, 0x6c, 0x01, 0x90, 0x03, 0x22, + 0x04, 0x92, 0x02, 0x91, 0x9a, 0xb2, 0x00, 0x92, 0x00, 0xeb, 0x81, 0x00, + 0x03, 0x94, 0x02, 0x1f, 0x69, 0x6a, 0x68, 0x6c, 0xdb, 0xb2, 0xf9, 0xf7, + 0x6c, 0xf9, 0x8d, 0xf8, 0x14, 0x00, 0x00, 0xf0, 0x4d, 0xf8, 0xe8, 0x6b, + 0x29, 0x6c, 0x05, 0xaa, 0xc0, 0xb2, 0xf9, 0xf7, 0x19, 0xfa, 0x9d, 0xf8, + 0x14, 0x10, 0xff, 0xf7, 0x60, 0xff, 0x29, 0x46, 0x20, 0x46, 0xf9, 0xf7, + 0x23, 0xff, 0x00, 0x20, 0x07, 0xb0, 0x30, 0xbd, 0x38, 0xb5, 0x05, 0x46, + 0x18, 0x48, 0x58, 0x21, 0x01, 0xfb, 0x05, 0x04, 0xfa, 0xf7, 0xee, 0xff, + 0x25, 0xb1, 0x17, 0x48, 0x28, 0x5c, 0xfb, 0xf7, 0x2b, 0xf8, 0xf8, 0xb1, + 0x28, 0x46, 0xfa, 0xf7, 0x99, 0xf8, 0xa0, 0x6a, 0x68, 0xb1, 0x6b, 0x46, + 0x00, 0x22, 0x00, 0x21, 0xf9, 0xf7, 0x46, 0xfb, 0xa0, 0x6a, 0x0d, 0xf1, + 0x01, 0x01, 0xf9, 0xf7, 0x99, 0xfa, 0x9d, 0xf8, 0x01, 0x10, 0xff, 0xf7, + 0x38, 0xff, 0x60, 0x68, 0x00, 0xf0, 0x1d, 0xf8, 0xff, 0xf7, 0x31, 0xff, + 0xe0, 0x6b, 0xc0, 0xb2, 0xf9, 0xf7, 0x74, 0xf9, 0x8d, 0xf8, 0x00, 0x00, + 0x00, 0xf0, 0x0e, 0xf8, 0x9d, 0xf8, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x20, + 0x32, 0xbd, 0x00, 0x00, 0xd8, 0x20, 0x00, 0x20, 0xc8, 0x20, 0x00, 0x20, + 0xf4, 0x1e, 0x00, 0x20, 0xf5, 0x94, 0x00, 0x01, 0x40, 0x1e, 0x80, 0x41, + 0xc0, 0x0f, 0xfe, 0xf7, 0xba, 0xbb, 0x6b, 0x46, 0x00, 0x22, 0x4f, 0xf6, + 0xff, 0x71, 0xf8, 0xf7, 0x51, 0xbe, 0x00, 0x00, 0x2c, 0x21, 0xfe, 0xf7, + 0x05, 0xba, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, 0x88, 0x46, 0x04, 0x46, + 0x00, 0x25, 0xc9, 0xb2, 0x48, 0x09, 0x05, 0x28, 0x01, 0xf0, 0x1f, 0x01, + 0x49, 0xda, 0x0f, 0xf2, 0xac, 0x03, 0x03, 0xeb, 0xc0, 0x02, 0x57, 0x68, + 0x00, 0x2f, 0x42, 0xd0, 0x13, 0xf8, 0x30, 0x30, 0x99, 0x42, 0x3e, 0xda, + 0x23, 0x4b, 0x53, 0xf8, 0x20, 0x60, 0x01, 0x27, 0x07, 0xfa, 0x01, 0xfe, + 0x0e, 0xea, 0x06, 0x06, 0xd3, 0xf8, 0x14, 0xe0, 0x9b, 0x69, 0x07, 0xfa, + 0x00, 0xf0, 0x00, 0xea, 0x0e, 0x00, 0x30, 0x43, 0x43, 0xea, 0x00, 0x07, + 0x50, 0x68, 0x00, 0xeb, 0xc1, 0x06, 0xfb, 0xf7, 0xc2, 0xf9, 0x04, 0x28, + 0x03, 0xd1, 0xf0, 0x88, 0x80, 0xf0, 0x01, 0x00, 0x07, 0x43, 0x00, 0x2c, + 0x1c, 0xbf, 0x00, 0x2f, 0x06, 0x25, 0x1d, 0xd1, 0x30, 0x68, 0xb1, 0x88, + 0x00, 0x28, 0x18, 0xbf, 0x00, 0x29, 0x14, 0xd0, 0x4f, 0xea, 0x08, 0x23, + 0x4f, 0xea, 0x18, 0x62, 0x02, 0xeb, 0x13, 0x46, 0xb1, 0x42, 0x0a, 0xdb, + 0x00, 0xeb, 0x13, 0x40, 0x0b, 0x4b, 0x00, 0x2c, 0x12, 0xbf, 0x19, 0x46, + 0x01, 0x46, 0x18, 0x46, 0x00, 0xf0, 0x6e, 0xfa, 0x04, 0xe0, 0x07, 0x25, + 0x02, 0xe0, 0x05, 0x25, 0x00, 0xe0, 0x04, 0x25, 0x28, 0x46, 0xbd, 0xe8, + 0xf0, 0x81, 0x02, 0x49, 0x00, 0xf0, 0x01, 0x00, 0x88, 0x61, 0x70, 0x47, + 0x14, 0x27, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x68, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x68, 0x6f, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, 0x76, 0x01, 0x01, + 0x10, 0xb5, 0x01, 0x21, 0x15, 0x20, 0xfe, 0xf7, 0x08, 0xfc, 0x00, 0xf0, + 0x4d, 0xf8, 0x84, 0x4c, 0xf9, 0xf7, 0x47, 0xfc, 0x21, 0x7a, 0x4f, 0xf4, + 0xdb, 0x70, 0xf9, 0xf7, 0x11, 0xfc, 0x61, 0x7a, 0x80, 0x4c, 0x40, 0xf2, + 0xb7, 0x10, 0xf9, 0xf7, 0x0b, 0xfc, 0xfe, 0xf7, 0xbc, 0xfa, 0x00, 0x22, + 0x03, 0x21, 0x40, 0xf2, 0x33, 0x40, 0xf9, 0xf7, 0x0d, 0xfc, 0x00, 0x22, + 0x01, 0x21, 0x40, 0xf2, 0x4c, 0x40, 0xf9, 0xf7, 0x07, 0xfc, 0x00, 0x22, + 0x0f, 0x21, 0x40, 0xf2, 0x2e, 0x40, 0xf9, 0xf7, 0x01, 0xfc, 0x00, 0x22, + 0x03, 0x21, 0x4f, 0xf4, 0x89, 0x60, 0xf9, 0xf7, 0xfb, 0xfb, 0x21, 0x78, + 0x40, 0xf2, 0x35, 0x40, 0xf9, 0xf7, 0xec, 0xfb, 0x61, 0x7d, 0x40, 0xf2, + 0x36, 0x40, 0xf9, 0xf7, 0xe7, 0xfb, 0xff, 0xf7, 0x8e, 0xf8, 0xff, 0xf7, + 0xbc, 0xf8, 0xff, 0xf7, 0xdb, 0xf8, 0xbd, 0xe8, 0x10, 0x40, 0x04, 0x20, + 0xfc, 0xf7, 0xc2, 0xbf, 0x80, 0xb5, 0x04, 0x20, 0xfd, 0xf7, 0x00, 0xf8, + 0x00, 0xf0, 0x0a, 0xf8, 0xf9, 0xf7, 0xf2, 0xfb, 0xfe, 0xf7, 0xa0, 0xfa, + 0xbd, 0xe8, 0x04, 0x40, 0x00, 0x21, 0x15, 0x20, 0xfe, 0xf7, 0xb9, 0xbb, + 0x09, 0x22, 0x5f, 0x49, 0x0f, 0xf2, 0x78, 0x20, 0x70, 0x47, 0x2d, 0xe9, + 0xf1, 0x4f, 0xdf, 0xf8, 0x74, 0xa1, 0x5d, 0x4e, 0x5d, 0x4f, 0x82, 0xb0, + 0x9a, 0xf8, 0x00, 0x00, 0x00, 0x90, 0x00, 0x24, 0x74, 0x60, 0xb4, 0x81, + 0x03, 0x21, 0xb8, 0x7a, 0x08, 0x42, 0x06, 0xd0, 0x01, 0x20, 0x03, 0xf0, + 0x5f, 0xf8, 0x00, 0x29, 0x08, 0xbf, 0x00, 0x28, 0x15, 0xd0, 0x78, 0x89, + 0xc0, 0xf3, 0x81, 0x00, 0x30, 0xb1, 0x00, 0x20, 0x03, 0xf0, 0x54, 0xf8, + 0x00, 0x29, 0x08, 0xbf, 0x00, 0x28, 0x0a, 0xd0, 0x78, 0x89, 0xc0, 0xf3, + 0x82, 0x10, 0x40, 0xb1, 0x02, 0x20, 0x03, 0xf0, 0x49, 0xf8, 0x00, 0x29, + 0x08, 0xbf, 0x00, 0x28, 0x01, 0xd1, 0x05, 0x24, 0x53, 0xe0, 0x00, 0x98, + 0x20, 0x28, 0x4f, 0xd2, 0x01, 0x20, 0xff, 0xf7, 0x54, 0xff, 0x34, 0x61, + 0x00, 0x27, 0xdf, 0xf8, 0x14, 0x81, 0xdf, 0xf8, 0x14, 0x91, 0x00, 0xe0, + 0x7f, 0x1c, 0x00, 0x98, 0x87, 0x42, 0x3d, 0xd2, 0x07, 0xeb, 0x0a, 0x00, + 0x0c, 0x21, 0x40, 0x78, 0x00, 0xf0, 0x1f, 0x05, 0x0f, 0xf2, 0x00, 0x10, + 0x01, 0xfb, 0x05, 0x0b, 0xdb, 0xf8, 0x04, 0x00, 0x00, 0x28, 0xed, 0xd0, + 0x02, 0x98, 0xe8, 0x40, 0xc0, 0x07, 0xe9, 0xd5, 0x29, 0x46, 0x16, 0x20, + 0xfe, 0xf7, 0x6c, 0xfb, 0x49, 0x46, 0x04, 0x20, 0xfc, 0xf7, 0x5e, 0xff, + 0x9b, 0xf8, 0x08, 0x00, 0xfe, 0xf7, 0x66, 0xfa, 0xdb, 0xf8, 0x04, 0x20, + 0x41, 0x46, 0x00, 0x20, 0x90, 0x47, 0x04, 0x46, 0x04, 0x20, 0xfc, 0xf7, + 0x77, 0xff, 0xe4, 0xb2, 0x1c, 0xb1, 0x35, 0x73, 0x74, 0x73, 0x07, 0x24, + 0x10, 0xe0, 0x01, 0x21, 0x72, 0x68, 0xa9, 0x40, 0x0a, 0x43, 0x72, 0x60, + 0x32, 0x68, 0x11, 0x43, 0x31, 0x60, 0x31, 0x69, 0x49, 0x44, 0x08, 0x1a, + 0x30, 0x61, 0xfa, 0xf7, 0x20, 0xfe, 0x00, 0x28, 0xbe, 0xd0, 0x06, 0x24, + 0x00, 0x20, 0xff, 0xf7, 0x08, 0xff, 0x00, 0xe0, 0x04, 0x24, 0x20, 0x46, + 0xbd, 0xe8, 0xfe, 0x8f, 0x1f, 0x49, 0x01, 0x20, 0x08, 0x70, 0x70, 0x47, + 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x16, 0x46, 0x19, 0x46, 0x00, 0x20, + 0xfc, 0xf7, 0xcc, 0xff, 0x00, 0x27, 0xfa, 0xf7, 0x06, 0xfe, 0x08, 0xb1, + 0x02, 0x27, 0x0d, 0xe0, 0x04, 0xf1, 0x8c, 0x40, 0x05, 0xea, 0x06, 0x01, + 0x00, 0x78, 0x28, 0x40, 0x88, 0x42, 0x05, 0xd0, 0x00, 0x20, 0xfc, 0xf7, + 0xd3, 0xff, 0x00, 0x28, 0xed, 0xd0, 0x01, 0x27, 0x00, 0x20, 0xfc, 0xf7, + 0x45, 0xff, 0x38, 0x46, 0xf2, 0xbd, 0x09, 0x48, 0x81, 0x68, 0x00, 0x68, + 0x08, 0x40, 0x88, 0x42, 0x0c, 0xbf, 0x01, 0x20, 0x00, 0x20, 0x70, 0x47, + 0x00, 0x00, 0x00, 0x00, 0x4c, 0x1f, 0x00, 0x20, 0x31, 0x04, 0x00, 0x46, + 0xfc, 0xf2, 0x00, 0x20, 0xd4, 0x28, 0x00, 0x20, 0xe8, 0xf2, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0x60, 0xb5, 0x00, 0x20, 0xc0, 0xe1, 0xe4, 0x00, + 0x9e, 0xf3, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xed, 0x52, 0x01, 0x01, + 0x05, 0x00, 0x00, 0x00, 0x91, 0x55, 0x01, 0x01, 0x93, 0x55, 0x01, 0x01, + 0x05, 0x00, 0x00, 0x00, 0x7d, 0x69, 0x01, 0x01, 0x7f, 0x69, 0x01, 0x01, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x38, 0x01, 0x01, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x64, 0x01, 0x01, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x76, 0x01, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x11, 0x31, 0x01, 0x01, 0x13, 0x31, 0x01, 0x01, + 0xc8, 0x00, 0x00, 0x00, 0x6d, 0x75, 0x00, 0x01, 0x81, 0x75, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x5d, 0x17, 0x00, 0x01, 0xc9, 0x13, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x15, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0xb7, 0x58, 0x01, 0x01, 0xf7, 0x58, 0x01, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x95, 0x5b, 0x01, 0x01, 0x8b, 0x5c, 0x01, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x91, 0x5d, 0x01, 0x01, 0xd5, 0x5d, 0x01, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf9, 0x5c, 0x01, 0x01, 0xa5, 0x5d, 0x01, 0x01, + 0xc8, 0x00, 0x00, 0x00, 0xd9, 0xdb, 0x00, 0x01, 0x31, 0xdc, 0x00, 0x01, + 0xf8, 0x00, 0x00, 0x00, 0xbd, 0xa5, 0x00, 0x01, 0x1d, 0xa6, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0xe5, 0x60, 0x00, 0x01, 0x15, 0x61, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x4b, 0x34, 0x00, 0x01, 0x4d, 0x34, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x2e, 0x04, 0x33, 0x04, 0x35, 0x04, 0x36, 0x04, + 0x48, 0x04, 0x4c, 0x04, 0x5b, 0x04, 0x5c, 0x04, 0x5d, 0x04, 0x00, 0x00, + 0x30, 0xb5, 0x04, 0x46, 0x4a, 0x4d, 0x87, 0xb0, 0x08, 0x21, 0x28, 0x1d, + 0xf8, 0xf7, 0x0f, 0xfd, 0x28, 0x60, 0x00, 0xb1, 0x01, 0x20, 0xfe, 0xf7, + 0x8e, 0xf9, 0x03, 0x21, 0x04, 0x91, 0x00, 0xf0, 0x24, 0xf8, 0x05, 0xaa, + 0x0f, 0xf2, 0x10, 0x11, 0x16, 0x20, 0xf8, 0xf7, 0x97, 0xff, 0x00, 0x20, + 0x12, 0xe0, 0x30, 0xb5, 0x87, 0xb0, 0x03, 0x21, 0x04, 0x91, 0x04, 0x46, + 0x00, 0xf0, 0x15, 0xf8, 0x00, 0xf0, 0x0d, 0xf8, 0x05, 0xaa, 0x0f, 0xf2, + 0x00, 0x11, 0x16, 0x20, 0xf8, 0xf7, 0x86, 0xff, 0x00, 0x2d, 0x0c, 0xbf, + 0x00, 0x20, 0x02, 0x20, 0x20, 0x70, 0x07, 0xb0, 0x30, 0xbd, 0x05, 0x46, + 0x40, 0x1e, 0x80, 0x41, 0xc0, 0x0f, 0xfe, 0xf7, 0x66, 0xb9, 0x00, 0x21, + 0x03, 0x91, 0x4f, 0xf4, 0x20, 0x71, 0x02, 0x91, 0x16, 0x21, 0x2f, 0x48, + 0x01, 0x90, 0x00, 0x91, 0x00, 0xf6, 0xfc, 0x12, 0x16, 0x23, 0x00, 0x21, + 0x0f, 0xf2, 0x39, 0x00, 0xf8, 0xf7, 0xb1, 0xbe, 0x38, 0xb5, 0x04, 0x46, + 0x00, 0x20, 0xfe, 0xf7, 0x1d, 0xfb, 0x03, 0x20, 0xfe, 0xf7, 0x1a, 0xfb, + 0x24, 0x48, 0x00, 0x68, 0xf8, 0xf7, 0x00, 0xfd, 0xff, 0xf7, 0xdc, 0xff, + 0x16, 0x20, 0xf8, 0xf7, 0xe7, 0xfe, 0xff, 0xf7, 0xd6, 0xff, 0x00, 0x2d, + 0x0c, 0xbf, 0x00, 0x20, 0x02, 0x20, 0x20, 0x70, 0x31, 0xbd, 0x00, 0x00, + 0x38, 0xb5, 0x1b, 0x4c, 0x23, 0xe0, 0xfe, 0xf7, 0x36, 0xf9, 0x00, 0x20, + 0xfe, 0xf7, 0xe2, 0xfa, 0x00, 0x20, 0xf9, 0xf7, 0x7f, 0xfe, 0x01, 0x28, + 0x19, 0xd0, 0x29, 0x0e, 0x0c, 0x20, 0xfe, 0xf7, 0x0d, 0xfa, 0x01, 0x21, + 0x0b, 0x20, 0xfe, 0xf7, 0xfa, 0xf9, 0x00, 0x20, 0xf9, 0xf7, 0x87, 0xfd, + 0x01, 0x00, 0x0c, 0xd0, 0x48, 0x68, 0xc9, 0x68, 0x88, 0x47, 0x00, 0x21, + 0x0b, 0x20, 0xfe, 0xf7, 0xee, 0xf9, 0x00, 0x20, 0xf9, 0xf7, 0xe0, 0xfd, + 0x00, 0x20, 0xfe, 0xf7, 0xe1, 0xfa, 0x00, 0x20, 0xfe, 0xf7, 0xde, 0xfa, + 0x20, 0x68, 0x6a, 0x46, 0x00, 0x21, 0xf8, 0xf7, 0xd2, 0xfc, 0x00, 0x68, + 0x05, 0x04, 0xc0, 0xb2, 0x07, 0x28, 0x0c, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0xcb, 0xe7, 0x00, 0x00, 0x88, 0xf2, 0x00, 0x20, 0x68, 0x2c, 0x00, 0x20, + 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x54, 0x61, 0x73, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, + 0x54, 0x73, 0x6b, 0x00, 0x62, 0xb3, 0x8b, 0x07, 0x08, 0xd0, 0x52, 0x1e, + 0x11, 0xf8, 0x01, 0x3b, 0x00, 0xf8, 0x01, 0x3b, 0x00, 0xf0, 0x24, 0x80, + 0x8b, 0x07, 0xf6, 0xd1, 0x83, 0x07, 0x40, 0xf0, 0x20, 0x80, 0x00, 0xbf, + 0x10, 0x3a, 0x07, 0xd3, 0x30, 0xb4, 0xb1, 0xe8, 0x38, 0x10, 0x10, 0x3a, + 0xa0, 0xe8, 0x38, 0x10, 0xf9, 0xd2, 0x30, 0xbc, 0x53, 0x07, 0x24, 0xbf, + 0xb1, 0xe8, 0x08, 0x10, 0xa0, 0xe8, 0x08, 0x10, 0x44, 0xbf, 0x51, 0xf8, + 0x04, 0x3b, 0x40, 0xf8, 0x04, 0x3b, 0xd2, 0x07, 0x24, 0xbf, 0x31, 0xf8, + 0x02, 0x2b, 0x20, 0xf8, 0x02, 0x2b, 0x44, 0xbf, 0x0b, 0x78, 0x03, 0x70, + 0x70, 0x47, 0x08, 0x3a, 0x07, 0xd3, 0xb1, 0xe8, 0x08, 0x10, 0x08, 0x3a, + 0x40, 0xf8, 0x04, 0x3b, 0x40, 0xf8, 0x04, 0xcb, 0xf7, 0xd2, 0x53, 0x07, + 0xe4, 0xe7, 0x00, 0x00, 0x80, 0xb5, 0x30, 0x48, 0x4f, 0xf0, 0x80, 0x71, + 0x01, 0x63, 0xc2, 0x6b, 0x42, 0xf0, 0x80, 0x72, 0xc2, 0x63, 0x01, 0x60, + 0x20, 0x20, 0x01, 0x21, 0xfe, 0xf7, 0x07, 0xf9, 0x20, 0x20, 0xfe, 0xf7, + 0xe9, 0xf8, 0xbd, 0xe8, 0x02, 0x40, 0x20, 0x20, 0xfe, 0xf7, 0xea, 0xb8, + 0x2d, 0xe9, 0xf0, 0x41, 0x82, 0xb0, 0x00, 0x24, 0x00, 0x25, 0x24, 0x4e, + 0x06, 0xeb, 0xc5, 0x07, 0xd7, 0xf8, 0x08, 0x80, 0x0e, 0xe0, 0x30, 0x68, + 0x64, 0x1c, 0x84, 0x42, 0x05, 0xd3, 0x71, 0x68, 0xb0, 0x69, 0x6a, 0x46, + 0xf8, 0xf7, 0x68, 0xfd, 0x00, 0x24, 0x40, 0x46, 0x00, 0xf0, 0x0a, 0xf8, + 0x08, 0xf1, 0x04, 0x08, 0xf8, 0x68, 0x80, 0x45, 0xed, 0xd3, 0x6d, 0x1c, + 0x02, 0x2d, 0xe5, 0xd3, 0xbd, 0xe8, 0xf3, 0x81, 0x80, 0xb5, 0x72, 0xb6, + 0x15, 0x48, 0x16, 0x49, 0x01, 0x60, 0x00, 0x21, 0x01, 0x60, 0x62, 0xb6, + 0x00, 0x22, 0xf0, 0x21, 0x40, 0xf6, 0x59, 0x40, 0xf9, 0xf7, 0x60, 0xf9, + 0xbd, 0xe8, 0x08, 0x40, 0x00, 0x22, 0xf0, 0x21, 0x40, 0xf6, 0x51, 0x40, + 0xf9, 0xf7, 0x58, 0xb9, 0x80, 0xb5, 0xff, 0xf7, 0xaf, 0xff, 0x00, 0x22, + 0x02, 0x21, 0x4f, 0xf4, 0x45, 0x60, 0xf9, 0xf7, 0x4f, 0xf9, 0x00, 0x20, + 0xf8, 0xf7, 0x10, 0xfd, 0x04, 0x49, 0x88, 0x61, 0x01, 0xbd, 0x03, 0x48, + 0x80, 0x69, 0xf8, 0xf7, 0x8d, 0xbd, 0x00, 0x00, 0x10, 0x00, 0x00, 0x58, + 0x30, 0x1f, 0x00, 0x20, 0x48, 0x00, 0x00, 0x50, 0x00, 0x00, 0xab, 0xab, + 0x00, 0x20, 0xfe, 0xf7, 0x48, 0xb8, 0x00, 0x00, 0x0f, 0x28, 0xb4, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x70, 0x47, 0x70, 0xb5, 0x00, 0xf0, 0x12, 0xf8, + 0x2c, 0x43, 0x1c, 0x60, 0x02, 0xeb, 0x40, 0x00, 0x01, 0x23, 0x07, 0xe0, + 0x70, 0xb5, 0x00, 0xf0, 0x09, 0xf8, 0xac, 0x43, 0x1c, 0x60, 0x02, 0xeb, + 0x40, 0x00, 0x00, 0x23, 0x43, 0x70, 0x81, 0xf3, 0x10, 0x88, 0x70, 0xbd, + 0xef, 0xf3, 0x10, 0x81, 0x72, 0xb6, 0x1d, 0x4b, 0x1d, 0x4a, 0x1c, 0x68, + 0x12, 0xf9, 0x10, 0x60, 0x01, 0x25, 0xb5, 0x40, 0x70, 0x47, 0x0f, 0xf2, + 0x78, 0x02, 0x19, 0x49, 0x82, 0x5c, 0x52, 0xb9, 0x11, 0xf8, 0x10, 0x00, + 0x17, 0x49, 0xc2, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x51, 0x5c, 0xc1, 0x40, + 0x01, 0xf0, 0x01, 0x00, 0x70, 0x47, 0x01, 0xeb, 0x40, 0x00, 0x40, 0x78, + 0x70, 0x47, 0x38, 0xb5, 0x0f, 0x4b, 0x03, 0xeb, 0x40, 0x03, 0xef, 0xf3, + 0x10, 0x84, 0x72, 0xb6, 0x0f, 0xf2, 0x40, 0x05, 0x45, 0x5d, 0x01, 0x2d, + 0x0a, 0xd1, 0x02, 0xb9, 0x13, 0x21, 0x19, 0x70, 0x59, 0x78, 0x11, 0xb1, + 0xff, 0xf7, 0xb9, 0xff, 0x03, 0xe0, 0xff, 0xf7, 0xbf, 0xff, 0x00, 0xe0, + 0x19, 0x70, 0x84, 0xf3, 0x10, 0x88, 0x31, 0xbd, 0x02, 0x49, 0x11, 0xf8, + 0x10, 0x00, 0x70, 0x47, 0x18, 0x00, 0x00, 0x49, 0xb4, 0x28, 0x00, 0x20, + 0x26, 0x0b, 0x00, 0x46, 0x0f, 0xf2, 0x04, 0x01, 0x40, 0x5c, 0x70, 0x47, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, + 0x11, 0x88, 0x70, 0x47, 0xdf, 0xf8, 0x9c, 0x06, 0x00, 0x78, 0x00, 0xf0, + 0x02, 0x00, 0x70, 0x47, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0xff, 0xf7, + 0xef, 0xff, 0x00, 0x22, 0x00, 0x23, 0xc5, 0xe9, 0x02, 0x23, 0xc5, 0xe9, + 0x04, 0x23, 0xc5, 0xe9, 0x06, 0x23, 0x00, 0x21, 0xca, 0x00, 0xdf, 0xf8, + 0x78, 0x56, 0xab, 0x50, 0x49, 0x1c, 0xdf, 0xf8, 0x74, 0x56, 0xab, 0x50, + 0x16, 0x29, 0xf5, 0xd3, 0xa1, 0x00, 0xdf, 0xf8, 0x6c, 0x26, 0x41, 0xf0, + 0x01, 0x01, 0x11, 0x60, 0x16, 0xe0, 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0xff, 0xf7, 0xd0, 0xff, 0xdf, 0xf8, 0x58, 0x26, 0x24, 0xb9, 0xdf, 0xf8, + 0x58, 0x36, 0x1c, 0x68, 0x12, 0x78, 0x03, 0xe0, 0xdf, 0xf8, 0x50, 0x36, + 0x1c, 0x68, 0x52, 0x78, 0x24, 0xf0, 0x02, 0x04, 0x44, 0xea, 0x45, 0x01, + 0x11, 0x43, 0x19, 0x60, 0x80, 0xf3, 0x11, 0x88, 0x31, 0xbd, 0x7f, 0xb5, + 0x0a, 0xb1, 0x00, 0xf5, 0x80, 0x70, 0x40, 0xf2, 0xfc, 0x72, 0x02, 0xea, + 0x80, 0x00, 0x40, 0xf0, 0x02, 0x00, 0x00, 0x22, 0x03, 0xeb, 0x82, 0x05, + 0x33, 0xf8, 0x22, 0x60, 0xb5, 0xf9, 0x02, 0x50, 0x46, 0xea, 0x05, 0x45, + 0x4d, 0xf8, 0x22, 0x50, 0x52, 0x1c, 0x04, 0x2a, 0xf2, 0xdb, 0x03, 0x9a, + 0x02, 0x9b, 0x01, 0x9c, 0x00, 0x29, 0x0c, 0xbf, 0xdf, 0xf8, 0x00, 0x16, + 0xdf, 0xf8, 0x00, 0x16, 0x00, 0x9d, 0x4d, 0x60, 0x8c, 0x60, 0xcb, 0x60, + 0x0a, 0x61, 0x08, 0x60, 0x7f, 0xbd, 0x7f, 0xb5, 0x04, 0x46, 0x68, 0x46, + 0x10, 0x21, 0xfd, 0xf7, 0xbf, 0xfd, 0x4f, 0xf4, 0x00, 0x50, 0xad, 0xf8, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x26, 0x86, 0xf0, 0x01, 0x01, 0xc9, 0xb2, + 0xe0, 0xb2, 0xff, 0xf7, 0xac, 0xff, 0x6b, 0x46, 0x32, 0x46, 0x21, 0x46, + 0x28, 0x46, 0xff, 0xf7, 0xc0, 0xff, 0x76, 0x1c, 0x02, 0x2e, 0xf0, 0xd3, + 0x6d, 0x1c, 0xff, 0x2d, 0xec, 0xd9, 0x7f, 0xbd, 0xc0, 0x0b, 0x00, 0x21, + 0x00, 0xfa, 0x01, 0xf2, 0x12, 0x05, 0x03, 0xd4, 0x49, 0x1c, 0xc9, 0xb2, + 0x07, 0x29, 0xf7, 0xdb, 0xc1, 0xf1, 0x07, 0x01, 0xc9, 0xb2, 0x00, 0x29, + 0x14, 0xbf, 0x4a, 0x1e, 0x00, 0x22, 0xd0, 0x40, 0x00, 0xf0, 0x1f, 0x00, + 0x40, 0xea, 0x41, 0x10, 0x70, 0x47, 0x41, 0x09, 0x05, 0xd0, 0x00, 0xf0, + 0x1f, 0x00, 0x40, 0xf0, 0x20, 0x00, 0x4a, 0x1e, 0x90, 0x40, 0x02, 0x29, + 0x04, 0xdb, 0x01, 0x22, 0x89, 0x1e, 0x02, 0xfa, 0x01, 0xf1, 0x08, 0x43, + 0x70, 0x47, 0x10, 0xb5, 0x02, 0x46, 0x0b, 0x46, 0x14, 0x68, 0x18, 0x46, + 0x21, 0x46, 0xfc, 0xf7, 0xb5, 0xfe, 0x38, 0xbf, 0x1c, 0x46, 0x83, 0xf0, + 0x00, 0x43, 0x20, 0x46, 0x19, 0x46, 0xfc, 0xf7, 0xad, 0xfe, 0x38, 0xbf, + 0x1c, 0x46, 0x14, 0x60, 0x10, 0xbd, 0x2d, 0xe9, 0xf7, 0x4f, 0x8e, 0xb0, + 0x9a, 0x46, 0x1a, 0x9c, 0xdf, 0xf8, 0x34, 0xb5, 0x00, 0x26, 0x4f, 0xf0, + 0x8c, 0x48, 0x0d, 0xf1, 0x14, 0x09, 0xf0, 0xb2, 0xff, 0xf7, 0xcd, 0xff, + 0x80, 0x03, 0x01, 0xf0, 0x2d, 0xf8, 0x01, 0x46, 0x0e, 0x9a, 0x00, 0x94, + 0x53, 0x46, 0x05, 0xa8, 0x01, 0xf0, 0x92, 0xfb, 0x00, 0x25, 0x59, 0xf8, + 0x35, 0x00, 0x41, 0x46, 0xfc, 0xf7, 0x9c, 0xfe, 0x49, 0xf8, 0x35, 0x00, + 0x41, 0x46, 0x05, 0xa8, 0x00, 0xeb, 0xc5, 0x07, 0x78, 0x68, 0xfc, 0xf7, + 0x93, 0xfe, 0x78, 0x60, 0x59, 0x46, 0x38, 0x46, 0xff, 0xf7, 0xbf, 0xff, + 0x59, 0x46, 0x38, 0x1d, 0xff, 0xf7, 0xbb, 0xff, 0x59, 0xf8, 0x35, 0x00, + 0xfc, 0xf7, 0xf2, 0xfe, 0x01, 0xa9, 0x21, 0xf8, 0x25, 0x00, 0x78, 0x68, + 0xfc, 0xf7, 0xec, 0xfe, 0x01, 0xa9, 0x01, 0xeb, 0x85, 0x01, 0x6d, 0x1c, + 0x04, 0x2d, 0x48, 0x80, 0xd7, 0xd3, 0x10, 0x9a, 0x0f, 0x99, 0x01, 0xab, + 0x30, 0x46, 0xff, 0xf7, 0x36, 0xff, 0x76, 0x1c, 0xff, 0x2e, 0xc0, 0xd9, + 0x11, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x10, 0xb5, 0x04, 0x00, 0x0c, 0xbf, + 0xdf, 0xf8, 0xa0, 0x24, 0xdf, 0xf8, 0xa0, 0x24, 0xc8, 0xb2, 0x10, 0x60, + 0x08, 0x1d, 0xdf, 0xf8, 0x9c, 0x14, 0xdf, 0xf8, 0x9c, 0x24, 0x89, 0x6b, + 0x52, 0x69, 0xa1, 0xfb, 0x00, 0x01, 0x00, 0x23, 0xfd, 0xf7, 0xc8, 0xf9, + 0xdf, 0xf8, 0x8c, 0x14, 0x40, 0x1c, 0x41, 0xf8, 0x24, 0x00, 0x10, 0xbd, + 0xf8, 0xb5, 0x00, 0x88, 0x00, 0x0a, 0x0c, 0x46, 0x80, 0xf0, 0x02, 0x00, + 0x59, 0x00, 0xc0, 0x00, 0x01, 0xf0, 0x02, 0x01, 0x00, 0xf0, 0x18, 0x00, + 0x08, 0x43, 0x15, 0x46, 0x40, 0xf0, 0x01, 0x07, 0xff, 0xf7, 0xbe, 0xfe, + 0x06, 0x46, 0x29, 0x46, 0x20, 0x46, 0xff, 0xf7, 0xce, 0xff, 0xdf, 0xf8, + 0x2c, 0x04, 0x1c, 0xb9, 0x00, 0x78, 0xdf, 0xf8, 0x28, 0x14, 0x02, 0xe0, + 0x40, 0x78, 0xdf, 0xf8, 0x24, 0x14, 0x38, 0x43, 0x08, 0x60, 0x86, 0xf3, + 0x11, 0x88, 0xf1, 0xbd, 0xf8, 0xb5, 0x07, 0x00, 0x0c, 0x46, 0x1a, 0xbf, + 0x00, 0x20, 0xdf, 0xf8, 0x30, 0x14, 0xdf, 0xf8, 0x30, 0x14, 0x15, 0x46, + 0x08, 0x60, 0x1e, 0x46, 0xdf, 0xf8, 0x1c, 0x04, 0x50, 0xf8, 0x27, 0x00, + 0xfc, 0xf7, 0x91, 0xfb, 0xc7, 0xb1, 0x00, 0x20, 0xb0, 0x42, 0x2e, 0xda, + 0x41, 0x42, 0xc9, 0x00, 0xdf, 0xf8, 0x10, 0x24, 0x00, 0xf0, 0x31, 0xf8, + 0xdf, 0xf8, 0x0c, 0x24, 0x52, 0x58, 0xd2, 0x08, 0x5a, 0x80, 0xdf, 0xf8, + 0x08, 0x24, 0x52, 0x58, 0xd2, 0x08, 0x25, 0xf8, 0x20, 0x20, 0xdf, 0xf8, + 0x00, 0x24, 0x00, 0xf0, 0x1b, 0xf8, 0xe7, 0xe7, 0x00, 0x20, 0x14, 0xe0, + 0x41, 0x42, 0xc9, 0x00, 0xdf, 0xf8, 0xf0, 0x23, 0x00, 0xf0, 0x19, 0xf8, + 0xdf, 0xf8, 0xec, 0x23, 0x52, 0x58, 0xd2, 0x08, 0x5a, 0x80, 0xdf, 0xf8, + 0xe8, 0x23, 0x52, 0x58, 0xd2, 0x08, 0x25, 0xf8, 0x20, 0x20, 0xdf, 0xf8, + 0xe0, 0x23, 0x00, 0xf0, 0x03, 0xf8, 0xb0, 0x42, 0xe8, 0xdb, 0xf1, 0xbd, + 0x51, 0x58, 0x05, 0xeb, 0x80, 0x02, 0xc9, 0x08, 0x51, 0x80, 0x40, 0x1c, + 0x70, 0x47, 0x52, 0x58, 0xd2, 0x08, 0x24, 0xf8, 0x20, 0x20, 0x04, 0xeb, + 0x80, 0x03, 0x70, 0x47, 0xf8, 0xb5, 0x06, 0x46, 0x0c, 0x46, 0x15, 0x46, + 0x1f, 0x46, 0xff, 0xf7, 0x4f, 0xfe, 0x00, 0x21, 0xca, 0x00, 0x56, 0xf8, + 0x31, 0x30, 0xdf, 0xf8, 0x44, 0xc3, 0x4c, 0xf8, 0x02, 0x30, 0x06, 0xeb, + 0xc1, 0x03, 0xdf, 0xf8, 0x3c, 0xc3, 0x5b, 0x68, 0x4c, 0xf8, 0x02, 0x30, + 0x49, 0x1c, 0x15, 0x29, 0xee, 0xd3, 0xdf, 0xf8, 0x88, 0x13, 0x0c, 0x60, + 0x4d, 0x60, 0x3f, 0x06, 0x06, 0x99, 0x3a, 0x0d, 0x02, 0xf0, 0xf0, 0x02, + 0x42, 0xea, 0x81, 0x01, 0xc6, 0x4a, 0x41, 0xf0, 0x03, 0x01, 0x11, 0x60, + 0x80, 0xf3, 0x11, 0x88, 0xf1, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x00, 0x21, + 0x00, 0x20, 0xf9, 0xf7, 0x3e, 0xf9, 0x20, 0x69, 0x04, 0xf1, 0xbc, 0x01, + 0x00, 0xf0, 0x21, 0xf8, 0x05, 0x00, 0x07, 0xd1, 0x21, 0x68, 0x20, 0x69, + 0x00, 0xf0, 0x76, 0xf8, 0x20, 0x69, 0x00, 0xf0, 0x58, 0xf8, 0x05, 0x46, + 0x20, 0x69, 0xfc, 0xf7, 0xe9, 0xf9, 0x28, 0x46, 0x32, 0xbd, 0x10, 0xb5, + 0x04, 0x46, 0xf9, 0xf7, 0x15, 0xfc, 0x03, 0x28, 0x06, 0xd1, 0x04, 0xf0, + 0x1b, 0xf9, 0x00, 0x21, 0x04, 0xf1, 0xbc, 0x00, 0xfb, 0xf7, 0x15, 0xf9, + 0xbd, 0xe8, 0x10, 0x40, 0x00, 0x20, 0xf9, 0xf7, 0x75, 0xb9, 0x2d, 0xe9, + 0xf0, 0x41, 0x04, 0x46, 0x88, 0x46, 0xf9, 0xf7, 0x01, 0xfc, 0x00, 0x26, + 0x03, 0x28, 0x25, 0xd1, 0xe0, 0xb2, 0xf9, 0xf7, 0x35, 0xfc, 0x05, 0x46, + 0x40, 0x46, 0xfb, 0xf7, 0xee, 0xf8, 0x00, 0x2d, 0x48, 0xbf, 0x14, 0x26, + 0x20, 0xd4, 0x28, 0x46, 0xfb, 0xf7, 0x0f, 0xf9, 0xfb, 0xf7, 0x41, 0xf9, + 0xfb, 0xf7, 0x2c, 0xf9, 0x01, 0x2d, 0x0c, 0xd1, 0x03, 0x27, 0x02, 0x20, + 0x04, 0xf0, 0x98, 0xf8, 0xb3, 0x48, 0xb0, 0xf8, 0x54, 0x10, 0x20, 0x46, + 0xfa, 0xf7, 0xc3, 0xfb, 0x60, 0xb1, 0x13, 0x26, 0x0a, 0xe0, 0x02, 0x27, + 0x00, 0x2d, 0xf0, 0xd1, 0x01, 0x20, 0xef, 0xe7, 0xf9, 0xf7, 0xd6, 0xfb, + 0x02, 0x28, 0x0c, 0xbf, 0x03, 0x27, 0x02, 0x27, 0xf8, 0xb2, 0xfa, 0xf7, + 0xd9, 0xf9, 0x18, 0xb9, 0xf9, 0xf7, 0x4b, 0xfc, 0x00, 0xb9, 0x0c, 0x26, + 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0x38, 0xb5, 0x04, 0x46, 0x01, 0x20, + 0xa0, 0x40, 0xf8, 0xf7, 0xe7, 0xfe, 0x00, 0x25, 0x08, 0xb9, 0x02, 0x25, + 0x0a, 0xe0, 0x04, 0x20, 0xf8, 0xf7, 0xd2, 0xfe, 0x08, 0xb9, 0x01, 0x25, + 0x04, 0xe0, 0xe0, 0xb2, 0xfb, 0xf7, 0x5d, 0xfa, 0x00, 0xb1, 0x11, 0x25, + 0xfa, 0xf7, 0x41, 0xf9, 0x00, 0xb1, 0x00, 0x25, 0x28, 0x46, 0x32, 0xbd, + 0x10, 0xb5, 0x0c, 0x46, 0x21, 0x78, 0x09, 0x04, 0x01, 0xf4, 0xfe, 0x01, + 0x41, 0xea, 0x80, 0x70, 0x40, 0xf0, 0x00, 0x40, 0x40, 0xf4, 0x80, 0x40, + 0xfb, 0xf7, 0x27, 0xfc, 0x60, 0x78, 0xbd, 0xe8, 0x10, 0x40, 0xfb, 0xf7, + 0x45, 0xbc, 0x38, 0xb5, 0x04, 0x46, 0xf7, 0xf7, 0xf1, 0xfc, 0x20, 0x68, + 0xc0, 0x78, 0x80, 0xf0, 0x01, 0x05, 0xa0, 0x68, 0x20, 0x30, 0x2a, 0x46, + 0x01, 0x79, 0x00, 0x91, 0x03, 0x68, 0x21, 0x69, 0x04, 0xf1, 0x14, 0x00, + 0xff, 0xf7, 0x45, 0xfe, 0x20, 0x68, 0x02, 0x78, 0x21, 0x69, 0xa0, 0x68, + 0x2b, 0x46, 0xff, 0xf7, 0xa7, 0xfe, 0x20, 0x68, 0xc5, 0x70, 0xbd, 0xe8, + 0x31, 0x40, 0xf7, 0xf7, 0xea, 0xbc, 0x2d, 0xe9, 0xf8, 0x43, 0x80, 0x46, + 0x4f, 0xf4, 0xd4, 0x70, 0x00, 0xfb, 0x08, 0xf5, 0x7a, 0x4e, 0xdf, 0xf8, + 0xec, 0x91, 0xaf, 0x19, 0xf8, 0x78, 0x80, 0xf0, 0x01, 0x04, 0x09, 0xf1, + 0x20, 0x00, 0x22, 0x46, 0x01, 0x79, 0x03, 0x68, 0x00, 0x91, 0x07, 0xf1, + 0x28, 0x00, 0x41, 0x46, 0xff, 0xf7, 0x1f, 0xfe, 0xaa, 0x5d, 0x23, 0x46, + 0x41, 0x46, 0x48, 0x46, 0xff, 0xf7, 0x82, 0xfe, 0xfc, 0x70, 0xbd, 0xe8, + 0xf1, 0x83, 0x10, 0xb5, 0xcb, 0x07, 0x55, 0x4a, 0x0d, 0xd5, 0x55, 0x4b, + 0x28, 0xb1, 0x04, 0x24, 0x14, 0x70, 0x1c, 0x68, 0x44, 0xf0, 0x04, 0x04, + 0x04, 0xe0, 0x00, 0x24, 0x14, 0x70, 0x1c, 0x68, 0x24, 0xf0, 0x04, 0x04, + 0x1c, 0x60, 0x89, 0x07, 0x0c, 0xd5, 0x4e, 0x49, 0x28, 0xb1, 0x04, 0x20, + 0x50, 0x70, 0x08, 0x68, 0x40, 0xf0, 0x04, 0x00, 0x03, 0xe0, 0x50, 0x70, + 0x08, 0x68, 0x20, 0xf0, 0x04, 0x00, 0x08, 0x60, 0x10, 0xbd, 0xf8, 0xb5, + 0x04, 0x46, 0x0d, 0x46, 0x16, 0x46, 0x1f, 0x46, 0x21, 0x46, 0x30, 0x46, + 0xff, 0xf7, 0x30, 0xfd, 0x20, 0x88, 0x00, 0x90, 0x4f, 0xf4, 0xd4, 0x71, + 0x20, 0x46, 0xfd, 0xf7, 0x4f, 0xfb, 0xbd, 0xf8, 0x00, 0x00, 0x20, 0x80, + 0x4f, 0xf2, 0xff, 0x71, 0x38, 0x88, 0x08, 0x40, 0xa0, 0x80, 0x04, 0xf5, + 0xce, 0x70, 0x39, 0x6a, 0x01, 0x60, 0x97, 0xf8, 0x24, 0x10, 0x01, 0x71, + 0x30, 0x46, 0xff, 0xf7, 0x78, 0xfd, 0x00, 0x20, 0xe0, 0x70, 0x00, 0x21, + 0xf0, 0xb2, 0xff, 0xf7, 0x30, 0xfd, 0x00, 0x20, 0x28, 0x85, 0x68, 0x85, + 0xf1, 0xbd, 0x46, 0x49, 0x4f, 0xf4, 0xd4, 0x72, 0x02, 0xfb, 0x00, 0x10, + 0x90, 0xf8, 0xa1, 0x01, 0x00, 0xb1, 0x01, 0x20, 0x70, 0x47, 0x41, 0x4a, + 0x4f, 0xf4, 0xd4, 0x73, 0x03, 0xfb, 0x00, 0x20, 0x80, 0xf8, 0xa1, 0x11, + 0x70, 0x47, 0x3d, 0x49, 0x4f, 0xf4, 0xd4, 0x72, 0x02, 0xfb, 0x00, 0x11, + 0x01, 0xf1, 0xe0, 0x00, 0x28, 0x31, 0xb8, 0x22, 0xff, 0xf7, 0xe0, 0xbb, + 0x70, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x36, 0x48, 0x4f, 0xf4, 0xd4, 0x71, + 0x01, 0xfb, 0x04, 0x06, 0x00, 0x20, 0x86, 0xf8, 0xa1, 0x01, 0x28, 0x07, + 0x03, 0xd5, 0x31, 0x46, 0x20, 0x46, 0xff, 0xf7, 0xdf, 0xfc, 0x68, 0x07, + 0x04, 0xd5, 0xb8, 0x21, 0x06, 0xf1, 0x28, 0x00, 0xf8, 0xf7, 0x52, 0xfd, + 0xe8, 0x07, 0x08, 0xd5, 0x2c, 0x48, 0x2b, 0x4b, 0x94, 0x21, 0x01, 0xfb, + 0x04, 0x01, 0x22, 0x46, 0x30, 0x46, 0xff, 0xf7, 0x94, 0xff, 0xa8, 0x07, + 0x0a, 0xd5, 0x06, 0xf1, 0x28, 0x00, 0x06, 0xf1, 0xe0, 0x01, 0xb8, 0x22, + 0xff, 0xf7, 0xb4, 0xfb, 0x20, 0x46, 0xbd, 0xe8, 0x70, 0x40, 0x42, 0xe7, + 0x70, 0xbd, 0x1f, 0x49, 0x4f, 0xf4, 0xd4, 0x72, 0x02, 0xfb, 0x00, 0x10, + 0x80, 0x78, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x46, + 0x08, 0x00, 0x60, 0x59, 0x0c, 0x00, 0x60, 0x59, 0x00, 0x00, 0x60, 0x59, + 0x98, 0xf3, 0x00, 0x20, 0x00, 0x00, 0x40, 0x59, 0x00, 0x00, 0x50, 0x59, + 0x04, 0x00, 0x40, 0x59, 0x04, 0x00, 0x50, 0x59, 0x00, 0xfc, 0x7f, 0x46, + 0x18, 0x00, 0x40, 0x59, 0x18, 0x00, 0x50, 0x59, 0x00, 0xf2, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0x38, 0xf3, 0x00, 0x20, 0x1c, 0x00, 0x50, 0x59, + 0x1c, 0x00, 0x40, 0x59, 0x4c, 0x00, 0x50, 0x59, 0x50, 0x00, 0x50, 0x59, + 0x8c, 0x00, 0x50, 0x59, 0x90, 0x00, 0x50, 0x59, 0x4c, 0x00, 0x40, 0x59, + 0x50, 0x00, 0x40, 0x59, 0x8c, 0x00, 0x40, 0x59, 0x90, 0x00, 0x40, 0x59, + 0xb0, 0x00, 0x60, 0x59, 0x4c, 0x1f, 0x00, 0x20, 0x10, 0xb2, 0x00, 0x20, + 0x30, 0x27, 0x00, 0x20, 0x74, 0x27, 0x00, 0x20, 0x2d, 0xe9, 0xf8, 0x43, + 0xdf, 0xf8, 0x88, 0x8a, 0x88, 0x21, 0x40, 0x46, 0xfd, 0xf7, 0x98, 0xfa, + 0x00, 0x25, 0x0f, 0xf6, 0x4d, 0x29, 0xdf, 0xf8, 0x7c, 0x7a, 0xd4, 0x20, + 0x00, 0xfb, 0x05, 0xf4, 0x44, 0x20, 0xe5, 0x53, 0x00, 0xfb, 0x05, 0x86, + 0x6f, 0xf0, 0xc7, 0x00, 0x70, 0x61, 0xf8, 0xf7, 0xa1, 0xfa, 0x70, 0x63, + 0x00, 0x21, 0xdf, 0xf8, 0x60, 0x0a, 0x28, 0x18, 0x4b, 0x46, 0x81, 0x70, + 0x01, 0x71, 0x01, 0x22, 0xe9, 0xb2, 0x02, 0x20, 0xf8, 0xf7, 0x38, 0xfe, + 0xe0, 0x19, 0x00, 0xf0, 0xb7, 0xfc, 0x6d, 0x1c, 0x02, 0x2d, 0xe0, 0xd3, + 0xbd, 0xe8, 0xf1, 0x43, 0xf8, 0xf7, 0xdc, 0xbe, 0x2d, 0xe9, 0xf0, 0x43, + 0xdf, 0xf8, 0x34, 0x0a, 0xdf, 0xf8, 0x24, 0x9a, 0xdf, 0xf8, 0x30, 0x7a, + 0x89, 0xb0, 0x80, 0x7a, 0x00, 0xf0, 0x03, 0x08, 0xff, 0xf7, 0xc2, 0xff, + 0x00, 0x24, 0x00, 0x25, 0x28, 0xfa, 0x05, 0xf0, 0xc0, 0x07, 0x3d, 0xd5, + 0xdf, 0xf8, 0x08, 0x0a, 0x01, 0x95, 0xd4, 0x21, 0x01, 0xfb, 0x05, 0x00, + 0xdf, 0xf8, 0x0c, 0x1a, 0x02, 0x91, 0x03, 0x97, 0x44, 0x21, 0x01, 0xfb, + 0x05, 0x91, 0x04, 0x91, 0x08, 0x90, 0x00, 0xf1, 0xd0, 0x06, 0x05, 0x80, + 0x00, 0x21, 0x31, 0x70, 0x71, 0x70, 0x00, 0xf0, 0x85, 0xfc, 0x01, 0xa8, + 0x00, 0xf0, 0x89, 0xfc, 0x04, 0x00, 0x09, 0xd1, 0x02, 0x98, 0x00, 0x96, + 0xb0, 0xf9, 0x02, 0x20, 0x01, 0x88, 0x03, 0x1d, 0x01, 0x98, 0xfd, 0xf7, + 0xde, 0xf8, 0x04, 0x46, 0x01, 0xa8, 0x00, 0xf0, 0xad, 0xfc, 0x14, 0xb9, + 0x30, 0x78, 0x5a, 0x28, 0x05, 0xda, 0x04, 0x98, 0x3c, 0x30, 0x00, 0x21, + 0xc1, 0x80, 0x81, 0x80, 0x0d, 0xe0, 0x04, 0x98, 0x3c, 0x30, 0x01, 0x21, + 0xc1, 0x80, 0x81, 0x80, 0x08, 0x99, 0x11, 0xf8, 0xd0, 0x2f, 0x42, 0x80, + 0x49, 0x78, 0x01, 0x80, 0x6d, 0x1c, 0x02, 0x2d, 0xba, 0xd3, 0x20, 0x46, + 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x83, 0x00, 0x00, 0x2d, 0xe9, 0xf1, 0x4f, + 0xa0, 0xb0, 0xf8, 0xf7, 0x02, 0xfe, 0x02, 0x90, 0x3a, 0x21, 0x20, 0x98, + 0xdf, 0xf8, 0x70, 0x69, 0xdf, 0xf8, 0x7c, 0x49, 0x04, 0x90, 0x44, 0x22, + 0x06, 0xf1, 0x10, 0x00, 0x05, 0x90, 0x4f, 0xf4, 0x84, 0x58, 0x20, 0x98, + 0x01, 0xfb, 0x00, 0xf5, 0x28, 0x19, 0x06, 0x90, 0x20, 0x99, 0xdf, 0xf8, + 0x48, 0x09, 0x02, 0xfb, 0x01, 0x00, 0x07, 0x90, 0xd4, 0x22, 0x20, 0x99, + 0xdf, 0xf8, 0x3c, 0x09, 0x02, 0xfb, 0x01, 0x00, 0x0b, 0x90, 0x0f, 0x90, + 0xf7, 0xf7, 0x20, 0xfb, 0x28, 0x19, 0xdf, 0xf8, 0x38, 0x19, 0x3a, 0x22, + 0xff, 0xf7, 0xa2, 0xfa, 0x07, 0x98, 0x0b, 0x99, 0xc0, 0x8f, 0x81, 0xf8, + 0xd0, 0x00, 0x07, 0x98, 0x0b, 0x99, 0x80, 0x8f, 0x81, 0xf8, 0xd1, 0x00, + 0xf7, 0xf7, 0x23, 0xfb, 0x06, 0x98, 0x20, 0x99, 0x30, 0xf9, 0x11, 0x00, + 0x03, 0x90, 0x07, 0x98, 0x41, 0x6b, 0x81, 0x63, 0xf8, 0xf7, 0xec, 0xf9, + 0x07, 0x9d, 0x68, 0x63, 0x28, 0x6b, 0x40, 0x1c, 0x28, 0x63, 0x20, 0x98, + 0x06, 0xeb, 0x80, 0x00, 0x11, 0x90, 0x03, 0x98, 0xfc, 0xf7, 0x6e, 0xf9, + 0xdf, 0xf8, 0xf4, 0x18, 0xfc, 0xf7, 0x84, 0xf9, 0xdf, 0xf8, 0xf0, 0x18, + 0xfc, 0xf7, 0x80, 0xf9, 0x00, 0xf0, 0xc9, 0xfa, 0x11, 0x99, 0x88, 0x60, + 0x03, 0x98, 0x68, 0x61, 0x02, 0x98, 0x68, 0x62, 0xb5, 0xf8, 0x40, 0x00, + 0x30, 0xb9, 0x0f, 0x98, 0x00, 0xf0, 0xf0, 0xfb, 0x49, 0xf2, 0x80, 0x28, + 0x06, 0x25, 0xab, 0xe2, 0x00, 0x20, 0x0e, 0x90, 0x00, 0x90, 0x0d, 0x90, + 0x0c, 0x90, 0x10, 0x90, 0x04, 0xa8, 0x00, 0xf0, 0xea, 0xfb, 0x05, 0x00, + 0x1d, 0xd1, 0x0b, 0x98, 0x90, 0xf8, 0xd0, 0x10, 0x04, 0x98, 0xff, 0xf7, + 0x7e, 0xfc, 0xef, 0xf3, 0x11, 0x8b, 0x60, 0x20, 0x80, 0xf3, 0x11, 0x88, + 0x20, 0x98, 0xf8, 0xf7, 0x15, 0xfe, 0x20, 0x98, 0x80, 0x19, 0x01, 0x90, + 0x00, 0x20, 0x01, 0x99, 0x08, 0x71, 0x00, 0xf0, 0x9f, 0xfa, 0x00, 0x8c, + 0x48, 0xb9, 0x01, 0x99, 0x88, 0x70, 0x8b, 0xf3, 0x11, 0x88, 0x00, 0x27, + 0x84, 0xe0, 0x04, 0xa8, 0x00, 0xf0, 0xfa, 0xfb, 0x7e, 0xe2, 0x20, 0x98, + 0x00, 0x21, 0xf8, 0xf7, 0xf0, 0xfd, 0x00, 0x28, 0xef, 0xd0, 0x01, 0x20, + 0xed, 0xe7, 0x00, 0x26, 0x12, 0xaa, 0x12, 0xa8, 0x32, 0xf9, 0x26, 0x20, + 0x00, 0xeb, 0x86, 0x0a, 0xd3, 0x17, 0xa2, 0xfb, 0x02, 0x49, 0xba, 0xf9, + 0x02, 0x00, 0x02, 0xfb, 0x03, 0x99, 0x03, 0xfb, 0x02, 0x99, 0xc1, 0x17, + 0xa0, 0xfb, 0x00, 0x23, 0x00, 0xfb, 0x01, 0x33, 0x01, 0xfb, 0x00, 0x33, + 0x49, 0x46, 0xa0, 0x18, 0x59, 0x41, 0xfc, 0xf7, 0xd1, 0xf8, 0x0e, 0x99, + 0xfc, 0xf7, 0x0c, 0xfa, 0x0e, 0x90, 0x19, 0xa8, 0x00, 0xeb, 0x86, 0x0b, + 0x30, 0xf9, 0x26, 0x00, 0xc1, 0x17, 0xa0, 0xfb, 0x00, 0x23, 0xbb, 0xf9, + 0x02, 0x40, 0x00, 0xfb, 0x01, 0x33, 0x01, 0xfb, 0x00, 0x33, 0x4f, 0xea, + 0xe4, 0x79, 0xa4, 0xfb, 0x04, 0x01, 0x04, 0xfb, 0x09, 0x11, 0x09, 0xfb, + 0x04, 0x11, 0x10, 0x18, 0x59, 0x41, 0xfc, 0xf7, 0xb3, 0xf8, 0x00, 0x99, + 0xfc, 0xf7, 0xee, 0xf9, 0x00, 0x90, 0x19, 0xa8, 0xbb, 0xf9, 0x02, 0x40, + 0x30, 0xf9, 0x26, 0xb0, 0xba, 0xf9, 0x02, 0x20, 0x12, 0xa8, 0x4f, 0xea, + 0xe4, 0x79, 0x30, 0xf9, 0x26, 0xc0, 0xa2, 0xfb, 0x04, 0x01, 0xd3, 0x17, + 0x02, 0xfb, 0x09, 0x11, 0x03, 0xfb, 0x04, 0x11, 0xcc, 0xfb, 0x0b, 0x01, + 0xfc, 0xf7, 0x98, 0xf8, 0x0d, 0x99, 0xfc, 0xf7, 0xd3, 0xf9, 0x0d, 0x90, + 0x22, 0x46, 0x12, 0xa8, 0x4b, 0x46, 0x30, 0xf9, 0x26, 0x00, 0xa0, 0xfb, + 0x02, 0x49, 0xc1, 0x17, 0x00, 0xfb, 0x03, 0x99, 0x19, 0xa8, 0x01, 0xfb, + 0x02, 0x99, 0x30, 0xf9, 0x26, 0x00, 0xba, 0xf9, 0x02, 0x10, 0x81, 0xfb, + 0x00, 0x01, 0x20, 0x1a, 0x69, 0xeb, 0x01, 0x01, 0xfc, 0xf7, 0x7c, 0xf8, + 0x0c, 0x99, 0xfc, 0xf7, 0xb7, 0xf9, 0x76, 0x1c, 0x07, 0x2e, 0x0c, 0x90, + 0x88, 0xd3, 0x7f, 0x1c, 0x00, 0xf0, 0x10, 0xfa, 0x00, 0x8b, 0x87, 0x42, + 0x19, 0xd2, 0x0f, 0x98, 0x00, 0x88, 0x07, 0x23, 0x12, 0xaa, 0x19, 0xa9, + 0xff, 0xf7, 0x16, 0xfc, 0xf9, 0xf7, 0x57, 0xfe, 0x00, 0x28, 0x3f, 0xf4, + 0x76, 0xaf, 0x07, 0x99, 0x04, 0x20, 0x08, 0x60, 0x7f, 0x1e, 0x04, 0xa8, + 0x00, 0xf0, 0x60, 0xfb, 0x04, 0xa8, 0x00, 0xf0, 0x2a, 0xfb, 0x05, 0x00, + 0xe1, 0xd0, 0x01, 0x20, 0x10, 0x90, 0x04, 0xa8, 0x00, 0xf0, 0x56, 0xfb, + 0x10, 0x98, 0x00, 0x28, 0x02, 0xbf, 0x01, 0x98, 0x00, 0x79, 0x00, 0x28, + 0x05, 0xd1, 0x01, 0x98, 0x80, 0x78, 0x18, 0xb1, 0x0f, 0x25, 0x49, 0xf2, + 0x80, 0x28, 0xcd, 0xe1, 0x06, 0x98, 0x20, 0x99, 0xdf, 0xf8, 0x04, 0xb7, + 0x00, 0xeb, 0x41, 0x07, 0x38, 0x8b, 0xc0, 0xeb, 0xc0, 0x00, 0xfc, 0xf7, + 0x6b, 0xf8, 0x04, 0x46, 0x00, 0x98, 0x21, 0x46, 0xfc, 0xf7, 0x80, 0xf8, + 0xfc, 0xf7, 0xb2, 0xf9, 0x00, 0xf0, 0xc3, 0xf9, 0x06, 0x46, 0x0e, 0x98, + 0x21, 0x46, 0xfc, 0xf7, 0x77, 0xf8, 0xfc, 0xf7, 0xa9, 0xf9, 0x00, 0xf0, + 0xba, 0xf9, 0x81, 0x46, 0x07, 0x9c, 0x01, 0x21, 0x30, 0x46, 0x03, 0xf0, + 0x05, 0xfb, 0x00, 0xf0, 0xe3, 0xfa, 0x00, 0xf0, 0xb8, 0xf9, 0xfc, 0xf7, + 0x61, 0xfa, 0xa0, 0x62, 0x01, 0x21, 0x48, 0x46, 0x03, 0xf0, 0xfa, 0xfa, + 0x00, 0xf0, 0xd8, 0xfa, 0x00, 0xf0, 0xad, 0xf9, 0xfc, 0xf7, 0x56, 0xfa, + 0xe0, 0x62, 0x01, 0x98, 0x80, 0x78, 0x10, 0xb1, 0x49, 0xf2, 0x80, 0x28, + 0x29, 0xe0, 0xf8, 0x8e, 0xfc, 0xf7, 0x42, 0xf8, 0x4f, 0xf0, 0x5e, 0x5a, + 0x00, 0xf0, 0xc3, 0xfa, 0x01, 0x46, 0x30, 0x46, 0xfc, 0xf7, 0xc6, 0xf9, + 0x04, 0xd2, 0x02, 0x98, 0x60, 0x62, 0x49, 0xf2, 0xb2, 0x28, 0x12, 0x25, + 0xb8, 0x8b, 0xfc, 0xf7, 0x31, 0xf8, 0x00, 0xf0, 0xb4, 0xfa, 0x01, 0x46, + 0x48, 0x46, 0xfc, 0xf7, 0xb7, 0xf9, 0x10, 0xd2, 0x02, 0x98, 0x60, 0x62, + 0x49, 0xf2, 0xb2, 0x28, 0x13, 0x25, 0x66, 0x6a, 0x48, 0xf4, 0x02, 0x40, + 0x40, 0xf0, 0xe4, 0x08, 0x01, 0x98, 0x80, 0x78, 0x00, 0x28, 0x00, 0xf0, + 0x27, 0x81, 0x0f, 0x25, 0x66, 0xe1, 0x00, 0x2d, 0xf1, 0xd1, 0x01, 0x98, + 0x04, 0x78, 0xb8, 0x8a, 0xfc, 0xf7, 0x12, 0xf8, 0xdf, 0xf8, 0x30, 0x16, + 0xfc, 0xf7, 0x1e, 0xf8, 0x31, 0x46, 0xfc, 0xf7, 0x97, 0xf9, 0x4f, 0xf0, + 0x00, 0x0a, 0x38, 0xbf, 0x00, 0x20, 0x0b, 0xd3, 0x38, 0x8a, 0xfc, 0xf7, + 0x03, 0xf8, 0xdf, 0xf8, 0x14, 0x16, 0xfc, 0xf7, 0x0f, 0xf8, 0x31, 0x46, + 0xfc, 0xf7, 0x88, 0xf9, 0x16, 0xd2, 0x01, 0x20, 0x04, 0x2c, 0x13, 0xd8, + 0xdf, 0xe8, 0x04, 0xf0, 0x03, 0x0c, 0x05, 0x03, 0x03, 0x00, 0x20, 0xb9, + 0x07, 0xe0, 0x10, 0xb9, 0x4f, 0xf0, 0x04, 0x0a, 0x08, 0xe0, 0x4f, 0xf0, + 0x02, 0x0a, 0x05, 0xe0, 0x10, 0xb9, 0x4f, 0xf0, 0x01, 0x0a, 0x01, 0xe0, + 0x4f, 0xf0, 0x03, 0x0a, 0x01, 0x98, 0x80, 0xf8, 0x00, 0xa0, 0xf7, 0xf7, + 0x5f, 0xf9, 0x01, 0x98, 0x04, 0x78, 0x54, 0xb9, 0x07, 0x9c, 0x00, 0x20, + 0xa0, 0x61, 0xe0, 0x61, 0x20, 0x62, 0x48, 0xf4, 0x02, 0x48, 0xf7, 0xf7, + 0x68, 0xf9, 0x0b, 0x25, 0x1e, 0xe1, 0x48, 0x46, 0x31, 0x46, 0xfb, 0xf7, + 0xdd, 0xff, 0x81, 0x46, 0x0d, 0x98, 0x00, 0x99, 0xfb, 0xf7, 0xd8, 0xff, + 0x4f, 0xf0, 0x8c, 0x47, 0x39, 0x46, 0xfc, 0xf7, 0x61, 0xf9, 0x00, 0xf0, + 0x18, 0xf9, 0x82, 0x46, 0x0c, 0x98, 0x00, 0x99, 0xfb, 0xf7, 0xcc, 0xff, + 0x39, 0x46, 0xfc, 0xf7, 0x57, 0xf9, 0x00, 0xf0, 0x0e, 0xf9, 0x07, 0x46, + 0x50, 0x46, 0x00, 0xf0, 0x38, 0xfa, 0x00, 0x90, 0x39, 0x46, 0x38, 0x46, + 0xfc, 0xf7, 0x4c, 0xf9, 0x00, 0x99, 0xfc, 0xf7, 0xad, 0xf8, 0xfc, 0xf7, + 0xed, 0xf8, 0x01, 0x2c, 0x1c, 0xbf, 0x03, 0x2c, 0x81, 0x46, 0x07, 0x9c, + 0x01, 0x21, 0x48, 0x46, 0x03, 0xf0, 0x48, 0xfa, 0x00, 0xf0, 0x26, 0xfa, + 0x00, 0xf0, 0xfb, 0xf8, 0xfc, 0xf7, 0xa4, 0xf9, 0xa0, 0x61, 0x51, 0x46, + 0xdf, 0xf8, 0x34, 0x05, 0xfc, 0xf7, 0x32, 0xf9, 0xfc, 0xf7, 0x9c, 0xf9, + 0xe0, 0x61, 0x39, 0x46, 0xdf, 0xf8, 0x24, 0x05, 0xfc, 0xf7, 0x2a, 0xf9, + 0xfc, 0xf7, 0x94, 0xf9, 0x20, 0x62, 0xf7, 0xf7, 0x1c, 0xf9, 0x00, 0xf0, + 0xe7, 0xf8, 0x81, 0x8c, 0x61, 0xb1, 0x07, 0x99, 0x03, 0x9a, 0x89, 0x69, + 0x00, 0x8d, 0x89, 0x1a, 0x48, 0xbf, 0x49, 0x42, 0x88, 0x42, 0x03, 0xda, + 0x48, 0xf4, 0x02, 0x48, 0x10, 0x25, 0xc3, 0xe0, 0x02, 0xa8, 0x00, 0x88, + 0xfb, 0xf7, 0x72, 0xff, 0x04, 0x46, 0xdf, 0xf8, 0xf4, 0x04, 0x21, 0x46, + 0xfc, 0xf7, 0x0a, 0xf9, 0xdf, 0xf8, 0xec, 0x14, 0xfb, 0xf7, 0x78, 0xff, + 0x00, 0xf0, 0xc1, 0xf8, 0x01, 0x46, 0x0f, 0x98, 0x33, 0x46, 0x4a, 0x46, + 0x00, 0xf0, 0xc7, 0xf8, 0x07, 0x46, 0xfc, 0xf7, 0x67, 0xf9, 0x10, 0xf1, + 0x01, 0x0f, 0x18, 0xbf, 0x10, 0xf1, 0x02, 0x0f, 0x49, 0xf2, 0xcb, 0x21, + 0x05, 0xd0, 0x10, 0xf1, 0x03, 0x0f, 0x18, 0xbf, 0x10, 0xf1, 0x04, 0x0f, + 0x05, 0xd1, 0x07, 0x9a, 0x02, 0x98, 0x50, 0x62, 0x88, 0x46, 0x07, 0x25, + 0x96, 0xe0, 0x06, 0x98, 0x20, 0x9a, 0x00, 0xeb, 0x42, 0x06, 0xb0, 0x88, + 0x28, 0xb9, 0x07, 0x9a, 0x02, 0x98, 0x50, 0x62, 0x88, 0x46, 0x09, 0x25, + 0x8a, 0xe0, 0xb0, 0x89, 0xfb, 0xf7, 0x3a, 0xff, 0xdf, 0xf8, 0x8c, 0x14, + 0xfc, 0xf7, 0xd4, 0xf8, 0x11, 0x99, 0x89, 0x68, 0x81, 0x46, 0x38, 0x46, + 0xfb, 0xf7, 0x40, 0xff, 0x01, 0x21, 0x03, 0xf0, 0xd5, 0xf9, 0x00, 0xf0, + 0xb3, 0xf9, 0x00, 0x90, 0x00, 0xf0, 0xb3, 0xf9, 0x00, 0xf0, 0xae, 0xf9, + 0x21, 0x46, 0xfc, 0xf7, 0x25, 0xf8, 0x82, 0x46, 0x11, 0xe0, 0x4f, 0xf0, + 0x7c, 0x50, 0x00, 0xf0, 0xa8, 0xf9, 0x81, 0x46, 0x00, 0x98, 0x00, 0xf0, + 0xa4, 0xf9, 0x00, 0xf0, 0x9f, 0xf9, 0x21, 0x46, 0xfc, 0xf7, 0x16, 0xf8, + 0x07, 0x99, 0x82, 0x46, 0x08, 0x20, 0x08, 0x60, 0x50, 0x46, 0xfc, 0xf7, + 0x17, 0xf9, 0x07, 0xb2, 0xb7, 0xf5, 0x52, 0x7f, 0xe7, 0xd2, 0x30, 0x89, + 0xfb, 0xf7, 0x06, 0xff, 0x00, 0xf0, 0x8c, 0xf9, 0x06, 0x46, 0x38, 0x46, + 0xfb, 0xf7, 0xf6, 0xfe, 0x01, 0x46, 0x30, 0x46, 0xfc, 0xf7, 0xa2, 0xf9, + 0x9c, 0xbf, 0xb2, 0x46, 0x0a, 0x25, 0x50, 0x46, 0xfc, 0xf7, 0x00, 0xf9, + 0x06, 0x46, 0xcf, 0xe6, 0x06, 0x98, 0x20, 0x99, 0x00, 0xeb, 0x41, 0x02, + 0xd1, 0x8d, 0x53, 0x8e, 0x5a, 0x18, 0xcb, 0x1a, 0xb6, 0xb2, 0xb2, 0x42, + 0xb4, 0xbf, 0x4f, 0xf0, 0x01, 0x0c, 0x4f, 0xf0, 0x00, 0x0c, 0x9e, 0x42, + 0xb4, 0xbf, 0x4f, 0xf0, 0x01, 0x0b, 0x4f, 0xf0, 0x00, 0x0b, 0x5b, 0xea, + 0x0c, 0x04, 0x13, 0xd0, 0x20, 0x9d, 0x28, 0x18, 0x90, 0xf8, 0x2c, 0x00, + 0x10, 0xb1, 0x02, 0x28, 0x02, 0xd0, 0x07, 0xe0, 0x0e, 0x46, 0x07, 0xe0, + 0xbc, 0xf1, 0x00, 0x0f, 0x0c, 0xbf, 0x1e, 0x46, 0x16, 0x46, 0x01, 0xe0, + 0x07, 0x98, 0x46, 0x6a, 0x11, 0x25, 0x01, 0xe0, 0x49, 0xf6, 0xe4, 0x28, + 0x20, 0x98, 0x0f, 0xf2, 0xc4, 0x34, 0x4f, 0xea, 0x40, 0x0b, 0x30, 0x04, + 0x01, 0x0e, 0x34, 0xf8, 0x1b, 0x00, 0xf8, 0xf7, 0x9b, 0xf9, 0x04, 0xeb, + 0x4b, 0x00, 0xf1, 0xb2, 0x40, 0x88, 0xf8, 0xf7, 0x95, 0xf9, 0x07, 0x98, + 0xb6, 0xb2, 0x46, 0x62, 0x42, 0x46, 0x07, 0x98, 0x29, 0x46, 0x03, 0xf0, + 0x15, 0xf9, 0x28, 0x46, 0x21, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x4f, 0xf0, + 0x64, 0x51, 0xfc, 0xf7, 0x43, 0xb8, 0x01, 0x46, 0xd9, 0x48, 0xfc, 0xf7, + 0xb6, 0xba, 0xd2, 0x49, 0xfc, 0xf7, 0x3c, 0xb8, 0x06, 0x98, 0x20, 0x99, + 0x00, 0xeb, 0x41, 0x00, 0x70, 0x47, 0x2d, 0xe9, 0xf6, 0x4f, 0x04, 0x46, + 0x1d, 0x46, 0x87, 0xb0, 0x28, 0x46, 0x00, 0x21, 0xfc, 0xf7, 0x1c, 0xf8, + 0x04, 0xd2, 0x20, 0x46, 0x00, 0xf0, 0x1a, 0xf9, 0xce, 0x48, 0x07, 0xe1, + 0x60, 0x88, 0x10, 0x28, 0x1d, 0xda, 0x0c, 0x22, 0x07, 0x99, 0x02, 0xfb, + 0x00, 0x40, 0x01, 0x61, 0x60, 0x88, 0x08, 0x99, 0x02, 0xfb, 0x00, 0x40, + 0x41, 0x61, 0x29, 0x46, 0x60, 0x88, 0x02, 0xfb, 0x00, 0x40, 0x85, 0x61, + 0xa0, 0x68, 0xfc, 0xf7, 0x01, 0xf8, 0x38, 0xbf, 0xa5, 0x60, 0x03, 0xd3, + 0x00, 0xf0, 0xf1, 0xf8, 0x38, 0xbf, 0xe5, 0x60, 0x60, 0x88, 0x40, 0x1c, + 0x60, 0x80, 0x08, 0x98, 0xe6, 0xe0, 0x8b, 0x46, 0x00, 0x26, 0x8a, 0x46, + 0x88, 0x46, 0x89, 0x46, 0x02, 0x91, 0x06, 0x91, 0x05, 0x91, 0xad, 0xf8, + 0x10, 0x10, 0x00, 0x27, 0x0c, 0x20, 0x00, 0xfb, 0x07, 0x40, 0x03, 0x90, + 0x59, 0x46, 0x00, 0x69, 0x01, 0x90, 0x7f, 0x1c, 0xfb, 0xf7, 0x56, 0xff, + 0x83, 0x46, 0x03, 0x98, 0x40, 0x69, 0x00, 0x90, 0x31, 0x46, 0xfb, 0xf7, + 0x4f, 0xff, 0x06, 0x46, 0x01, 0x98, 0x00, 0x99, 0xfb, 0xf7, 0xe6, 0xff, + 0x49, 0x46, 0xfb, 0xf7, 0x47, 0xff, 0x81, 0x46, 0x01, 0x98, 0x01, 0x46, + 0xfb, 0xf7, 0xde, 0xff, 0x51, 0x46, 0xfb, 0xf7, 0x3f, 0xff, 0x82, 0x46, + 0x00, 0x98, 0x01, 0x46, 0xfb, 0xf7, 0xd6, 0xff, 0x41, 0x46, 0xfb, 0xf7, + 0x37, 0xff, 0x10, 0x2f, 0x80, 0x46, 0xd3, 0xd3, 0x4f, 0xf0, 0x83, 0x40, + 0x00, 0xf0, 0xb3, 0xf8, 0x07, 0x46, 0x58, 0x46, 0x00, 0xf0, 0xb2, 0xf8, + 0x01, 0x46, 0x38, 0x46, 0xfb, 0xf7, 0xb4, 0xfe, 0x07, 0x46, 0x4f, 0xf0, + 0x83, 0x40, 0x41, 0x46, 0xfb, 0xf7, 0xbe, 0xff, 0x80, 0x46, 0x30, 0x46, + 0x31, 0x46, 0xfb, 0xf7, 0xb9, 0xff, 0x01, 0x46, 0x40, 0x46, 0xfb, 0xf7, + 0xa5, 0xfe, 0x80, 0x46, 0x4f, 0xf0, 0x83, 0x40, 0x00, 0xf0, 0x9d, 0xf8, + 0x81, 0x46, 0x58, 0x46, 0x31, 0x46, 0xfb, 0xf7, 0xab, 0xff, 0x01, 0x46, + 0x48, 0x46, 0xfb, 0xf7, 0x97, 0xfe, 0x81, 0x46, 0x8d, 0x49, 0x38, 0x46, + 0xfc, 0xf7, 0xaa, 0xf8, 0x21, 0xd8, 0x40, 0x46, 0xfc, 0xf7, 0xa6, 0xf8, + 0x1d, 0xd8, 0x01, 0x20, 0xad, 0xf8, 0x10, 0x00, 0x41, 0x46, 0x38, 0x46, + 0xfb, 0xf7, 0x96, 0xff, 0xfb, 0xf7, 0x3a, 0xff, 0x01, 0x46, 0x48, 0x46, + 0xfb, 0xf7, 0x02, 0xfe, 0x05, 0x90, 0x39, 0x46, 0x48, 0x46, 0xfb, 0xf7, + 0xfd, 0xfd, 0x02, 0x90, 0x00, 0xf0, 0x72, 0xf8, 0x01, 0x46, 0x30, 0x46, + 0xfb, 0xf7, 0x74, 0xfe, 0x4f, 0xf0, 0x76, 0x51, 0xfb, 0xf7, 0x80, 0xff, + 0x06, 0x90, 0x29, 0x46, 0xe0, 0x68, 0xfb, 0xf7, 0x69, 0xff, 0x03, 0xd2, + 0xa1, 0x68, 0x00, 0xf0, 0x5b, 0xf8, 0x26, 0xd3, 0xbd, 0xf8, 0x10, 0x00, + 0x20, 0xb1, 0x05, 0x98, 0x74, 0x49, 0xfb, 0xf7, 0x5d, 0xff, 0x01, 0xd2, + 0x73, 0x4a, 0x1d, 0xe0, 0x02, 0x99, 0x07, 0x98, 0xfb, 0xf7, 0x68, 0xff, + 0x06, 0x99, 0xfb, 0xf7, 0xc9, 0xfe, 0x08, 0x99, 0x06, 0x46, 0xfb, 0xf7, + 0x51, 0xfe, 0x00, 0x21, 0xfb, 0xf7, 0x4c, 0xff, 0x03, 0xd2, 0x08, 0x98, + 0x31, 0x46, 0xfb, 0xf7, 0x49, 0xfe, 0x08, 0x99, 0xfb, 0xf7, 0xc8, 0xfd, + 0x68, 0x49, 0xfc, 0xf7, 0x5b, 0xf8, 0x98, 0xbf, 0x4f, 0xf0, 0x40, 0x42, + 0x00, 0xd9, 0x08, 0x9a, 0xa0, 0x88, 0x0c, 0x21, 0x01, 0xfb, 0x00, 0x40, + 0x07, 0x99, 0x01, 0x61, 0x0c, 0x21, 0xa0, 0x88, 0x01, 0xfb, 0x00, 0x40, + 0x08, 0x99, 0x41, 0x61, 0x0c, 0x21, 0xa0, 0x88, 0x01, 0xfb, 0x00, 0x40, + 0x00, 0x23, 0x85, 0x61, 0xa0, 0x88, 0x40, 0x1c, 0xc1, 0x10, 0x00, 0xeb, + 0x11, 0x71, 0x09, 0x11, 0xa0, 0xeb, 0x01, 0x10, 0xa0, 0x80, 0x0c, 0x20, + 0x00, 0xfb, 0x03, 0x40, 0x85, 0x69, 0xa0, 0x68, 0x29, 0x46, 0xfb, 0xf7, + 0x19, 0xff, 0x38, 0xbf, 0xa5, 0x60, 0x03, 0xd3, 0x00, 0xf0, 0x09, 0xf8, + 0x38, 0xbf, 0xe5, 0x60, 0x5b, 0x1c, 0x10, 0x2b, 0xed, 0xd3, 0x10, 0x46, + 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0xe1, 0x68, 0x28, 0x46, 0xfb, 0xf7, + 0x07, 0xbf, 0x51, 0x46, 0xfb, 0xf7, 0x16, 0xbf, 0x59, 0x46, 0xfb, 0xf7, + 0x13, 0xbf, 0x49, 0x46, 0xfb, 0xf7, 0x10, 0xbf, 0x00, 0x21, 0x41, 0x80, + 0x81, 0x80, 0x81, 0x60, 0x44, 0x49, 0xc1, 0x60, 0x70, 0x47, 0x38, 0xb5, + 0x04, 0x46, 0x00, 0x21, 0x00, 0x20, 0xf8, 0xf7, 0x9a, 0xfa, 0x20, 0x68, + 0x04, 0xf1, 0x10, 0x01, 0xff, 0xf7, 0x7d, 0xf9, 0x05, 0x00, 0x09, 0xd1, + 0xe0, 0x69, 0x00, 0xf1, 0xd0, 0x01, 0x20, 0x68, 0xff, 0xf7, 0xd0, 0xf9, + 0x20, 0x68, 0xff, 0xf7, 0xb2, 0xf9, 0x05, 0x46, 0x01, 0x2d, 0x0b, 0xd0, + 0x02, 0x2d, 0x0b, 0xd0, 0x0c, 0x2d, 0x0b, 0xd0, 0x11, 0x2d, 0x0b, 0xd0, + 0x13, 0x2d, 0x0b, 0xd0, 0x14, 0x2d, 0x08, 0xbf, 0x0d, 0x25, 0x08, 0xe0, + 0x02, 0x25, 0x06, 0xe0, 0x01, 0x25, 0x04, 0xe0, 0x0e, 0x25, 0x02, 0xe0, + 0x03, 0x25, 0x00, 0xe0, 0x0c, 0x25, 0x20, 0x68, 0xfb, 0xf7, 0x2c, 0xfb, + 0x28, 0x46, 0x32, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0xf8, 0xf7, 0x58, 0xfd, + 0x03, 0x28, 0x06, 0xd1, 0x03, 0xf0, 0x5e, 0xfa, 0x00, 0x21, 0x04, 0xf1, + 0x10, 0x00, 0xfa, 0xf7, 0x58, 0xfa, 0xbd, 0xe8, 0x10, 0x40, 0x00, 0x20, + 0xf8, 0xf7, 0xb8, 0xba, 0x11, 0x4a, 0x22, 0xf8, 0x10, 0x10, 0x70, 0x47, + 0x10, 0xb5, 0x04, 0x46, 0x0e, 0x49, 0x01, 0xeb, 0x44, 0x01, 0x09, 0x8c, + 0x29, 0xb1, 0x01, 0x21, 0xf8, 0xf7, 0xdb, 0xf9, 0x10, 0xb1, 0x01, 0x20, + 0x00, 0xe0, 0x00, 0x20, 0x06, 0x49, 0x61, 0x18, 0x88, 0x70, 0x8a, 0x78, + 0x50, 0x1e, 0x80, 0x41, 0xc0, 0x0f, 0x08, 0x71, 0x10, 0xbd, 0x00, 0x00, + 0xa8, 0xef, 0x00, 0x20, 0xcc, 0xe6, 0x00, 0x20, 0xb0, 0x26, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0xd8, 0x26, 0x00, 0x20, 0xc0, 0x26, 0x00, 0x20, + 0xd4, 0xac, 0x00, 0x20, 0x00, 0x00, 0xc8, 0x42, 0x00, 0x00, 0xa0, 0x41, + 0x00, 0x00, 0x7a, 0x44, 0xcd, 0xcc, 0x4c, 0x3d, 0x00, 0x00, 0xa0, 0xc1, + 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0x80, 0xc0, + 0x70, 0x12, 0x83, 0x3a, 0xcd, 0xcc, 0xcc, 0x3d, 0x00, 0x00, 0x40, 0xc0, + 0xce, 0xcc, 0x4c, 0x3d, 0xec, 0x78, 0xad, 0x60, 0x61, 0x09, 0x60, 0x09, + 0x63, 0x09, 0x62, 0x09, 0x01, 0x22, 0x41, 0x1c, 0x03, 0xe0, 0x0a, 0x46, + 0xb0, 0xfb, 0xf2, 0xf1, 0x89, 0x18, 0x49, 0x08, 0x8a, 0x1a, 0x48, 0xbf, + 0x52, 0x42, 0x02, 0x2a, 0xf5, 0xda, 0x01, 0xfb, 0x01, 0xf2, 0x90, 0x42, + 0x38, 0xbf, 0x49, 0x1e, 0xf9, 0xd3, 0x08, 0x46, 0x70, 0x47, 0x30, 0xb5, + 0x4f, 0xf4, 0x80, 0x53, 0x03, 0x60, 0x41, 0x60, 0x02, 0x23, 0x00, 0xeb, + 0x83, 0x05, 0x01, 0xfb, 0x02, 0xf4, 0x55, 0xf8, 0x04, 0x5c, 0x6c, 0x43, + 0x64, 0x0b, 0x40, 0xf8, 0x23, 0x40, 0x5b, 0x1c, 0x08, 0x2b, 0xf2, 0xdb, + 0x30, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, 0x06, 0x9e, 0x00, 0x24, 0x00, 0x25, + 0x26, 0xfa, 0x05, 0xfe, 0x5f, 0xea, 0xce, 0x7e, 0x4f, 0xea, 0xd5, 0x0c, + 0x05, 0xf0, 0x07, 0x07, 0x49, 0xd5, 0xbc, 0xf1, 0x03, 0x0f, 0x01, 0xeb, + 0x87, 0x07, 0x11, 0xd0, 0xbc, 0xf1, 0x01, 0x0f, 0x05, 0xd1, 0x3f, 0x6a, + 0xb2, 0xf9, 0x00, 0xc0, 0xb2, 0xf9, 0x02, 0xe0, 0x1f, 0xe0, 0x3f, 0x68, + 0xbc, 0xf1, 0x02, 0x0f, 0xf6, 0xd1, 0xb2, 0xf9, 0x04, 0xc0, 0xb2, 0xf9, + 0x06, 0xe0, 0x16, 0xe0, 0x93, 0xb1, 0x5f, 0xea, 0x83, 0x7c, 0x4c, 0xbf, + 0x3f, 0x6c, 0x3f, 0x6a, 0x5f, 0xea, 0xc3, 0x7c, 0xe8, 0xd5, 0xb2, 0xf8, + 0x00, 0xc0, 0xb2, 0xf8, 0x04, 0xe0, 0xb2, 0xf8, 0x06, 0x80, 0xf4, 0x44, + 0xb2, 0xf8, 0x02, 0xe0, 0xc6, 0x44, 0x02, 0xe0, 0x00, 0x27, 0xbe, 0x46, + 0xbc, 0x46, 0x0f, 0xfa, 0x8c, 0xfc, 0x07, 0xfb, 0x0c, 0xfc, 0x4f, 0xea, + 0x6c, 0x28, 0x0c, 0xeb, 0x98, 0x5c, 0x4f, 0xea, 0xac, 0x2c, 0x40, 0xf8, + 0x34, 0xc0, 0x0f, 0xfa, 0x8e, 0xfe, 0x07, 0xfb, 0x0e, 0xf7, 0x4f, 0xea, + 0x67, 0x2c, 0x07, 0xeb, 0x9c, 0x57, 0x00, 0xeb, 0xc4, 0x0c, 0x64, 0x1c, + 0xbf, 0x12, 0x15, 0x2c, 0xcc, 0xf8, 0x04, 0x70, 0x02, 0xd2, 0x6d, 0x1c, + 0x20, 0x2d, 0xa9, 0xd3, 0xbd, 0xe8, 0xf0, 0x81, 0x2d, 0xe9, 0xf0, 0x43, + 0x00, 0x24, 0x61, 0xe0, 0x00, 0x26, 0x00, 0xeb, 0x44, 0x05, 0xa8, 0x27, + 0x07, 0xfb, 0x04, 0x27, 0x07, 0xeb, 0xc6, 0x07, 0x57, 0xf8, 0xa8, 0xef, + 0x95, 0xf9, 0x01, 0x80, 0xd7, 0xf8, 0x04, 0x90, 0x10, 0xf9, 0x14, 0xc0, + 0x09, 0xfb, 0x08, 0xf8, 0x0e, 0xfb, 0x0c, 0x8c, 0x52, 0xf8, 0x36, 0xe0, + 0x4f, 0xea, 0x6c, 0x18, 0x0c, 0xeb, 0x98, 0x6c, 0x0e, 0xeb, 0xac, 0x1c, + 0x42, 0xf8, 0x36, 0xc0, 0xd7, 0xf8, 0x04, 0xe0, 0x10, 0xf9, 0x14, 0xc0, + 0x3f, 0x68, 0x0e, 0xfb, 0x0c, 0xfc, 0x95, 0xf9, 0x01, 0xe0, 0x07, 0xfb, + 0x1e, 0xc7, 0x02, 0xeb, 0xc6, 0x0c, 0x4f, 0xea, 0x67, 0x18, 0xdc, 0xf8, + 0x04, 0xe0, 0x07, 0xeb, 0x98, 0x67, 0x76, 0x1c, 0x0e, 0xeb, 0xa7, 0x17, + 0x15, 0x2e, 0xcc, 0xf8, 0x04, 0x70, 0xca, 0xd3, 0x03, 0xeb, 0xc4, 0x06, + 0x95, 0xf9, 0x01, 0xe0, 0xd6, 0xf8, 0x0c, 0x80, 0x10, 0xf9, 0x14, 0x70, + 0xd6, 0xf8, 0x08, 0xc0, 0x08, 0xfb, 0x0e, 0xfe, 0x0c, 0xfb, 0x07, 0xe7, + 0xd3, 0xf8, 0x00, 0xc0, 0x4f, 0xea, 0x67, 0x1e, 0x07, 0xeb, 0x9e, 0x67, + 0x0c, 0xeb, 0xa7, 0x17, 0x1f, 0x60, 0xd6, 0xf8, 0x0c, 0xc0, 0x10, 0xf9, + 0x14, 0x70, 0x95, 0xf9, 0x01, 0x50, 0xb6, 0x68, 0x0c, 0xfb, 0x07, 0xf7, + 0x06, 0xfb, 0x15, 0x75, 0x5e, 0x68, 0x6f, 0x11, 0x05, 0xeb, 0x97, 0x65, + 0x06, 0xeb, 0xa5, 0x15, 0x5d, 0x60, 0x64, 0x1c, 0x8c, 0x42, 0x9b, 0xd3, + 0xbd, 0xe8, 0xf0, 0x83, 0x2d, 0xe9, 0xf0, 0x4f, 0x04, 0x46, 0xad, 0xf2, + 0x5c, 0x4d, 0xa0, 0x68, 0x00, 0x88, 0xc0, 0xf3, 0x01, 0x1a, 0x20, 0x68, + 0x0f, 0x46, 0x81, 0x88, 0x08, 0x0a, 0x00, 0xf0, 0x03, 0x00, 0x8d, 0xf8, + 0x04, 0x00, 0x90, 0x46, 0x01, 0xf0, 0x0f, 0x00, 0x8d, 0xf8, 0x05, 0x00, + 0x00, 0x25, 0x08, 0xeb, 0x85, 0x00, 0xb0, 0xf9, 0x02, 0x00, 0x38, 0xf9, + 0x25, 0x10, 0x00, 0xf0, 0x63, 0xfb, 0xa1, 0x68, 0x91, 0xf8, 0x24, 0x20, + 0x01, 0x46, 0xde, 0xa8, 0x00, 0xeb, 0x45, 0x10, 0xff, 0xf7, 0xfd, 0xfe, + 0x6d, 0x1c, 0x07, 0x2d, 0xeb, 0xd3, 0x00, 0x20, 0x02, 0xae, 0x37, 0xf9, + 0x20, 0x10, 0x46, 0xf8, 0x30, 0x10, 0x02, 0xaa, 0x07, 0xeb, 0x80, 0x01, + 0x02, 0xeb, 0xc0, 0x02, 0xb1, 0xf9, 0x02, 0x10, 0x51, 0x60, 0x40, 0x1c, + 0x05, 0x28, 0xf0, 0xd3, 0x00, 0x27, 0xa8, 0x25, 0x02, 0xe0, 0x00, 0xf0, + 0x29, 0xf8, 0x7f, 0x1c, 0x57, 0x45, 0xfa, 0xd3, 0x05, 0x2f, 0x1f, 0xd2, + 0x00, 0xf0, 0x22, 0xf8, 0xa7, 0xeb, 0x0a, 0x0b, 0x0c, 0xa8, 0x05, 0xfb, + 0x0b, 0x09, 0x02, 0xa8, 0x00, 0xeb, 0xcb, 0x03, 0xa0, 0x68, 0x4a, 0x46, + 0x51, 0x46, 0x0e, 0x30, 0xff, 0xf7, 0x40, 0xff, 0x20, 0x69, 0x9d, 0xf8, + 0x05, 0x30, 0xc0, 0xb2, 0x00, 0x90, 0x06, 0xeb, 0xcb, 0x02, 0x7f, 0x1c, + 0xd2, 0xe9, 0x00, 0x01, 0x0a, 0x46, 0x01, 0x46, 0x48, 0x46, 0xfe, 0xf7, + 0x4f, 0xff, 0xdd, 0xe7, 0x0d, 0xf2, 0x5c, 0x4d, 0xbd, 0xe8, 0xf0, 0x8f, + 0xa0, 0x68, 0x00, 0x6a, 0x9d, 0xf8, 0x04, 0x30, 0x00, 0x90, 0x08, 0xeb, + 0x87, 0x02, 0xde, 0xa8, 0x00, 0xeb, 0x47, 0x11, 0x0c, 0xa8, 0x05, 0xfb, + 0x07, 0x00, 0xc0, 0xe6, 0x2d, 0xe9, 0xf6, 0x4f, 0xdf, 0xb0, 0x04, 0x46, + 0x01, 0x20, 0xa2, 0x68, 0xd2, 0x7e, 0x00, 0x21, 0xfb, 0xf7, 0x84, 0xff, + 0x04, 0xf0, 0x74, 0xf8, 0xcd, 0xe9, 0x0e, 0x01, 0x20, 0x69, 0x00, 0x28, + 0x14, 0xbf, 0xdf, 0xf8, 0x6c, 0x0b, 0xdf, 0xf8, 0x6c, 0x0b, 0x04, 0x90, + 0x00, 0x20, 0x02, 0x90, 0x5f, 0x98, 0x02, 0x99, 0xa8, 0x22, 0x02, 0xfb, + 0x01, 0x00, 0x00, 0x27, 0x03, 0x90, 0x04, 0x98, 0x02, 0x99, 0x00, 0xeb, + 0xc1, 0x00, 0x00, 0xeb, 0x07, 0x22, 0x00, 0xf0, 0xc5, 0xf9, 0x04, 0x46, + 0x88, 0x46, 0x5f, 0x98, 0xa8, 0x21, 0x01, 0xfb, 0x07, 0x00, 0x06, 0x90, + 0x5f, 0x98, 0x02, 0x99, 0x00, 0xeb, 0xc7, 0x00, 0x07, 0x90, 0x5f, 0x98, + 0x00, 0xeb, 0xc1, 0x00, 0x05, 0x90, 0x02, 0x98, 0xb8, 0x42, 0x37, 0xd1, + 0x38, 0xb1, 0xdd, 0xe9, 0x0e, 0x01, 0x22, 0x46, 0x43, 0x46, 0x04, 0xf0, + 0x5f, 0xf8, 0x04, 0x46, 0x88, 0x46, 0x00, 0x25, 0x21, 0xe0, 0xa8, 0x20, + 0x00, 0xfb, 0x05, 0xf2, 0x05, 0x98, 0x13, 0x18, 0xd3, 0xe9, 0x00, 0x01, + 0x07, 0x9b, 0xd6, 0x18, 0xd6, 0xe9, 0x00, 0x23, 0x04, 0xf0, 0xc2, 0xf8, + 0x06, 0x46, 0x03, 0x98, 0x00, 0xeb, 0xc5, 0x02, 0x89, 0x46, 0xd2, 0xe9, + 0x00, 0x01, 0x06, 0x9a, 0x02, 0xeb, 0xc5, 0x0c, 0x6d, 0x1c, 0xdc, 0xe9, + 0x00, 0x23, 0x04, 0xf0, 0xb3, 0xf8, 0x00, 0xf0, 0x7f, 0xf9, 0x00, 0xf0, + 0x6c, 0xf9, 0x04, 0x46, 0x88, 0x46, 0xbd, 0x42, 0xdb, 0xdb, 0x20, 0x46, + 0x41, 0x46, 0x04, 0xf0, 0x79, 0xf9, 0x03, 0x9a, 0x02, 0x9b, 0x02, 0xeb, + 0xc3, 0x02, 0x5c, 0xe0, 0x04, 0x98, 0x02, 0x99, 0x00, 0xeb, 0x01, 0x20, + 0x00, 0xeb, 0xc7, 0x02, 0x00, 0x25, 0x00, 0xf0, 0x71, 0xf9, 0x40, 0xe0, + 0x06, 0x98, 0x00, 0xeb, 0xc5, 0x02, 0xd2, 0xe9, 0x00, 0x01, 0xcd, 0xe9, + 0x0c, 0x01, 0x00, 0xf0, 0x46, 0xf9, 0xcd, 0xe9, 0x0a, 0x01, 0xa8, 0x20, + 0x00, 0xfb, 0x05, 0xf2, 0x07, 0x98, 0x13, 0x18, 0x6d, 0x1c, 0xd3, 0xe9, + 0x00, 0x01, 0xcd, 0xe9, 0x08, 0x01, 0x05, 0x98, 0x10, 0x18, 0xd0, 0xe9, + 0x00, 0xab, 0xdd, 0xe9, 0x08, 0x01, 0x00, 0xf0, 0x28, 0xf9, 0xcd, 0xe9, + 0x00, 0x01, 0xdd, 0xe9, 0x0a, 0x23, 0xdd, 0xe9, 0x0c, 0x01, 0x04, 0xf0, + 0x73, 0xf8, 0xdd, 0xe9, 0x00, 0x23, 0x03, 0xf0, 0xfb, 0xff, 0x00, 0xf0, + 0x2a, 0xf9, 0x04, 0x46, 0x88, 0x46, 0xdd, 0xe9, 0x0c, 0x01, 0x00, 0xf0, + 0x14, 0xf9, 0x82, 0x46, 0x8b, 0x46, 0xdd, 0xe9, 0x0a, 0x23, 0xdd, 0xe9, + 0x08, 0x01, 0x04, 0xf0, 0x5f, 0xf8, 0x02, 0x46, 0x0b, 0x46, 0x50, 0x46, + 0x59, 0x46, 0x04, 0xf0, 0xa3, 0xf9, 0x00, 0xf0, 0x25, 0xf9, 0x06, 0x46, + 0x89, 0x46, 0xbd, 0x42, 0xba, 0xdb, 0x06, 0x9a, 0x00, 0xf0, 0x37, 0xf9, + 0x00, 0xf0, 0x20, 0xf9, 0x05, 0x9a, 0xa8, 0x23, 0x03, 0xfb, 0x07, 0x22, + 0x00, 0xf0, 0x0e, 0xf9, 0x03, 0x9a, 0x02, 0xeb, 0xc7, 0x02, 0xc2, 0xe9, + 0x00, 0x01, 0x02, 0x98, 0x7f, 0x1c, 0xb8, 0x42, 0xbf, 0xf6, 0x49, 0xaf, + 0x40, 0x1c, 0x15, 0x28, 0x02, 0x90, 0xff, 0xf6, 0x3d, 0xaf, 0x00, 0x27, + 0x04, 0x98, 0x00, 0xeb, 0x07, 0x22, 0x7d, 0x1e, 0xd2, 0xe9, 0x2a, 0x01, + 0x03, 0xf0, 0x8e, 0xff, 0x04, 0x46, 0x04, 0x98, 0x00, 0xeb, 0xc7, 0x00, + 0x00, 0xf5, 0xa8, 0x52, 0x88, 0x46, 0x00, 0xf0, 0xff, 0xf8, 0x06, 0x46, + 0x89, 0x46, 0x5f, 0x98, 0xa8, 0x21, 0x01, 0xfb, 0x07, 0x00, 0x03, 0x90, + 0x3d, 0xe0, 0x00, 0xf0, 0xd4, 0xf8, 0xcd, 0xe9, 0x06, 0x01, 0x00, 0xf0, + 0xf5, 0xf8, 0x00, 0xeb, 0x05, 0x10, 0x02, 0x90, 0x5b, 0x46, 0x0a, 0xa8, + 0x00, 0xeb, 0x05, 0x12, 0xd2, 0xe9, 0x00, 0x01, 0x52, 0x46, 0x04, 0xf0, + 0x0d, 0xf8, 0xcd, 0xe9, 0x00, 0x01, 0xdd, 0xf8, 0x08, 0xc0, 0xdd, 0xe9, + 0x06, 0x23, 0xdc, 0xe9, 0x02, 0x01, 0x04, 0xf0, 0x03, 0xf8, 0xdd, 0xe9, + 0x00, 0x23, 0x03, 0xf0, 0x8b, 0xff, 0x00, 0xf0, 0xba, 0xf8, 0x04, 0x46, + 0x0a, 0xa8, 0x00, 0xeb, 0x05, 0x1c, 0x88, 0x46, 0xdd, 0xe9, 0x06, 0x23, + 0xdc, 0xe9, 0x00, 0x01, 0x03, 0xf0, 0xf2, 0xff, 0xdd, 0xf8, 0x08, 0xc0, + 0xcd, 0xe9, 0x00, 0x01, 0xdc, 0xe9, 0x02, 0x23, 0x50, 0x46, 0x59, 0x46, + 0x03, 0xf0, 0xe8, 0xff, 0x00, 0xf0, 0x97, 0xf8, 0x00, 0xf0, 0xb2, 0xf8, + 0x06, 0x46, 0x89, 0x46, 0x6d, 0x1e, 0x00, 0x2d, 0xbf, 0xd5, 0x00, 0xf0, + 0xc3, 0xf8, 0x00, 0xf0, 0xad, 0xf8, 0x00, 0xf0, 0x9c, 0xf8, 0x0a, 0xaa, + 0x02, 0xeb, 0x07, 0x12, 0x7f, 0x1c, 0xc2, 0xe9, 0x02, 0x01, 0x15, 0x2f, + 0x98, 0xdb, 0x14, 0x27, 0x0a, 0xa8, 0x00, 0xeb, 0x07, 0x10, 0xa8, 0x21, + 0xd0, 0xe9, 0x00, 0x48, 0x0a, 0xa8, 0x00, 0xeb, 0x07, 0x10, 0x04, 0x90, + 0xd0, 0xe9, 0x02, 0x69, 0x5f, 0x98, 0x01, 0xfb, 0x07, 0x00, 0x7d, 0x1c, + 0x03, 0x90, 0x41, 0xe0, 0x00, 0xf0, 0x73, 0xf8, 0xcd, 0xe9, 0x08, 0x01, + 0x00, 0xf0, 0x94, 0xf8, 0x00, 0xeb, 0x05, 0x13, 0xd3, 0xe9, 0x00, 0x01, + 0xcd, 0xe9, 0x06, 0x01, 0x5b, 0x46, 0x0a, 0xa8, 0x00, 0xeb, 0x05, 0x10, + 0x02, 0x90, 0x02, 0x46, 0x6d, 0x1c, 0xd2, 0xe9, 0x02, 0x01, 0x52, 0x46, + 0x03, 0xf0, 0xa6, 0xff, 0xcd, 0xe9, 0x00, 0x01, 0xdd, 0xe9, 0x08, 0x23, + 0xdd, 0xe9, 0x06, 0x01, 0x03, 0xf0, 0x9e, 0xff, 0x00, 0xf0, 0x4d, 0xf8, + 0x22, 0x46, 0x43, 0x46, 0x03, 0xf0, 0x24, 0xff, 0x04, 0x46, 0x88, 0x46, + 0xdd, 0xe9, 0x06, 0x01, 0x00, 0xf0, 0x3f, 0xf8, 0xdd, 0xf8, 0x08, 0xc0, + 0x82, 0x46, 0x8b, 0x46, 0xdd, 0xe9, 0x08, 0x23, 0xdc, 0xe9, 0x02, 0x01, + 0x03, 0xf0, 0x88, 0xff, 0x52, 0x46, 0x5b, 0x46, 0x03, 0xf0, 0x10, 0xff, + 0x02, 0x46, 0x0b, 0x46, 0x30, 0x46, 0x49, 0x46, 0x04, 0xf0, 0xc8, 0xf8, + 0x06, 0x46, 0x89, 0x46, 0x15, 0x2d, 0xbb, 0xdb, 0x00, 0xf0, 0x5e, 0xf8, + 0x00, 0xf0, 0x48, 0xf8, 0x00, 0xf0, 0x37, 0xf8, 0x04, 0x9a, 0x7f, 0x1e, + 0xc2, 0xe9, 0x02, 0x01, 0x9e, 0xd5, 0x00, 0x24, 0x0a, 0xa8, 0x00, 0xeb, + 0x04, 0x12, 0xd2, 0xe9, 0x00, 0x01, 0x04, 0xf0, 0x71, 0xf9, 0x60, 0x99, + 0x41, 0xf8, 0x34, 0x00, 0x0a, 0xa8, 0x00, 0xeb, 0x04, 0x12, 0xd2, 0xe9, + 0x02, 0x01, 0x04, 0xf0, 0x67, 0xf9, 0x60, 0x99, 0x01, 0xeb, 0xc4, 0x01, + 0x64, 0x1c, 0x15, 0x2c, 0x48, 0x60, 0xe7, 0xdb, 0x61, 0xb0, 0xbd, 0xe8, + 0xf0, 0x8f, 0x52, 0x46, 0x5b, 0x46, 0x03, 0xf0, 0x4f, 0xbf, 0x02, 0x46, + 0x0b, 0x46, 0xdd, 0xe9, 0x00, 0x01, 0x04, 0xf0, 0x93, 0xb8, 0x03, 0x98, + 0x00, 0xeb, 0xc5, 0x02, 0xd2, 0xe9, 0x00, 0x01, 0x70, 0x47, 0x02, 0x46, + 0x0b, 0x46, 0x20, 0x46, 0x41, 0x46, 0x04, 0xf0, 0x87, 0xb8, 0x0a, 0xaa, + 0x02, 0xeb, 0x07, 0x12, 0x4b, 0x46, 0xc2, 0xe9, 0x00, 0x01, 0x32, 0x46, + 0x28, 0x46, 0x59, 0x46, 0x03, 0xf0, 0x32, 0xbf, 0x32, 0x46, 0x4b, 0x46, + 0x03, 0xf0, 0xba, 0xbe, 0x05, 0x46, 0x8b, 0x46, 0x22, 0x46, 0x43, 0x46, + 0x03, 0xf0, 0x28, 0xbf, 0xd2, 0xe9, 0x00, 0x01, 0x03, 0xf0, 0x82, 0xbe, + 0x5f, 0x98, 0x00, 0xeb, 0xc7, 0x00, 0xa8, 0x21, 0x01, 0xfb, 0x05, 0x00, + 0xd0, 0xe9, 0x00, 0xab, 0x0a, 0xa8, 0x70, 0x47, 0x03, 0x9a, 0xdf, 0xf8, + 0xa0, 0x17, 0x02, 0xeb, 0xc7, 0x0c, 0x00, 0x20, 0xdc, 0xe9, 0x00, 0x23, + 0x04, 0xf0, 0x62, 0xb9, 0x2d, 0xe9, 0xf0, 0x4f, 0x89, 0xb0, 0x90, 0x46, + 0x04, 0x46, 0x12, 0x9a, 0x9b, 0x46, 0x68, 0x46, 0xff, 0xf7, 0x9f, 0xfc, + 0x00, 0x20, 0x00, 0x21, 0x44, 0xf8, 0x30, 0x10, 0x04, 0xeb, 0xc0, 0x02, + 0x40, 0x1c, 0x04, 0x28, 0x51, 0x60, 0xf7, 0xd3, 0x00, 0x27, 0x00, 0x25, + 0x4f, 0xf0, 0x6a, 0x59, 0x2b, 0xfa, 0x05, 0xf0, 0xc0, 0x07, 0x27, 0xd5, + 0x05, 0xf0, 0x07, 0x00, 0x5d, 0xf8, 0x20, 0x00, 0xfb, 0xf7, 0x46, 0xf9, + 0x82, 0x46, 0x58, 0xf8, 0x37, 0x00, 0x51, 0x46, 0xfb, 0xf7, 0xe8, 0xfa, + 0x49, 0x46, 0xfb, 0xf7, 0xe5, 0xfa, 0xee, 0x08, 0x54, 0xf8, 0x36, 0x10, + 0xfb, 0xf7, 0x44, 0xfa, 0x51, 0x46, 0x44, 0xf8, 0x36, 0x00, 0x04, 0xeb, + 0xc6, 0x06, 0x08, 0xeb, 0xc7, 0x00, 0x7f, 0x1c, 0x40, 0x68, 0xfb, 0xf7, + 0xd5, 0xfa, 0x49, 0x46, 0xfb, 0xf7, 0xd2, 0xfa, 0x71, 0x68, 0xfb, 0xf7, + 0x33, 0xfa, 0x15, 0x2f, 0x70, 0x60, 0x02, 0xd2, 0x6d, 0x1c, 0x20, 0x2d, + 0xd0, 0xd3, 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xf0, 0x4f, + 0x0d, 0x46, 0x9d, 0xb0, 0x82, 0x46, 0xa8, 0x68, 0x00, 0x88, 0x00, 0x0a, + 0x00, 0xf0, 0x03, 0x04, 0x00, 0x26, 0x0a, 0xeb, 0x86, 0x00, 0xb0, 0xf9, + 0x02, 0x00, 0x3a, 0xf9, 0x26, 0x10, 0x00, 0xf0, 0xa9, 0xf8, 0xa9, 0x68, + 0x20, 0x31, 0x0a, 0x79, 0x00, 0x92, 0x05, 0xf1, 0x14, 0x02, 0x0b, 0x68, + 0x01, 0x46, 0x04, 0xa8, 0x00, 0xeb, 0x46, 0x10, 0xff, 0xf7, 0x96, 0xff, + 0x76, 0x1c, 0x03, 0x2e, 0xe7, 0xd3, 0xa0, 0x07, 0x4c, 0xbf, 0x40, 0x27, + 0x20, 0x27, 0xba, 0xf9, 0x06, 0x00, 0xfb, 0xf7, 0xf3, 0xf8, 0x04, 0xae, + 0x05, 0x46, 0x71, 0x68, 0xf0, 0x6a, 0xfb, 0xf7, 0xf9, 0xf9, 0x83, 0x46, + 0xba, 0xf9, 0x02, 0x00, 0xfb, 0xf7, 0xe8, 0xf8, 0x03, 0x90, 0xba, 0xf9, + 0x04, 0x00, 0xfb, 0xf7, 0xe3, 0xf8, 0x80, 0x46, 0x04, 0x99, 0xb0, 0x6a, + 0xfb, 0xf7, 0xea, 0xf9, 0x81, 0x46, 0xba, 0xf9, 0x00, 0x00, 0xfb, 0xf7, + 0xd9, 0xf8, 0x82, 0x46, 0x04, 0xa8, 0x3f, 0x18, 0x49, 0x46, 0xb8, 0x69, + 0xfb, 0xf7, 0xde, 0xf9, 0x51, 0x46, 0xfb, 0xf7, 0x77, 0xfa, 0x00, 0x90, + 0x41, 0x46, 0x30, 0x69, 0xfb, 0xf7, 0x72, 0xfa, 0x00, 0x99, 0xfb, 0xf7, + 0xd3, 0xf9, 0x01, 0x90, 0x59, 0x46, 0xf8, 0x69, 0xfb, 0xf7, 0xce, 0xf9, + 0x03, 0x99, 0xfb, 0xf7, 0x67, 0xfa, 0x00, 0x90, 0x29, 0x46, 0x70, 0x69, + 0xfb, 0xf7, 0x62, 0xfa, 0x00, 0x99, 0xfb, 0xf7, 0xc3, 0xf9, 0x01, 0x46, + 0x01, 0x98, 0xfb, 0xf7, 0x4b, 0xf9, 0xfb, 0xf7, 0xc5, 0xfa, 0xad, 0xf8, + 0x08, 0x00, 0x49, 0x46, 0xb8, 0x69, 0xfb, 0xf7, 0xb7, 0xf9, 0x03, 0x99, + 0xfb, 0xf7, 0x50, 0xfa, 0x81, 0x46, 0x30, 0x69, 0x00, 0xf0, 0x98, 0xf8, + 0x49, 0x46, 0xfb, 0xf7, 0xad, 0xf9, 0x81, 0x46, 0xf8, 0x69, 0x59, 0x46, + 0xfb, 0xf7, 0xa8, 0xf9, 0x51, 0x46, 0xfb, 0xf7, 0x41, 0xfa, 0x83, 0x46, + 0x70, 0x69, 0x00, 0xf0, 0x15, 0xff, 0x59, 0x46, 0xfb, 0xf7, 0x9e, 0xf9, + 0x49, 0x46, 0xfb, 0xf7, 0x9b, 0xf9, 0xfb, 0xf7, 0xa1, 0xfa, 0x06, 0x46, + 0xe0, 0x07, 0xad, 0xf8, 0x0a, 0x60, 0x21, 0xd5, 0xbd, 0xf8, 0x08, 0x40, + 0xb8, 0x69, 0x00, 0xf0, 0x03, 0xff, 0x83, 0x46, 0xf8, 0x69, 0x00, 0xf0, + 0x73, 0xf8, 0x01, 0x46, 0x58, 0x46, 0xfb, 0xf7, 0x13, 0xf9, 0xfb, 0xf7, + 0x8d, 0xfa, 0x00, 0x19, 0xad, 0xf8, 0x08, 0x00, 0x29, 0x46, 0xb8, 0x69, + 0xfb, 0xf7, 0x1a, 0xfa, 0x04, 0x46, 0xf8, 0x69, 0x00, 0xf0, 0xee, 0xfe, + 0x21, 0x46, 0xfb, 0xf7, 0x77, 0xf9, 0xfb, 0xf7, 0x7d, 0xfa, 0x80, 0x19, + 0xad, 0xf8, 0x0a, 0x00, 0x02, 0x98, 0x1d, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, + 0x40, 0x43, 0x01, 0xfb, 0x01, 0x00, 0x00, 0xeb, 0xd0, 0x70, 0x40, 0x10, + 0xff, 0xf7, 0x86, 0xbb, 0x01, 0xb4, 0xbd, 0xf9, 0x02, 0x00, 0xbd, 0xf9, + 0x00, 0x10, 0x40, 0x43, 0x01, 0xfb, 0x01, 0x00, 0x01, 0xb0, 0x70, 0x47, + 0x49, 0x43, 0x00, 0xfb, 0x00, 0x10, 0x70, 0x47, 0x38, 0xb5, 0x0d, 0x46, + 0x01, 0x46, 0xfb, 0xf7, 0xef, 0xf9, 0x04, 0x46, 0x28, 0x46, 0x00, 0xf0, + 0x37, 0xf8, 0x21, 0x46, 0xbd, 0xe8, 0x34, 0x40, 0xfb, 0xf7, 0x4a, 0xb9, + 0x2d, 0xe9, 0xf9, 0x42, 0x82, 0xb0, 0x0c, 0x46, 0xbd, 0xf9, 0x0a, 0x00, + 0x15, 0x46, 0xfb, 0xf7, 0x35, 0xf8, 0x07, 0x46, 0xbd, 0xf9, 0x08, 0x00, + 0xfb, 0xf7, 0x30, 0xf8, 0x06, 0x46, 0x20, 0x46, 0x31, 0x46, 0xfb, 0xf7, + 0xd3, 0xf9, 0x81, 0x46, 0x38, 0x46, 0x00, 0xf0, 0x1b, 0xf8, 0x01, 0x46, + 0x48, 0x46, 0xfb, 0xf7, 0xbb, 0xf8, 0xfb, 0xf7, 0x35, 0xfa, 0xad, 0xf8, + 0x00, 0x00, 0x39, 0x46, 0x20, 0x46, 0xfb, 0xf7, 0xc3, 0xf9, 0x04, 0x46, + 0x30, 0x46, 0x00, 0xf0, 0x0b, 0xf8, 0x21, 0x46, 0xfb, 0xf7, 0x20, 0xf9, + 0xfb, 0xf7, 0x26, 0xfa, 0xad, 0xf8, 0x02, 0x00, 0x00, 0x98, 0x04, 0xb0, + 0xbd, 0xe8, 0xf0, 0x82, 0x29, 0x46, 0xfb, 0xf7, 0xb1, 0xb9, 0x0e, 0xb4, + 0x2d, 0xe9, 0xf0, 0x4a, 0x84, 0xb0, 0x81, 0x46, 0x0f, 0x98, 0x00, 0x28, + 0x14, 0xbf, 0x4f, 0xf0, 0xff, 0x37, 0x01, 0x27, 0xdd, 0xe9, 0x0d, 0x45, + 0x93, 0x46, 0x20, 0x46, 0xfb, 0xf7, 0xa0, 0xf9, 0x00, 0x90, 0x38, 0x46, + 0xfa, 0xf7, 0xf4, 0xff, 0x59, 0x46, 0xfb, 0xf7, 0x99, 0xf9, 0xff, 0xf7, + 0xe3, 0xff, 0x01, 0x46, 0x00, 0x98, 0xfb, 0xf7, 0x83, 0xf8, 0x06, 0x46, + 0x20, 0x46, 0x59, 0x46, 0xfb, 0xf7, 0x8e, 0xf9, 0x04, 0x46, 0x38, 0x46, + 0xfa, 0xf7, 0xe2, 0xff, 0x0b, 0x99, 0xfb, 0xf7, 0x87, 0xf9, 0xff, 0xf7, + 0xd1, 0xff, 0x21, 0x46, 0xfb, 0xf7, 0xe6, 0xf8, 0xc9, 0xe9, 0x00, 0x60, + 0x04, 0xb0, 0xbd, 0xe8, 0xf0, 0x0a, 0x5d, 0xf8, 0x10, 0xfb, 0xfe, 0xb5, + 0x06, 0x46, 0x10, 0x46, 0x19, 0x46, 0xfa, 0xf7, 0x9b, 0xff, 0x07, 0x46, + 0xdd, 0xe9, 0x08, 0x01, 0xfa, 0xf7, 0x96, 0xff, 0x39, 0x46, 0xfa, 0xf7, + 0xdf, 0xff, 0x05, 0x46, 0xdd, 0xe9, 0x0a, 0x01, 0xfa, 0xf7, 0x8e, 0xff, + 0x39, 0x46, 0xfa, 0xf7, 0xd7, 0xff, 0x07, 0x46, 0x28, 0x46, 0x39, 0x46, + 0xff, 0xf7, 0x6c, 0xff, 0x04, 0x46, 0x29, 0x46, 0xdf, 0xf8, 0x88, 0x0d, + 0xfb, 0xf7, 0x5a, 0xf9, 0x21, 0x46, 0xfa, 0xf7, 0xc9, 0xff, 0x04, 0x46, + 0x28, 0x46, 0x39, 0x46, 0xff, 0xf7, 0x5e, 0xff, 0x05, 0x46, 0xdf, 0xf8, + 0x74, 0x0d, 0x39, 0x46, 0xfb, 0xf7, 0x4c, 0xf9, 0x29, 0x46, 0xfa, 0xf7, + 0xbb, 0xff, 0xc6, 0xe9, 0x00, 0x40, 0xfe, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, + 0x07, 0x46, 0x8f, 0xb0, 0x38, 0x68, 0x00, 0x22, 0xc0, 0xe9, 0x06, 0x22, + 0xc0, 0xe9, 0x04, 0x22, 0xc0, 0xe9, 0x02, 0x22, 0x00, 0x24, 0x0d, 0xf1, + 0x04, 0x0a, 0x0d, 0xf1, 0x20, 0x09, 0x38, 0x69, 0x07, 0x23, 0x01, 0xaa, + 0x08, 0xa9, 0xfe, 0xf7, 0x03, 0xfb, 0xf8, 0xf7, 0x44, 0xfd, 0x48, 0xb1, + 0x38, 0x46, 0xfe, 0xf7, 0x96, 0xfb, 0x38, 0x46, 0xfe, 0xf7, 0x79, 0xfb, + 0x64, 0x1e, 0x00, 0x28, 0x40, 0xd0, 0x56, 0xe0, 0x00, 0x25, 0x01, 0xa8, + 0x00, 0xeb, 0x85, 0x06, 0xd7, 0xf8, 0x00, 0xc0, 0xb6, 0xf9, 0x02, 0xb0, + 0x08, 0xa8, 0x00, 0xeb, 0x85, 0x08, 0xdc, 0xe9, 0x02, 0x01, 0x02, 0x46, + 0x0b, 0x46, 0xb8, 0xf9, 0x02, 0xe0, 0x39, 0xf9, 0x25, 0x00, 0x3a, 0xf9, + 0x25, 0x10, 0x0b, 0xfb, 0x0e, 0xfe, 0x01, 0xfb, 0x00, 0xe0, 0xc1, 0x17, + 0x10, 0x18, 0x59, 0x41, 0xcc, 0xe9, 0x02, 0x01, 0x39, 0xf9, 0x25, 0x20, + 0xb6, 0xf9, 0x02, 0x30, 0x3a, 0xf9, 0x25, 0x60, 0x5a, 0x43, 0xdc, 0xe9, + 0x04, 0x01, 0xb8, 0xf9, 0x02, 0x30, 0x06, 0xfb, 0x13, 0x22, 0x80, 0x18, + 0x41, 0xeb, 0xe2, 0x71, 0xcc, 0xe9, 0x04, 0x01, 0x59, 0xf8, 0x25, 0x00, + 0x00, 0x90, 0xff, 0xf7, 0xeb, 0xfe, 0x3e, 0x68, 0x00, 0x21, 0xd6, 0xe9, + 0x06, 0x23, 0x10, 0x18, 0x59, 0x41, 0xc6, 0xe9, 0x06, 0x01, 0x6d, 0x1c, + 0x07, 0x2d, 0xc0, 0xdb, 0x64, 0x1c, 0x80, 0x2c, 0xa9, 0xdb, 0x3a, 0x68, + 0xb8, 0x68, 0x80, 0x8b, 0xd2, 0xe9, 0x06, 0x45, 0xa0, 0xfb, 0x00, 0x23, + 0x4f, 0xf4, 0x60, 0x70, 0xa0, 0xfb, 0x02, 0x68, 0x00, 0xfb, 0x03, 0x88, + 0x45, 0x45, 0x03, 0xd8, 0x2c, 0xbf, 0xb4, 0x42, 0x07, 0x20, 0x00, 0xd3, + 0x00, 0x20, 0x0f, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xf1, 0x4f, + 0xad, 0xf5, 0x06, 0x7d, 0x84, 0x68, 0x00, 0x68, 0x03, 0x90, 0x20, 0x21, + 0x7e, 0xa8, 0xfb, 0xf7, 0x6d, 0xff, 0x66, 0xa8, 0x60, 0x21, 0xfb, 0xf7, + 0x69, 0xff, 0x3c, 0xa8, 0xa8, 0x21, 0xfb, 0xf7, 0x65, 0xff, 0x12, 0xa8, + 0xa8, 0x21, 0xfb, 0xf7, 0x61, 0xff, 0x07, 0xa8, 0x00, 0x21, 0x00, 0x22, + 0x06, 0xc0, 0x03, 0x98, 0xd4, 0x30, 0x02, 0x90, 0x00, 0x68, 0xfb, 0xf7, + 0x87, 0xf8, 0x05, 0xd1, 0x02, 0x98, 0x40, 0x68, 0xfb, 0xf7, 0x82, 0xf8, + 0x00, 0xf0, 0xf2, 0x80, 0x03, 0x9a, 0x0d, 0xf5, 0xfc, 0x7a, 0xd2, 0xe9, + 0x08, 0x01, 0xff, 0xf7, 0xa5, 0xfe, 0x02, 0x9a, 0x09, 0x90, 0xd2, 0xe9, + 0x00, 0x01, 0xff, 0xf7, 0x9f, 0xfe, 0x04, 0x90, 0x01, 0x20, 0x01, 0x90, + 0x02, 0x98, 0xd0, 0xe9, 0x00, 0x9b, 0x03, 0x98, 0xcd, 0xf8, 0x00, 0xb0, + 0x4b, 0x46, 0xd0, 0xe9, 0x08, 0x9b, 0x49, 0x46, 0x5a, 0x46, 0x05, 0xa8, + 0xff, 0xf7, 0xd1, 0xfe, 0x05, 0x98, 0x04, 0x99, 0xfa, 0xf7, 0xf0, 0xfe, + 0x05, 0x90, 0x4f, 0xf0, 0x8c, 0x49, 0x06, 0x98, 0x04, 0x99, 0xfa, 0xf7, + 0xe9, 0xfe, 0x02, 0x99, 0x06, 0x90, 0x09, 0x89, 0x34, 0xf8, 0x0c, 0x2f, + 0x8d, 0x1a, 0x49, 0x46, 0xfb, 0xf7, 0x6e, 0xf8, 0xfb, 0xf7, 0xd8, 0xf8, + 0xad, 0xf8, 0x06, 0x00, 0x49, 0x46, 0x05, 0x98, 0xfb, 0xf7, 0x66, 0xf8, + 0xfb, 0xf7, 0xd0, 0xf8, 0xad, 0xf8, 0x04, 0x00, 0x0d, 0xf1, 0x48, 0x0b, + 0x0b, 0xe0, 0x00, 0xbf, 0x00, 0x98, 0x41, 0x1e, 0x00, 0x28, 0x00, 0x91, + 0xf9, 0xd1, 0x08, 0xf1, 0x01, 0x08, 0xb8, 0xf1, 0x04, 0x0f, 0x6f, 0xd3, + 0x6d, 0x1c, 0x02, 0x99, 0x09, 0x89, 0xe8, 0xb2, 0x88, 0x42, 0x80, 0xf0, + 0x9f, 0x80, 0xfe, 0xf7, 0x6c, 0xf9, 0x80, 0x03, 0xff, 0xf7, 0xcc, 0xf9, + 0x01, 0x46, 0x20, 0x7e, 0x00, 0x90, 0x00, 0x27, 0x03, 0x98, 0x63, 0x69, + 0x00, 0xf1, 0x28, 0x02, 0x0a, 0xa8, 0xff, 0xf7, 0x2d, 0xfd, 0x0a, 0xa8, + 0x49, 0x46, 0x50, 0xf8, 0x37, 0x00, 0xfb, 0xf7, 0x37, 0xf8, 0xfb, 0xf7, + 0xa1, 0xf8, 0x4a, 0xf8, 0x37, 0x00, 0x49, 0x46, 0x0a, 0xa8, 0x00, 0xeb, + 0xc7, 0x00, 0x40, 0x68, 0xfb, 0xf7, 0x2c, 0xf8, 0xfb, 0xf7, 0x96, 0xf8, + 0x7e, 0xa9, 0x01, 0xeb, 0xc7, 0x01, 0x7f, 0x1c, 0x04, 0x2f, 0x48, 0x60, + 0xe5, 0xdb, 0xe8, 0xb2, 0xfe, 0xf7, 0x41, 0xf9, 0xfa, 0xf7, 0x80, 0xfe, + 0x4f, 0xf0, 0x8d, 0x41, 0xfb, 0xf7, 0x1a, 0xf8, 0x09, 0x99, 0xfb, 0xf7, + 0x17, 0xf8, 0x04, 0x99, 0xfa, 0xf7, 0x86, 0xfe, 0x01, 0xf0, 0x12, 0xff, + 0xff, 0xf7, 0x94, 0xf9, 0x07, 0x46, 0xbd, 0xf8, 0x04, 0x00, 0xad, 0xf8, + 0x1c, 0x00, 0x00, 0x26, 0xbd, 0xf8, 0x06, 0x00, 0xad, 0xf8, 0x1e, 0x00, + 0xbd, 0xf8, 0x04, 0x00, 0xad, 0xf8, 0x20, 0x00, 0xbd, 0xf8, 0x06, 0x00, + 0xad, 0xf8, 0x22, 0x00, 0x22, 0x7e, 0x66, 0xa8, 0x39, 0x46, 0x00, 0xeb, + 0x46, 0x10, 0xff, 0xf7, 0x90, 0xf9, 0x76, 0x1c, 0x03, 0x2e, 0xf5, 0xdb, + 0x07, 0xaa, 0x86, 0x98, 0x80, 0x68, 0x00, 0x6a, 0x00, 0x90, 0x66, 0xa9, + 0x03, 0x98, 0x80, 0x88, 0x00, 0x0a, 0x00, 0xf0, 0x03, 0x03, 0x3c, 0xa8, + 0xff, 0xf7, 0x93, 0xf9, 0x00, 0x26, 0xb0, 0x46, 0x00, 0x27, 0x00, 0x20, + 0x4b, 0xf8, 0x37, 0x00, 0x12, 0xa9, 0x01, 0xeb, 0xc7, 0x01, 0x7f, 0x1c, + 0x15, 0x2f, 0x48, 0x60, 0xf6, 0xdb, 0x61, 0x69, 0x00, 0xeb, 0xc8, 0x02, + 0xd1, 0x40, 0xc9, 0x07, 0x0f, 0xd5, 0x3c, 0xa9, 0x12, 0xaa, 0x51, 0xf8, + 0x36, 0x10, 0x4b, 0xf8, 0x36, 0x10, 0x02, 0xeb, 0xc6, 0x02, 0x3c, 0xa9, + 0x01, 0xeb, 0xc6, 0x01, 0x76, 0x1c, 0x49, 0x68, 0x51, 0x60, 0x15, 0x2e, + 0x02, 0xd2, 0x40, 0x1c, 0x08, 0x28, 0xe6, 0xd3, 0x86, 0x98, 0x00, 0x69, + 0xc0, 0xb2, 0x00, 0x90, 0x0a, 0xeb, 0xc8, 0x02, 0x00, 0x23, 0xd2, 0xe9, + 0x00, 0x01, 0x0a, 0x46, 0x01, 0x46, 0x12, 0xa8, 0xfe, 0xf7, 0xda, 0xf9, + 0x4f, 0xf4, 0xc8, 0x70, 0x00, 0x90, 0x4f, 0xe7, 0x0d, 0xf5, 0x07, 0x7d, + 0xbd, 0xe8, 0xf0, 0x8f, 0x70, 0xb5, 0x82, 0xb0, 0x04, 0x46, 0x00, 0x25, + 0x00, 0x26, 0x54, 0xf8, 0x26, 0x00, 0x00, 0x90, 0x76, 0x1c, 0xff, 0xf7, + 0x9d, 0xfd, 0x45, 0x19, 0x07, 0x2e, 0xf6, 0xd3, 0x28, 0x46, 0x76, 0xbd, + 0x70, 0xb5, 0x82, 0xb0, 0x04, 0x46, 0x00, 0x25, 0x00, 0x26, 0x54, 0xf8, + 0x26, 0x00, 0x00, 0x90, 0xff, 0xf7, 0x8e, 0xfd, 0x85, 0x42, 0x38, 0xbf, + 0x05, 0x46, 0x76, 0x1c, 0x07, 0x2e, 0xf4, 0xd3, 0x28, 0x46, 0x76, 0xbd, + 0x38, 0xb5, 0x00, 0x24, 0x02, 0xfb, 0x02, 0xf5, 0x11, 0xb9, 0xff, 0xf7, + 0xe7, 0xff, 0x03, 0xe0, 0xff, 0xf7, 0xd4, 0xff, 0xc5, 0xeb, 0xc5, 0x05, + 0xa8, 0x42, 0x28, 0xbf, 0x01, 0x24, 0x20, 0x46, 0x32, 0xbd, 0xc9, 0xb2, + 0x51, 0xb1, 0x15, 0x29, 0x08, 0xda, 0xc0, 0x68, 0x00, 0xeb, 0x81, 0x01, + 0x0a, 0x6c, 0x52, 0x1c, 0x0a, 0x64, 0x01, 0x6c, 0x49, 0x1c, 0x01, 0x64, + 0x70, 0x47, 0x03, 0x68, 0x00, 0xf1, 0x08, 0x01, 0x03, 0xf1, 0x14, 0x02, + 0x18, 0x46, 0xff, 0xf7, 0x4d, 0xba, 0x10, 0xb5, 0x82, 0xb0, 0x04, 0x46, + 0x6a, 0x46, 0x00, 0x21, 0x00, 0x20, 0xf7, 0xf7, 0xa2, 0xfc, 0x00, 0x98, + 0xdf, 0xf8, 0x84, 0x29, 0x04, 0x60, 0x00, 0x21, 0x00, 0x20, 0xf7, 0xf7, + 0x26, 0xfd, 0x00, 0x20, 0xf7, 0xf7, 0xdf, 0xfc, 0x13, 0xbd, 0x00, 0x00, + 0x00, 0x20, 0x70, 0x59, 0x00, 0x00, 0x70, 0x59, 0x00, 0x00, 0xf0, 0x3f, + 0x2d, 0xe9, 0xf0, 0x4f, 0x04, 0x46, 0xd3, 0xb0, 0xa3, 0x68, 0x08, 0x93, + 0x20, 0x68, 0x08, 0x9a, 0x05, 0x90, 0xe1, 0x68, 0x06, 0x91, 0x00, 0x21, + 0x10, 0x91, 0x0f, 0x91, 0x0e, 0x91, 0x08, 0x99, 0x24, 0x31, 0x04, 0x91, + 0x05, 0x99, 0x01, 0xf5, 0xcc, 0x71, 0x09, 0x91, 0x05, 0x99, 0x12, 0x88, + 0x89, 0x88, 0x22, 0xf4, 0x00, 0x62, 0x91, 0x42, 0x0b, 0xd1, 0x09, 0x99, + 0x08, 0x9a, 0x49, 0x68, 0x12, 0x6a, 0x91, 0x42, 0x05, 0xd1, 0x09, 0x99, + 0x04, 0x9a, 0x09, 0x7a, 0x12, 0x78, 0x91, 0x42, 0x03, 0xd0, 0x22, 0x69, + 0x06, 0x99, 0xfe, 0xf7, 0x6a, 0xfa, 0x05, 0x98, 0x08, 0x30, 0x07, 0x90, + 0xd0, 0xe9, 0x04, 0x23, 0x00, 0x2b, 0x08, 0xbf, 0x00, 0x2a, 0x0b, 0xd0, + 0xd0, 0xe9, 0x00, 0x23, 0x00, 0x2b, 0x08, 0xbf, 0x00, 0x2a, 0x0c, 0xd1, + 0xd0, 0xe9, 0x02, 0x23, 0x00, 0x2b, 0x08, 0xbf, 0x00, 0x2a, 0x06, 0xd1, + 0x20, 0x46, 0xff, 0xf7, 0xbb, 0xfd, 0x5f, 0xea, 0x00, 0x09, 0x40, 0xf0, + 0xbe, 0x82, 0x00, 0x20, 0x0b, 0x90, 0x6a, 0x46, 0x07, 0x98, 0x0a, 0xc8, + 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc2, 0x07, 0x98, 0x00, 0x25, 0xd0, 0xe9, + 0x04, 0x23, 0x0c, 0xa8, 0xff, 0xf7, 0x73, 0xfd, 0xdd, 0xe9, 0x0c, 0x01, + 0x05, 0x9a, 0xc2, 0xe9, 0x08, 0x01, 0x00, 0x20, 0xcd, 0xe9, 0x18, 0x00, + 0xcd, 0xe9, 0x0c, 0x00, 0x04, 0x9a, 0x08, 0x98, 0x04, 0x99, 0x04, 0x9b, + 0x40, 0x88, 0x92, 0x89, 0x49, 0x8a, 0xdb, 0x89, 0x03, 0x90, 0x12, 0x18, + 0x64, 0x31, 0x9a, 0x18, 0x51, 0x43, 0x64, 0x22, 0xb1, 0xfb, 0xf2, 0xf1, + 0x01, 0x20, 0x14, 0x91, 0x01, 0x90, 0x0d, 0xe0, 0x02, 0x28, 0x03, 0xd1, + 0x04, 0x99, 0x03, 0x98, 0x89, 0x89, 0x04, 0xe0, 0x03, 0x28, 0x05, 0xd1, + 0x04, 0x99, 0x03, 0x98, 0xc9, 0x89, 0x08, 0x18, 0x80, 0xb2, 0x03, 0x90, + 0x01, 0x20, 0xad, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0xa1, 0xfb, 0x0a, 0x90, + 0x00, 0x20, 0x02, 0x90, 0x76, 0xe0, 0xdd, 0xe9, 0x18, 0x01, 0x0b, 0x46, + 0x00, 0x21, 0xc0, 0x19, 0x59, 0x41, 0xcd, 0xe9, 0x18, 0x01, 0xdd, 0xe9, + 0x0c, 0x23, 0x00, 0x21, 0x12, 0xeb, 0x0b, 0x00, 0x59, 0x41, 0xcd, 0xe9, + 0x0c, 0x01, 0x05, 0x98, 0x00, 0x79, 0x00, 0xf0, 0x0f, 0x00, 0x01, 0x21, + 0x08, 0x30, 0x01, 0xfa, 0x00, 0xf0, 0xc1, 0x17, 0xcd, 0xe9, 0x16, 0x01, + 0x07, 0x98, 0xd0, 0xe9, 0x00, 0x79, 0x00, 0xf0, 0x6b, 0xfb, 0x38, 0x1a, + 0x69, 0xeb, 0x01, 0x01, 0x07, 0x9a, 0x10, 0xeb, 0x0a, 0x00, 0x41, 0xeb, + 0xea, 0x71, 0xc2, 0xe9, 0x00, 0x01, 0x07, 0x98, 0xd0, 0xe9, 0x02, 0x79, + 0x00, 0xf0, 0x5c, 0xfb, 0x3a, 0x1a, 0x15, 0x98, 0x69, 0xeb, 0x01, 0x03, + 0xc1, 0x17, 0x10, 0x18, 0x07, 0x9a, 0x59, 0x41, 0xc2, 0xe9, 0x02, 0x01, + 0x07, 0x98, 0xd0, 0xe9, 0x04, 0x79, 0x00, 0xf0, 0x4d, 0xfb, 0x38, 0x1a, + 0x69, 0xeb, 0x01, 0x01, 0x00, 0x23, 0x07, 0x9a, 0x10, 0xeb, 0x0b, 0x00, + 0x59, 0x41, 0xc2, 0xe9, 0x04, 0x01, 0x1a, 0xa8, 0x50, 0xf8, 0x26, 0x00, + 0x15, 0x90, 0x05, 0x98, 0xd0, 0xe9, 0x08, 0x23, 0x11, 0x46, 0x15, 0x98, + 0x1a, 0x46, 0xff, 0xf7, 0x7f, 0xfc, 0x1a, 0xa9, 0x41, 0xf8, 0x26, 0x00, + 0x1a, 0xa8, 0x21, 0xa9, 0x30, 0xf9, 0x26, 0x00, 0x31, 0xf9, 0x26, 0x10, + 0x40, 0x1a, 0x11, 0x90, 0x13, 0x98, 0xb8, 0xf9, 0x02, 0x10, 0xb0, 0xf9, + 0x02, 0x00, 0x00, 0xf0, 0x14, 0xfb, 0x08, 0x99, 0x49, 0x89, 0x49, 0x43, + 0x81, 0x42, 0x02, 0xd2, 0x0e, 0x98, 0x40, 0x1c, 0x0e, 0x90, 0x76, 0x1c, + 0x07, 0x2e, 0x62, 0xd3, 0x1a, 0xaa, 0x21, 0xa9, 0x20, 0x46, 0xff, 0xf7, + 0xb7, 0xf8, 0x6d, 0x1c, 0x03, 0x98, 0x85, 0x42, 0x80, 0xf0, 0x90, 0x80, + 0x00, 0xf0, 0x28, 0xfb, 0x06, 0x99, 0x0a, 0x98, 0x08, 0x62, 0x6e, 0x1e, + 0xf8, 0xf7, 0x4d, 0xfa, 0x88, 0xb1, 0x00, 0xf0, 0x0e, 0xfb, 0x20, 0x46, + 0xfe, 0xf7, 0x83, 0xf8, 0x5f, 0xea, 0x00, 0x09, 0x35, 0x46, 0x07, 0xd1, + 0x08, 0x99, 0x05, 0x98, 0x09, 0x88, 0x80, 0x88, 0x21, 0xf4, 0x00, 0x61, + 0x88, 0x42, 0xe0, 0xd0, 0xe3, 0xe1, 0x01, 0x98, 0x01, 0x28, 0x31, 0xd0, + 0x0a, 0x98, 0xfa, 0xf7, 0x89, 0xfe, 0x00, 0xf0, 0xf9, 0xfa, 0x40, 0xbb, + 0x02, 0x98, 0x45, 0x1c, 0x01, 0x98, 0x03, 0x28, 0x1b, 0xd1, 0x04, 0x99, + 0xbd, 0xf8, 0x00, 0x00, 0x09, 0x8a, 0x88, 0x42, 0x03, 0xd2, 0x40, 0x1c, + 0xad, 0xf8, 0x00, 0x00, 0x12, 0xe0, 0x04, 0x98, 0xc0, 0x88, 0xfa, 0xf7, + 0x69, 0xfc, 0x00, 0xf0, 0xd4, 0xfa, 0x00, 0xf0, 0xcf, 0xfa, 0x00, 0xf0, + 0xf3, 0xfa, 0x01, 0x46, 0x0a, 0x98, 0xfa, 0xf7, 0xfd, 0xfd, 0x0a, 0x90, + 0x01, 0x20, 0xad, 0xf8, 0x00, 0x00, 0x02, 0x95, 0x02, 0x98, 0x14, 0x99, + 0x88, 0x42, 0x80, 0xf0, 0xdc, 0x81, 0x35, 0x46, 0xad, 0xe7, 0x00, 0xf0, + 0xd3, 0xfa, 0x0a, 0x90, 0x21, 0xa8, 0xff, 0xf7, 0x51, 0xfe, 0x0b, 0x99, + 0x81, 0x42, 0x38, 0xbf, 0x01, 0x46, 0x0b, 0x91, 0x00, 0x26, 0x21, 0xa8, + 0x00, 0xf0, 0xa9, 0xfa, 0x83, 0x46, 0x1a, 0xa8, 0x00, 0xf0, 0xa5, 0xfa, + 0x07, 0x46, 0x1a, 0xa8, 0x00, 0xeb, 0x86, 0x01, 0x13, 0x91, 0x1a, 0xaa, + 0xb1, 0xf9, 0x02, 0x00, 0x32, 0xf9, 0x26, 0x20, 0x21, 0xa9, 0x01, 0xeb, + 0x86, 0x08, 0xb8, 0xf9, 0x02, 0x30, 0x31, 0xf9, 0x26, 0x10, 0x43, 0x43, + 0x02, 0xfb, 0x01, 0x3a, 0x21, 0xa9, 0x1a, 0xaa, 0x31, 0xf9, 0x26, 0x10, + 0x32, 0xf9, 0x26, 0x20, 0x48, 0x43, 0xb8, 0xf9, 0x02, 0x10, 0x02, 0xfb, + 0x11, 0x01, 0x08, 0x98, 0x15, 0x91, 0x00, 0x89, 0x40, 0x43, 0x58, 0x45, + 0x03, 0xd2, 0x10, 0x98, 0x40, 0x1c, 0x10, 0x90, 0x69, 0xe7, 0xb8, 0x42, + 0xbf, 0xf4, 0xf9, 0xae, 0x0f, 0x98, 0x40, 0x1c, 0x0f, 0x90, 0x62, 0xe7, + 0x01, 0x98, 0x40, 0x1c, 0xc0, 0xb2, 0x04, 0x28, 0x01, 0x90, 0xff, 0xf6, + 0xd7, 0xae, 0x00, 0xf0, 0x80, 0xfa, 0x03, 0xa8, 0x00, 0x21, 0x00, 0x88, + 0xcd, 0xe9, 0x00, 0x01, 0x07, 0x26, 0x04, 0x98, 0x80, 0x7e, 0x00, 0x28, + 0x60, 0xd0, 0x04, 0x98, 0xc0, 0x8b, 0xfa, 0xf7, 0xf9, 0xfb, 0x00, 0xf0, + 0x64, 0xfa, 0xdf, 0xf8, 0x04, 0x16, 0xfa, 0xf7, 0x03, 0xfc, 0x00, 0xf0, + 0x81, 0xfa, 0x05, 0x46, 0x04, 0x98, 0x82, 0x8b, 0xdd, 0xe9, 0x00, 0x01, + 0xa2, 0xfb, 0x00, 0x79, 0x02, 0xfb, 0x01, 0x99, 0xa2, 0xfb, 0x07, 0x01, + 0x02, 0xfb, 0x09, 0x11, 0xa6, 0xfb, 0x00, 0x79, 0x06, 0xfb, 0x01, 0x99, + 0x38, 0x46, 0x49, 0x46, 0xfa, 0xf7, 0xae, 0xfb, 0xff, 0xf7, 0xc4, 0xfb, + 0x03, 0xf0, 0xf4, 0xfc, 0x02, 0x46, 0x20, 0x69, 0x0b, 0x46, 0x01, 0x28, + 0x0c, 0xbf, 0x02, 0x21, 0x01, 0x21, 0x00, 0x25, 0xef, 0xf3, 0x11, 0x8a, + 0x60, 0x20, 0x80, 0xf3, 0x11, 0x88, 0x09, 0x98, 0xc0, 0x7a, 0x38, 0xbb, + 0x09, 0x98, 0x80, 0x7a, 0x80, 0xb1, 0xdd, 0xe9, 0x0c, 0x70, 0x83, 0x42, + 0x08, 0xd8, 0x28, 0xbf, 0xba, 0x42, 0x05, 0xd2, 0x09, 0x9a, 0x95, 0x72, + 0x01, 0x20, 0xfe, 0xf7, 0x86, 0xf8, 0x17, 0xe0, 0x00, 0x20, 0xfe, 0xf7, + 0x82, 0xf8, 0x12, 0xe0, 0xdd, 0xe9, 0x0c, 0x23, 0x4b, 0x45, 0x0f, 0xd8, + 0x28, 0xbf, 0xba, 0x42, 0x0c, 0xd2, 0x09, 0x9a, 0x01, 0x20, 0x90, 0x72, + 0x00, 0x20, 0xfe, 0xf7, 0x74, 0xf8, 0xa0, 0x68, 0x90, 0xf8, 0x3f, 0x10, + 0x20, 0x69, 0xfe, 0xf7, 0xd9, 0xf8, 0x0f, 0x25, 0x8a, 0xf3, 0x11, 0x88, + 0x00, 0x2d, 0x72, 0xd1, 0x08, 0x98, 0x80, 0x8b, 0xdd, 0xe9, 0x00, 0x23, + 0xa0, 0xfb, 0x02, 0x79, 0x00, 0xfb, 0x03, 0x99, 0xa0, 0xfb, 0x07, 0x23, + 0x00, 0xfb, 0x09, 0x33, 0xa6, 0xfb, 0x02, 0x01, 0x06, 0xfb, 0x03, 0x11, + 0xdd, 0xe9, 0x0c, 0x23, 0x8b, 0x42, 0x07, 0xd8, 0x28, 0xbf, 0x82, 0x42, + 0x04, 0xd2, 0x21, 0x68, 0x00, 0xf0, 0x09, 0xfa, 0x07, 0x20, 0xdb, 0xe1, + 0x10, 0x9a, 0x02, 0x2a, 0x07, 0xd3, 0xa3, 0x68, 0x22, 0x69, 0x06, 0x99, + 0x05, 0x98, 0xfe, 0xf7, 0x66, 0xf8, 0x08, 0x20, 0xd0, 0xe1, 0xdd, 0xe9, + 0x18, 0x23, 0x8b, 0x42, 0x03, 0xd8, 0x2c, 0xbf, 0x82, 0x42, 0x05, 0x20, + 0xf6, 0xd3, 0x0f, 0x98, 0x04, 0x28, 0x03, 0xd3, 0x00, 0xf0, 0xee, 0xf9, + 0x06, 0x20, 0xc1, 0xe1, 0x0e, 0x98, 0x03, 0x28, 0x03, 0xd3, 0x00, 0xf0, + 0xe7, 0xf9, 0x0a, 0x20, 0xba, 0xe1, 0xdd, 0xe9, 0x0c, 0x01, 0xdd, 0xe9, + 0x00, 0x23, 0xfb, 0xf7, 0x67, 0xf8, 0xfa, 0xf7, 0x29, 0xfb, 0xfa, 0xf7, + 0x99, 0xfc, 0x01, 0xf0, 0xf1, 0xfb, 0x07, 0x90, 0x11, 0x25, 0x0f, 0xf2, + 0x80, 0x56, 0x0f, 0xf2, 0xd4, 0x47, 0x28, 0xa8, 0x39, 0x46, 0xa8, 0x22, + 0xfd, 0xf7, 0x60, 0xfc, 0xd6, 0xe9, 0x00, 0x01, 0x28, 0xab, 0x01, 0x22, + 0x43, 0xf8, 0x35, 0x20, 0x00, 0x23, 0x22, 0x69, 0xd2, 0xb2, 0x00, 0x92, + 0x6d, 0x1c, 0x0a, 0x46, 0x01, 0x46, 0x28, 0xa8, 0xfd, 0xf7, 0xfe, 0xfe, + 0x15, 0x2d, 0xe8, 0xd3, 0x20, 0x46, 0xff, 0xf7, 0x09, 0xfc, 0x20, 0x46, + 0xff, 0xf7, 0x6d, 0xfd, 0x20, 0x46, 0xfd, 0xf7, 0x1e, 0xff, 0x05, 0x00, + 0x03, 0xd0, 0x00, 0xf0, 0xa2, 0xf9, 0x28, 0x46, 0x82, 0xe1, 0x00, 0x20, + 0xcd, 0xe9, 0x0c, 0x00, 0x03, 0x90, 0x00, 0x27, 0x00, 0xf0, 0xa2, 0xf9, + 0x80, 0x46, 0x02, 0x97, 0xbb, 0x46, 0xba, 0x46, 0x01, 0x25, 0x00, 0x26, + 0x63, 0xe0, 0x80, 0x88, 0xfa, 0xf7, 0x16, 0xfb, 0x80, 0x46, 0x4f, 0xf0, + 0x00, 0x09, 0x1a, 0xa8, 0x50, 0xf8, 0x29, 0x00, 0x05, 0x9a, 0x00, 0x90, + 0xd2, 0xe9, 0x08, 0x01, 0x0a, 0x46, 0x01, 0x46, 0x00, 0x98, 0xff, 0xf7, + 0xbf, 0xfa, 0x1a, 0xa9, 0x41, 0xf8, 0x29, 0x00, 0x09, 0xf1, 0x01, 0x09, + 0xb9, 0xf1, 0x03, 0x0f, 0xeb, 0xd3, 0x21, 0x46, 0x1a, 0xa8, 0xff, 0xf7, + 0xd3, 0xf9, 0x00, 0x90, 0xbd, 0xf9, 0x00, 0x10, 0xbd, 0xf9, 0x84, 0x00, + 0x40, 0x1a, 0x11, 0x90, 0xbd, 0xf9, 0x02, 0x10, 0xbd, 0xf9, 0x86, 0x00, + 0x00, 0xf0, 0x4d, 0xf9, 0xfa, 0xf7, 0xec, 0xfa, 0x03, 0x99, 0xfa, 0xf7, + 0xeb, 0xfb, 0x03, 0x90, 0x1a, 0x98, 0xff, 0xf7, 0x81, 0xfa, 0xfa, 0xf7, + 0xe3, 0xfa, 0x59, 0x46, 0xfa, 0xf7, 0xe2, 0xfb, 0x83, 0x46, 0x00, 0x98, + 0xff, 0xf7, 0x78, 0xfa, 0xfa, 0xf7, 0xda, 0xfa, 0x51, 0x46, 0xfa, 0xf7, + 0xd9, 0xfb, 0x82, 0x46, 0x21, 0x98, 0xff, 0xf7, 0x6f, 0xfa, 0xfd, 0xf7, + 0x79, 0xfd, 0x5f, 0xfa, 0x80, 0xf9, 0xdd, 0xe9, 0x11, 0x01, 0xff, 0xf7, + 0x71, 0xfa, 0x04, 0x99, 0x49, 0x88, 0x49, 0x43, 0x88, 0x42, 0x3c, 0xbf, + 0x4f, 0x45, 0x4f, 0x46, 0xdd, 0xe9, 0x0c, 0x01, 0xcd, 0xe9, 0x00, 0x01, + 0x21, 0x98, 0xff, 0xf7, 0x59, 0xfa, 0xdd, 0xe9, 0x00, 0x23, 0x00, 0x21, + 0x10, 0x18, 0x59, 0x41, 0xcd, 0xe9, 0x0c, 0x01, 0x76, 0x1c, 0x08, 0x98, + 0xc0, 0x88, 0x86, 0x42, 0x3d, 0xda, 0x00, 0xf0, 0x39, 0xf9, 0xf8, 0xf7, + 0x62, 0xf8, 0xa6, 0xf1, 0x01, 0x09, 0x60, 0xb1, 0x00, 0xf0, 0x21, 0xf9, + 0x20, 0x46, 0xfd, 0xf7, 0x96, 0xfe, 0x4e, 0x46, 0x5f, 0xea, 0x00, 0x09, + 0xea, 0xd0, 0x00, 0xf0, 0x18, 0xf9, 0x48, 0x46, 0xf8, 0xe0, 0x40, 0x46, + 0xfa, 0xf7, 0xa4, 0xfc, 0x00, 0xf0, 0x14, 0xf9, 0x00, 0x28, 0x04, 0x98, + 0x7f, 0xf4, 0x7b, 0xaf, 0x00, 0x8a, 0xad, 0xb2, 0x85, 0x42, 0x38, 0xbf, + 0x6d, 0x1c, 0x10, 0xd3, 0x04, 0x98, 0xc0, 0x88, 0xfa, 0xf7, 0x8a, 0xfa, + 0x00, 0xf0, 0xf5, 0xf8, 0x00, 0xf0, 0xf0, 0xf8, 0x00, 0xf0, 0x14, 0xf9, + 0x00, 0xf0, 0xf8, 0xf8, 0x80, 0x46, 0x02, 0x98, 0x40, 0x1c, 0x01, 0x25, + 0x02, 0x90, 0x02, 0x98, 0x14, 0x99, 0x88, 0x42, 0x03, 0xd3, 0x00, 0xf0, + 0xf0, 0xf8, 0x0d, 0x20, 0xd0, 0xe0, 0x4e, 0x46, 0xbc, 0xe7, 0x00, 0xf0, + 0xea, 0xf8, 0xdd, 0xe9, 0x0c, 0x01, 0x40, 0x1c, 0x41, 0xf1, 0x00, 0x01, + 0xfa, 0xf7, 0x3c, 0xfa, 0x01, 0x46, 0x03, 0x98, 0xfa, 0xf7, 0x76, 0xfa, + 0xfa, 0xf7, 0xa8, 0xfb, 0xb8, 0x49, 0xfa, 0xf7, 0xff, 0xfb, 0x01, 0xf0, + 0xfd, 0xfa, 0x06, 0x99, 0xc8, 0x60, 0x09, 0x98, 0x06, 0x99, 0x00, 0x68, + 0x48, 0x62, 0x06, 0x98, 0xc6, 0x68, 0x08, 0x98, 0x80, 0x88, 0xb0, 0x42, + 0x02, 0xd2, 0x00, 0xf0, 0xd7, 0xf8, 0x33, 0xe0, 0x04, 0x98, 0xb0, 0xf8, + 0x0a, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x2f, 0xd0, 0x00, 0x89, 0xfa, 0xf7, + 0x47, 0xfa, 0x00, 0xf0, 0xb2, 0xf8, 0x00, 0xf0, 0xad, 0xf8, 0x00, 0xf0, + 0xd1, 0xf8, 0x05, 0x46, 0x40, 0x46, 0xfa, 0xf7, 0x3d, 0xfa, 0x00, 0xf0, + 0xa8, 0xf8, 0x80, 0x46, 0x30, 0x46, 0xfa, 0xf7, 0x37, 0xfa, 0x06, 0x46, + 0x09, 0x98, 0x00, 0x68, 0xff, 0xf7, 0x1c, 0xfa, 0x81, 0x46, 0x4f, 0xf0, + 0x7e, 0x50, 0x29, 0x46, 0xfa, 0xf7, 0xba, 0xfa, 0x31, 0x46, 0xfa, 0xf7, + 0xc7, 0xfb, 0x49, 0x46, 0xfa, 0xf7, 0x28, 0xfb, 0x01, 0x46, 0x09, 0x98, + 0x01, 0x60, 0x40, 0x46, 0xfa, 0xf7, 0xbe, 0xfb, 0x31, 0x46, 0xfa, 0xf7, + 0xa9, 0xfb, 0x01, 0xd2, 0x09, 0x20, 0x75, 0xe0, 0xa0, 0x68, 0x90, 0xf8, + 0x3a, 0x00, 0xa0, 0xb3, 0x01, 0x21, 0x58, 0x46, 0x01, 0xf0, 0xba, 0xfc, + 0x90, 0x49, 0xfa, 0xf7, 0xad, 0xfb, 0x06, 0x46, 0x01, 0x21, 0x50, 0x46, + 0x01, 0xf0, 0xb2, 0xfc, 0x8c, 0x49, 0xfa, 0xf7, 0xa5, 0xfb, 0x80, 0x46, + 0x30, 0x46, 0x41, 0x46, 0xfa, 0xf7, 0x90, 0xfa, 0x00, 0x21, 0xfa, 0xf7, + 0x8b, 0xfb, 0x05, 0x46, 0x04, 0xd2, 0x40, 0x46, 0x31, 0x46, 0xfa, 0xf7, + 0x87, 0xfa, 0x05, 0x46, 0x84, 0x48, 0xff, 0xf7, 0xdf, 0xf9, 0x05, 0x46, + 0x01, 0xf0, 0x90, 0xfa, 0xe1, 0x68, 0x08, 0x63, 0xa6, 0x68, 0xb0, 0x8f, + 0xfa, 0xf7, 0xec, 0xf9, 0x29, 0x46, 0xfa, 0xf7, 0x75, 0xfb, 0x06, 0xd2, + 0x96, 0xf8, 0x3b, 0x10, 0x20, 0x69, 0xfd, 0xf7, 0x1b, 0xff, 0x0e, 0x20, + 0x3c, 0xe0, 0x20, 0x46, 0xfd, 0xf7, 0x69, 0xfe, 0x0b, 0x98, 0xfe, 0xf7, + 0xfd, 0xfc, 0x06, 0x99, 0x08, 0x85, 0x06, 0x98, 0x06, 0x99, 0x40, 0x8d, + 0x09, 0x8d, 0x88, 0x42, 0x38, 0xbf, 0x08, 0x46, 0x06, 0x99, 0x48, 0x85, + 0xa0, 0x68, 0x00, 0x88, 0x40, 0x05, 0x26, 0xd5, 0x05, 0x98, 0x08, 0x9a, + 0x50, 0xf8, 0xd0, 0x1f, 0x92, 0x7e, 0x51, 0x43, 0x64, 0x22, 0x91, 0xfb, + 0xf2, 0xf1, 0x07, 0x9a, 0x91, 0x42, 0x1a, 0xd2, 0x81, 0x89, 0x02, 0x60, + 0xb9, 0x42, 0x38, 0xbf, 0x87, 0x81, 0x05, 0x98, 0x00, 0x25, 0xd0, 0xe9, + 0x08, 0x23, 0xd4, 0x30, 0xc0, 0xe9, 0x00, 0x23, 0x04, 0xeb, 0xc5, 0x00, + 0x00, 0xf1, 0x14, 0x02, 0xd2, 0xe9, 0x00, 0x01, 0x05, 0x9a, 0x02, 0xeb, + 0xc5, 0x02, 0x28, 0x32, 0x6d, 0x1c, 0xc2, 0xe9, 0x00, 0x01, 0x15, 0x2d, + 0xf0, 0xd3, 0x00, 0x20, 0x53, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x40, 0x1a, + 0x12, 0x90, 0xdd, 0xe9, 0x11, 0x01, 0xff, 0xf7, 0x41, 0xb9, 0x50, 0xf8, + 0x26, 0x00, 0x13, 0x90, 0xff, 0xf7, 0x32, 0xb9, 0x54, 0x49, 0xfa, 0xf7, + 0xa3, 0xb9, 0x52, 0x49, 0xfa, 0xf7, 0xa0, 0xb9, 0xdd, 0xe9, 0x16, 0x23, + 0x38, 0x46, 0x49, 0x46, 0xfa, 0xf7, 0x76, 0xbe, 0x41, 0x46, 0xfa, 0xf7, + 0x25, 0xbb, 0x20, 0x46, 0xfd, 0xf7, 0x8f, 0xbd, 0x02, 0x46, 0x04, 0x98, + 0x81, 0x8a, 0x21, 0xa8, 0xff, 0xf7, 0x94, 0xbb, 0x04, 0x98, 0x80, 0x88, + 0xfa, 0xf7, 0x7a, 0xb9, 0x05, 0x99, 0x20, 0x69, 0xfd, 0xf7, 0x9e, 0xbb, + 0x20, 0x69, 0x07, 0x23, 0x1a, 0xaa, 0x21, 0xa9, 0xfd, 0xf7, 0xe2, 0xbc, + 0x01, 0x46, 0x3f, 0x48, 0xfa, 0xf7, 0x81, 0xbd, 0x80, 0xb5, 0x41, 0x68, + 0x02, 0x68, 0x00, 0x92, 0x0b, 0x1d, 0xb1, 0xf9, 0x02, 0x20, 0x09, 0x88, + 0x00, 0x69, 0xfb, 0xf7, 0x56, 0xf8, 0x02, 0xbd, 0x2d, 0xe9, 0xf8, 0x43, + 0x04, 0x46, 0x25, 0x69, 0x26, 0x68, 0xd4, 0xf8, 0x0c, 0x90, 0x88, 0x46, + 0xfd, 0xf7, 0x78, 0xfb, 0x00, 0x27, 0x08, 0xb9, 0x0b, 0x27, 0x30, 0xe0, + 0x00, 0x2d, 0x14, 0xbf, 0x32, 0x48, 0x33, 0x48, 0x01, 0x21, 0x01, 0x60, + 0x2a, 0x46, 0xa3, 0x68, 0x49, 0x46, 0x30, 0x46, 0xfd, 0xf7, 0x35, 0xfe, + 0xb8, 0xf1, 0x00, 0x0f, 0x86, 0xf8, 0xa1, 0x71, 0x03, 0xd1, 0xe0, 0x68, + 0xf3, 0x78, 0x42, 0x8b, 0x15, 0xe0, 0x20, 0x46, 0xff, 0xf7, 0xce, 0xff, + 0x07, 0x00, 0x03, 0xd1, 0x20, 0x68, 0x01, 0x78, 0x5a, 0x29, 0x04, 0xda, + 0xe1, 0x68, 0x00, 0x20, 0x88, 0x83, 0x03, 0x27, 0x0d, 0xe0, 0xe2, 0x68, + 0x51, 0x83, 0x40, 0x78, 0x10, 0x83, 0x01, 0x20, 0x90, 0x83, 0xf3, 0x78, + 0x32, 0x78, 0xa0, 0x68, 0x29, 0x46, 0xfd, 0xf7, 0x6f, 0xfc, 0x01, 0x20, + 0xb0, 0x70, 0x38, 0x46, 0xbd, 0xe8, 0xf2, 0x83, 0x10, 0xb5, 0x00, 0x21, + 0x1a, 0x4a, 0x20, 0xfa, 0x01, 0xf3, 0xdb, 0x07, 0x06, 0xd5, 0x4f, 0xf4, + 0xd4, 0x74, 0x04, 0xfb, 0x01, 0x24, 0x01, 0x23, 0x84, 0xf8, 0xa3, 0x31, + 0x49, 0x1c, 0x02, 0x29, 0xf1, 0xd3, 0x10, 0xbd, 0x10, 0xb5, 0x00, 0x21, + 0x11, 0x4a, 0x20, 0xfa, 0x01, 0xf3, 0xdb, 0x07, 0x06, 0xd5, 0x4f, 0xf4, + 0xd4, 0x74, 0x04, 0xfb, 0x01, 0x24, 0x00, 0x23, 0x84, 0xf8, 0xa3, 0x31, + 0x49, 0x1c, 0x02, 0x29, 0xf1, 0xd3, 0x10, 0xbd, 0xae, 0x47, 0x81, 0x3f, + 0xae, 0x47, 0x81, 0xbf, 0xcb, 0xbe, 0x00, 0x01, 0x00, 0x00, 0xa0, 0x41, + 0x00, 0x00, 0x7a, 0x44, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0xc8, 0x42, + 0x00, 0x00, 0xa0, 0xc1, 0x00, 0x00, 0x50, 0x59, 0x00, 0x00, 0x40, 0x59, + 0x10, 0xb2, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xb4, 0x50, 0xf8, 0x04, 0x1b, 0x79, 0xb1, 0x02, 0x68, 0x43, 0x68, + 0x12, 0x18, 0x08, 0x30, 0xdc, 0x07, 0x44, 0xbf, 0xa9, 0xf1, 0x01, 0x04, + 0xe3, 0x18, 0x52, 0xf8, 0x04, 0x4b, 0x43, 0xf8, 0x04, 0x4b, 0x09, 0x1f, + 0xf9, 0xd1, 0xec, 0xe7, 0x10, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x28, 0x07, 0xda, 0xdf, 0xf8, 0xa0, 0x1c, 0x28, 0x22, 0x02, 0xfb, + 0x00, 0x12, 0xd2, 0xe9, 0x02, 0x01, 0x70, 0x47, 0x00, 0x20, 0x00, 0x21, + 0x70, 0x47, 0xf0, 0xb5, 0xdf, 0xf8, 0x8c, 0x3c, 0x0f, 0xf2, 0x48, 0x05, + 0x1b, 0x68, 0x4f, 0xf4, 0x7a, 0x74, 0x0a, 0x46, 0xb3, 0xfb, 0xf4, 0xf3, + 0x00, 0x21, 0x00, 0x24, 0x42, 0xf2, 0x10, 0x77, 0x15, 0xf8, 0x14, 0x60, + 0x7e, 0x43, 0x9e, 0x42, 0x0d, 0xd3, 0x05, 0xeb, 0x44, 0x04, 0x94, 0xf9, + 0x01, 0x40, 0x00, 0x2c, 0x0a, 0xd4, 0x14, 0x70, 0x03, 0x2c, 0x07, 0xbf, + 0x5a, 0x00, 0x02, 0x60, 0xe3, 0x40, 0x03, 0x60, 0x03, 0xe0, 0x64, 0x1c, + 0x05, 0x2c, 0xe9, 0xd3, 0x04, 0x21, 0x08, 0x46, 0xf0, 0xbd, 0x00, 0x00, + 0x02, 0xff, 0x04, 0x03, 0x08, 0x00, 0x10, 0x01, 0x20, 0x02, 0x00, 0x00, + 0xf8, 0xb5, 0x00, 0x24, 0x00, 0x27, 0x0f, 0xf2, 0xf4, 0x25, 0xdf, 0xf8, + 0x24, 0x6c, 0x28, 0x20, 0x78, 0x43, 0xf9, 0xb2, 0x81, 0x53, 0x80, 0x19, + 0x35, 0xf8, 0x17, 0x20, 0x42, 0x80, 0x01, 0x21, 0x80, 0xf8, 0x27, 0x10, + 0x02, 0xf1, 0x22, 0x00, 0x0e, 0x21, 0x00, 0xf0, 0x70, 0xfb, 0x7f, 0x1c, + 0x04, 0x2f, 0xec, 0xdb, 0xdf, 0xf8, 0xfc, 0x5b, 0x68, 0x89, 0xc0, 0xf3, + 0x81, 0x00, 0x80, 0xb1, 0x00, 0x22, 0x10, 0x21, 0x4f, 0xf4, 0x10, 0x70, + 0xf6, 0xf7, 0xfc, 0xfa, 0x03, 0x22, 0x32, 0x21, 0x00, 0x20, 0x00, 0xf0, + 0x36, 0xfc, 0x04, 0x46, 0x4f, 0xf4, 0x10, 0x70, 0x00, 0xf0, 0x20, 0xfc, + 0xec, 0xb9, 0xa8, 0x7a, 0x03, 0x21, 0x08, 0x42, 0x1a, 0xd0, 0x00, 0x22, + 0x10, 0x21, 0x4f, 0xf4, 0x2c, 0x70, 0xf6, 0xf7, 0xe7, 0xfa, 0x03, 0x22, + 0x32, 0x21, 0x01, 0x20, 0x00, 0xf0, 0x21, 0xfc, 0x04, 0x46, 0x4f, 0xf4, + 0x2c, 0x70, 0x00, 0xf0, 0x0b, 0xfc, 0xa8, 0x69, 0xdf, 0xf8, 0xa8, 0x2b, + 0x40, 0x08, 0x00, 0xf5, 0x43, 0x40, 0x50, 0x30, 0x00, 0x21, 0xc2, 0xe9, + 0x00, 0x01, 0xec, 0xb9, 0x68, 0x89, 0x4f, 0xf4, 0xf8, 0x71, 0x08, 0x42, + 0x18, 0xd0, 0x00, 0x22, 0x10, 0x21, 0x4f, 0xf4, 0x50, 0x70, 0xf6, 0xf7, + 0xc7, 0xfa, 0x03, 0x22, 0x4f, 0xf4, 0xfa, 0x71, 0x02, 0x20, 0x00, 0xf0, + 0x00, 0xfc, 0x04, 0x46, 0x03, 0x22, 0x4f, 0xf4, 0xfa, 0x71, 0x03, 0x20, + 0x00, 0xf0, 0xf9, 0xfb, 0x04, 0xb9, 0x04, 0x46, 0x4f, 0xf4, 0x50, 0x70, + 0x00, 0xf0, 0xe2, 0xfb, 0x20, 0x46, 0xf2, 0xbd, 0x2d, 0xe9, 0xf0, 0x47, + 0x16, 0x46, 0x86, 0xb0, 0x04, 0x46, 0x8a, 0x46, 0x35, 0x88, 0x06, 0xf1, + 0x10, 0x01, 0x02, 0xa8, 0xff, 0xf7, 0x55, 0xff, 0x00, 0x28, 0x42, 0xd1, + 0x30, 0x7c, 0x0f, 0xf6, 0x44, 0x51, 0x00, 0xf0, 0x03, 0x00, 0x80, 0x00, + 0x40, 0xf0, 0x13, 0x00, 0x30, 0x74, 0x00, 0x27, 0x4f, 0xf4, 0x7a, 0x70, + 0x51, 0xf8, 0x27, 0x20, 0xa0, 0xfb, 0x02, 0x89, 0xca, 0x45, 0x05, 0xd3, + 0x01, 0xd8, 0x44, 0x45, 0x02, 0xd3, 0x7f, 0x1c, 0x08, 0x2f, 0xf3, 0xd3, + 0x00, 0x2f, 0x18, 0xbf, 0x08, 0x2f, 0x25, 0xd0, 0xc7, 0xf1, 0x07, 0x07, + 0x02, 0x22, 0xba, 0x40, 0xd3, 0x17, 0xa4, 0xfb, 0x02, 0x89, 0x04, 0xfb, + 0x03, 0x99, 0x0a, 0xfb, 0x02, 0x99, 0xcd, 0xe9, 0x04, 0x89, 0x77, 0x74, + 0x00, 0x27, 0x0f, 0xf6, 0x64, 0x31, 0xdd, 0xe9, 0x04, 0x23, 0xcd, 0xe9, + 0x00, 0x23, 0x51, 0xf8, 0x27, 0x80, 0xa0, 0xfb, 0x08, 0x23, 0xdd, 0xe9, + 0x00, 0x89, 0x99, 0x45, 0x04, 0xd8, 0x2e, 0xbf, 0x90, 0x45, 0x7f, 0x1c, + 0x34, 0x2f, 0xee, 0xd3, 0x78, 0x1c, 0x01, 0xd0, 0x36, 0x28, 0x01, 0xd3, + 0x04, 0x20, 0x8c, 0xe0, 0x00, 0x27, 0x0f, 0xf6, 0xdc, 0x41, 0x7a, 0x5c, + 0x82, 0x42, 0x3c, 0xbf, 0x7f, 0x1c, 0x07, 0x2f, 0xf9, 0xd3, 0xc7, 0xf1, + 0x0d, 0x01, 0x41, 0xf0, 0x40, 0x01, 0xb1, 0x74, 0xa0, 0xf1, 0x1e, 0x01, + 0x05, 0x29, 0x34, 0xbf, 0xc2, 0x22, 0xc1, 0x22, 0xf2, 0x74, 0x08, 0x28, + 0x38, 0xbf, 0x04, 0x22, 0x06, 0xd3, 0x11, 0x28, 0x38, 0xbf, 0x06, 0x22, + 0x02, 0xd3, 0x07, 0x22, 0x1a, 0x28, 0x05, 0xd0, 0x08, 0x29, 0x03, 0xd3, + 0x28, 0x28, 0x01, 0xd0, 0x2c, 0x28, 0x01, 0xd3, 0x03, 0x21, 0x00, 0xe0, + 0x02, 0x21, 0x42, 0xea, 0xc1, 0x01, 0x31, 0x75, 0x0f, 0xf6, 0xa0, 0x21, + 0x41, 0x18, 0x11, 0xf8, 0x01, 0x1c, 0x01, 0xf0, 0x0f, 0x01, 0xc9, 0x00, + 0x71, 0x75, 0x1e, 0x28, 0x38, 0xbf, 0x0c, 0x21, 0x03, 0xd3, 0x23, 0x28, + 0x34, 0xbf, 0x0d, 0x21, 0x0e, 0x21, 0xb1, 0x75, 0xd4, 0x22, 0xdf, 0xf8, + 0x38, 0x1a, 0xdf, 0xf8, 0x38, 0x7a, 0x02, 0xfb, 0x05, 0x11, 0x01, 0xeb, + 0x80, 0x00, 0x00, 0x21, 0x50, 0xf8, 0x04, 0x0c, 0x0f, 0xf6, 0x20, 0x42, + 0xc6, 0xf8, 0x17, 0x00, 0x00, 0x20, 0x12, 0xf8, 0x11, 0x30, 0xa7, 0xfb, + 0x03, 0x89, 0xd1, 0x45, 0x06, 0xd8, 0x28, 0xbf, 0xa0, 0x45, 0x03, 0xd2, + 0x49, 0x1c, 0x04, 0x29, 0xf3, 0xd3, 0x02, 0xe0, 0x02, 0xeb, 0x41, 0x00, + 0x40, 0x78, 0xf0, 0x76, 0x4f, 0xf4, 0x7a, 0x71, 0x02, 0x98, 0x01, 0xfb, + 0x00, 0xf4, 0xdd, 0xe9, 0x04, 0x01, 0x00, 0xf0, 0xe9, 0xfc, 0xdd, 0xe9, + 0x04, 0x23, 0x07, 0x46, 0x04, 0xfb, 0x10, 0x20, 0xdf, 0xf8, 0xe0, 0x19, + 0xa1, 0xfb, 0x00, 0x01, 0x00, 0xf0, 0xde, 0xfc, 0x40, 0x1c, 0x40, 0x08, + 0xdf, 0xf8, 0xd4, 0x19, 0x88, 0x42, 0x06, 0xf1, 0x21, 0x01, 0x04, 0xbf, + 0x00, 0x20, 0x7f, 0x1c, 0x0f, 0x70, 0x3f, 0x04, 0x3a, 0x0e, 0x02, 0xf0, + 0x03, 0x02, 0x4a, 0x70, 0xb0, 0x77, 0x01, 0x0a, 0x00, 0x0c, 0x00, 0xf0, + 0x7f, 0x00, 0x86, 0xf8, 0x20, 0x00, 0xf1, 0x77, 0x00, 0x20, 0x06, 0xb0, + 0xbd, 0xe8, 0xf0, 0x87, 0x70, 0xb5, 0x04, 0x46, 0x0f, 0xf2, 0x50, 0x00, + 0x30, 0xf8, 0x14, 0x60, 0x4f, 0xf4, 0x96, 0x71, 0x02, 0x20, 0xf9, 0xf7, + 0x53, 0xfe, 0x00, 0x25, 0x06, 0xf1, 0x8c, 0x46, 0x30, 0x78, 0xc0, 0x07, + 0x04, 0xd5, 0x02, 0x20, 0xf9, 0xf7, 0x62, 0xfe, 0x00, 0x28, 0xf7, 0xd0, + 0x30, 0x78, 0xc0, 0x07, 0x0d, 0xd4, 0x20, 0x46, 0x00, 0xf0, 0x92, 0xf9, + 0x20, 0xb9, 0x02, 0x20, 0xf9, 0xf7, 0x56, 0xfe, 0x00, 0x28, 0xf6, 0xd0, + 0x20, 0x46, 0x00, 0xf0, 0x89, 0xf9, 0x00, 0xb1, 0x01, 0x25, 0x02, 0x20, + 0xf9, 0xf7, 0xc4, 0xfd, 0x28, 0x46, 0x70, 0xbd, 0x40, 0x02, 0xb0, 0x02, + 0x40, 0x03, 0x40, 0x03, 0x2d, 0xe9, 0xf0, 0x4d, 0x80, 0x46, 0x8a, 0x46, + 0x15, 0x46, 0xdf, 0xf8, 0x20, 0x09, 0xdf, 0xf8, 0x38, 0x29, 0x28, 0x21, + 0x01, 0xfb, 0x05, 0x06, 0x00, 0x20, 0x01, 0x23, 0x9a, 0x45, 0x04, 0xd3, + 0x01, 0xd8, 0x90, 0x45, 0x01, 0xd3, 0x02, 0x20, 0x06, 0xe0, 0x82, 0x45, + 0xdf, 0xf8, 0x1c, 0x29, 0x01, 0xd8, 0x90, 0x45, 0x00, 0xd3, 0x01, 0x20, + 0xdf, 0xf8, 0x14, 0x19, 0xdf, 0xf8, 0xf0, 0x28, 0x47, 0x18, 0x20, 0x31, + 0x05, 0xb3, 0x02, 0x2d, 0x3b, 0xd0, 0x62, 0xd2, 0x93, 0x7a, 0x12, 0x7b, + 0x08, 0x70, 0x02, 0xf0, 0x01, 0x0b, 0x3a, 0x78, 0x03, 0xf0, 0x03, 0x04, + 0x3f, 0x21, 0x4f, 0xf4, 0x01, 0x60, 0xf6, 0xf7, 0x6d, 0xf9, 0xba, 0x79, + 0x3f, 0x21, 0x40, 0xf6, 0x11, 0x00, 0xf6, 0xf7, 0x67, 0xf9, 0xfa, 0x78, + 0x3f, 0x21, 0x40, 0xf6, 0x12, 0x00, 0xf6, 0xf7, 0x61, 0xf9, 0x7a, 0x7a, + 0x3f, 0x21, 0x40, 0xf6, 0x13, 0x00, 0x2f, 0xe0, 0x50, 0x89, 0xc0, 0xf3, + 0x81, 0x04, 0x10, 0x7b, 0x3a, 0x78, 0x00, 0xf0, 0x02, 0x0b, 0x3f, 0x21, + 0x4f, 0xf4, 0xa4, 0x60, 0xf6, 0xf7, 0x50, 0xf9, 0xba, 0x79, 0x3f, 0x21, + 0x40, 0xf2, 0x21, 0x50, 0xf6, 0xf7, 0x4a, 0xf9, 0xfa, 0x78, 0x3f, 0x21, + 0x40, 0xf2, 0x22, 0x50, 0xf6, 0xf7, 0x44, 0xf9, 0x7a, 0x7a, 0x3f, 0x21, + 0x40, 0xf2, 0x23, 0x50, 0x12, 0xe0, 0x52, 0x89, 0x12, 0xf4, 0xf8, 0x72, + 0x14, 0x46, 0x18, 0xbf, 0x01, 0x24, 0x48, 0x70, 0x3f, 0x21, 0x3a, 0x7b, + 0x40, 0xf6, 0x1e, 0x00, 0xf6, 0xf7, 0x32, 0xf9, 0xfa, 0x7b, 0x4f, 0xf0, + 0x00, 0x0b, 0x3f, 0x21, 0x40, 0xf6, 0x1f, 0x00, 0xf6, 0xf7, 0x2a, 0xf9, + 0x00, 0x20, 0xc6, 0xe9, 0x02, 0x00, 0x4f, 0xf0, 0xff, 0x31, 0xdf, 0xf8, + 0x5c, 0x08, 0x18, 0xeb, 0x00, 0x02, 0x4a, 0xeb, 0x01, 0x03, 0x01, 0x21, + 0x8b, 0x42, 0xdf, 0xf8, 0x50, 0x08, 0x04, 0xd3, 0x01, 0xd8, 0x82, 0x42, + 0x01, 0xd3, 0x05, 0x20, 0x4b, 0xe0, 0x0c, 0xb9, 0x05, 0x27, 0x47, 0xe0, + 0x32, 0x46, 0x40, 0x46, 0x51, 0x46, 0xff, 0xf7, 0x5b, 0xfe, 0x07, 0x00, + 0x6e, 0xd1, 0x74, 0x88, 0xbb, 0xf1, 0x00, 0x0f, 0x3f, 0xd0, 0x01, 0x2d, + 0x1a, 0xd1, 0x80, 0x21, 0x40, 0xf2, 0x02, 0x20, 0xf6, 0xf7, 0xf6, 0xf8, + 0x01, 0x21, 0x4f, 0xf4, 0x40, 0x70, 0xf6, 0xf7, 0xf1, 0xf8, 0x10, 0x21, + 0x40, 0xf2, 0xca, 0x20, 0xf6, 0xf7, 0xec, 0xf8, 0xf2, 0x7e, 0x1f, 0x21, + 0x40, 0xf6, 0x15, 0x00, 0xf6, 0xf7, 0xf0, 0xf8, 0x40, 0x46, 0x51, 0x46, + 0x00, 0xf0, 0x52, 0xf8, 0x07, 0x46, 0x14, 0xe0, 0x80, 0x21, 0x4f, 0xf4, + 0x00, 0x70, 0xf6, 0xf7, 0xdb, 0xf8, 0x01, 0x21, 0x4f, 0xf4, 0x24, 0x70, + 0xf6, 0xf7, 0xd6, 0xf8, 0x10, 0x21, 0x40, 0xf2, 0x5a, 0x20, 0xf6, 0xf7, + 0xd1, 0xf8, 0xf2, 0x7e, 0x1f, 0x21, 0x40, 0xf2, 0x25, 0x50, 0xf6, 0xf7, + 0xd5, 0xf8, 0x04, 0xf1, 0x42, 0x00, 0x07, 0x21, 0x00, 0xf0, 0x35, 0xf9, + 0x27, 0xb9, 0xc6, 0xe9, 0x02, 0x8a, 0x28, 0x46, 0xfa, 0xf7, 0x66, 0xfe, + 0x38, 0x46, 0xbd, 0xe8, 0xf0, 0x8d, 0x00, 0x21, 0x30, 0x46, 0x00, 0xf0, + 0xaf, 0xf8, 0x28, 0x46, 0xff, 0xf7, 0xf0, 0xfe, 0x08, 0xb9, 0x07, 0x27, + 0xf2, 0xe7, 0x04, 0xf1, 0x08, 0x00, 0x80, 0xb2, 0x00, 0xf1, 0x8c, 0x40, + 0x00, 0x78, 0x00, 0xf0, 0xfd, 0x00, 0x70, 0x75, 0xe0, 0x1d, 0x80, 0xb2, + 0x00, 0xf1, 0x8c, 0x40, 0x00, 0x78, 0x30, 0x77, 0xa0, 0x1d, 0x80, 0xb2, + 0x00, 0xf1, 0x8c, 0x40, 0x01, 0x2d, 0x00, 0x78, 0x00, 0xf0, 0x7f, 0x00, + 0x70, 0x77, 0xd4, 0xd1, 0x40, 0x46, 0x51, 0x46, 0x00, 0xf0, 0x06, 0xf8, + 0x07, 0x46, 0x00, 0xf0, 0x64, 0xf8, 0xcb, 0xe7, 0x06, 0x27, 0xcf, 0xe7, + 0x2d, 0xe9, 0xf0, 0x42, 0xdf, 0xf8, 0x20, 0x47, 0xdf, 0xf8, 0x44, 0x77, + 0xd4, 0xe9, 0x00, 0x23, 0x00, 0x26, 0x84, 0x18, 0x41, 0xeb, 0x03, 0x09, + 0x01, 0x25, 0xa9, 0x45, 0x05, 0xd3, 0x01, 0xd8, 0xbc, 0x42, 0x02, 0xd3, + 0x84, 0x1a, 0x61, 0xeb, 0x03, 0x09, 0xdf, 0xf8, 0xf4, 0x56, 0x05, 0xf1, + 0x80, 0x07, 0xd7, 0xe9, 0x00, 0x01, 0x89, 0x45, 0x08, 0xbf, 0x84, 0x42, + 0x22, 0xd0, 0xc7, 0xe9, 0x00, 0x66, 0x05, 0xf1, 0x78, 0x02, 0x20, 0x46, + 0x49, 0x46, 0xff, 0xf7, 0xc1, 0xfd, 0x06, 0x00, 0x18, 0xd1, 0x00, 0x21, + 0x05, 0xf1, 0x78, 0x00, 0x00, 0xf0, 0x58, 0xf8, 0x02, 0x20, 0xff, 0xf7, + 0x99, 0xfe, 0x70, 0xb1, 0xdf, 0xf8, 0xec, 0x06, 0x81, 0x78, 0x01, 0xf0, + 0xfd, 0x01, 0x79, 0x73, 0x41, 0x78, 0x39, 0x75, 0x00, 0x78, 0xc7, 0xe9, + 0x00, 0x49, 0x00, 0xf0, 0x7f, 0x00, 0x78, 0x75, 0x00, 0xe0, 0x04, 0x26, + 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x82, 0xdf, 0xf8, 0x94, 0x06, 0x10, 0xb5, + 0xd0, 0xe9, 0x20, 0x23, 0x00, 0x24, 0x00, 0x2b, 0x08, 0xbf, 0x00, 0x2a, + 0x0b, 0xd0, 0x01, 0x21, 0x78, 0x30, 0x00, 0xf0, 0xaf, 0xf8, 0x04, 0x46, + 0x32, 0x20, 0xf9, 0xf7, 0x7d, 0xfc, 0xdf, 0xf8, 0xa8, 0x16, 0x01, 0x20, + 0x08, 0x60, 0x20, 0x46, 0x10, 0xbd, 0xdf, 0xf8, 0x9c, 0x06, 0x00, 0x68, + 0x70, 0x47, 0x38, 0xb5, 0xdf, 0xf8, 0x58, 0x26, 0x04, 0x20, 0xd2, 0xe9, + 0x16, 0x45, 0x00, 0x2d, 0x08, 0xbf, 0x00, 0x2c, 0x0b, 0xd0, 0x01, 0x21, + 0x02, 0xf1, 0x50, 0x00, 0x00, 0xf0, 0x16, 0xf8, 0x32, 0x20, 0xf9, 0xf7, + 0x61, 0xfc, 0xdf, 0xf8, 0x70, 0x16, 0x00, 0x20, 0x08, 0x60, 0x32, 0xbd, + 0x30, 0xb1, 0x01, 0x28, 0x0c, 0xbf, 0xdf, 0xf8, 0x64, 0x06, 0xdf, 0xf8, + 0x64, 0x06, 0x01, 0xe0, 0xdf, 0xf8, 0x60, 0x06, 0x00, 0x78, 0x00, 0xf0, + 0x01, 0x00, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x41, 0x07, 0x46, 0xbc, 0x1c, + 0x88, 0x46, 0x25, 0x88, 0xb5, 0xf5, 0x10, 0x7f, 0x0c, 0xd0, 0xb5, 0xf5, + 0x2c, 0x7f, 0xa1, 0x7b, 0x14, 0xd1, 0x40, 0xf2, 0x32, 0x20, 0xf5, 0xf7, + 0xf9, 0xff, 0x62, 0x7e, 0x1f, 0x21, 0x40, 0xf6, 0x15, 0x00, 0x08, 0xe0, + 0xa1, 0x7b, 0x4f, 0xf4, 0x0c, 0x70, 0xf5, 0xf7, 0xef, 0xff, 0x62, 0x7e, + 0x1f, 0x21, 0x40, 0xf2, 0x25, 0x50, 0xf5, 0xf7, 0xf3, 0xff, 0x03, 0xe0, + 0x40, 0xf2, 0x33, 0x20, 0xf5, 0xf7, 0xe4, 0xff, 0x39, 0x46, 0x00, 0x20, + 0x00, 0xf0, 0xd3, 0xf8, 0x17, 0xf8, 0x22, 0x2f, 0xa8, 0x1c, 0x07, 0x21, + 0x80, 0xb2, 0xf5, 0xf7, 0xe3, 0xff, 0xe1, 0x7f, 0x68, 0x1c, 0x00, 0xf0, + 0x44, 0xf8, 0xe1, 0x7b, 0x05, 0xf1, 0x42, 0x00, 0x00, 0xf0, 0x3f, 0xf8, + 0x78, 0x79, 0x28, 0xb1, 0x4f, 0xf4, 0xfa, 0x60, 0xf9, 0xf7, 0x0e, 0xfc, + 0x00, 0x20, 0x78, 0x71, 0xae, 0x1d, 0xb8, 0xf1, 0x00, 0x0f, 0x05, 0xf1, + 0x08, 0x07, 0x12, 0xd1, 0x80, 0x22, 0x80, 0x21, 0xb0, 0xb2, 0xf5, 0xf7, + 0xc7, 0xff, 0x00, 0x22, 0x80, 0x21, 0xb0, 0xb2, 0xf5, 0xf7, 0xc2, 0xff, + 0x00, 0x22, 0x02, 0x21, 0xb8, 0xb2, 0xf5, 0xf7, 0xbd, 0xff, 0x01, 0x22, + 0x01, 0x21, 0x28, 0x46, 0x18, 0xe0, 0x00, 0xf0, 0x99, 0xf8, 0xf5, 0xf7, + 0xb5, 0xff, 0xe0, 0x7e, 0x40, 0xf0, 0x80, 0x01, 0xb0, 0xb2, 0xf5, 0xf7, + 0xa5, 0xff, 0xa1, 0x7e, 0xe8, 0x1d, 0x00, 0xf0, 0x10, 0xf8, 0x00, 0xf0, + 0x84, 0xf8, 0xb8, 0xb2, 0xf5, 0xf7, 0xa6, 0xff, 0x01, 0x20, 0xf9, 0xf7, + 0xdd, 0xfb, 0x00, 0x22, 0x00, 0xf0, 0x85, 0xf8, 0xf5, 0xf7, 0x9e, 0xff, + 0x00, 0x20, 0xbd, 0xe8, 0xf0, 0x81, 0x80, 0xb2, 0xf5, 0xf7, 0x8e, 0xbf, + 0x2d, 0xe9, 0xf0, 0x41, 0x06, 0x46, 0xb4, 0x1c, 0x88, 0x46, 0x25, 0x88, + 0xb5, 0xf5, 0x10, 0x7f, 0x40, 0xf6, 0x15, 0x07, 0x08, 0xd0, 0xa1, 0x7b, + 0xb5, 0xf5, 0x2c, 0x7f, 0x0c, 0xbf, 0x40, 0xf2, 0x32, 0x20, 0x40, 0xf2, + 0x33, 0x20, 0x09, 0xe0, 0xa1, 0x7b, 0x4f, 0xf4, 0x0c, 0x70, 0xf8, 0xf7, + 0x2a, 0xf9, 0x62, 0x7e, 0x1f, 0x21, 0x40, 0xf2, 0x25, 0x50, 0x04, 0xe0, + 0xf8, 0xf7, 0x23, 0xf9, 0x62, 0x7e, 0x1f, 0x21, 0x38, 0x46, 0xf8, 0xf7, + 0x45, 0xf9, 0x31, 0x46, 0x01, 0x20, 0x00, 0xf0, 0x58, 0xf8, 0x96, 0xf8, + 0x22, 0x20, 0xa8, 0x1c, 0x07, 0x21, 0x80, 0xb2, 0xf8, 0xf7, 0x3a, 0xf9, + 0xe1, 0x7f, 0x68, 0x1c, 0x80, 0xb2, 0xf8, 0xf7, 0x0e, 0xf9, 0xe1, 0x7b, + 0x05, 0xf1, 0x42, 0x00, 0x80, 0xb2, 0xf8, 0xf7, 0x08, 0xf9, 0xaf, 0x1d, + 0xb8, 0xf1, 0x00, 0x0f, 0x05, 0xf1, 0x08, 0x06, 0x12, 0xd1, 0x80, 0x22, + 0x80, 0x21, 0xb8, 0xb2, 0xf8, 0xf7, 0x24, 0xf9, 0x00, 0x22, 0x80, 0x21, + 0xb8, 0xb2, 0xf8, 0xf7, 0x1f, 0xf9, 0x00, 0x22, 0x02, 0x21, 0xb0, 0xb2, + 0xf8, 0xf7, 0x1a, 0xf9, 0x01, 0x22, 0x01, 0x21, 0x28, 0x46, 0x19, 0xe0, + 0x00, 0xf0, 0x24, 0xf8, 0xf8, 0xf7, 0x12, 0xf9, 0xe0, 0x7e, 0x40, 0xf0, + 0x80, 0x01, 0xb8, 0xb2, 0xf8, 0xf7, 0xe5, 0xf8, 0xa1, 0x7e, 0xe8, 0x1d, + 0x80, 0xb2, 0xf8, 0xf7, 0xe0, 0xf8, 0x00, 0xf0, 0x0e, 0xf8, 0xb0, 0xb2, + 0xf8, 0xf7, 0x02, 0xf9, 0x01, 0x20, 0xf9, 0xf7, 0x67, 0xfb, 0x00, 0x22, + 0x00, 0xf0, 0x0f, 0xf8, 0xf8, 0xf7, 0xfa, 0xf8, 0x04, 0x20, 0xbd, 0xe8, + 0xf0, 0x81, 0xe0, 0x7c, 0x00, 0xf0, 0x01, 0x00, 0x40, 0xf0, 0x02, 0x02, + 0x03, 0x21, 0x70, 0x47, 0x05, 0xf1, 0x13, 0x08, 0x80, 0x22, 0x80, 0x21, + 0x1f, 0xfa, 0x88, 0xf0, 0x70, 0x47, 0xb0, 0xb5, 0x88, 0xb0, 0x04, 0x46, + 0x0d, 0x46, 0x68, 0x46, 0x0f, 0xf2, 0x48, 0x61, 0x20, 0x22, 0xfc, 0xf7, + 0x3b, 0xfd, 0xa8, 0x7c, 0x8d, 0xf8, 0x01, 0x00, 0x00, 0x27, 0xe8, 0x7c, + 0x8d, 0xf8, 0x03, 0x00, 0x28, 0x7d, 0x8d, 0xf8, 0x05, 0x00, 0x68, 0x7d, + 0x8d, 0xf8, 0x07, 0x00, 0xa8, 0x7d, 0x8d, 0xf8, 0x0b, 0x00, 0xe8, 0x7d, + 0x8d, 0xf8, 0x0f, 0x00, 0x28, 0x7e, 0x8d, 0xf8, 0x11, 0x00, 0x68, 0x7e, + 0x8d, 0xf8, 0x13, 0x00, 0xa8, 0x7e, 0x8d, 0xf8, 0x15, 0x00, 0xa8, 0x7f, + 0x8d, 0xf8, 0x19, 0x00, 0xe8, 0x7f, 0x8d, 0xf8, 0x1b, 0x00, 0x95, 0xf8, + 0x20, 0x00, 0x8d, 0xf8, 0x1d, 0x00, 0x68, 0x88, 0x1d, 0xf8, 0x17, 0x10, + 0x08, 0x18, 0x69, 0x46, 0x01, 0xeb, 0x47, 0x01, 0x01, 0x2c, 0x49, 0x78, + 0x80, 0xb2, 0x02, 0xd1, 0xf8, 0xf7, 0x85, 0xf8, 0x01, 0xe0, 0xf5, 0xf7, + 0xcd, 0xfe, 0x7f, 0x1c, 0x0f, 0x2f, 0xec, 0xd3, 0x08, 0xb0, 0xb0, 0xbd, + 0x70, 0xb5, 0x04, 0x46, 0x00, 0x25, 0x0f, 0xf2, 0xe4, 0x56, 0x06, 0xeb, + 0x45, 0x00, 0x41, 0x78, 0x16, 0xf8, 0x15, 0x00, 0x00, 0x19, 0xff, 0xf7, + 0x2a, 0xff, 0x6d, 0x1c, 0x14, 0x2d, 0xf4, 0xd3, 0x70, 0xbd, 0x03, 0x46, + 0x06, 0x20, 0x04, 0x2b, 0x00, 0xdb, 0x70, 0x47, 0x10, 0xb5, 0x0f, 0xf2, + 0xe4, 0x54, 0x34, 0xf8, 0x13, 0x40, 0xa1, 0x42, 0x22, 0xbf, 0x0f, 0xf2, + 0xe0, 0x54, 0x34, 0xf8, 0x13, 0x40, 0x8c, 0x42, 0x14, 0xd3, 0x0f, 0xf2, + 0xdc, 0x54, 0x1c, 0x5d, 0xa2, 0x42, 0x22, 0xbf, 0x0f, 0xf2, 0xd4, 0x54, + 0x1c, 0x5d, 0x94, 0x42, 0x0a, 0xd3, 0xcd, 0x48, 0x28, 0x24, 0x04, 0xfb, + 0x03, 0x00, 0x00, 0xf1, 0x24, 0x03, 0x19, 0x80, 0x9a, 0x70, 0xbd, 0xe8, + 0x10, 0x40, 0x0b, 0xe0, 0x10, 0xbd, 0x10, 0xb5, 0xc6, 0x4b, 0x28, 0x24, + 0x04, 0xfb, 0x00, 0x30, 0x30, 0xf8, 0x24, 0x3f, 0x0b, 0x80, 0x80, 0x78, + 0x10, 0x70, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, 0x04, 0x46, 0x89, 0xb0, + 0x20, 0x78, 0x0f, 0xf2, 0x98, 0x58, 0x0f, 0xf2, 0x80, 0x39, 0x07, 0x90, + 0x04, 0xf1, 0x10, 0x01, 0x06, 0xa8, 0xff, 0xf7, 0x2e, 0xfb, 0xc0, 0xb2, + 0x00, 0x25, 0x00, 0x28, 0x55, 0xd1, 0x59, 0xf8, 0x25, 0x00, 0x06, 0x99, + 0xb0, 0xfb, 0xf1, 0xfb, 0x0f, 0xf2, 0x74, 0x40, 0x30, 0xf8, 0x15, 0xa0, + 0x0f, 0xf2, 0x18, 0x30, 0x00, 0x68, 0x03, 0x90, 0x00, 0x27, 0x03, 0xa8, + 0x02, 0x90, 0x08, 0xeb, 0x87, 0x06, 0x04, 0xa8, 0x01, 0x90, 0xcd, 0xf8, + 0x00, 0xa0, 0x72, 0x78, 0x31, 0x78, 0x5b, 0x46, 0x20, 0x46, 0x00, 0xf0, + 0x3d, 0xf8, 0xf1, 0x78, 0x01, 0x29, 0x05, 0xd1, 0xbd, 0xf8, 0x0c, 0x10, + 0xb2, 0x78, 0x91, 0x42, 0x07, 0xd1, 0x09, 0xe0, 0x02, 0x29, 0x02, 0xbf, + 0xbd, 0xf8, 0x0e, 0x10, 0xb2, 0x78, 0x91, 0x42, 0x02, 0xd0, 0x7f, 0x1c, + 0x04, 0x2f, 0xde, 0xd3, 0x10, 0xbb, 0x07, 0x9a, 0xa2, 0x49, 0xd4, 0x23, + 0x03, 0xfb, 0x02, 0x11, 0x9d, 0xf8, 0x15, 0x20, 0x01, 0xeb, 0x85, 0x01, + 0x02, 0xf0, 0x3f, 0x02, 0x0a, 0x70, 0x9d, 0xf8, 0x10, 0x30, 0x9d, 0xf8, + 0x11, 0x20, 0x03, 0xf0, 0x0f, 0x03, 0x43, 0xea, 0x02, 0x12, 0x4a, 0x70, + 0x9d, 0xf8, 0x12, 0x30, 0x9d, 0xf8, 0x13, 0x20, 0x03, 0xf0, 0x0f, 0x03, + 0x43, 0xea, 0x02, 0x12, 0x8a, 0x70, 0x9d, 0xf8, 0x14, 0x20, 0x02, 0xf0, + 0x0f, 0x02, 0xca, 0x70, 0x6d, 0x1c, 0x35, 0x2d, 0xa7, 0xd3, 0x09, 0xb0, + 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xfe, 0x4f, 0x9c, 0xb0, 0x04, 0x46, + 0x04, 0xa8, 0x28, 0x21, 0xfa, 0xf7, 0x7e, 0xfb, 0x12, 0xa8, 0x28, 0x21, + 0xfa, 0xf7, 0x7a, 0xfb, 0x04, 0xf1, 0x24, 0x00, 0x4f, 0xf4, 0x7a, 0x72, + 0x01, 0x88, 0x0f, 0xf2, 0x6c, 0x3b, 0x51, 0x43, 0x93, 0x4a, 0xa2, 0xfb, + 0x01, 0x23, 0x12, 0x0c, 0x42, 0xea, 0x03, 0x42, 0x1b, 0x0c, 0xcd, 0xe9, + 0x00, 0x23, 0x84, 0x78, 0xdd, 0xe9, 0x00, 0x01, 0x00, 0x23, 0x22, 0x46, + 0xfa, 0xf7, 0x22, 0xf8, 0xcd, 0xe9, 0x10, 0x01, 0x4f, 0xf0, 0x00, 0x09, + 0xdd, 0xe9, 0x00, 0x01, 0xa4, 0xfb, 0x00, 0x23, 0x04, 0xfb, 0x01, 0x33, + 0xcd, 0xe9, 0x02, 0x23, 0xdd, 0xe9, 0x02, 0x01, 0x89, 0x00, 0x41, 0xea, + 0x90, 0x71, 0x80, 0x00, 0xcd, 0xe9, 0x0e, 0x01, 0xca, 0x46, 0x3f, 0x27, + 0x0c, 0x97, 0xdd, 0xe9, 0x00, 0x45, 0x1e, 0x9a, 0x28, 0x9b, 0xa2, 0xfb, + 0x04, 0x01, 0x02, 0xfb, 0x05, 0x11, 0x3a, 0x46, 0x5a, 0x43, 0x00, 0xf0, + 0xce, 0xf8, 0xdd, 0xe9, 0x10, 0x45, 0x0a, 0x90, 0x02, 0x46, 0xa2, 0xfb, + 0x04, 0x68, 0x02, 0xfb, 0x05, 0x88, 0xcd, 0xe9, 0x04, 0x68, 0x14, 0x46, + 0x50, 0x08, 0xdd, 0xe9, 0x02, 0x23, 0xa2, 0xfb, 0x04, 0x68, 0x03, 0xfb, + 0x04, 0x88, 0xdd, 0xe9, 0x04, 0x23, 0xb2, 0x1a, 0x68, 0xeb, 0x03, 0x03, + 0xcd, 0xe9, 0x06, 0x23, 0x0b, 0x90, 0xdd, 0xe9, 0x0e, 0x23, 0xa0, 0xfb, + 0x02, 0x45, 0x00, 0xfb, 0x03, 0x55, 0xcd, 0xe9, 0x08, 0x45, 0x00, 0x22, + 0x04, 0xab, 0x0a, 0xac, 0x00, 0x25, 0x0b, 0xeb, 0x05, 0x1e, 0xd3, 0xe9, + 0x00, 0x01, 0xde, 0xe9, 0x02, 0x68, 0x41, 0x45, 0x0c, 0xd3, 0x01, 0xd8, + 0xb0, 0x42, 0x09, 0xd3, 0x0b, 0xeb, 0x05, 0x1c, 0xdc, 0xe9, 0x00, 0x68, + 0x88, 0x45, 0x03, 0xd3, 0x01, 0xd8, 0x86, 0x42, 0x00, 0xd3, 0x52, 0x1c, + 0x08, 0x33, 0x6d, 0x1c, 0x03, 0x2d, 0xe6, 0xd3, 0x00, 0x20, 0x0f, 0xf2, + 0xb0, 0x23, 0x21, 0x68, 0x53, 0xf8, 0x30, 0x30, 0x99, 0x42, 0x21, 0xbf, + 0x0f, 0xf2, 0xa0, 0x23, 0x03, 0xeb, 0xc0, 0x03, 0x5b, 0x68, 0x8b, 0x42, + 0x28, 0xbf, 0x52, 0x1c, 0x24, 0x1d, 0x40, 0x1c, 0x02, 0x28, 0xec, 0xd3, + 0xad, 0xf8, 0x34, 0x20, 0x92, 0xb2, 0xbd, 0xf9, 0x70, 0x10, 0x8a, 0x42, + 0x18, 0xda, 0xbd, 0xf9, 0x74, 0x10, 0x8a, 0x42, 0x07, 0xdb, 0x91, 0x46, + 0x12, 0xa8, 0x04, 0xa9, 0x28, 0x22, 0xfc, 0xf7, 0xa5, 0xfb, 0xad, 0xf8, + 0x6e, 0x90, 0x7f, 0x1e, 0x01, 0x2f, 0x89, 0xda, 0xbd, 0xf9, 0x74, 0x00, + 0x81, 0x45, 0x0d, 0xdb, 0x29, 0x99, 0x12, 0xa8, 0x00, 0xf0, 0x10, 0xf8, + 0x1b, 0x98, 0x04, 0xe0, 0x29, 0x99, 0x04, 0xa8, 0x00, 0xf0, 0x0a, 0xf8, + 0x0d, 0x98, 0x2a, 0x99, 0x08, 0x60, 0x01, 0xe0, 0x4f, 0xf0, 0x05, 0x0a, + 0x50, 0x46, 0x1f, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xf0, 0x43, + 0x00, 0xf1, 0x18, 0x04, 0x05, 0x46, 0x00, 0x6a, 0x0f, 0xf2, 0x20, 0x29, + 0x48, 0x71, 0xce, 0x1c, 0x88, 0x46, 0x00, 0x27, 0x09, 0xeb, 0xc7, 0x00, + 0x22, 0x68, 0x41, 0x68, 0x91, 0x42, 0x38, 0xbf, 0x0f, 0x20, 0x0d, 0xd3, + 0x59, 0xf8, 0x37, 0x10, 0x91, 0x42, 0x28, 0xbf, 0x00, 0x20, 0x07, 0xd2, + 0x40, 0x68, 0x41, 0x0c, 0xc0, 0x03, 0x00, 0xf0, 0x2e, 0xf8, 0xc0, 0xf5, + 0x04, 0x20, 0xc0, 0x0b, 0x24, 0x1d, 0x7f, 0x1c, 0x02, 0x2f, 0x06, 0xf8, + 0x01, 0x0b, 0xe3, 0xd3, 0x00, 0x24, 0x0f, 0xf2, 0xac, 0x16, 0x06, 0xeb, + 0x04, 0x1e, 0xd5, 0xe9, 0x00, 0x23, 0xde, 0xe9, 0x02, 0x01, 0x8b, 0x42, + 0x03, 0xd8, 0x2c, 0xbf, 0x82, 0x42, 0x0f, 0x20, 0x0c, 0xd3, 0x06, 0xeb, + 0x04, 0x1c, 0xdc, 0xe9, 0x00, 0x01, 0x8b, 0x42, 0x04, 0xd3, 0x01, 0xd8, + 0x82, 0x42, 0x01, 0xd3, 0x00, 0x20, 0x01, 0xe0, 0xf9, 0xf7, 0x3a, 0xff, + 0x08, 0x35, 0x64, 0x1c, 0x03, 0x2c, 0x08, 0xf8, 0x01, 0x0b, 0xe0, 0xd3, + 0xbd, 0xe8, 0xf0, 0x83, 0x22, 0x46, 0x00, 0x23, 0xf9, 0xf7, 0x2e, 0xbf, + 0x68, 0xee, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, 0x48, 0xf3, 0x00, 0x20, + 0x7c, 0xdf, 0x00, 0x20, 0x80, 0x96, 0x98, 0x00, 0x00, 0xf0, 0xff, 0x00, + 0x00, 0xf8, 0x7f, 0x00, 0x00, 0xf2, 0x05, 0x2a, 0x00, 0x5e, 0xd0, 0xb2, + 0x4c, 0x29, 0x00, 0x20, 0x80, 0x18, 0x42, 0xfd, 0x81, 0xb5, 0xd8, 0x68, + 0x01, 0x9d, 0x96, 0x6b, 0x46, 0x03, 0x00, 0x46, 0x78, 0xf3, 0x00, 0x20, + 0xc7, 0x02, 0x00, 0x46, 0x57, 0x03, 0x00, 0x46, 0x57, 0x02, 0x00, 0x46, + 0x7e, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0c, 0x0c, 0x0d, 0x0c, 0x0c, + 0x0c, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0c, + 0x0b, 0x0b, 0x0b, 0x0c, 0x0d, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x00, 0x00, 0x00, 0x48, 0x56, 0xc0, 0x00, 0x08, 0xd8, 0xba, 0x00, + 0xd0, 0xab, 0xb5, 0x00, 0xa0, 0xd1, 0xb0, 0x00, 0xc0, 0x3d, 0xac, 0x00, + 0x18, 0xf4, 0xa7, 0x00, 0xf0, 0xe8, 0xa3, 0x00, 0x60, 0x18, 0xa0, 0x00, + 0x50, 0x86, 0x9c, 0x00, 0x20, 0x23, 0x99, 0x00, 0xd8, 0xf5, 0x95, 0x00, + 0x7c, 0xf5, 0x92, 0x00, 0xb4, 0x1f, 0x90, 0x00, 0x28, 0x72, 0x8d, 0x00, + 0xf0, 0xe8, 0x8a, 0x00, 0x7c, 0x82, 0x88, 0x00, 0x48, 0x3b, 0x86, 0x00, + 0xc4, 0x11, 0x84, 0x00, 0x98, 0x03, 0x82, 0x00, 0x6c, 0x0e, 0x80, 0x00, + 0x4c, 0x30, 0x7e, 0x00, 0x0c, 0x68, 0x7c, 0x00, 0xb8, 0xb3, 0x7a, 0x00, + 0xc0, 0x11, 0x79, 0x00, 0xf8, 0x80, 0x77, 0x00, 0xd0, 0xff, 0x75, 0x00, + 0x80, 0x8d, 0x74, 0x00, 0xdc, 0x28, 0x73, 0x00, 0xb8, 0xd0, 0x71, 0x00, + 0xb0, 0x84, 0x70, 0x00, 0xfc, 0x43, 0x6f, 0x00, 0x70, 0x0d, 0x6e, 0x00, + 0x0c, 0xe1, 0x6c, 0x00, 0x08, 0xbe, 0x6b, 0x00, 0x9c, 0xa3, 0x6a, 0x00, + 0xc8, 0x91, 0x69, 0x00, 0x28, 0x88, 0x68, 0x00, 0x58, 0x86, 0x67, 0x00, + 0xf4, 0x8b, 0x66, 0x00, 0x98, 0x98, 0x65, 0x00, 0xa8, 0xac, 0x64, 0x00, + 0xc0, 0xc7, 0x63, 0x00, 0x7c, 0xe9, 0x62, 0x00, 0x78, 0x11, 0x62, 0x00, + 0x18, 0x40, 0x61, 0x00, 0xf8, 0x74, 0x60, 0x00, 0xb4, 0xaf, 0x5f, 0x00, + 0xb0, 0xf0, 0x5e, 0x00, 0x24, 0x37, 0x5e, 0x00, 0x10, 0x83, 0x5d, 0x00, + 0x10, 0xd4, 0x5c, 0x00, 0x24, 0x2a, 0x5c, 0x00, 0x84, 0x84, 0x5b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x09, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x95, 0x8d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaf, 0x2b, + 0x78, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xba, 0x82, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xf1, 0x42, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2f, 0xf4, + 0x04, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0xdb, 0x21, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0xe2, 0x0a, 0x00, 0x00, 0x6e, 0x46, 0xb6, 0x3f, + 0xee, 0x39, 0xf8, 0x34, 0xac, 0x30, 0xe2, 0x2c, 0x90, 0x29, 0x9d, 0x26, + 0xff, 0x23, 0xa8, 0x21, 0x8e, 0x1f, 0xa9, 0x1d, 0xf3, 0x1b, 0x65, 0x1a, + 0xfb, 0x18, 0xb0, 0x17, 0xa8, 0x17, 0x83, 0x16, 0x75, 0x15, 0x7c, 0x14, + 0x95, 0x13, 0xbf, 0x12, 0xf8, 0x11, 0x2d, 0x12, 0x77, 0x11, 0xc2, 0x11, + 0x18, 0x11, 0x79, 0x10, 0xe4, 0x0f, 0xa7, 0x13, 0xfd, 0x12, 0x5c, 0x12, + 0xc3, 0x11, 0x33, 0x11, 0x02, 0x0d, 0x60, 0x0d, 0xfa, 0x0c, 0x99, 0x0c, + 0x3c, 0x0c, 0x38, 0x10, 0xc6, 0x0f, 0x58, 0x0f, 0xf0, 0x0e, 0x8d, 0x0f, + 0x27, 0x0f, 0xc6, 0x0e, 0x69, 0x0e, 0x0f, 0x0e, 0xbe, 0x0e, 0x66, 0x0e, + 0x11, 0x0e, 0xc0, 0x0d, 0x72, 0x0d, 0x00, 0x00, 0x1e, 0x0b, 0x50, 0x0a, + 0x78, 0x0a, 0xa0, 0x05, 0xb0, 0xb3, 0x00, 0x00, 0x36, 0x6e, 0x01, 0x00, + 0x6c, 0xdc, 0x02, 0x00, 0xd8, 0xb8, 0x05, 0x00, 0xb0, 0x71, 0x0b, 0x00, + 0x60, 0xe3, 0x16, 0x00, 0xc0, 0xc6, 0x2d, 0x00, 0x20, 0x14, 0x5d, 0x00, + 0x10, 0x17, 0x19, 0x23, 0x27, 0x2b, 0x30, 0x00, 0x0a, 0x00, 0x09, 0x00, + 0x12, 0x00, 0x08, 0x00, 0x15, 0x00, 0x21, 0x00, 0x20, 0x70, 0x0b, 0x00, + 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x0d, 0x84, 0x03, 0x00, 0x04, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x1d, 0x2b, 0x1c, 0x0f, 0x1d, 0x6b, + 0x1d, 0x2a, 0x1c, 0x0f, 0x1d, 0x6a, 0x1d, 0x29, 0x1c, 0x0f, 0x1d, 0x69, + 0x1d, 0x28, 0x1c, 0x00, 0x1d, 0x68, 0x1d, 0x27, 0x1c, 0x00, 0x1d, 0x67, + 0x1d, 0x26, 0x1c, 0x00, 0x1d, 0x66, 0x1d, 0x20, 0x32, 0x00, 0x32, 0x00, + 0xf4, 0x01, 0xf4, 0x01, 0xee, 0x02, 0xee, 0x02, 0xee, 0x02, 0xee, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x0f, 0x0f, 0x0f, 0x0f, 0x05, 0x02, 0x05, 0x01, + 0x04, 0x04, 0x04, 0x01, 0x04, 0x03, 0x03, 0x02, 0x03, 0x02, 0x00, 0x00, + 0x03, 0x49, 0x09, 0x68, 0xc1, 0x40, 0xc8, 0x07, 0x01, 0xd4, 0x01, 0x21, + 0x03, 0xe0, 0x70, 0x47, 0x84, 0xf3, 0x00, 0x20, 0x00, 0x21, 0x40, 0xf6, + 0x01, 0x50, 0xf5, 0xf7, 0x9b, 0xbb, 0x00, 0x00, 0x70, 0xb5, 0x00, 0x20, + 0x0f, 0xf2, 0x74, 0x21, 0x11, 0xf8, 0x10, 0x30, 0x7b, 0x4c, 0x63, 0x43, + 0x7b, 0x4c, 0x24, 0x68, 0xa3, 0x42, 0x24, 0xbf, 0x01, 0xeb, 0x40, 0x02, + 0x52, 0x78, 0x40, 0x1c, 0x04, 0x28, 0xf1, 0xd3, 0xd2, 0xb2, 0x03, 0x21, + 0x4f, 0xf4, 0xbb, 0x70, 0xf5, 0xf7, 0x8c, 0xfb, 0x00, 0x24, 0x0f, 0xf2, + 0x50, 0x25, 0x0f, 0xf2, 0x60, 0x26, 0xa1, 0x5d, 0x35, 0xf8, 0x14, 0x00, + 0xf5, 0xf7, 0x78, 0xfb, 0x64, 0x1c, 0x09, 0x2c, 0xf7, 0xd3, 0x01, 0x20, + 0x70, 0xbd, 0x30, 0xb5, 0x14, 0x46, 0x6c, 0x4a, 0x0f, 0xf2, 0x18, 0x23, + 0x12, 0x78, 0x0f, 0xf2, 0x48, 0x25, 0xe3, 0x5c, 0x02, 0xf0, 0x03, 0x02, + 0x52, 0x5d, 0xd2, 0x18, 0x52, 0xb2, 0x00, 0x2a, 0x02, 0xd4, 0xf9, 0xf7, + 0x99, 0xfc, 0x02, 0xe0, 0x52, 0x42, 0xf5, 0xf7, 0x63, 0xfd, 0x07, 0x2c, + 0x08, 0xbf, 0x03, 0x22, 0x02, 0xd0, 0x08, 0x2c, 0x05, 0xd1, 0x05, 0x22, + 0xbd, 0xe8, 0x30, 0x40, 0x00, 0x23, 0xf9, 0xf7, 0x7f, 0xbd, 0x30, 0xbd, + 0x23, 0x29, 0x05, 0xd3, 0x02, 0xd8, 0xb0, 0xf1, 0xf1, 0x4f, 0x01, 0xd3, + 0x3f, 0x20, 0x0d, 0xe0, 0x40, 0x0b, 0x40, 0xea, 0xc1, 0x40, 0x50, 0x21, + 0x48, 0x43, 0x40, 0xf2, 0xcb, 0x21, 0xb0, 0xfb, 0xf1, 0xf0, 0x00, 0xf5, + 0x80, 0x40, 0xc0, 0x0b, 0x18, 0xbf, 0x40, 0x1e, 0xc0, 0xb2, 0x70, 0x47, + 0xf8, 0xb5, 0x06, 0x46, 0x4d, 0x48, 0x14, 0x46, 0x02, 0x68, 0x1d, 0x46, + 0xa2, 0xfb, 0x04, 0x01, 0x02, 0xfb, 0x05, 0x11, 0x00, 0x0f, 0x40, 0xea, + 0x01, 0x10, 0x09, 0x0f, 0x00, 0xf0, 0x98, 0xf8, 0x07, 0x00, 0x01, 0xd5, + 0x00, 0x20, 0xf2, 0xbd, 0x3a, 0x46, 0x20, 0x46, 0x29, 0x46, 0xff, 0xf7, + 0xac, 0xff, 0x05, 0x2e, 0x04, 0x46, 0x0d, 0x46, 0x03, 0xda, 0x0f, 0xf2, + 0xa8, 0x10, 0x31, 0x5c, 0x09, 0xb9, 0x40, 0x48, 0x01, 0x78, 0x40, 0xf2, + 0x0b, 0x20, 0xf5, 0xf7, 0x11, 0xfb, 0x0f, 0xf2, 0x50, 0x10, 0x39, 0x5c, + 0x40, 0xf2, 0x81, 0x10, 0xf5, 0xf7, 0x0a, 0xfb, 0x20, 0x46, 0x29, 0x46, + 0xff, 0xf7, 0xb6, 0xff, 0x02, 0x46, 0x3f, 0x21, 0x40, 0xf2, 0x77, 0x10, + 0xf5, 0xf7, 0x0a, 0xfb, 0x22, 0x0f, 0x42, 0xea, 0x05, 0x12, 0xd1, 0xb2, + 0x40, 0xf2, 0x75, 0x10, 0xf5, 0xf7, 0xf8, 0xfa, 0x6f, 0xf0, 0x70, 0x40, + 0x20, 0x40, 0x4f, 0xf4, 0xff, 0x12, 0xa2, 0xfb, 0x00, 0x45, 0x24, 0x0f, + 0x44, 0xea, 0x05, 0x14, 0xe1, 0xb2, 0x4f, 0xf4, 0xba, 0x70, 0x2d, 0x0f, + 0xf5, 0xf7, 0xe8, 0xfa, 0x24, 0x0a, 0x44, 0xea, 0x05, 0x64, 0xe1, 0xb2, + 0x40, 0xf2, 0x73, 0x10, 0xf5, 0xf7, 0xe0, 0xfa, 0x21, 0x0a, 0x4f, 0xf4, + 0xb9, 0x70, 0xf5, 0xf7, 0xdb, 0xfa, 0x01, 0x21, 0x40, 0xf2, 0x7f, 0x10, + 0xf5, 0xf7, 0xd6, 0xfa, 0x01, 0x20, 0xf2, 0xbd, 0x10, 0xb5, 0x05, 0x21, + 0x4f, 0xf4, 0xb8, 0x70, 0xf5, 0xf7, 0xce, 0xfa, 0x01, 0x21, 0x4f, 0xf4, + 0xb8, 0x70, 0xf5, 0xf7, 0xc9, 0xfa, 0x1a, 0x49, 0x01, 0x20, 0xf8, 0xf7, + 0x5d, 0xff, 0xf6, 0xf7, 0x98, 0xfd, 0x50, 0xb9, 0x17, 0x48, 0x00, 0x78, + 0x00, 0x06, 0x01, 0xd5, 0x01, 0x24, 0x05, 0xe0, 0x01, 0x20, 0xf8, 0xf7, + 0x69, 0xff, 0x00, 0x28, 0xf1, 0xd0, 0x00, 0x24, 0x01, 0x20, 0xf8, 0xf7, + 0xdb, 0xfe, 0x20, 0x46, 0x10, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0x00, 0x20, + 0x10, 0x2b, 0x0e, 0xd2, 0x1b, 0x07, 0x43, 0xea, 0x12, 0x11, 0x10, 0x07, + 0x06, 0x4a, 0x12, 0x68, 0x00, 0x23, 0xf9, 0xf7, 0xd1, 0xfc, 0x02, 0x46, + 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x0b, 0x46, 0x64, 0xe7, 0x10, 0xbd, + 0x80, 0x96, 0x98, 0x00, 0x78, 0x29, 0x00, 0x20, 0x76, 0x01, 0x00, 0x46, + 0x0b, 0x02, 0x00, 0x46, 0x40, 0x42, 0x0f, 0x00, 0x7f, 0x01, 0x00, 0x46, + 0x10, 0xb5, 0x4f, 0xf4, 0x7a, 0x72, 0x00, 0x23, 0xf9, 0xf7, 0xb8, 0xfc, + 0x4f, 0xf0, 0xff, 0x34, 0x00, 0x21, 0x0f, 0xf2, 0x18, 0x02, 0x52, 0xf8, + 0x21, 0x30, 0x83, 0x42, 0x01, 0xd3, 0x0c, 0x46, 0x02, 0xe0, 0x49, 0x1c, + 0x09, 0x29, 0xf6, 0xd3, 0x20, 0x46, 0x10, 0xbd, 0xf4, 0xef, 0x02, 0x00, + 0xe8, 0xdf, 0x05, 0x00, 0xd0, 0xbf, 0x0b, 0x00, 0xa0, 0x7f, 0x17, 0x00, + 0x98, 0x9e, 0x19, 0x00, 0x38, 0x07, 0x20, 0x00, 0x80, 0xb9, 0x2a, 0x00, + 0xe0, 0x7e, 0x46, 0x00, 0x60, 0x56, 0x6c, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x14, 0x24, 0x05, 0x05, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x08, 0x00, + 0x10, 0x01, 0x64, 0x02, 0x7d, 0x01, 0x7e, 0x01, 0x7e, 0x01, 0x7e, 0x01, + 0x79, 0x01, 0x7a, 0x01, 0x7b, 0x01, 0x7c, 0x01, 0x7f, 0x01, 0x00, 0x00, + 0x86, 0x08, 0x01, 0x05, 0xe5, 0x5b, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0xff, 0x00, 0x54, 0x2c, 0x04, 0xf8, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x0d, 0xd2, 0x01, 0x0e, 0x7f, 0x39, 0x0a, 0xd4, 0xd1, 0xf1, + 0x1f, 0x01, 0x04, 0xd4, 0xc0, 0x01, 0x40, 0xf0, 0x00, 0x40, 0xc8, 0x40, + 0x70, 0x47, 0x7f, 0xf0, 0x00, 0x00, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, + 0x03, 0x48, 0x00, 0x78, 0x18, 0xb9, 0x03, 0x48, 0x00, 0x78, 0x00, 0xf0, + 0x07, 0x00, 0x70, 0x47, 0x88, 0x02, 0x00, 0x20, 0x04, 0x00, 0x00, 0x46, + 0x2d, 0xe9, 0xf8, 0x43, 0x88, 0x4c, 0x4f, 0xf4, 0x94, 0x71, 0x04, 0xf1, + 0x44, 0x00, 0xf9, 0xf7, 0x89, 0xff, 0x00, 0x25, 0x85, 0x4e, 0x0f, 0xf2, + 0x2c, 0x28, 0x85, 0x4f, 0x4f, 0xf4, 0xd4, 0x79, 0x84, 0x48, 0x09, 0xfb, + 0x05, 0x00, 0x49, 0x46, 0x88, 0x30, 0xf5, 0xf7, 0xcf, 0xf9, 0x94, 0x20, + 0x00, 0xfb, 0x05, 0x40, 0x4f, 0xf4, 0x7a, 0x71, 0x01, 0x65, 0x79, 0x69, + 0x41, 0x65, 0x39, 0x6c, 0x81, 0x65, 0x00, 0x20, 0x58, 0xf8, 0x25, 0x10, + 0x08, 0x60, 0x04, 0x20, 0xa8, 0x55, 0x6d, 0x1c, 0x02, 0x2d, 0xe5, 0xd3, + 0xbd, 0xe8, 0xf1, 0x83, 0x2d, 0xe9, 0xf8, 0x43, 0x74, 0x48, 0xdf, 0xf8, + 0xc8, 0x81, 0x80, 0x7a, 0x0c, 0x46, 0x00, 0x25, 0x00, 0xf0, 0x03, 0x09, + 0x00, 0x27, 0x29, 0xfa, 0x07, 0xf0, 0xc0, 0x07, 0x35, 0xd5, 0x08, 0xf5, + 0xb6, 0x70, 0x60, 0x60, 0x4f, 0xf4, 0xd4, 0x71, 0x6c, 0x48, 0x27, 0x61, + 0x01, 0xfb, 0x07, 0x00, 0xc4, 0xf8, 0x08, 0x80, 0x88, 0x30, 0x20, 0x60, + 0x94, 0x21, 0x08, 0xf1, 0x44, 0x00, 0x01, 0xfb, 0x07, 0x00, 0xe0, 0x60, + 0xf4, 0xf7, 0x74, 0xf8, 0xe0, 0x68, 0x00, 0x21, 0x41, 0x60, 0x01, 0x60, + 0x81, 0x60, 0xc1, 0x62, 0x4f, 0xf4, 0x7a, 0x71, 0xc1, 0x60, 0xf4, 0xf7, + 0x7e, 0xf8, 0x20, 0x46, 0xfc, 0xf7, 0xd7, 0xfa, 0x06, 0x00, 0x04, 0xd1, + 0x01, 0x21, 0x20, 0x46, 0xfe, 0xf7, 0x80, 0xfd, 0x06, 0x46, 0x20, 0x46, + 0xfc, 0xf7, 0xe7, 0xfa, 0xe0, 0x68, 0x16, 0xb9, 0x01, 0x21, 0xc1, 0x83, + 0x03, 0xe0, 0x00, 0x21, 0xc1, 0x83, 0x06, 0x60, 0x35, 0x46, 0x7f, 0x1c, + 0x02, 0x2f, 0xc2, 0xd3, 0x28, 0x46, 0xbd, 0xe8, 0xf2, 0x83, 0x70, 0x47, + 0x00, 0x28, 0x0c, 0xbf, 0x50, 0x49, 0x51, 0x49, 0x00, 0x22, 0x08, 0x68, + 0x0a, 0x60, 0x70, 0x47, 0x00, 0x28, 0x0c, 0xbf, 0x4c, 0x48, 0x4d, 0x48, + 0x01, 0x60, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x47, 0x48, 0x4e, 0xdf, 0xf8, + 0x14, 0xa1, 0x0c, 0x46, 0x80, 0x46, 0x44, 0x20, 0x00, 0xfb, 0x08, 0xf5, + 0xa8, 0x19, 0xa0, 0x60, 0xc4, 0xf8, 0x10, 0x80, 0x4f, 0xf4, 0xd4, 0x70, + 0x00, 0xfb, 0x08, 0x60, 0x88, 0x30, 0x20, 0x60, 0x91, 0x46, 0x94, 0x20, + 0x00, 0xfb, 0x08, 0xa0, 0x44, 0x30, 0xe0, 0x60, 0x01, 0x27, 0xf4, 0xf7, + 0x21, 0xf8, 0xa8, 0x19, 0x51, 0x46, 0x44, 0x22, 0xfb, 0xf7, 0xb4, 0xff, + 0x20, 0x68, 0x90, 0xf8, 0xa1, 0x11, 0x40, 0x46, 0xfc, 0xf7, 0xce, 0xfb, + 0xe0, 0x68, 0x21, 0x68, 0x40, 0x8b, 0x08, 0x70, 0xe0, 0x68, 0x21, 0x68, + 0x00, 0x8b, 0x48, 0x70, 0xf4, 0xf7, 0x21, 0xf8, 0xfc, 0xf7, 0xac, 0xf8, + 0x48, 0xb9, 0x0b, 0x25, 0x29, 0x46, 0x20, 0x46, 0xfe, 0xf7, 0xab, 0xf8, + 0xe0, 0x68, 0x05, 0x60, 0x28, 0x46, 0xbd, 0xe8, 0xf0, 0x87, 0xe0, 0x68, + 0x80, 0x8b, 0x10, 0xb9, 0x03, 0x25, 0xf1, 0xe7, 0x7f, 0x1c, 0x20, 0x46, + 0xfc, 0xf7, 0x67, 0xfa, 0x05, 0x00, 0x06, 0xd0, 0x20, 0x46, 0xfc, 0xf7, + 0x7c, 0xfa, 0x15, 0x2d, 0xe6, 0xd3, 0x00, 0x25, 0xe8, 0xe7, 0x20, 0x68, + 0x01, 0x78, 0x40, 0x46, 0xfc, 0xf7, 0x99, 0xf9, 0x20, 0x46, 0xfe, 0xf7, + 0xbd, 0xf8, 0x05, 0x46, 0xe0, 0x68, 0xc1, 0x6a, 0x49, 0x1c, 0x00, 0x2d, + 0xc1, 0x62, 0xec, 0xd1, 0x81, 0x68, 0x49, 0x1c, 0xb9, 0xf1, 0x00, 0x0f, + 0x81, 0x60, 0xcf, 0xd0, 0xa1, 0x68, 0x09, 0x8b, 0x8f, 0x42, 0xd9, 0xd3, + 0xc0, 0x68, 0xf8, 0xf7, 0x51, 0xfe, 0x21, 0x68, 0xc1, 0xf8, 0x98, 0x01, + 0xc4, 0xe7, 0x10, 0xb5, 0x4f, 0xf4, 0xd4, 0x74, 0x12, 0x49, 0xc8, 0x22, + 0x02, 0xfb, 0x00, 0x12, 0x0a, 0x49, 0x10, 0x61, 0x01, 0xf5, 0xb6, 0x73, + 0x53, 0x60, 0x91, 0x60, 0x0a, 0x4b, 0x04, 0xfb, 0x00, 0x33, 0x88, 0x33, + 0x13, 0x60, 0x94, 0x23, 0x03, 0xfb, 0x00, 0x10, 0x44, 0x30, 0xd0, 0x60, + 0x00, 0x21, 0xbd, 0xe8, 0x10, 0x40, 0x10, 0x46, 0xfe, 0xf7, 0xd0, 0xbc, + 0x30, 0x27, 0x00, 0x20, 0x98, 0xf3, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, + 0x88, 0xb1, 0x00, 0x20, 0x00, 0x00, 0x40, 0x59, 0x00, 0x00, 0x50, 0x59, + 0x74, 0xe8, 0x00, 0x20, 0x00, 0x00, 0x40, 0x59, 0x00, 0x00, 0x50, 0x59, + 0x2d, 0xe9, 0xf0, 0x41, 0xf9, 0xf7, 0xf2, 0xfe, 0xf8, 0xf7, 0x6a, 0xfd, + 0xf5, 0xf7, 0xf8, 0xf9, 0x01, 0xf0, 0x54, 0xff, 0xf6, 0xf7, 0x68, 0xfe, + 0xf7, 0xf7, 0xf1, 0xfd, 0xff, 0xf7, 0x54, 0xfd, 0xfe, 0xf7, 0xd4, 0xfd, + 0xfa, 0xf7, 0x7e, 0xfa, 0xfa, 0xf7, 0x6d, 0xfa, 0x00, 0x24, 0x0f, 0xf2, + 0x54, 0x15, 0x0f, 0xf2, 0x48, 0x16, 0x36, 0xf8, 0x24, 0x00, 0x93, 0x21, + 0xf5, 0xf7, 0xde, 0xf8, 0x06, 0xeb, 0x84, 0x00, 0x82, 0x21, 0x00, 0xf0, + 0x5d, 0xf8, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xbf, 0x02, 0x21, 0x00, 0xf0, + 0x58, 0xf8, 0x35, 0xf8, 0x24, 0x00, 0x8c, 0x21, 0xf5, 0xf7, 0xce, 0xf8, + 0x05, 0xeb, 0x84, 0x00, 0x80, 0x21, 0x00, 0xf0, 0x4d, 0xf8, 0x00, 0xbf, + 0x00, 0xbf, 0x00, 0xbf, 0x00, 0x21, 0x00, 0xf0, 0x48, 0xf8, 0x64, 0x1c, + 0x02, 0x2c, 0xdc, 0xd3, 0x0f, 0xf2, 0xe4, 0x06, 0xf7, 0xf7, 0x5c, 0xfc, + 0x00, 0x24, 0x4f, 0xf0, 0x0c, 0x08, 0x00, 0x27, 0x08, 0xfb, 0x04, 0xf5, + 0x09, 0xe0, 0xa8, 0x19, 0x40, 0x68, 0x08, 0xfb, 0x07, 0x00, 0x18, 0xb1, + 0x00, 0x68, 0x01, 0x00, 0x18, 0xbf, 0x80, 0x47, 0x7f, 0x1c, 0xa8, 0x5d, + 0x87, 0x42, 0xf2, 0xd3, 0x64, 0x1c, 0x02, 0x2c, 0xeb, 0xd3, 0x12, 0x48, + 0x12, 0x4a, 0x40, 0x89, 0x10, 0xf0, 0x03, 0x01, 0x18, 0xbf, 0x01, 0x21, + 0x91, 0x60, 0xc0, 0xf3, 0x81, 0x01, 0x01, 0xb1, 0x4e, 0x21, 0x93, 0x68, + 0x19, 0x43, 0x91, 0x60, 0xc0, 0xf3, 0x01, 0x13, 0x03, 0xb1, 0x4e, 0x23, + 0x19, 0x43, 0x91, 0x60, 0xc0, 0xf3, 0x82, 0x10, 0x00, 0xb1, 0x08, 0x20, + 0x08, 0x43, 0x90, 0x60, 0x00, 0x22, 0x70, 0x21, 0x40, 0xf6, 0x8a, 0x50, + 0xf5, 0xf7, 0x8e, 0xf8, 0xbd, 0xe8, 0xf0, 0x41, 0xfb, 0xf7, 0x40, 0xbd, + 0x78, 0x29, 0x00, 0x20, 0xe8, 0xf2, 0x00, 0x20, 0x47, 0x88, 0x38, 0x46, + 0xf5, 0xf7, 0x78, 0xb8, 0x70, 0xb5, 0x04, 0x46, 0x15, 0x46, 0x0e, 0x46, + 0x28, 0x04, 0x48, 0xbf, 0xf3, 0xf7, 0x10, 0xff, 0x26, 0x60, 0x28, 0x06, + 0x44, 0xbf, 0x05, 0xf0, 0x7f, 0x00, 0x60, 0x60, 0xe8, 0x05, 0x48, 0xbf, + 0x00, 0x20, 0x03, 0xd4, 0xa8, 0x05, 0x02, 0xd5, 0xe0, 0x68, 0x40, 0x1c, + 0xe0, 0x60, 0x68, 0x05, 0x48, 0xbf, 0x00, 0x20, 0x03, 0xd4, 0x28, 0x05, + 0x02, 0xd5, 0x20, 0x69, 0x40, 0x1c, 0x20, 0x61, 0xe8, 0x04, 0x44, 0xbf, + 0x00, 0x20, 0xa0, 0x60, 0x28, 0x04, 0x44, 0xbf, 0xbd, 0xe8, 0x70, 0x40, + 0xf3, 0xf7, 0x03, 0xbf, 0x70, 0xbd, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x24, 0x9a, 0x00, 0x01, 0x60, 0xb5, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x6f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x06, 0xe7, 0x06, + 0xe8, 0x06, 0xe9, 0x06, 0xe0, 0x08, 0xe1, 0x08, 0xe2, 0x08, 0xe3, 0x08, + 0x2d, 0xe9, 0xf1, 0x41, 0xc0, 0xf3, 0xc7, 0x50, 0xff, 0x28, 0x81, 0xb0, + 0x0c, 0x46, 0x09, 0xd1, 0x01, 0x98, 0x00, 0x26, 0x40, 0x02, 0x02, 0xd1, + 0x01, 0x98, 0x00, 0x28, 0x18, 0xd4, 0x01, 0x98, 0xbd, 0xe8, 0xf6, 0x81, + 0x01, 0x28, 0x0b, 0xda, 0x01, 0xa8, 0x00, 0xf0, 0x0f, 0xff, 0x01, 0x28, + 0x06, 0xdb, 0x00, 0xf0, 0x45, 0xff, 0x22, 0x21, 0x01, 0x60, 0x5a, 0x48, + 0xbd, 0xe8, 0xf6, 0x81, 0x01, 0x99, 0x21, 0xf0, 0xff, 0x41, 0x41, 0xf0, + 0x7c, 0x51, 0x01, 0x91, 0xa0, 0xf1, 0x7e, 0x06, 0x01, 0x98, 0x00, 0x28, + 0x07, 0xd5, 0x00, 0xf0, 0x33, 0xff, 0x21, 0x21, 0x01, 0x60, 0x6f, 0xf0, + 0x00, 0x40, 0xbd, 0xe8, 0xf6, 0x81, 0x50, 0x49, 0xf8, 0xf7, 0xae, 0xfe, + 0x06, 0xd2, 0x01, 0x46, 0x4f, 0xf0, 0x80, 0x40, 0xf8, 0xf7, 0xba, 0xfe, + 0x01, 0x90, 0x76, 0x1e, 0x01, 0x99, 0x4b, 0x48, 0xf8, 0xf7, 0x18, 0xfe, + 0x05, 0x46, 0x01, 0x99, 0x4f, 0xf0, 0x7e, 0x50, 0xf8, 0xf7, 0x12, 0xfe, + 0x01, 0x46, 0x28, 0x46, 0xf8, 0xf7, 0x1c, 0xfd, 0x07, 0x46, 0x39, 0x46, + 0xf8, 0xf7, 0xa6, 0xfe, 0x80, 0x46, 0x43, 0x48, 0x41, 0x46, 0xf8, 0xf7, + 0xa1, 0xfe, 0x42, 0x49, 0xf8, 0xf7, 0x02, 0xfe, 0x41, 0x46, 0xf8, 0xf7, + 0x9b, 0xfe, 0x40, 0x49, 0xf8, 0xf7, 0xfc, 0xfd, 0x41, 0x46, 0xf8, 0xf7, + 0x95, 0xfe, 0x01, 0x46, 0x28, 0x46, 0xf8, 0xf7, 0x81, 0xfd, 0x39, 0x46, + 0xf8, 0xf7, 0x8e, 0xfe, 0x07, 0x46, 0x30, 0xb2, 0xf8, 0xf7, 0xe2, 0xfc, + 0x06, 0x46, 0x84, 0xb9, 0x37, 0x48, 0x31, 0x46, 0xf8, 0xf7, 0x84, 0xfe, + 0x39, 0x46, 0xf8, 0xf7, 0x71, 0xfd, 0x29, 0x46, 0xf8, 0xf7, 0xe2, 0xfd, + 0x04, 0x46, 0x33, 0x48, 0x31, 0x46, 0xf8, 0xf7, 0x79, 0xfe, 0x21, 0x46, + 0x3c, 0xe0, 0x01, 0x2c, 0x23, 0xdb, 0x30, 0x48, 0x29, 0x46, 0xf8, 0xf7, + 0x71, 0xfe, 0x04, 0x46, 0x2e, 0x48, 0x29, 0x46, 0xf8, 0xf7, 0x6c, 0xfe, + 0x05, 0x46, 0x2d, 0x48, 0x31, 0x46, 0xf8, 0xf7, 0x67, 0xfe, 0x80, 0x46, + 0x2b, 0x48, 0x39, 0x46, 0xf8, 0xf7, 0x62, 0xfe, 0x01, 0x46, 0x40, 0x46, + 0xf8, 0xf7, 0x4e, 0xfd, 0x29, 0x46, 0xf8, 0xf7, 0xbf, 0xfd, 0x21, 0x46, + 0xf8, 0xf7, 0xbc, 0xfd, 0x04, 0x46, 0x25, 0x48, 0x31, 0x46, 0xf8, 0xf7, + 0x53, 0xfe, 0x21, 0x46, 0x16, 0xe0, 0x23, 0x4c, 0x28, 0x46, 0x21, 0x46, + 0xf8, 0xf7, 0x4c, 0xfe, 0x80, 0x46, 0x21, 0x48, 0x29, 0x46, 0xf8, 0xf7, + 0x47, 0xfe, 0x05, 0x46, 0x38, 0x46, 0x21, 0x46, 0xf8, 0xf7, 0x42, 0xfe, + 0x01, 0x46, 0x28, 0x46, 0xf8, 0xf7, 0x2e, 0xfd, 0x41, 0x46, 0xf8, 0xf7, + 0x9f, 0xfd, 0x31, 0x46, 0xf8, 0xf7, 0x9c, 0xfd, 0xbd, 0xe8, 0xf6, 0x81, + 0x10, 0xb5, 0x04, 0x46, 0x0a, 0x48, 0x21, 0x46, 0xf8, 0xf7, 0x30, 0xfe, + 0x09, 0x49, 0xf8, 0xf7, 0x91, 0xfd, 0x21, 0x46, 0xf8, 0xf7, 0x2a, 0xfe, + 0xbd, 0xe8, 0x10, 0x40, 0x06, 0x49, 0xf8, 0xf7, 0x89, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xf3, 0x04, 0x35, 0x3f, 0x00, 0x00, 0x80, 0xbf, + 0x15, 0x02, 0x99, 0x3e, 0x11, 0xae, 0xcc, 0x3e, 0xc0, 0xaa, 0x2a, 0x3f, + 0xe8, 0xe8, 0xfb, 0x33, 0x16, 0x72, 0x31, 0x3f, 0xd8, 0x5b, 0xde, 0x3e, + 0x28, 0x37, 0xa9, 0x32, 0xf4, 0x3e, 0xa1, 0x33, 0xd9, 0x5b, 0xde, 0x3e, + 0x98, 0x20, 0x9a, 0x3e, 0x3b, 0xaa, 0xb8, 0x3f, 0x60, 0x70, 0xa5, 0x32, + 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, + 0x80, 0xb5, 0xff, 0xf7, 0xf7, 0xff, 0xdf, 0xf8, 0x9c, 0x1a, 0xdf, 0xf8, + 0x9c, 0x3a, 0x09, 0x68, 0x4f, 0xf0, 0x00, 0x42, 0x1a, 0x60, 0x04, 0xbd, + 0xdf, 0xf8, 0x88, 0x3a, 0x01, 0xf0, 0x00, 0x42, 0x1a, 0x60, 0x80, 0xf3, + 0x11, 0x88, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x41, 0xdf, 0xf8, 0x7c, 0x6a, + 0xdf, 0xf8, 0x7c, 0x4a, 0xdf, 0xf8, 0x7c, 0x5a, 0x82, 0xb0, 0x70, 0x89, + 0xc0, 0xf3, 0x01, 0x10, 0x00, 0x28, 0x41, 0xd0, 0x07, 0x21, 0x05, 0xf1, + 0x32, 0x00, 0x00, 0xf0, 0xa3, 0xfc, 0x00, 0x21, 0x05, 0xf1, 0x34, 0x00, + 0x00, 0xf0, 0xa3, 0xfc, 0x30, 0x6c, 0xdf, 0xf8, 0x5c, 0x8a, 0x00, 0x90, + 0x23, 0x46, 0x13, 0x22, 0x05, 0xf1, 0x36, 0x01, 0x05, 0xf1, 0x38, 0x00, + 0x00, 0xf0, 0x1b, 0xfc, 0x00, 0x20, 0x00, 0x90, 0x4f, 0xf4, 0x00, 0x63, + 0x32, 0x6c, 0x05, 0xf1, 0x36, 0x01, 0x05, 0xf1, 0x38, 0x00, 0x00, 0xf0, + 0x45, 0xfc, 0x33, 0x6c, 0x22, 0x46, 0x0a, 0x21, 0x05, 0xf1, 0x3a, 0x00, + 0x00, 0xf0, 0x21, 0xfc, 0x02, 0x27, 0x0c, 0x20, 0xc0, 0x21, 0x00, 0xfb, + 0x07, 0x80, 0x01, 0xfb, 0x07, 0x81, 0x01, 0xf5, 0x2c, 0x71, 0x01, 0x60, + 0x07, 0xeb, 0x47, 0x01, 0x41, 0x44, 0x01, 0xf2, 0xba, 0x51, 0x41, 0x60, + 0x7f, 0x1c, 0x18, 0x21, 0x01, 0x72, 0x2f, 0x21, 0x41, 0x72, 0x18, 0x21, + 0x00, 0xf0, 0x73, 0xfc, 0x04, 0x2f, 0xe6, 0xd3, 0x70, 0x89, 0xc0, 0xf3, + 0x82, 0x10, 0xd0, 0xb1, 0x07, 0x21, 0x05, 0xf1, 0x40, 0x00, 0x00, 0xf0, + 0x5d, 0xfc, 0x00, 0x21, 0x05, 0xf1, 0x42, 0x00, 0x00, 0xf0, 0x5d, 0xfc, + 0x70, 0x6d, 0x00, 0x90, 0x23, 0x46, 0x13, 0x22, 0x05, 0xf1, 0x44, 0x01, + 0x05, 0xf1, 0x46, 0x00, 0x00, 0xf0, 0xd7, 0xfb, 0x73, 0x6d, 0x22, 0x46, + 0x0a, 0x21, 0x05, 0xf1, 0x48, 0x00, 0x00, 0xf0, 0xe8, 0xfb, 0xbd, 0xe8, + 0xf3, 0x41, 0x00, 0xe0, 0x00, 0xbf, 0xf8, 0xb5, 0xdf, 0xf8, 0xa8, 0x49, + 0xdf, 0xf8, 0x9c, 0x59, 0x0e, 0x22, 0x05, 0xf1, 0x2e, 0x01, 0x20, 0x46, + 0xfb, 0xf7, 0xd8, 0xfc, 0x0e, 0x22, 0x05, 0xf1, 0x3c, 0x01, 0x04, 0xf1, + 0x10, 0x00, 0xfb, 0xf7, 0xe1, 0xfc, 0xa5, 0x88, 0x4f, 0xf6, 0xfe, 0x70, + 0x00, 0xea, 0x05, 0x06, 0x20, 0x78, 0x01, 0x06, 0x45, 0xf0, 0x01, 0x07, + 0x07, 0xd5, 0x00, 0xf0, 0x7f, 0x00, 0x65, 0x84, 0xa5, 0x84, 0x65, 0x85, + 0xa5, 0x85, 0x20, 0x70, 0x1b, 0xe0, 0x02, 0x20, 0xf6, 0xf7, 0xe2, 0xf9, + 0x00, 0x28, 0x14, 0xbf, 0x67, 0x84, 0x66, 0x84, 0x03, 0x20, 0xf6, 0xf7, + 0xdb, 0xf9, 0x00, 0x28, 0x14, 0xbf, 0xa7, 0x84, 0xa6, 0x84, 0x10, 0x20, + 0xf6, 0xf7, 0xd4, 0xf9, 0x00, 0x28, 0x14, 0xbf, 0x67, 0x85, 0x66, 0x85, + 0x11, 0x20, 0xf6, 0xf7, 0xcd, 0xf9, 0x00, 0x28, 0x14, 0xbf, 0xa7, 0x85, + 0xa6, 0x85, 0x20, 0x7c, 0x01, 0x06, 0x04, 0xd5, 0x00, 0xf0, 0x7f, 0x00, + 0x25, 0x85, 0x20, 0x74, 0x06, 0xe0, 0x12, 0x20, 0xf6, 0xf7, 0xbe, 0xf9, + 0x00, 0x28, 0x14, 0xbf, 0x27, 0x85, 0x26, 0x85, 0x21, 0x78, 0x60, 0x88, + 0x00, 0x29, 0x0e, 0xbf, 0x40, 0xf0, 0x10, 0x00, 0x4f, 0xf6, 0xef, 0x71, + 0x08, 0x40, 0x60, 0x80, 0x21, 0x7c, 0x60, 0x8a, 0x00, 0x29, 0x0e, 0xbf, + 0x40, 0xf0, 0x10, 0x00, 0x4f, 0xf6, 0xef, 0x71, 0x08, 0x40, 0x60, 0x82, + 0xf1, 0xbd, 0x30, 0xb5, 0x0f, 0xf6, 0x50, 0x11, 0x0f, 0xf6, 0x2c, 0x12, + 0x51, 0xf8, 0x20, 0x30, 0xdf, 0xf8, 0xd4, 0x18, 0x0f, 0xf6, 0x60, 0x14, + 0xdf, 0xf8, 0xd0, 0x58, 0x0b, 0x63, 0x52, 0xf8, 0x20, 0x20, 0x34, 0xf8, + 0x10, 0x40, 0x2c, 0x80, 0x01, 0xeb, 0x40, 0x00, 0x00, 0x24, 0x1c, 0x70, + 0xdf, 0xf8, 0xbc, 0x38, 0xd4, 0x88, 0x5c, 0x80, 0x14, 0x89, 0x9c, 0x80, + 0x54, 0x89, 0xdc, 0x80, 0x94, 0x89, 0x1c, 0x81, 0x0c, 0x6b, 0xdf, 0xf8, + 0xac, 0x18, 0xa5, 0x89, 0x1d, 0x82, 0xe5, 0x89, 0x5d, 0x82, 0x25, 0x8a, + 0x9d, 0x82, 0x64, 0x8a, 0xdc, 0x82, 0x00, 0x24, 0x1c, 0x80, 0x00, 0x8c, + 0x18, 0x80, 0x50, 0x88, 0x08, 0x80, 0x30, 0xbd, 0xdf, 0xf8, 0x84, 0x08, + 0x4f, 0xf4, 0xc0, 0x41, 0x01, 0x80, 0xdf, 0xf8, 0x74, 0x18, 0x0a, 0x6b, + 0x7a, 0xb1, 0xb0, 0xf9, 0x10, 0x30, 0x93, 0x81, 0xb0, 0xf9, 0x12, 0x30, + 0xd3, 0x81, 0xb0, 0xf9, 0x14, 0x30, 0x13, 0x82, 0xb0, 0xf9, 0x16, 0x00, + 0x50, 0x82, 0x01, 0x20, 0x10, 0x70, 0x00, 0x20, 0x08, 0x63, 0x70, 0x47, + 0xf8, 0xb5, 0x04, 0x46, 0x0f, 0xf6, 0xb4, 0x00, 0xdf, 0xf8, 0x40, 0x78, + 0x50, 0xf8, 0x24, 0x50, 0x0f, 0xf6, 0x88, 0x00, 0x50, 0xf8, 0x24, 0x60, + 0x0f, 0xf6, 0xc0, 0x00, 0x30, 0xf8, 0x14, 0x10, 0xdf, 0xf8, 0x2c, 0x08, + 0xf7, 0xf7, 0x00, 0xf8, 0xf1, 0x88, 0xdf, 0xf8, 0x30, 0x08, 0xf6, 0xf7, + 0xfb, 0xff, 0x31, 0x89, 0xdf, 0xf8, 0x28, 0x08, 0xf6, 0xf7, 0xf6, 0xff, + 0x71, 0x89, 0xdf, 0xf8, 0x24, 0x08, 0xf6, 0xf7, 0xf1, 0xff, 0xb1, 0x89, + 0xdf, 0xf8, 0x1c, 0x08, 0xf6, 0xf7, 0xec, 0xff, 0xa9, 0x89, 0xdf, 0xf8, + 0x18, 0x08, 0xf6, 0xf7, 0xe7, 0xff, 0xe9, 0x89, 0xdf, 0xf8, 0x10, 0x08, + 0xf6, 0xf7, 0xe2, 0xff, 0x29, 0x8a, 0xdf, 0xf8, 0x0c, 0x08, 0xf6, 0xf7, + 0xdd, 0xff, 0x69, 0x8a, 0xdf, 0xf8, 0x04, 0x08, 0xf6, 0xf7, 0xd8, 0xff, + 0x29, 0x46, 0x07, 0xf1, 0x30, 0x00, 0xf6, 0xf7, 0xfb, 0xff, 0x00, 0x21, + 0x28, 0x46, 0xf6, 0xf7, 0xbf, 0xff, 0xdf, 0xf8, 0xc8, 0x57, 0x00, 0x21, + 0x28, 0x46, 0xf6, 0xf7, 0xc9, 0xff, 0x07, 0xeb, 0x44, 0x00, 0x01, 0x8c, + 0x28, 0x46, 0xf6, 0xf7, 0xc3, 0xff, 0x71, 0x88, 0xdf, 0xf8, 0xb0, 0x07, + 0xbd, 0xe8, 0xf4, 0x40, 0xf6, 0xf7, 0xbc, 0xbf, 0x70, 0xb5, 0xdf, 0xf8, + 0xa0, 0x47, 0x4f, 0xf4, 0xc0, 0x41, 0x20, 0x46, 0xf6, 0xf7, 0xb4, 0xff, + 0xdf, 0xf8, 0x88, 0x57, 0x2e, 0x6b, 0xf6, 0xb1, 0x21, 0x8a, 0x06, 0xf1, + 0x0c, 0x00, 0xf6, 0xf7, 0xab, 0xff, 0x61, 0x8a, 0x06, 0xf1, 0x0e, 0x00, + 0xf6, 0xf7, 0xa6, 0xff, 0xa1, 0x8a, 0x06, 0xf1, 0x10, 0x00, 0xf6, 0xf7, + 0xa1, 0xff, 0xe1, 0x8a, 0x06, 0xf1, 0x12, 0x00, 0xf6, 0xf7, 0x9c, 0xff, + 0x01, 0x21, 0x30, 0x46, 0xf6, 0xf7, 0x88, 0xff, 0x05, 0xf1, 0x30, 0x00, + 0xbd, 0xe8, 0x70, 0x40, 0x00, 0x21, 0xf6, 0xf7, 0xb9, 0xbf, 0x70, 0xbd, + 0xdf, 0xf8, 0x38, 0x17, 0xdf, 0xf8, 0x50, 0x07, 0xca, 0x8e, 0x4f, 0xf6, + 0xe0, 0x73, 0x1a, 0x40, 0x02, 0x80, 0x09, 0x8f, 0xc8, 0xe0, 0xdf, 0xf8, + 0x24, 0x17, 0xdf, 0xf8, 0x3c, 0x07, 0xca, 0x8e, 0x02, 0x80, 0x09, 0x8f, + 0x41, 0x80, 0x70, 0x47, 0x70, 0xb5, 0xdf, 0xf8, 0x48, 0x17, 0x82, 0xb0, + 0x00, 0x20, 0x88, 0x61, 0xdf, 0xf8, 0xfc, 0x46, 0x60, 0x89, 0xc0, 0xf3, + 0x81, 0x00, 0xb8, 0xb3, 0xdf, 0xf8, 0xf8, 0x56, 0x07, 0x21, 0x05, 0xf1, + 0x24, 0x00, 0x00, 0xf0, 0xe7, 0xfa, 0x0c, 0x21, 0x05, 0xf1, 0x26, 0x00, + 0x00, 0xf0, 0xe7, 0xfa, 0xe0, 0x6a, 0xdf, 0xf8, 0xdc, 0x66, 0x00, 0x90, + 0x33, 0x46, 0x13, 0x22, 0x05, 0xf1, 0x28, 0x01, 0x05, 0xf1, 0x2a, 0x00, + 0x00, 0xf0, 0x5f, 0xfa, 0xe3, 0x6a, 0x32, 0x46, 0x0a, 0x21, 0x05, 0xf1, + 0x2c, 0x00, 0x00, 0xf0, 0x70, 0xfa, 0x00, 0x24, 0xdf, 0xf8, 0xbc, 0x56, + 0x0c, 0x20, 0x00, 0xfb, 0x04, 0x50, 0x05, 0xeb, 0x44, 0x21, 0x30, 0x31, + 0x01, 0x60, 0x05, 0xeb, 0xc4, 0x01, 0x01, 0xf5, 0xb6, 0x61, 0x41, 0x60, + 0x64, 0x1c, 0xc0, 0x21, 0x01, 0x72, 0xff, 0x21, 0x41, 0x72, 0x40, 0x21, + 0x00, 0xf0, 0xc3, 0xfa, 0x02, 0x2c, 0xe9, 0xd3, 0x73, 0xbd, 0x10, 0xb5, + 0xdf, 0xf8, 0xbc, 0x46, 0xdf, 0xf8, 0xbc, 0x16, 0x0e, 0x22, 0x20, 0x46, + 0xfb, 0xf7, 0x5c, 0xfb, 0x20, 0x78, 0x01, 0x06, 0x03, 0xd5, 0x00, 0xf0, + 0x7f, 0x00, 0x20, 0x70, 0x17, 0xe0, 0x00, 0x20, 0xf6, 0xf7, 0x68, 0xf8, + 0xa1, 0x88, 0x00, 0x28, 0x12, 0xbf, 0x41, 0xf0, 0x01, 0x00, 0x4f, 0xf6, + 0xfe, 0x70, 0x08, 0x40, 0xa0, 0x80, 0x01, 0x20, 0xf6, 0xf7, 0x5c, 0xf8, + 0x00, 0x28, 0xa0, 0x88, 0x12, 0xbf, 0x40, 0xf0, 0x02, 0x00, 0x4f, 0xf6, + 0xfd, 0x71, 0x08, 0x40, 0xa0, 0x80, 0x00, 0x20, 0x20, 0x61, 0x06, 0x21, + 0x4f, 0xf0, 0xff, 0x30, 0xa0, 0x82, 0x02, 0x20, 0xf9, 0xf7, 0x75, 0xfc, + 0xdf, 0xf8, 0x64, 0x06, 0x4f, 0xf6, 0xff, 0x71, 0x01, 0x80, 0x4f, 0xf6, + 0xff, 0x61, 0x41, 0x80, 0x02, 0x20, 0xf9, 0xf7, 0x4f, 0xfc, 0x02, 0x20, + 0xf9, 0xf7, 0x52, 0xfc, 0x61, 0x88, 0x23, 0x78, 0xdf, 0xf8, 0x48, 0x06, + 0xdf, 0xf8, 0x48, 0x26, 0x33, 0xb9, 0x00, 0xf0, 0x11, 0xf8, 0x01, 0x20, + 0xa0, 0x61, 0xbd, 0xe8, 0x10, 0x40, 0x39, 0xe0, 0x4e, 0xf6, 0xef, 0x73, + 0x19, 0x40, 0x00, 0xf0, 0x07, 0xf8, 0x00, 0x21, 0x01, 0x82, 0x41, 0x82, + 0x01, 0x83, 0x41, 0x83, 0xa1, 0x61, 0x10, 0xbd, 0x11, 0x80, 0x4f, 0xf6, + 0xfc, 0x72, 0xa1, 0x88, 0x11, 0x40, 0x01, 0x80, 0x70, 0x47, 0xdf, 0xf8, + 0x00, 0x06, 0x00, 0x21, 0x81, 0x61, 0x4f, 0xf6, 0xfc, 0x72, 0x4f, 0xf0, + 0xff, 0x31, 0x81, 0x82, 0xdf, 0xf8, 0xf8, 0x05, 0x01, 0x88, 0x11, 0x40, + 0x01, 0x80, 0x02, 0x20, 0xf9, 0xf7, 0x29, 0xbc, 0xdf, 0xf8, 0xdc, 0x15, + 0xdf, 0xf8, 0xec, 0x05, 0x0a, 0x89, 0x4f, 0xf6, 0xe0, 0x73, 0x1a, 0x40, + 0x02, 0x80, 0x49, 0x89, 0x19, 0x40, 0x41, 0x80, 0x70, 0x47, 0xdf, 0xf8, + 0xc4, 0x15, 0xdf, 0xf8, 0xd4, 0x05, 0x0a, 0x89, 0x02, 0x80, 0x49, 0x89, + 0x41, 0x80, 0x70, 0x47, 0xf8, 0xb5, 0xdf, 0xf8, 0xb0, 0x45, 0xa0, 0x69, + 0x00, 0x28, 0x5d, 0xd0, 0xdf, 0xf8, 0xb0, 0x55, 0x28, 0x88, 0x4f, 0xf6, + 0xfc, 0x71, 0x08, 0x40, 0x28, 0x80, 0x00, 0xf0, 0x9f, 0xfa, 0x20, 0x79, + 0x00, 0x27, 0xc0, 0x07, 0x4f, 0xf0, 0xff, 0x36, 0x05, 0xd5, 0x00, 0x20, + 0x00, 0xf0, 0x84, 0xfd, 0x08, 0xb9, 0x26, 0x8a, 0x01, 0x27, 0x20, 0x79, + 0x80, 0x07, 0x09, 0xd5, 0x01, 0x20, 0x00, 0xf0, 0x7b, 0xfd, 0x28, 0xb9, + 0x60, 0x8a, 0x86, 0x42, 0x47, 0xf0, 0x02, 0x07, 0x28, 0xbf, 0x06, 0x46, + 0x22, 0x8a, 0xdf, 0xf8, 0x28, 0x05, 0x0a, 0x21, 0x96, 0x42, 0x01, 0xfb, + 0x06, 0x01, 0x06, 0xd2, 0x91, 0xf8, 0x5a, 0x20, 0xd2, 0x07, 0x5c, 0xbf, + 0x4f, 0xf6, 0xfe, 0x72, 0x17, 0x40, 0x62, 0x8a, 0x96, 0x42, 0x06, 0xd2, + 0x91, 0xf8, 0x5a, 0x20, 0x92, 0x07, 0x5c, 0xbf, 0x4f, 0xf6, 0xfd, 0x72, + 0x17, 0x40, 0xbf, 0xb1, 0xb0, 0xf8, 0x58, 0x00, 0x86, 0x42, 0x32, 0xbf, + 0x01, 0xf1, 0x5a, 0x00, 0x06, 0x46, 0x20, 0x1d, 0x41, 0x88, 0x69, 0x80, + 0x81, 0x88, 0xa9, 0x80, 0xc1, 0x88, 0xe9, 0x80, 0x01, 0x89, 0x29, 0x81, + 0x4f, 0xf6, 0xfc, 0x71, 0x00, 0x88, 0x08, 0x40, 0x38, 0x43, 0x28, 0x80, + 0x30, 0x46, 0x01, 0xe0, 0x4f, 0xf0, 0xff, 0x30, 0x47, 0xea, 0x06, 0x11, + 0xa0, 0x82, 0x3d, 0x20, 0xbd, 0xe8, 0xf4, 0x40, 0xf9, 0xf7, 0x3e, 0xbc, + 0xf1, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0xff, 0xf7, 0xf5, 0xfc, 0xdf, 0xf8, + 0xe0, 0x14, 0x05, 0x46, 0x01, 0xeb, 0x44, 0x01, 0x00, 0x20, 0x08, 0x82, + 0x00, 0x22, 0x00, 0x21, 0x20, 0x46, 0x00, 0xf0, 0x03, 0xf8, 0x85, 0xf3, + 0x11, 0x88, 0x31, 0xbd, 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x16, 0x46, + 0xff, 0xf7, 0xe0, 0xfc, 0x07, 0x46, 0xdf, 0xf8, 0xc0, 0x04, 0x01, 0x88, + 0x4f, 0xf6, 0xfc, 0x72, 0x11, 0x40, 0x01, 0x80, 0x14, 0xb9, 0x05, 0x82, + 0x46, 0x82, 0x03, 0xe0, 0x01, 0x2c, 0x04, 0xbf, 0x05, 0x83, 0x46, 0x83, + 0xff, 0xf7, 0x70, 0xff, 0x87, 0xf3, 0x11, 0x88, 0xf1, 0xbd, 0x2d, 0xe9, + 0xf8, 0x43, 0x80, 0x46, 0x0f, 0xf2, 0xc4, 0x40, 0x50, 0xf8, 0x28, 0x50, + 0x0e, 0x46, 0x17, 0x46, 0xff, 0xf7, 0xc6, 0xfc, 0x04, 0x46, 0x89, 0x46, + 0xf9, 0xf7, 0x7e, 0xfd, 0x40, 0x45, 0x0a, 0xd1, 0xdf, 0xf8, 0x40, 0x04, + 0x01, 0x88, 0x4f, 0xf6, 0xfe, 0x72, 0x0a, 0x40, 0x02, 0x80, 0x06, 0x82, + 0x47, 0x82, 0x01, 0x80, 0x03, 0xe0, 0xae, 0x81, 0xef, 0x81, 0x01, 0x20, + 0x28, 0x70, 0x20, 0x46, 0x49, 0x46, 0xbd, 0xe8, 0xf4, 0x43, 0xb7, 0xe4, + 0x00, 0x28, 0xdf, 0xf8, 0x40, 0x14, 0x0c, 0xbf, 0x01, 0x20, 0x02, 0x20, + 0x89, 0x88, 0x08, 0x40, 0x70, 0x47, 0xdf, 0xf8, 0x00, 0x14, 0x01, 0xeb, + 0x40, 0x00, 0x90, 0xf8, 0x20, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x70, 0x47, + 0xdf, 0xf8, 0x1c, 0x24, 0x02, 0xeb, 0x40, 0x00, 0x00, 0x21, 0x01, 0x82, + 0x2e, 0xe7, 0x2d, 0xe9, 0xfc, 0x47, 0x06, 0x46, 0xdf, 0xf8, 0xd4, 0x93, + 0x0c, 0x20, 0x88, 0x46, 0x17, 0x46, 0x00, 0xfb, 0x06, 0x9a, 0x39, 0x46, + 0x50, 0x46, 0x00, 0xf0, 0x6a, 0xf9, 0x00, 0x25, 0x20, 0xb1, 0x39, 0x46, + 0x50, 0x46, 0x00, 0xf0, 0x58, 0xf9, 0x05, 0x46, 0xdf, 0xf8, 0xf0, 0x73, + 0xdf, 0xf8, 0xe0, 0x43, 0x38, 0x88, 0x4f, 0xf6, 0xfc, 0x71, 0x08, 0x40, + 0x38, 0x80, 0x06, 0xbb, 0xb7, 0xf9, 0x10, 0x00, 0xad, 0xf8, 0x00, 0x00, + 0x6a, 0x46, 0xb7, 0xf9, 0x12, 0x00, 0xad, 0xf8, 0x02, 0x00, 0x41, 0x46, + 0xb7, 0xf9, 0x14, 0x00, 0xad, 0xf8, 0x04, 0x00, 0xb7, 0xf9, 0x16, 0x00, + 0xad, 0xf8, 0x06, 0x00, 0x48, 0x46, 0x00, 0xf0, 0x59, 0xf9, 0x3d, 0xb1, + 0x28, 0x88, 0x38, 0x82, 0x68, 0x88, 0x78, 0x82, 0xa8, 0x88, 0xb8, 0x82, + 0xe8, 0x88, 0xf8, 0x82, 0x00, 0x20, 0x20, 0x82, 0x21, 0xe0, 0x01, 0x2e, + 0x1f, 0xd1, 0xb7, 0xf9, 0x18, 0x00, 0xad, 0xf8, 0x00, 0x00, 0x6a, 0x46, + 0xb7, 0xf9, 0x1a, 0x00, 0xad, 0xf8, 0x02, 0x00, 0x41, 0x46, 0xb7, 0xf9, + 0x1c, 0x00, 0xad, 0xf8, 0x04, 0x00, 0xb7, 0xf9, 0x1e, 0x00, 0xad, 0xf8, + 0x06, 0x00, 0x50, 0x46, 0x00, 0xf0, 0x36, 0xf9, 0x3d, 0xb1, 0x28, 0x88, + 0x38, 0x83, 0x68, 0x88, 0x78, 0x83, 0xa8, 0x88, 0xb8, 0x83, 0xe8, 0x88, + 0xf8, 0x83, 0x00, 0x20, 0x60, 0x82, 0xff, 0xf7, 0xcb, 0xfe, 0xbd, 0xe8, + 0xf3, 0x87, 0x2d, 0xe9, 0xfc, 0x47, 0x06, 0x46, 0x04, 0x2e, 0x8a, 0x46, + 0x14, 0x46, 0x57, 0xda, 0xc0, 0x48, 0x0c, 0x21, 0x01, 0xfb, 0x06, 0x08, + 0x21, 0x46, 0x40, 0x46, 0x00, 0xf0, 0x03, 0xf9, 0x00, 0x25, 0x20, 0xb1, + 0x21, 0x46, 0x40, 0x46, 0x00, 0xf0, 0xf1, 0xf8, 0x05, 0x46, 0xff, 0xf7, + 0x15, 0xfc, 0x02, 0x2e, 0x04, 0x46, 0x89, 0x46, 0x02, 0xd1, 0xf5, 0xf7, + 0xec, 0xf8, 0x01, 0xe0, 0xf5, 0xf7, 0xfd, 0xf8, 0x06, 0x46, 0xf9, 0xf7, + 0xc5, 0xfc, 0xb0, 0x42, 0x25, 0xd1, 0xb4, 0x4e, 0x37, 0x88, 0x4f, 0xf6, + 0xfe, 0x70, 0x38, 0x40, 0x30, 0x80, 0x6a, 0x46, 0xb6, 0xf9, 0x10, 0x00, + 0xad, 0xf8, 0x00, 0x00, 0x51, 0x46, 0xb6, 0xf9, 0x12, 0x00, 0xad, 0xf8, + 0x02, 0x00, 0xb6, 0xf9, 0x14, 0x00, 0xad, 0xf8, 0x04, 0x00, 0xb6, 0xf9, + 0x16, 0x00, 0xad, 0xf8, 0x06, 0x00, 0x40, 0x46, 0x00, 0xf0, 0xe6, 0xf8, + 0x3d, 0xb1, 0x28, 0x88, 0x30, 0x82, 0x68, 0x88, 0x70, 0x82, 0xa8, 0x88, + 0xb0, 0x82, 0xe8, 0x88, 0xf0, 0x82, 0x37, 0x80, 0x0e, 0xe0, 0x6d, 0xb1, + 0x0f, 0xf2, 0xe8, 0x20, 0x50, 0xf8, 0x26, 0x00, 0x29, 0x88, 0x81, 0x81, + 0x69, 0x88, 0xc1, 0x81, 0xa9, 0x88, 0x01, 0x82, 0xe9, 0x88, 0x41, 0x82, + 0x01, 0x21, 0x01, 0x70, 0x20, 0x46, 0x49, 0x46, 0xff, 0xf7, 0xda, 0xfb, + 0xbd, 0xe8, 0xf3, 0x87, 0x10, 0xf1, 0x14, 0x0f, 0xb8, 0xbf, 0x1f, 0x20, + 0x04, 0xdb, 0x0a, 0x28, 0xac, 0xbf, 0x00, 0x20, 0xc0, 0xf1, 0x0a, 0x00, + 0x80, 0xb2, 0x70, 0x47, 0x10, 0xb5, 0x91, 0x42, 0x04, 0x46, 0x05, 0xd2, + 0xb2, 0xfb, 0xf1, 0xf0, 0xf9, 0xf7, 0x4f, 0xfa, 0x24, 0x1a, 0x06, 0xe0, + 0x8a, 0x42, 0x04, 0xd2, 0xb1, 0xfb, 0xf2, 0xf0, 0xf9, 0xf7, 0x47, 0xfa, + 0x04, 0x19, 0x20, 0x46, 0x10, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x1f, 0x2a, + 0xac, 0xbf, 0x6f, 0xf0, 0x14, 0x00, 0xc2, 0xf1, 0x0a, 0x00, 0x0d, 0x46, + 0x04, 0x9a, 0x19, 0x46, 0xff, 0xf7, 0xe0, 0xff, 0xff, 0xf7, 0xd2, 0xff, + 0x21, 0x88, 0x4e, 0xf2, 0xff, 0x02, 0x11, 0x40, 0x41, 0xea, 0x00, 0x21, + 0x21, 0x80, 0x29, 0x88, 0x17, 0xe0, 0x38, 0xb5, 0x05, 0x46, 0x0f, 0x29, + 0x14, 0x46, 0xac, 0xbf, 0x6f, 0xf0, 0x0e, 0x00, 0x48, 0x42, 0x1a, 0x46, + 0x21, 0x46, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x28, 0x58, 0xbf, 0x00, 0x20, + 0x04, 0xd5, 0x10, 0xf1, 0x0e, 0x0f, 0xb4, 0xbf, 0x0f, 0x20, 0x40, 0x42, + 0x29, 0x88, 0x4f, 0xf2, 0xff, 0x02, 0x11, 0x40, 0x41, 0xea, 0x00, 0x20, + 0x28, 0x80, 0x31, 0xbd, 0xf8, 0xb5, 0x05, 0x46, 0x0c, 0x46, 0x10, 0x46, + 0x1e, 0x46, 0xf7, 0xf7, 0xd3, 0xff, 0x79, 0x49, 0xf8, 0xf7, 0x6e, 0xf9, + 0x07, 0x46, 0x30, 0x46, 0xf7, 0xf7, 0xcc, 0xff, 0x01, 0x46, 0x38, 0x46, + 0xf7, 0xf7, 0xd8, 0xff, 0xff, 0xf7, 0x64, 0xf8, 0x06, 0x99, 0x46, 0x1a, + 0x30, 0x00, 0x18, 0xbf, 0x01, 0x20, 0xc0, 0xb2, 0xf9, 0xf7, 0xb7, 0xf9, + 0x30, 0x46, 0xf7, 0xf7, 0xbb, 0xff, 0x4f, 0xf0, 0xff, 0x37, 0x39, 0x46, + 0xff, 0xf7, 0x5e, 0xfa, 0x01, 0x46, 0x6b, 0x48, 0xf8, 0xf7, 0x40, 0xf8, + 0xf8, 0xf7, 0xba, 0xf9, 0xff, 0xf7, 0x80, 0xff, 0x2a, 0x88, 0x01, 0x02, + 0xc2, 0xf3, 0x04, 0x23, 0x98, 0x42, 0x04, 0xd2, 0x4e, 0xf2, 0xff, 0x03, + 0x1a, 0x40, 0x0a, 0x43, 0x2a, 0x80, 0x22, 0x88, 0xc2, 0xf3, 0x04, 0x23, + 0x98, 0x42, 0x04, 0xd2, 0x4e, 0xf2, 0xff, 0x00, 0x10, 0x40, 0x08, 0x43, + 0x20, 0x80, 0xf1, 0xbd, 0x02, 0x88, 0x61, 0xf3, 0x0a, 0x22, 0x02, 0x80, + 0x70, 0x47, 0x02, 0x88, 0x02, 0xf4, 0x7f, 0x42, 0x11, 0x43, 0x01, 0x80, + 0x70, 0x47, 0x40, 0x68, 0xc9, 0x08, 0xf4, 0xf7, 0x2b, 0xba, 0x38, 0xb5, + 0x04, 0x46, 0x00, 0xf0, 0x3e, 0xf8, 0x00, 0x25, 0x00, 0x28, 0x5c, 0xbf, + 0x21, 0x68, 0x01, 0xeb, 0xc0, 0x05, 0x28, 0x46, 0x32, 0xbd, 0x38, 0xb5, + 0x05, 0x46, 0x00, 0xf0, 0x32, 0xf8, 0x00, 0x24, 0x00, 0x28, 0x0b, 0xd4, + 0x69, 0x68, 0xc2, 0x10, 0x00, 0xf0, 0x07, 0x00, 0x51, 0x5c, 0x01, 0x22, + 0x02, 0xfa, 0x00, 0xf0, 0x08, 0x40, 0x01, 0x28, 0xa8, 0xbf, 0x01, 0x24, + 0x20, 0x46, 0x32, 0xbd, 0x70, 0xb5, 0x04, 0x46, 0x15, 0x46, 0x00, 0xf0, + 0x1c, 0xf8, 0x00, 0x28, 0x18, 0xd4, 0x00, 0xf0, 0x07, 0x02, 0x01, 0x23, + 0x03, 0xfa, 0x02, 0xf2, 0x63, 0x68, 0xc1, 0x10, 0xce, 0x5c, 0x96, 0x43, + 0xce, 0x54, 0x23, 0x68, 0x03, 0xeb, 0xc0, 0x00, 0x2b, 0x88, 0x03, 0x80, + 0x6b, 0x88, 0x43, 0x80, 0xab, 0x88, 0x83, 0x80, 0xeb, 0x88, 0xc3, 0x80, + 0x60, 0x68, 0x0b, 0x5c, 0x1a, 0x43, 0x0a, 0x54, 0x70, 0xbd, 0x03, 0x7a, + 0x4f, 0xf0, 0xff, 0x32, 0x99, 0x42, 0x22, 0xbf, 0x40, 0x7a, 0x88, 0x42, + 0xca, 0x1a, 0x10, 0x46, 0x70, 0x47, 0x70, 0xb5, 0x3c, 0x20, 0xf9, 0xf7, + 0xf6, 0xf9, 0x29, 0x48, 0x04, 0x88, 0x4f, 0xf6, 0xfc, 0x71, 0x21, 0x40, + 0x01, 0x80, 0x00, 0xf0, 0x19, 0xf8, 0x22, 0x48, 0xb0, 0xf9, 0x14, 0x10, + 0x00, 0x29, 0x10, 0xd4, 0x00, 0x22, 0x0f, 0xf2, 0xec, 0x03, 0x33, 0xf8, + 0x12, 0x50, 0x2c, 0x42, 0x06, 0xd0, 0x00, 0xeb, 0x42, 0x05, 0x2e, 0x8a, + 0xb1, 0x42, 0xa4, 0xbf, 0x76, 0x1c, 0x2e, 0x82, 0x52, 0x1c, 0x02, 0x2a, + 0xf1, 0xd3, 0xbd, 0xe8, 0x70, 0x40, 0x51, 0xe5, 0x4f, 0xf4, 0x80, 0x70, + 0x16, 0x49, 0x08, 0x80, 0x02, 0x20, 0xf9, 0xf7, 0x4f, 0xb9, 0x00, 0x00, + 0x00, 0xe1, 0x00, 0xe0, 0x80, 0xe1, 0x00, 0xe0, 0x78, 0x29, 0x00, 0x20, + 0x00, 0x00, 0xa6, 0x0e, 0x4c, 0x1f, 0x00, 0x20, 0x80, 0xa2, 0x00, 0x20, + 0x14, 0xc8, 0x00, 0x20, 0x02, 0x08, 0x00, 0x41, 0x20, 0x01, 0x00, 0x41, + 0xfe, 0x01, 0x00, 0x41, 0x22, 0x01, 0x00, 0x41, 0x24, 0x01, 0x00, 0x41, + 0x26, 0x01, 0x00, 0x41, 0x28, 0x01, 0x00, 0x41, 0x30, 0x01, 0x00, 0x41, + 0x32, 0x01, 0x00, 0x41, 0x34, 0x01, 0x00, 0x41, 0x36, 0x01, 0x00, 0x41, + 0xcc, 0xf2, 0x00, 0x20, 0x6c, 0x1f, 0x00, 0x20, 0x08, 0x08, 0x00, 0x41, + 0x00, 0x01, 0x00, 0x41, 0xfc, 0x01, 0x00, 0x41, 0x04, 0x01, 0x00, 0x41, + 0x34, 0x80, 0x37, 0x3a, 0x48, 0xe1, 0x9a, 0xbf, 0x00, 0x00, 0x00, 0x00, + 0x14, 0xc8, 0x00, 0x20, 0x14, 0xc8, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x24, 0xc8, 0x00, 0x20, 0x14, 0xc8, 0x00, 0x20, 0x14, 0xc8, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x20, 0x00, 0x20, + 0x78, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x20, 0x00, 0x20, + 0xa0, 0x20, 0x00, 0x20, 0xb4, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x1f, 0xb5, 0x00, 0xf0, + 0xb7, 0xf8, 0x21, 0x21, 0x01, 0x60, 0x1f, 0xbd, 0xf8, 0xb5, 0x0c, 0x46, + 0x2b, 0x49, 0xf8, 0xf7, 0x4d, 0xf9, 0x05, 0x46, 0x12, 0xd8, 0x2a, 0x4e, + 0x31, 0x46, 0xf8, 0xf7, 0x3f, 0xf8, 0x29, 0x49, 0xf7, 0xf7, 0xa0, 0xff, + 0x07, 0x46, 0x28, 0x46, 0x31, 0x46, 0xf7, 0xf7, 0x9b, 0xff, 0x01, 0x46, + 0x38, 0x46, 0xf7, 0xf7, 0xa5, 0xfe, 0x05, 0x46, 0x44, 0xf0, 0x01, 0x04, + 0x28, 0x46, 0x22, 0x49, 0xf8, 0xf7, 0x1a, 0xf8, 0x03, 0xd3, 0x21, 0x49, + 0xf8, 0xf7, 0x30, 0xf9, 0x21, 0xd8, 0x29, 0x46, 0xf8, 0xf7, 0x24, 0xf8, + 0x06, 0x46, 0x28, 0x46, 0x31, 0x46, 0xf8, 0xf7, 0x1f, 0xf8, 0x1c, 0x49, + 0xf8, 0xf7, 0x1c, 0xf8, 0x29, 0x46, 0xf7, 0xf7, 0x7d, 0xff, 0x05, 0x46, + 0x19, 0x48, 0x31, 0x46, 0xf8, 0xf7, 0x14, 0xf8, 0x18, 0x49, 0xf7, 0xf7, + 0x75, 0xff, 0x31, 0x46, 0xf8, 0xf7, 0x0e, 0xf8, 0x4f, 0xf0, 0x7e, 0x51, + 0xf7, 0xf7, 0x6e, 0xff, 0x01, 0x46, 0x28, 0x46, 0xf7, 0xf7, 0x78, 0xfe, + 0x05, 0x46, 0xa0, 0x07, 0x48, 0xbf, 0x85, 0xf0, 0x00, 0x45, 0x14, 0xf0, + 0x07, 0x00, 0x07, 0xd0, 0x0f, 0xf2, 0x38, 0x01, 0x51, 0xf8, 0x20, 0x00, + 0x29, 0x46, 0xf7, 0xf7, 0x5b, 0xff, 0x05, 0x46, 0x20, 0x07, 0x48, 0xbf, + 0x85, 0xf0, 0x00, 0x45, 0x28, 0x46, 0xf2, 0xbd, 0xa4, 0x30, 0x89, 0x3e, + 0xd7, 0xb3, 0xdd, 0x3f, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x80, 0xb9, + 0x01, 0x00, 0x80, 0x39, 0x6a, 0xd5, 0x03, 0x3f, 0x2b, 0x94, 0xa9, 0x3d, + 0xb8, 0x2a, 0x59, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x92, 0x0a, 0x06, 0x3f, + 0xdb, 0x0f, 0xc9, 0x3f, 0x92, 0x0a, 0x86, 0x3f, 0xdb, 0x0f, 0xc9, 0x3f, + 0x92, 0x0a, 0x06, 0x40, 0xdb, 0x0f, 0x49, 0x40, 0x36, 0x8d, 0x27, 0x40, + 0x02, 0x68, 0x02, 0xf0, 0x00, 0x43, 0x01, 0x21, 0x52, 0x02, 0x52, 0x0a, + 0x02, 0xd1, 0x06, 0xe0, 0x52, 0x00, 0x49, 0x1e, 0x5f, 0xea, 0x02, 0x2c, + 0xfa, 0xd5, 0x52, 0x02, 0x52, 0x0a, 0x1a, 0x43, 0x02, 0x60, 0x08, 0x46, + 0x70, 0x47, 0x02, 0x68, 0xc2, 0xf3, 0xc7, 0x52, 0xff, 0x2a, 0x05, 0xd1, + 0x00, 0x68, 0x40, 0x02, 0x0c, 0xbf, 0x01, 0x20, 0x02, 0x20, 0x70, 0x47, + 0x03, 0x68, 0x5b, 0x00, 0x16, 0xd0, 0xc2, 0xf1, 0x96, 0x02, 0x52, 0x1a, + 0x01, 0x2a, 0x11, 0xdb, 0x18, 0x2a, 0x04, 0xdb, 0x01, 0x68, 0x01, 0xf0, + 0x00, 0x41, 0x01, 0x60, 0x07, 0xe0, 0x01, 0x21, 0x91, 0x40, 0x02, 0x68, + 0x49, 0x1e, 0x11, 0x40, 0x4a, 0x40, 0x02, 0x60, 0x11, 0xb1, 0x4f, 0xf0, + 0xff, 0x30, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x48, 0xf1, 0xf7, + 0x86, 0xb9, 0x00, 0x00, 0x1c, 0xbd, 0x00, 0x20, 0x2d, 0xe9, 0xf0, 0x4d, + 0x04, 0x46, 0x0d, 0x46, 0x27, 0x68, 0xc7, 0xf3, 0xc7, 0x51, 0xff, 0x29, + 0x16, 0x46, 0x09, 0xd0, 0x11, 0xb1, 0x4f, 0xf0, 0xff, 0x30, 0x09, 0xe0, + 0x78, 0x02, 0x0c, 0xbf, 0x00, 0x20, 0x6f, 0xf0, 0x01, 0x00, 0x03, 0xe0, + 0x78, 0x02, 0x14, 0xbf, 0x02, 0x20, 0x01, 0x20, 0xc5, 0xf3, 0xc7, 0x52, + 0xff, 0x2a, 0x09, 0xd0, 0x12, 0xb1, 0x4f, 0xf0, 0xff, 0x31, 0x09, 0xe0, + 0x69, 0x02, 0x0c, 0xbf, 0x00, 0x21, 0x6f, 0xf0, 0x01, 0x01, 0x03, 0xe0, + 0x69, 0x02, 0x14, 0xbf, 0x02, 0x21, 0x01, 0x21, 0x02, 0x00, 0x48, 0xbf, + 0x00, 0x29, 0x3e, 0xd4, 0x02, 0x28, 0x00, 0xf0, 0xc6, 0x80, 0x02, 0x29, + 0x08, 0xbf, 0x25, 0x60, 0x18, 0xd0, 0x39, 0xb9, 0x38, 0x46, 0x4f, 0xf0, + 0xff, 0x41, 0xf7, 0xf7, 0x35, 0xff, 0x0a, 0xd0, 0x25, 0x60, 0x38, 0xe0, + 0x01, 0x29, 0x10, 0xd1, 0x38, 0x46, 0x5c, 0x49, 0xf7, 0xf7, 0x2c, 0xff, + 0x18, 0xbf, 0x25, 0x60, 0x40, 0xd1, 0xff, 0xf7, 0xb1, 0xff, 0x21, 0x21, + 0x01, 0x60, 0x6f, 0xf0, 0x00, 0x40, 0x20, 0x60, 0x02, 0x20, 0xbd, 0xe8, + 0xf0, 0x8d, 0x70, 0xb9, 0x25, 0x60, 0x31, 0x46, 0x20, 0x46, 0x00, 0xf0, + 0x61, 0xff, 0x04, 0x00, 0x18, 0xbf, 0x01, 0x2c, 0x40, 0xf0, 0x9a, 0x80, + 0xff, 0xf7, 0x9c, 0xff, 0x22, 0x21, 0x01, 0x60, 0x94, 0xe0, 0x38, 0x46, + 0x4f, 0xf0, 0xff, 0x41, 0xf7, 0xf7, 0x0a, 0xff, 0x0a, 0xd1, 0x08, 0x46, + 0x29, 0x46, 0xf7, 0xf7, 0x25, 0xff, 0x20, 0x60, 0x1a, 0xe0, 0x38, 0x46, + 0x46, 0x49, 0xf7, 0xf7, 0x0d, 0xff, 0x07, 0xd2, 0x00, 0x20, 0x29, 0x46, + 0xf7, 0xf7, 0x1a, 0xff, 0x20, 0x60, 0x00, 0x20, 0xbd, 0xe8, 0xf0, 0x8d, + 0x41, 0x49, 0xf8, 0xf7, 0x1b, 0xf8, 0x0c, 0xd8, 0x4f, 0xf0, 0xff, 0x40, + 0x29, 0x46, 0xf7, 0xf7, 0x0d, 0xff, 0x20, 0x60, 0xff, 0xf7, 0x74, 0xff, + 0x22, 0x21, 0x01, 0x60, 0x01, 0x20, 0xbd, 0xe8, 0xf0, 0x8d, 0x3a, 0x48, + 0x39, 0x46, 0xf7, 0xf7, 0x01, 0xff, 0x00, 0x21, 0xf7, 0xf7, 0xec, 0xfe, + 0x34, 0xbf, 0x4f, 0xf0, 0x3f, 0x41, 0x4f, 0xf0, 0x7c, 0x51, 0xf7, 0xf7, + 0x5b, 0xfe, 0xf7, 0xf7, 0x61, 0xff, 0x80, 0x46, 0xf7, 0xf7, 0x4a, 0xfd, + 0x82, 0x46, 0x31, 0x48, 0x51, 0x46, 0xf7, 0xf7, 0xed, 0xfe, 0x01, 0x46, + 0x38, 0x46, 0xf7, 0xf7, 0xd9, 0xfd, 0x07, 0x46, 0x2d, 0x48, 0x51, 0x46, + 0xf7, 0xf7, 0xe4, 0xfe, 0x01, 0x46, 0x38, 0x46, 0xf7, 0xf7, 0xd0, 0xfd, + 0x4f, 0xf0, 0x33, 0x41, 0xf7, 0xf7, 0xe4, 0xff, 0x82, 0x46, 0x03, 0xd8, + 0x27, 0x49, 0xf7, 0xf7, 0xc5, 0xfe, 0x2d, 0xd3, 0x51, 0x46, 0xf7, 0xf7, + 0xd3, 0xfe, 0x83, 0x46, 0x24, 0x48, 0x59, 0x46, 0xf7, 0xf7, 0xce, 0xfe, + 0x07, 0x46, 0x23, 0x48, 0x59, 0x46, 0xf7, 0xf7, 0xc9, 0xfe, 0x4f, 0xf0, + 0x7c, 0x51, 0xf7, 0xf7, 0x29, 0xfe, 0x51, 0x46, 0xf7, 0xf7, 0xc2, 0xfe, + 0x82, 0x46, 0x38, 0x46, 0x51, 0x46, 0xf7, 0xf7, 0x21, 0xfe, 0x4f, 0xf0, + 0x7e, 0x51, 0xf7, 0xf7, 0x1d, 0xfe, 0x83, 0x46, 0x38, 0x46, 0x51, 0x46, + 0xf7, 0xf7, 0xa4, 0xfd, 0x4f, 0xf0, 0x7e, 0x51, 0xf7, 0xf7, 0x14, 0xfe, + 0x01, 0x46, 0x58, 0x46, 0xf7, 0xf7, 0x1e, 0xfd, 0x29, 0x46, 0xf7, 0xf7, + 0xa9, 0xfe, 0x05, 0x46, 0x25, 0x60, 0x06, 0xeb, 0x08, 0x01, 0x20, 0x46, + 0x00, 0xf0, 0xca, 0xfe, 0x04, 0x00, 0x18, 0xbf, 0x01, 0x2c, 0x03, 0xd1, + 0xff, 0xf7, 0x06, 0xff, 0x22, 0x21, 0x01, 0x60, 0x20, 0x46, 0xbd, 0xe8, + 0xf0, 0x8d, 0x00, 0xbf, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x65, 0xc3, + 0x01, 0x00, 0x65, 0x43, 0x3b, 0xaa, 0xb8, 0x3f, 0x00, 0x60, 0x31, 0x3f, + 0xbf, 0xbf, 0x90, 0x39, 0x01, 0x00, 0x00, 0x33, 0x9e, 0xbf, 0xcc, 0x3d, + 0x13, 0x54, 0x08, 0x3c, 0x70, 0x47, 0x00, 0x00, 0xd2, 0xb2, 0x20, 0x3a, + 0x22, 0xbf, 0x41, 0xfa, 0x02, 0xf0, 0xc9, 0x17, 0x70, 0x47, 0x20, 0x32, + 0xd1, 0x41, 0xd0, 0x40, 0x48, 0x40, 0x91, 0x40, 0xd1, 0x40, 0x48, 0x40, + 0x91, 0x40, 0x11, 0x41, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x00, 0xf0, + 0xad, 0xb9, 0x70, 0x47, 0x80, 0xb5, 0xf5, 0xf7, 0x0c, 0xfa, 0xbd, 0xe8, + 0x01, 0x40, 0x00, 0xf0, 0xa5, 0xb9, 0x70, 0x47, 0x00, 0xf0, 0xa1, 0xb8, + 0x00, 0xb5, 0x00, 0xbf, 0x13, 0x00, 0x96, 0x46, 0x94, 0x46, 0x10, 0x39, + 0x28, 0xbf, 0xa0, 0xe8, 0x0c, 0x50, 0xfa, 0xd8, 0x5f, 0xea, 0x41, 0x7c, + 0x28, 0xbf, 0x0c, 0xc0, 0x48, 0xbf, 0x40, 0xf8, 0x04, 0x2b, 0xc9, 0x07, + 0x28, 0xbf, 0x20, 0xf8, 0x02, 0x2b, 0x48, 0xbf, 0x00, 0xf8, 0x01, 0x2b, + 0x00, 0xbd, 0x00, 0x00, 0x80, 0xb5, 0x4f, 0xf0, 0x92, 0x41, 0x00, 0x20, + 0x08, 0x60, 0x06, 0x21, 0x0f, 0x20, 0xf8, 0xf7, 0xfa, 0xfe, 0xbd, 0xe8, + 0x02, 0x40, 0x02, 0xe0, 0x0c, 0x49, 0x08, 0x60, 0x70, 0x47, 0x0f, 0x20, + 0xf8, 0xf7, 0xdc, 0xbe, 0x1c, 0xb5, 0x4f, 0xf0, 0x92, 0x44, 0x08, 0x49, + 0x20, 0x68, 0x00, 0x90, 0x60, 0x68, 0x09, 0x68, 0x01, 0x90, 0x00, 0x98, + 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x90, 0x68, 0x46, 0x88, 0x47, 0x00, 0x20, + 0x20, 0x60, 0x13, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xf3, 0x00, 0x20, + 0x10, 0xb5, 0x93, 0x48, 0x93, 0x4c, 0x4f, 0xf4, 0xf0, 0x01, 0x01, 0x62, + 0xc2, 0x6a, 0x42, 0xf4, 0xf0, 0x02, 0xc2, 0x62, 0x02, 0x6b, 0x42, 0xf4, + 0xf0, 0x02, 0x02, 0x63, 0x01, 0x60, 0x11, 0x20, 0xf8, 0xf7, 0xc3, 0xfe, + 0x06, 0x21, 0x11, 0x20, 0xf8, 0xf7, 0xc5, 0xfe, 0x11, 0x20, 0xf8, 0xf7, + 0xad, 0xfe, 0x4f, 0xf4, 0x40, 0x30, 0xe0, 0x62, 0xa1, 0x6b, 0x41, 0xf4, + 0x40, 0x31, 0xa1, 0x63, 0xe1, 0x6b, 0x41, 0xf4, 0x40, 0x31, 0xe1, 0x63, + 0x20, 0x60, 0x21, 0x20, 0xf8, 0xf7, 0xad, 0xfe, 0x06, 0x21, 0x21, 0x20, + 0xf8, 0xf7, 0xaf, 0xfe, 0x21, 0x20, 0xf8, 0xf7, 0x97, 0xfe, 0x00, 0x20, + 0x60, 0x60, 0x22, 0x20, 0xf8, 0xf7, 0xa1, 0xfe, 0x06, 0x21, 0x22, 0x20, + 0xf8, 0xf7, 0xa3, 0xfe, 0x22, 0x20, 0xf8, 0xf7, 0x8b, 0xfe, 0x00, 0x20, + 0xa0, 0x60, 0x23, 0x20, 0xf8, 0xf7, 0x95, 0xfe, 0x06, 0x21, 0x23, 0x20, + 0xf8, 0xf7, 0x97, 0xfe, 0xbd, 0xe8, 0x10, 0x40, 0x23, 0x20, 0xf8, 0xf7, + 0x7d, 0xbe, 0x80, 0xb5, 0x11, 0x20, 0xf8, 0xf7, 0x82, 0xfe, 0x21, 0x20, + 0xf8, 0xf7, 0x7f, 0xfe, 0x22, 0x20, 0xf8, 0xf7, 0x7c, 0xfe, 0xbd, 0xe8, + 0x02, 0x40, 0x23, 0x20, 0xf8, 0xf7, 0x77, 0xbe, 0x69, 0x49, 0x51, 0xf8, + 0x20, 0x00, 0x00, 0xb1, 0x01, 0x20, 0xc0, 0xb2, 0x70, 0x47, 0x80, 0xb5, + 0x22, 0x20, 0xf8, 0xf7, 0x72, 0xfe, 0xbd, 0xe8, 0x02, 0x40, 0x23, 0x20, + 0xf8, 0xf7, 0x6d, 0xbe, 0xf8, 0xb5, 0x00, 0x24, 0x0f, 0xf2, 0x88, 0x15, + 0x5d, 0x4e, 0x5f, 0x4f, 0x57, 0xf8, 0x24, 0x00, 0x38, 0xb1, 0x30, 0x68, + 0x55, 0xf8, 0x24, 0x10, 0x08, 0x43, 0x30, 0x60, 0x11, 0x20, 0xf8, 0xf7, + 0x5c, 0xfe, 0x07, 0xeb, 0x84, 0x01, 0x64, 0x1c, 0x00, 0x20, 0x02, 0x2c, + 0xc8, 0x60, 0xed, 0xd3, 0xf1, 0xbd, 0x10, 0xb5, 0x54, 0x4c, 0xa0, 0x68, + 0x30, 0xb1, 0x52, 0x49, 0x4f, 0xf4, 0x40, 0x30, 0x08, 0x60, 0x21, 0x20, + 0xf8, 0xf7, 0x49, 0xfe, 0x00, 0x20, 0x60, 0x61, 0x10, 0xbd, 0x2d, 0xe9, + 0xf8, 0x4f, 0x01, 0x21, 0x36, 0x20, 0xf8, 0xf7, 0xba, 0xfe, 0x00, 0x24, + 0x48, 0x4d, 0xdf, 0xf8, 0x2c, 0x81, 0x0f, 0xf2, 0x44, 0x1b, 0x48, 0x4e, + 0x0f, 0xf2, 0x24, 0x19, 0x0f, 0xf2, 0x2c, 0x1a, 0x5a, 0xf8, 0x24, 0x00, + 0x59, 0xf8, 0x24, 0x70, 0x01, 0x68, 0x39, 0x40, 0x29, 0xd0, 0x01, 0x60, + 0xf0, 0x69, 0xa0, 0x42, 0x05, 0xd1, 0x01, 0x20, 0xb0, 0x61, 0x01, 0x21, + 0x3b, 0x20, 0xf8, 0xf7, 0x9e, 0xfe, 0x5b, 0xf8, 0x24, 0x00, 0x00, 0x68, + 0x06, 0xeb, 0x84, 0x01, 0x38, 0x40, 0xca, 0x68, 0x46, 0xf8, 0x24, 0x00, + 0x52, 0x1c, 0xca, 0x60, 0x30, 0xb1, 0xb8, 0xf8, 0x56, 0x00, 0x90, 0x42, + 0x02, 0xd2, 0x28, 0x68, 0xb8, 0x43, 0x28, 0x60, 0x20, 0x46, 0xff, 0xf7, + 0xbf, 0xfa, 0x56, 0xf8, 0x24, 0x10, 0x01, 0xb1, 0x01, 0x21, 0x04, 0xf1, + 0x38, 0x00, 0xc9, 0xb2, 0xc0, 0xb2, 0xf8, 0xf7, 0x7e, 0xfe, 0x64, 0x1c, + 0x02, 0x2c, 0xcb, 0xd3, 0xbd, 0xe8, 0xf4, 0x4f, 0x00, 0x21, 0x36, 0x20, + 0xf8, 0xf7, 0x75, 0xbe, 0x38, 0xb5, 0x01, 0x21, 0x37, 0x20, 0xf8, 0xf7, + 0x70, 0xfe, 0x25, 0x4c, 0x25, 0x4d, 0xe0, 0x6a, 0x00, 0xf4, 0x40, 0x30, + 0xe0, 0x62, 0xe9, 0x69, 0x02, 0x29, 0x06, 0xd1, 0x28, 0xb1, 0x01, 0x20, + 0xa8, 0x61, 0x01, 0x21, 0x3b, 0x20, 0xf8, 0xf7, 0x60, 0xfe, 0x20, 0x6b, + 0x69, 0x69, 0x00, 0xf4, 0x40, 0x30, 0x49, 0x1c, 0xa8, 0x60, 0x69, 0x61, + 0x50, 0xb1, 0x1b, 0x48, 0xb0, 0xf8, 0x56, 0x00, 0x88, 0x42, 0x3c, 0xbf, + 0x00, 0x20, 0x20, 0x60, 0xa9, 0x68, 0x11, 0xb1, 0x01, 0x21, 0x00, 0xe0, + 0x00, 0x21, 0xc9, 0xb2, 0x3a, 0x20, 0xf8, 0xf7, 0x48, 0xfe, 0xbd, 0xe8, + 0x34, 0x40, 0x00, 0x21, 0x37, 0x20, 0xf8, 0xf7, 0x42, 0xbe, 0x0f, 0x49, + 0x0f, 0xf2, 0x58, 0x02, 0x0f, 0xf2, 0x3c, 0x03, 0xc8, 0x61, 0x52, 0xf8, + 0x20, 0x20, 0x12, 0x68, 0x53, 0xf8, 0x20, 0x00, 0x10, 0x40, 0x88, 0x61, + 0x01, 0x00, 0x18, 0xbf, 0x01, 0x21, 0xc9, 0xb2, 0x3b, 0x20, 0xf8, 0xf7, + 0x2e, 0xbe, 0x05, 0x49, 0x89, 0x69, 0x00, 0x20, 0x01, 0xb1, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x00, 0x20, 0x00, 0x00, 0x50, 0x14, 0x00, 0x00, 0x58, + 0xac, 0xf2, 0x00, 0x20, 0x4c, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x50, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x50, + 0x40, 0x00, 0x00, 0x50, 0x40, 0x00, 0x00, 0x58, 0x44, 0x00, 0x00, 0x50, + 0x44, 0x00, 0x00, 0x50, 0x44, 0x00, 0x00, 0x58, 0x80, 0xb5, 0x00, 0xf0, + 0x13, 0xf8, 0x19, 0x20, 0xf8, 0xf7, 0x78, 0xfd, 0x4f, 0xf0, 0xa4, 0x41, + 0x15, 0x48, 0x08, 0x60, 0x00, 0x21, 0x19, 0x20, 0xf8, 0xf7, 0x8b, 0xfd, + 0xbd, 0xe8, 0x01, 0x40, 0x12, 0x49, 0x01, 0x20, 0x08, 0x60, 0x19, 0x20, + 0xf8, 0xf7, 0x6e, 0xbd, 0x80, 0xb5, 0x19, 0x20, 0xf8, 0xf7, 0x73, 0xfd, + 0x0d, 0x49, 0x00, 0x20, 0x08, 0x60, 0x01, 0xbd, 0xef, 0xf3, 0x11, 0x80, + 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x09, 0x49, 0x0a, 0x68, 0x42, 0xf0, + 0x02, 0x03, 0x0b, 0x60, 0x22, 0xf0, 0x02, 0x02, 0x0a, 0x60, 0x80, 0xf3, + 0x11, 0x88, 0x70, 0x47, 0x03, 0x48, 0x00, 0x68, 0x00, 0xf0, 0x01, 0x00, + 0x70, 0x47, 0x00, 0x00, 0x00, 0x70, 0x17, 0x00, 0x04, 0x00, 0x00, 0x52, + 0x00, 0x20, 0xf8, 0xf7, 0xfe, 0xbc, 0x00, 0x00, 0x09, 0x42, 0x40, 0xf1, + 0x0d, 0x80, 0xf4, 0x46, 0x49, 0x42, 0x40, 0x42, 0x71, 0xf1, 0x00, 0x01, + 0x00, 0xf0, 0x06, 0xf8, 0x51, 0xf0, 0x00, 0x41, 0x60, 0x47, 0x00, 0x00, + 0x09, 0x42, 0x00, 0xbf, 0x08, 0xbf, 0x00, 0xf0, 0x15, 0xbd, 0x02, 0x46, + 0x08, 0x46, 0xb0, 0xfa, 0x80, 0xf1, 0x50, 0x40, 0x8a, 0x40, 0xc1, 0xf1, + 0x20, 0x01, 0xc8, 0x41, 0x50, 0x40, 0xc9, 0x1e, 0x01, 0xf5, 0x84, 0x61, + 0x09, 0x05, 0x01, 0xeb, 0xd0, 0x21, 0x40, 0x05, 0x40, 0xea, 0xd2, 0x20, + 0x52, 0x05, 0x72, 0xf1, 0x00, 0x42, 0x50, 0xf1, 0x00, 0x00, 0x41, 0xf1, + 0x00, 0x01, 0x70, 0x47, 0xf0, 0xb4, 0x4f, 0xf0, 0x00, 0x45, 0x91, 0xea, + 0x03, 0x0c, 0x44, 0xbf, 0x6b, 0x40, 0x00, 0xf0, 0xbf, 0xb9, 0x00, 0xbf, + 0x84, 0x1a, 0x71, 0xeb, 0x03, 0x06, 0x03, 0xd2, 0x00, 0x1b, 0xb1, 0x41, + 0x12, 0x19, 0x73, 0x41, 0x4f, 0xf4, 0x00, 0x1c, 0x1c, 0xeb, 0x41, 0x0f, + 0x34, 0xbf, 0x7c, 0xeb, 0x43, 0x04, 0x43, 0xe0, 0x0c, 0x0d, 0xa4, 0xeb, + 0x13, 0x56, 0x35, 0x2e, 0x50, 0xdc, 0x45, 0xea, 0xc3, 0x23, 0xdb, 0x0a, + 0x45, 0xea, 0xc1, 0x21, 0xc9, 0x12, 0xb6, 0xf1, 0x20, 0x05, 0x0d, 0xdd, + 0x63, 0xfa, 0x05, 0xf6, 0xeb, 0x40, 0x86, 0xea, 0x03, 0x05, 0x12, 0x42, + 0x18, 0xbf, 0x45, 0xf0, 0x01, 0x05, 0xc0, 0x18, 0x51, 0xf1, 0x00, 0x01, + 0x0c, 0xd2, 0x13, 0xe0, 0x62, 0xfa, 0x06, 0xf5, 0xf2, 0x40, 0x55, 0x40, + 0xf3, 0x41, 0x5a, 0x40, 0xb3, 0x40, 0xf3, 0x40, 0x5a, 0x40, 0x80, 0x18, + 0x59, 0x41, 0x07, 0xd3, 0x49, 0x08, 0x5f, 0xea, 0x30, 0x00, 0x5f, 0xea, + 0x35, 0x05, 0x28, 0xbf, 0x45, 0xf0, 0x01, 0x05, 0x01, 0xf5, 0x80, 0x11, + 0x42, 0x08, 0x75, 0xf1, 0x00, 0x42, 0x50, 0xf1, 0x00, 0x00, 0x41, 0xeb, + 0x04, 0x51, 0xf0, 0xbc, 0x4f, 0xf4, 0x00, 0x1c, 0x1c, 0xeb, 0x41, 0x0f, + 0x38, 0xbf, 0x70, 0x47, 0x00, 0x20, 0x09, 0x0d, 0x09, 0x05, 0x70, 0x47, + 0x1c, 0xeb, 0x41, 0x0f, 0x10, 0xd2, 0x52, 0xea, 0x43, 0x06, 0x0b, 0xd0, + 0xbc, 0xeb, 0x41, 0x0f, 0x05, 0xd8, 0x0c, 0x0d, 0xab, 0x43, 0x66, 0x1e, + 0x34, 0x2e, 0xb5, 0xdd, 0x02, 0xe0, 0xab, 0x43, 0x80, 0x18, 0x59, 0x41, + 0xf0, 0xbc, 0x70, 0x47, 0xf0, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0x81, 0xea, + 0x03, 0x0c, 0x0c, 0xf0, 0x00, 0x4c, 0x40, 0xf2, 0xff, 0x75, 0x15, 0xea, + 0x11, 0x54, 0x1d, 0xbf, 0x15, 0xea, 0x13, 0x57, 0xac, 0x42, 0xaf, 0x42, + 0x39, 0xe0, 0xe4, 0x19, 0x23, 0xea, 0x45, 0x53, 0x43, 0xf4, 0x80, 0x13, + 0xc9, 0x02, 0x41, 0xf0, 0x00, 0x41, 0x41, 0xea, 0x50, 0x5e, 0xc7, 0x02, + 0x11, 0x00, 0xa7, 0xfb, 0x02, 0x02, 0x00, 0x28, 0x4f, 0xf0, 0x00, 0x00, + 0xee, 0xfb, 0x01, 0x20, 0x4f, 0xf0, 0x00, 0x01, 0xe3, 0xfb, 0x07, 0x21, + 0x18, 0xbf, 0x42, 0xf0, 0x01, 0x02, 0x40, 0x18, 0x00, 0x21, 0x49, 0x41, + 0xe3, 0xfb, 0x0e, 0x01, 0xa4, 0xf5, 0x80, 0x64, 0x0f, 0x03, 0x02, 0xd2, + 0x52, 0x00, 0x40, 0x41, 0x49, 0x41, 0x54, 0xf1, 0x01, 0x04, 0x6c, 0xdd, + 0x47, 0x08, 0x72, 0xf1, 0x00, 0x42, 0x50, 0xf1, 0x00, 0x00, 0x51, 0xeb, + 0x04, 0x51, 0xa1, 0xf5, 0x80, 0x11, 0x5c, 0xbf, 0x41, 0xea, 0x0c, 0x01, + 0xb0, 0xbd, 0x4c, 0xea, 0x05, 0x51, 0x00, 0x20, 0xb0, 0xbd, 0x05, 0xea, + 0x13, 0x57, 0xac, 0x42, 0x14, 0xbf, 0xaf, 0x42, 0x41, 0xe0, 0x50, 0xea, + 0x41, 0x0e, 0x1c, 0xbf, 0x52, 0xea, 0x43, 0x0e, 0x02, 0xe0, 0x61, 0x46, + 0x00, 0x20, 0xb0, 0xbd, 0x24, 0x42, 0x3c, 0x44, 0x1b, 0xd1, 0x5f, 0xea, + 0x07, 0x0e, 0xf6, 0xd0, 0x09, 0x03, 0x02, 0xbf, 0x01, 0x46, 0x00, 0x20, + 0xae, 0xf1, 0x14, 0x0e, 0xb1, 0xfa, 0x81, 0xf7, 0xae, 0xeb, 0x07, 0x04, + 0x01, 0xfa, 0x07, 0xfe, 0x0c, 0x37, 0xc7, 0xf1, 0x20, 0x01, 0x00, 0xfa, + 0x07, 0xf7, 0xc8, 0x40, 0x4e, 0xea, 0x00, 0x0e, 0x23, 0xea, 0x45, 0x53, + 0x43, 0xf4, 0x80, 0x13, 0xa2, 0xe7, 0x33, 0xf0, 0x00, 0x43, 0xb3, 0xfa, + 0x83, 0xf7, 0x04, 0xbf, 0xb2, 0xfa, 0x82, 0xfe, 0x77, 0x44, 0x0b, 0x3f, + 0xe4, 0x1b, 0xb7, 0xf1, 0x20, 0x0e, 0x2f, 0xbf, 0x02, 0xfa, 0x0e, 0xf3, + 0xbb, 0x40, 0xc7, 0xf1, 0x20, 0x0e, 0x22, 0xfa, 0x0e, 0xfe, 0x38, 0xbf, + 0x43, 0xea, 0x0e, 0x03, 0xba, 0x40, 0x64, 0x1c, 0x82, 0xe7, 0x50, 0xea, + 0x41, 0x0e, 0x14, 0xbf, 0x52, 0xea, 0x43, 0x0e, 0x6f, 0xf0, 0x00, 0x01, + 0x4f, 0xf4, 0x00, 0x17, 0x17, 0xeb, 0x43, 0x0f, 0x8a, 0xbf, 0x19, 0x46, + 0x17, 0xeb, 0x41, 0x0f, 0xb5, 0xe7, 0x4c, 0xea, 0x05, 0x51, 0x00, 0x20, + 0xb0, 0xbd, 0xd4, 0xf1, 0x01, 0x04, 0xb4, 0xf1, 0x20, 0x07, 0x0f, 0xda, + 0xc4, 0xf1, 0x20, 0x07, 0x52, 0x08, 0x28, 0xbf, 0x42, 0xf0, 0x01, 0x02, + 0x10, 0xfa, 0x07, 0xf5, 0x01, 0xfa, 0x07, 0xf7, 0xe1, 0xbf, 0x2a, 0x43, + 0xe0, 0x40, 0x38, 0x43, 0xe1, 0x40, 0x0f, 0xe0, 0x35, 0x2c, 0x98, 0xdc, + 0xc7, 0xf1, 0x20, 0x04, 0x52, 0xea, 0x40, 0x02, 0x20, 0xfa, 0x07, 0xf2, + 0x18, 0xbf, 0x42, 0xf0, 0x01, 0x02, 0x31, 0xfa, 0x07, 0xf0, 0xa1, 0x40, + 0x0a, 0x43, 0x00, 0x21, 0x72, 0xf1, 0x00, 0x42, 0x50, 0xf1, 0x00, 0x00, + 0x51, 0xeb, 0x0c, 0x01, 0xb0, 0xbd, 0x00, 0x00, 0x40, 0xf2, 0xff, 0x7c, + 0x0b, 0x0d, 0x4d, 0xd0, 0x63, 0x45, 0x66, 0xd2, 0x30, 0xb4, 0x21, 0xea, + 0x03, 0x51, 0x41, 0xf4, 0x80, 0x11, 0x03, 0xf2, 0xfd, 0x3c, 0x5f, 0xea, + 0x5c, 0x0c, 0x01, 0xd3, 0x00, 0x18, 0x49, 0x41, 0x89, 0x00, 0x41, 0xea, + 0x90, 0x71, 0x80, 0x00, 0x4f, 0xf4, 0x40, 0x14, 0x00, 0x23, 0xe2, 0x02, + 0xd5, 0x0a, 0xb1, 0xf5, 0x10, 0x01, 0x07, 0xd4, 0x6d, 0x08, 0x1d, 0xd2, + 0x09, 0x1b, 0x64, 0x19, 0x00, 0x18, 0x49, 0x41, 0x49, 0x1b, 0xf7, 0xd5, + 0x6d, 0x08, 0x0a, 0xd2, 0x09, 0x19, 0x64, 0x1b, 0x00, 0x18, 0x49, 0x41, + 0x49, 0x1b, 0xef, 0xd5, 0x6d, 0x08, 0xf7, 0xd3, 0x01, 0xe0, 0x52, 0x08, + 0x17, 0xd0, 0xc0, 0x18, 0x61, 0x41, 0x9b, 0x1a, 0xac, 0x41, 0x00, 0x18, + 0x49, 0x41, 0x80, 0x1a, 0xa9, 0x41, 0xf4, 0xd4, 0x52, 0x08, 0x0a, 0xd0, + 0xc0, 0x1a, 0xa1, 0x41, 0x9b, 0x18, 0x6c, 0x41, 0x00, 0x18, 0x49, 0x41, + 0x80, 0x1a, 0xa9, 0x41, 0xe9, 0xd4, 0x52, 0x08, 0xf4, 0xd1, 0x5b, 0x1c, + 0x6c, 0x41, 0x61, 0x08, 0x4f, 0xea, 0x33, 0x00, 0x01, 0xeb, 0x0c, 0x51, + 0x30, 0xbc, 0x70, 0x47, 0x50, 0xea, 0x01, 0x03, 0xfb, 0xd0, 0x30, 0xb4, + 0xb1, 0xfa, 0x81, 0xf3, 0x11, 0xb9, 0xb0, 0xfa, 0x80, 0xf4, 0x1b, 0x19, + 0x0b, 0x3b, 0xb3, 0xf1, 0x20, 0x04, 0x2f, 0xbf, 0x00, 0xfa, 0x04, 0xf1, + 0x99, 0x40, 0xc3, 0xf1, 0x20, 0x04, 0x20, 0xfa, 0x04, 0xf4, 0x38, 0xbf, + 0x21, 0x43, 0x98, 0x40, 0xd3, 0xf1, 0x01, 0x03, 0x9d, 0xe7, 0x63, 0x45, + 0xe1, 0xd0, 0x11, 0xf5, 0x80, 0x1f, 0xde, 0xd8, 0x50, 0xea, 0x41, 0x01, + 0xdb, 0xd0, 0xd9, 0x43, 0xff, 0xf7, 0x66, 0xba, 0xf0, 0xb4, 0x4f, 0xf0, + 0x00, 0x45, 0x91, 0xea, 0x03, 0x0f, 0x44, 0xbf, 0x6b, 0x40, 0xff, 0xf7, + 0x43, 0xbe, 0x00, 0xbf, 0x84, 0x1a, 0x71, 0xeb, 0x03, 0x06, 0x04, 0xd2, + 0x6e, 0x40, 0x00, 0x1b, 0xb1, 0x41, 0x12, 0x19, 0x73, 0x41, 0x4f, 0xf4, + 0x00, 0x1c, 0x1c, 0xeb, 0x41, 0x0f, 0x34, 0xbf, 0x7c, 0xeb, 0x43, 0x06, + 0x84, 0xe0, 0x0c, 0x0d, 0xa4, 0xeb, 0x13, 0x56, 0x36, 0x2e, 0x7d, 0xdc, + 0x01, 0x2e, 0x43, 0xdc, 0x45, 0xea, 0xc3, 0x23, 0x43, 0xea, 0x52, 0x53, + 0x12, 0xbf, 0xd2, 0x02, 0x92, 0x02, 0x5b, 0x08, 0x24, 0x05, 0x45, 0xea, + 0xc1, 0x21, 0x41, 0xea, 0x50, 0x51, 0xd2, 0xeb, 0xc0, 0x20, 0x99, 0x41, + 0x25, 0xd4, 0x07, 0xd1, 0xb0, 0xfa, 0x80, 0xf6, 0x10, 0xfa, 0x06, 0xf1, + 0x64, 0xd0, 0x00, 0x20, 0x20, 0x36, 0x08, 0xe0, 0xb1, 0xfa, 0x81, 0xf6, + 0xb1, 0x40, 0xc6, 0xf1, 0x20, 0x02, 0x20, 0xfa, 0x02, 0xf2, 0x11, 0x43, + 0xb0, 0x40, 0x4f, 0xea, 0xf4, 0x74, 0xb4, 0xeb, 0x46, 0x54, 0x34, 0xf0, + 0x01, 0x06, 0x4f, 0xea, 0x74, 0x04, 0x0a, 0xd8, 0xd6, 0xf5, 0x00, 0x16, + 0x76, 0x0d, 0x04, 0xf0, 0x00, 0x44, 0xf0, 0x40, 0x61, 0xfa, 0x06, 0xf2, + 0x50, 0x40, 0xf1, 0x40, 0x48, 0x40, 0xc0, 0x0a, 0x40, 0xea, 0x41, 0x50, + 0x21, 0xf0, 0x00, 0x41, 0x28, 0xbf, 0x5f, 0xea, 0x50, 0x05, 0x50, 0xf1, + 0x00, 0x00, 0x44, 0xeb, 0xd1, 0x21, 0x37, 0xe0, 0x45, 0xea, 0xc3, 0x23, + 0xdb, 0x0a, 0x45, 0xea, 0xc1, 0x21, 0xc9, 0x0a, 0xb6, 0xf1, 0x20, 0x05, + 0x0e, 0xdd, 0x42, 0xea, 0x02, 0x42, 0x12, 0x0c, 0xc5, 0xf1, 0x20, 0x06, + 0x03, 0xfa, 0x06, 0xf6, 0xeb, 0x40, 0x42, 0xea, 0x06, 0x05, 0x6d, 0x42, + 0x98, 0x41, 0x61, 0xf1, 0x00, 0x01, 0x0d, 0xe0, 0x62, 0xfa, 0x06, 0xf5, + 0xf2, 0x40, 0x55, 0x40, 0x63, 0xfa, 0x06, 0xfc, 0x82, 0xea, 0x0c, 0x02, + 0xf3, 0x40, 0x5a, 0x40, 0x6d, 0x42, 0x90, 0x41, 0x61, 0xeb, 0x03, 0x01, + 0x11, 0xf4, 0x80, 0x1f, 0x05, 0xd1, 0x64, 0x1e, 0x62, 0x05, 0x02, 0xd0, + 0x6d, 0x00, 0x40, 0x41, 0x49, 0x41, 0x21, 0xf4, 0x80, 0x11, 0x43, 0x08, + 0x75, 0xf1, 0x00, 0x43, 0x50, 0xf1, 0x00, 0x00, 0x41, 0xeb, 0x04, 0x51, + 0xf0, 0xbc, 0x70, 0x47, 0x1c, 0xeb, 0x41, 0x0f, 0x15, 0xd2, 0x23, 0xf0, + 0x00, 0x43, 0x52, 0xea, 0x43, 0x06, 0x0b, 0xd0, 0x4f, 0xea, 0x4c, 0x0c, + 0xbc, 0xeb, 0x41, 0x0f, 0x04, 0xd8, 0x0c, 0x0d, 0x66, 0x1e, 0x34, 0x2e, + 0xb7, 0xdd, 0xeb, 0xe7, 0x80, 0x1a, 0x99, 0x41, 0x50, 0xea, 0x41, 0x06, + 0x08, 0xbf, 0x00, 0x21, 0xe4, 0xe7, 0x08, 0xbf, 0x1c, 0xeb, 0x43, 0x0f, + 0x28, 0xbf, 0x6f, 0xf0, 0x00, 0x01, 0xdd, 0xe7, 0x4f, 0xea, 0xf1, 0x7c, + 0xbc, 0xf1, 0xe0, 0x4c, 0x2c, 0xbf, 0xbc, 0xf5, 0x00, 0x1f, 0x11, 0xe0, + 0x5f, 0xea, 0x4c, 0x0c, 0x34, 0xbf, 0xbc, 0xf1, 0x7f, 0x5f, 0x2e, 0xe0, + 0x5f, 0xea, 0x9c, 0x0c, 0x4f, 0xea, 0x0c, 0x1c, 0x4f, 0xea, 0x3c, 0x0c, + 0xc1, 0x00, 0x71, 0xf1, 0x00, 0x41, 0x4c, 0xeb, 0x50, 0x70, 0x70, 0x47, + 0xc9, 0x02, 0x41, 0xea, 0x50, 0x51, 0xc0, 0x02, 0x18, 0xbf, 0x41, 0xf0, + 0x01, 0x01, 0x41, 0xf0, 0x00, 0x41, 0x4f, 0xea, 0x6c, 0x50, 0xc0, 0xf1, + 0x09, 0x00, 0x21, 0x28, 0x10, 0xd2, 0x40, 0xea, 0xcc, 0x7c, 0xcc, 0xf1, + 0x20, 0x0c, 0x11, 0xfa, 0x0c, 0xf0, 0x70, 0xf1, 0x00, 0x40, 0xcc, 0xf1, + 0x20, 0x0c, 0x21, 0xfa, 0x0c, 0xf0, 0x0c, 0xf0, 0x00, 0x4c, 0x40, 0xeb, + 0x0c, 0x00, 0x70, 0x47, 0x4f, 0xea, 0xcc, 0x70, 0x70, 0x47, 0x49, 0x00, + 0x11, 0xf5, 0x00, 0x1f, 0x04, 0xd8, 0x4f, 0xea, 0xcc, 0x10, 0xff, 0x30, + 0xc0, 0x05, 0x70, 0x47, 0xc8, 0x17, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x41, + 0x40, 0xf2, 0xff, 0x75, 0x81, 0xea, 0x03, 0x0c, 0x0c, 0xf0, 0x00, 0x4c, + 0x15, 0xea, 0x11, 0x54, 0x1d, 0xbf, 0x15, 0xea, 0x13, 0x57, 0xac, 0x42, + 0xaf, 0x42, 0xe9, 0xe0, 0xbc, 0x41, 0xc1, 0xf3, 0x13, 0x01, 0xc3, 0xf3, + 0x13, 0x03, 0x80, 0x1a, 0x99, 0x41, 0x43, 0xf4, 0x80, 0x13, 0x04, 0xd2, + 0x64, 0x1e, 0x40, 0x00, 0x49, 0x41, 0x80, 0x18, 0x59, 0x41, 0xc9, 0x02, + 0x41, 0xea, 0x50, 0x51, 0xb1, 0xfb, 0xf3, 0xf6, 0x03, 0xfb, 0x16, 0x11, + 0xa2, 0xfb, 0x06, 0x75, 0xd7, 0xeb, 0xc0, 0x20, 0xa9, 0x41, 0x02, 0xd2, + 0x76, 0x1e, 0x80, 0x18, 0x59, 0x41, 0xc9, 0x02, 0x41, 0xea, 0x50, 0x51, + 0xb1, 0xfb, 0xf3, 0xfe, 0x03, 0xfb, 0x1e, 0x11, 0xa2, 0xfb, 0x0e, 0x75, + 0xd7, 0xeb, 0xc0, 0x20, 0xa9, 0x41, 0x03, 0xd2, 0xae, 0xf1, 0x01, 0x0e, + 0x80, 0x18, 0x59, 0x41, 0x89, 0x02, 0x41, 0xea, 0x90, 0x51, 0x76, 0x05, + 0x46, 0xea, 0x8e, 0x2e, 0xb1, 0xfb, 0xf3, 0xf6, 0x03, 0xfb, 0x16, 0x11, + 0xa2, 0xfb, 0x06, 0x75, 0xd7, 0xeb, 0x80, 0x20, 0xa9, 0x41, 0x02, 0xd2, + 0x76, 0x1e, 0x80, 0x18, 0x59, 0x41, 0xc9, 0x02, 0x41, 0xea, 0x50, 0x51, + 0x4e, 0xea, 0x06, 0x0e, 0xb1, 0xfb, 0xf3, 0xf6, 0x03, 0xfb, 0x16, 0x11, + 0xa2, 0xfb, 0x06, 0x75, 0xd7, 0xeb, 0xc0, 0x20, 0xa9, 0x41, 0x02, 0xd2, + 0x76, 0x1e, 0x80, 0x18, 0x59, 0x41, 0xc9, 0x02, 0x41, 0xea, 0x50, 0x51, + 0xb1, 0xfb, 0xf3, 0xf7, 0x03, 0xfb, 0x17, 0x11, 0xa2, 0xfb, 0x07, 0x35, + 0xd3, 0xeb, 0xc0, 0x20, 0xa9, 0x41, 0x67, 0xf1, 0x00, 0x07, 0x0c, 0xbf, + 0x00, 0x42, 0x47, 0xf0, 0x01, 0x07, 0x66, 0xf3, 0xd5, 0x27, 0x4f, 0xea, + 0x1e, 0x31, 0xb8, 0x08, 0x14, 0xf5, 0x80, 0x64, 0x14, 0xdd, 0xbd, 0x07, + 0x75, 0xf1, 0x00, 0x42, 0x50, 0xeb, 0x0e, 0x50, 0x51, 0xeb, 0x04, 0x51, + 0x11, 0xf5, 0x80, 0x1f, 0x5c, 0xbf, 0x41, 0xea, 0x0c, 0x01, 0xbd, 0xe8, + 0xf0, 0x81, 0x4c, 0xf0, 0x7f, 0x61, 0x41, 0xf0, 0xe0, 0x41, 0x00, 0x20, + 0xbd, 0xe8, 0xf0, 0x81, 0xbd, 0x07, 0x6d, 0x08, 0x40, 0xea, 0x0e, 0x50, + 0x41, 0xf4, 0x80, 0x11, 0xd4, 0xf1, 0x01, 0x04, 0xb4, 0xf1, 0x20, 0x06, + 0x0a, 0xda, 0xc4, 0xf1, 0x20, 0x06, 0x02, 0x00, 0xe0, 0x40, 0x01, 0xfa, + 0x06, 0xf3, 0xe1, 0x40, 0x18, 0x43, 0xb2, 0x40, 0x15, 0x43, 0x0e, 0xe0, + 0x34, 0x2c, 0x14, 0xdc, 0xc6, 0xf1, 0x20, 0x04, 0x45, 0xea, 0x40, 0x05, + 0x6d, 0x08, 0x20, 0xfa, 0x06, 0xf2, 0x15, 0x43, 0x21, 0xfa, 0x06, 0xf0, + 0xa1, 0x40, 0x0d, 0x43, 0x00, 0x21, 0x75, 0xf1, 0x00, 0x42, 0x50, 0xf1, + 0x00, 0x00, 0x51, 0xeb, 0x0c, 0x01, 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x20, + 0x5f, 0xea, 0x0c, 0x01, 0xbd, 0xe8, 0xf0, 0x81, 0xcf, 0xb9, 0x92, 0x18, + 0x5b, 0x41, 0xb3, 0xfa, 0x83, 0xf7, 0x04, 0xbf, 0xb2, 0xfa, 0x82, 0xf6, + 0xbf, 0x19, 0x0b, 0x3f, 0xb7, 0xf1, 0x20, 0x06, 0x2f, 0xbf, 0x02, 0xfa, + 0x06, 0xf3, 0xbb, 0x40, 0xc7, 0xf1, 0x20, 0x06, 0x22, 0xfa, 0x06, 0xf6, + 0x38, 0xbf, 0x33, 0x43, 0xba, 0x40, 0x1c, 0xb1, 0xe4, 0x19, 0x64, 0x1e, + 0x2f, 0xe7, 0x7f, 0x42, 0x31, 0xf0, 0x00, 0x41, 0xb1, 0xfa, 0x81, 0xf4, + 0x04, 0xbf, 0xb0, 0xfa, 0x80, 0xf6, 0xa4, 0x19, 0x0b, 0x3c, 0xb4, 0xf1, + 0x20, 0x06, 0x2f, 0xbf, 0x00, 0xfa, 0x06, 0xf1, 0xa1, 0x40, 0xc4, 0xf1, + 0x20, 0x06, 0x20, 0xfa, 0x06, 0xf6, 0x38, 0xbf, 0x31, 0x43, 0xa0, 0x40, + 0x3c, 0x1b, 0x16, 0xe7, 0xac, 0x42, 0x1a, 0xbf, 0x05, 0xea, 0x13, 0x57, + 0xaf, 0x42, 0x14, 0xe0, 0x50, 0xea, 0x41, 0x06, 0x1c, 0xbf, 0x52, 0xea, + 0x43, 0x06, 0xbf, 0xe7, 0x50, 0xea, 0x41, 0x07, 0x30, 0x46, 0x61, 0x46, + 0x1c, 0xbf, 0x41, 0xea, 0x05, 0x51, 0xbd, 0xe8, 0xf0, 0x81, 0x52, 0xea, + 0x43, 0x0c, 0x08, 0xbf, 0xc1, 0x43, 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x20, + 0x4f, 0xf4, 0x00, 0x16, 0x16, 0xeb, 0x41, 0x0f, 0x98, 0xbf, 0x16, 0xeb, + 0x43, 0x0f, 0x08, 0xbf, 0x16, 0xeb, 0x41, 0x0f, 0x24, 0xbf, 0xc1, 0x43, + 0x05, 0xe0, 0x16, 0xeb, 0x43, 0x0f, 0x0c, 0xbf, 0x61, 0x46, 0x4c, 0xea, + 0x05, 0x51, 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x00, 0x41, 0x00, 0x1d, 0xd2, + 0x09, 0x0e, 0x7f, 0x39, 0x1a, 0xd4, 0x20, 0x29, 0x08, 0xda, 0xc1, 0xf1, + 0x1f, 0x0c, 0x01, 0x02, 0x41, 0xf0, 0x00, 0x41, 0x21, 0xfa, 0x0c, 0xf0, + 0x00, 0x21, 0x70, 0x47, 0xd1, 0xf1, 0x3f, 0x0c, 0x08, 0xd4, 0x01, 0x02, + 0x41, 0xf0, 0x00, 0x41, 0x61, 0xfa, 0x0c, 0xf0, 0x21, 0xfa, 0x0c, 0xf1, + 0x48, 0x40, 0x70, 0x47, 0x6f, 0xf0, 0x00, 0x00, 0x01, 0x00, 0x70, 0x47, + 0x00, 0x20, 0x00, 0x21, 0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0x20, + 0xf8, 0xf7, 0xb5, 0xf8, 0x01, 0x20, 0xf8, 0xf7, 0xb2, 0xf8, 0x4f, 0xf0, + 0xa0, 0x40, 0x03, 0x21, 0x01, 0x64, 0x01, 0x60, 0x09, 0x20, 0x06, 0x21, + 0xf8, 0xf7, 0x09, 0xf9, 0x09, 0x20, 0xf8, 0xf7, 0x00, 0xf9, 0x09, 0x20, + 0xf8, 0xf7, 0xee, 0xf8, 0x4f, 0xf0, 0xb0, 0x40, 0x4f, 0xf0, 0x00, 0x71, + 0x01, 0x64, 0x01, 0x60, 0x1c, 0x20, 0x06, 0x21, 0xf8, 0xf7, 0xf9, 0xf8, + 0x1c, 0x20, 0xf8, 0xf7, 0xf0, 0xf8, 0xff, 0xe7, 0xbd, 0xe8, 0x02, 0x40, + 0x1c, 0x20, 0xf8, 0xf7, 0xdb, 0xb8, 0x05, 0x28, 0xba, 0xbf, 0x27, 0x49, + 0x40, 0x5c, 0x00, 0x20, 0x70, 0x47, 0x38, 0xb5, 0x25, 0x49, 0x24, 0x4d, + 0x03, 0x20, 0x08, 0x60, 0x00, 0x20, 0xf3, 0xf7, 0xdf, 0xf9, 0x29, 0x78, + 0x04, 0x46, 0x8c, 0x42, 0x0a, 0xd0, 0x22, 0x46, 0x00, 0x20, 0xfe, 0xf7, + 0x8c, 0xfd, 0x00, 0x20, 0x00, 0xf0, 0x77, 0xf9, 0x18, 0x20, 0xf8, 0xf7, + 0x38, 0xf9, 0x2c, 0x70, 0x01, 0x20, 0xf3, 0xf7, 0xcd, 0xf9, 0x69, 0x78, + 0x04, 0x46, 0x8c, 0x42, 0x0a, 0xd0, 0x22, 0x46, 0x01, 0x20, 0xfe, 0xf7, + 0x7a, 0xfd, 0x01, 0x20, 0x00, 0xf0, 0x65, 0xf9, 0x19, 0x20, 0xf8, 0xf7, + 0x26, 0xf9, 0x6c, 0x70, 0x31, 0xbd, 0xf8, 0xb5, 0x11, 0x49, 0x0f, 0x4d, + 0x0f, 0xf2, 0x44, 0x06, 0x4f, 0xf0, 0x00, 0x70, 0x08, 0x60, 0x02, 0x24, + 0x36, 0xf8, 0x14, 0x00, 0x00, 0xf1, 0x8c, 0x40, 0x07, 0x78, 0x61, 0x5d, + 0x8f, 0x42, 0x0a, 0xd0, 0x3a, 0x46, 0xe0, 0xb2, 0xfe, 0xf7, 0xc3, 0xfd, + 0xe0, 0xb2, 0x00, 0xf0, 0x48, 0xf9, 0x1a, 0x20, 0xf8, 0xf7, 0x09, 0xf9, + 0x67, 0x55, 0x64, 0x1c, 0x05, 0x2c, 0xe9, 0xd3, 0xf1, 0xbd, 0x00, 0x00, + 0x50, 0xf3, 0x00, 0x20, 0x40, 0x00, 0x00, 0x50, 0x40, 0x00, 0x00, 0x58, + 0xb0, 0x04, 0xb3, 0x04, 0x5b, 0x04, 0x5c, 0x04, 0x5d, 0x04, 0x00, 0x00, + 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x20, 0x68, 0x40, 0x00, 0x00, 0x0e, + 0xff, 0x28, 0x04, 0xd1, 0x20, 0x68, 0x40, 0x02, 0x14, 0xd0, 0x02, 0x20, + 0x32, 0xbd, 0x20, 0xb9, 0x20, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x01, 0x28, + 0x46, 0xda, 0x01, 0x2d, 0x0c, 0xdb, 0xc0, 0xf1, 0xff, 0x01, 0x8d, 0x42, + 0x08, 0xd3, 0x20, 0x68, 0x00, 0x28, 0x4c, 0xbf, 0x1f, 0x48, 0x4f, 0xf0, + 0xff, 0x40, 0x20, 0x60, 0x01, 0x20, 0x32, 0xbd, 0x41, 0x42, 0xa9, 0x42, + 0x21, 0x68, 0x06, 0xda, 0x21, 0xf0, 0xff, 0x41, 0x40, 0x19, 0x41, 0xea, + 0xc0, 0x50, 0x20, 0x60, 0x26, 0xe0, 0x22, 0x68, 0x52, 0x02, 0x40, 0x1e, + 0x52, 0x0a, 0x45, 0x19, 0x42, 0xf4, 0x00, 0x02, 0x05, 0xf1, 0x18, 0x00, + 0x01, 0xf0, 0x00, 0x41, 0x22, 0x60, 0x18, 0x28, 0x28, 0xbf, 0x21, 0x60, + 0x1c, 0xd2, 0x00, 0x20, 0x6a, 0x42, 0x06, 0xd0, 0x20, 0x68, 0xc2, 0xf1, + 0x20, 0x03, 0x98, 0x40, 0x23, 0x68, 0xd3, 0x40, 0x23, 0x60, 0x22, 0x68, + 0x0a, 0x43, 0xb0, 0xf1, 0x00, 0x4f, 0x22, 0x60, 0x03, 0xd8, 0x08, 0xd1, + 0x20, 0x78, 0xc0, 0x07, 0x05, 0xd5, 0x20, 0x68, 0x40, 0x1c, 0x20, 0x60, + 0x4f, 0xf0, 0xff, 0x30, 0x32, 0xbd, 0x20, 0x68, 0x88, 0x42, 0xf9, 0xd1, + 0x00, 0x20, 0x32, 0xbd, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0xbf, + 0x09, 0xd0, 0xb0, 0xfa, 0x80, 0xf1, 0x88, 0x40, 0xc9, 0x1c, 0xc1, 0xf5, + 0x84, 0x61, 0x09, 0x05, 0x01, 0xeb, 0xd0, 0x21, 0x40, 0x05, 0x70, 0x47, + 0x70, 0xb5, 0x00, 0x24, 0x67, 0x4d, 0x0f, 0xf2, 0xbc, 0x16, 0x56, 0xf8, + 0x24, 0x10, 0x4f, 0xf4, 0x7c, 0x70, 0x00, 0xfb, 0x04, 0x50, 0x00, 0xf0, + 0xf2, 0xf8, 0x64, 0x1c, 0x04, 0x2c, 0xf4, 0xd3, 0x61, 0x4e, 0x62, 0x4d, + 0xf4, 0xf7, 0x0c, 0xfe, 0xf1, 0x6a, 0x04, 0x46, 0x00, 0xf0, 0x43, 0xf8, + 0xa5, 0xf8, 0x4a, 0x00, 0x20, 0x46, 0x31, 0x6c, 0x00, 0xf0, 0x3d, 0xf8, + 0xa5, 0xf8, 0x5a, 0x01, 0x70, 0xbd, 0x0f, 0xf2, 0x80, 0x11, 0x51, 0xf8, + 0x20, 0x00, 0x00, 0xf0, 0x6a, 0xb9, 0x00, 0xe0, 0x00, 0xbf, 0xf0, 0xb5, + 0x14, 0x46, 0x83, 0xb0, 0x20, 0x70, 0x61, 0x70, 0x05, 0x00, 0x0f, 0xf2, + 0x54, 0x11, 0x51, 0xf8, 0x25, 0x60, 0x4f, 0x49, 0x66, 0x60, 0x4f, 0xf4, + 0x7c, 0x72, 0x02, 0xfb, 0x05, 0x11, 0xa1, 0x60, 0x18, 0xbf, 0x01, 0x2d, + 0x4b, 0x49, 0x07, 0xbf, 0xcf, 0x6a, 0x01, 0x20, 0x0f, 0x6c, 0x03, 0x20, + 0xf4, 0xf7, 0x5a, 0xf9, 0x04, 0xf1, 0x10, 0x01, 0x01, 0x91, 0x06, 0xf1, + 0x48, 0x03, 0x04, 0xf1, 0x0c, 0x01, 0x00, 0x91, 0x3a, 0x46, 0x01, 0x46, + 0x30, 0x46, 0x00, 0xf0, 0x27, 0xf8, 0x0f, 0xf2, 0x20, 0x10, 0x50, 0xf8, + 0x25, 0x10, 0x20, 0x46, 0x03, 0xb0, 0xbd, 0xe8, 0xf0, 0x40, 0x00, 0xf0, + 0x4a, 0xb9, 0x38, 0xb5, 0x0d, 0x46, 0x04, 0x46, 0xb5, 0xf1, 0x00, 0x5f, + 0x80, 0x41, 0xc0, 0x0f, 0xf7, 0xf7, 0x63, 0xff, 0xb4, 0xeb, 0x45, 0x0f, + 0x01, 0xd3, 0x00, 0x20, 0x32, 0xbd, 0x28, 0x09, 0x60, 0x21, 0x48, 0x43, + 0x21, 0x09, 0xb0, 0xfb, 0xf1, 0xf0, 0x30, 0x28, 0x01, 0xd2, 0x01, 0x20, + 0x32, 0xbd, 0x2f, 0x38, 0xff, 0x28, 0x88, 0xbf, 0xff, 0x20, 0x32, 0xbd, + 0x2d, 0xe9, 0xf8, 0x43, 0x80, 0x46, 0x08, 0xf1, 0x48, 0x06, 0x0c, 0x46, + 0x70, 0x88, 0x91, 0x46, 0x1d, 0x46, 0xf5, 0xf7, 0x9f, 0xf8, 0x07, 0x46, + 0x15, 0x2c, 0x2c, 0xbf, 0x14, 0x3c, 0x00, 0x24, 0x48, 0x46, 0xf6, 0xf7, + 0x43, 0xfd, 0x81, 0x46, 0x20, 0x46, 0xf6, 0xf7, 0x3f, 0xfd, 0x49, 0x46, + 0xf6, 0xf7, 0xda, 0xfe, 0x04, 0x46, 0x07, 0xf1, 0x30, 0x00, 0x21, 0x49, + 0x48, 0x43, 0xf6, 0xf7, 0x35, 0xfd, 0x01, 0x46, 0x20, 0x46, 0xf6, 0xf7, + 0x41, 0xfd, 0xfd, 0xf7, 0xcd, 0xfd, 0x08, 0x9f, 0x09, 0x9c, 0xd0, 0xb1, + 0xf7, 0xf7, 0x5f, 0xff, 0x0c, 0x28, 0x28, 0xbf, 0x0c, 0x20, 0x31, 0x88, + 0x4f, 0xf2, 0xff, 0x02, 0x11, 0x40, 0x41, 0xea, 0x00, 0x21, 0x29, 0x80, + 0xc0, 0xf1, 0x0c, 0x00, 0x01, 0x21, 0x01, 0xfa, 0x00, 0xf0, 0x08, 0xf5, + 0x84, 0x71, 0x0a, 0x88, 0x02, 0xb9, 0x02, 0x46, 0x3a, 0x60, 0x49, 0x88, + 0x41, 0xb1, 0x21, 0x60, 0x07, 0xe0, 0x30, 0x88, 0x4f, 0xf2, 0xff, 0x01, + 0x08, 0x40, 0x28, 0x80, 0x00, 0x20, 0x38, 0x60, 0x20, 0x60, 0xbd, 0xe8, + 0xf1, 0x83, 0x04, 0x28, 0x06, 0xda, 0x04, 0x49, 0x4f, 0xf4, 0x7c, 0x72, + 0x02, 0xfb, 0x00, 0x10, 0x00, 0xf0, 0xe3, 0xbc, 0x70, 0x47, 0x00, 0x00, + 0xc0, 0x92, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, 0x98, 0x02, 0x00, 0x20, + 0x40, 0x42, 0x0f, 0x00, 0x98, 0x02, 0x00, 0x20, 0x98, 0x02, 0x00, 0x20, + 0xa8, 0x03, 0x00, 0x20, 0xa8, 0x03, 0x00, 0x20, 0x04, 0xea, 0x00, 0x20, + 0xa0, 0xea, 0x00, 0x20, 0x3c, 0xeb, 0x00, 0x20, 0xd8, 0xeb, 0x00, 0x20, + 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, + 0x01, 0x68, 0x11, 0xf1, 0x01, 0x0f, 0x1c, 0xbf, 0x49, 0x1c, 0x01, 0x60, + 0x70, 0x47, 0x01, 0x88, 0x4f, 0xf6, 0xff, 0x72, 0x91, 0x42, 0x1c, 0xbf, + 0x49, 0x1c, 0x01, 0x80, 0x70, 0x47, 0x38, 0xb5, 0x04, 0x46, 0x00, 0x20, + 0x20, 0x80, 0x60, 0x80, 0x60, 0x60, 0x0d, 0x46, 0xc0, 0x21, 0x04, 0xf1, + 0x08, 0x00, 0xf7, 0xf7, 0x11, 0xfd, 0x4f, 0xf0, 0x80, 0x40, 0xa0, 0x66, + 0x00, 0x21, 0x04, 0xf1, 0xd0, 0x00, 0x01, 0x70, 0x4f, 0xf0, 0x7e, 0x51, + 0x41, 0x60, 0x00, 0x21, 0x81, 0x60, 0x01, 0x73, 0x04, 0xf1, 0xe0, 0x00, + 0x01, 0xf0, 0xea, 0xfe, 0x28, 0x46, 0xbd, 0xe8, 0x32, 0x40, 0x58, 0xe0, + 0x38, 0xb5, 0x00, 0x25, 0x05, 0x80, 0x00, 0xf1, 0xe0, 0x04, 0x45, 0x80, + 0xd0, 0x30, 0x65, 0x68, 0x45, 0x60, 0x25, 0x68, 0x85, 0x60, 0x01, 0x25, + 0x05, 0x73, 0x00, 0x25, 0x45, 0x73, 0x05, 0x70, 0x20, 0x46, 0x01, 0xb0, + 0xbd, 0xe8, 0x30, 0x40, 0x01, 0xf0, 0x53, 0xbe, 0x70, 0xb5, 0x0c, 0x46, + 0xc0, 0x21, 0x06, 0x46, 0x00, 0x20, 0x30, 0x80, 0x70, 0x80, 0x70, 0x60, + 0x06, 0xf1, 0xe0, 0x05, 0x06, 0xf1, 0x08, 0x00, 0xf7, 0xf7, 0xd8, 0xfc, + 0x4f, 0xf0, 0x80, 0x40, 0xb0, 0x66, 0x06, 0xf1, 0xd0, 0x01, 0x05, 0xf5, + 0x0a, 0x70, 0x42, 0x68, 0x4a, 0x60, 0x00, 0x68, 0x88, 0x60, 0x01, 0x20, + 0x08, 0x73, 0x00, 0x20, 0x48, 0x73, 0x95, 0xf8, 0xf4, 0x02, 0x08, 0x70, + 0x21, 0x46, 0x28, 0x46, 0xbd, 0xe8, 0x70, 0x40, 0x01, 0xf0, 0xf6, 0xbe, + 0x00, 0x21, 0x01, 0x60, 0x41, 0x60, 0x81, 0x60, 0xc1, 0x60, 0x4f, 0xf0, + 0xff, 0x31, 0x01, 0x61, 0x00, 0x21, 0x41, 0x61, 0x70, 0x47, 0x42, 0x68, + 0x11, 0x43, 0x41, 0x60, 0x08, 0x30, 0x83, 0xe7, 0x02, 0x69, 0x8a, 0x42, + 0x88, 0xbf, 0x0a, 0x46, 0x02, 0x61, 0x42, 0x69, 0x91, 0x42, 0x38, 0xbf, + 0x11, 0x46, 0x41, 0x61, 0x70, 0x47, 0x0c, 0x30, 0x76, 0xe7, 0x10, 0xb5, + 0x04, 0x46, 0x00, 0x20, 0x20, 0x60, 0x28, 0x21, 0x64, 0x20, 0x60, 0x60, + 0x4f, 0xf0, 0xff, 0x30, 0xa0, 0x60, 0x00, 0x20, 0xe0, 0x60, 0x20, 0x61, + 0x04, 0xf1, 0x74, 0x00, 0xf7, 0xf7, 0x92, 0xfc, 0x04, 0xf1, 0x5c, 0x00, + 0xff, 0xf7, 0xce, 0xff, 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x10, 0xb5, + 0x04, 0x46, 0x04, 0xf1, 0x44, 0x00, 0xff, 0xf7, 0xc5, 0xff, 0x20, 0x46, + 0xbd, 0xe8, 0x10, 0x40, 0x10, 0xb5, 0x04, 0x46, 0x04, 0xf1, 0x2c, 0x00, + 0xff, 0xf7, 0xbc, 0xff, 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x14, 0x30, + 0xb6, 0xe7, 0x2d, 0xe9, 0xf0, 0x41, 0x04, 0x46, 0x0d, 0x46, 0xad, 0xf5, + 0x7c, 0x7d, 0x05, 0xf1, 0x74, 0x00, 0xc4, 0xf8, 0x60, 0x03, 0x00, 0x22, + 0x00, 0x21, 0x04, 0xf1, 0x30, 0x00, 0xf4, 0xf7, 0xea, 0xfe, 0xff, 0xf7, + 0x33, 0xff, 0x06, 0x46, 0x00, 0x20, 0x28, 0x60, 0x68, 0x60, 0x28, 0x46, + 0xff, 0xf7, 0xdc, 0xff, 0x86, 0xf3, 0x11, 0x88, 0x4f, 0xf4, 0x7c, 0x78, + 0xa1, 0x68, 0x42, 0x46, 0x68, 0x46, 0xf9, 0xf7, 0x1f, 0xfd, 0x00, 0x27, + 0x28, 0x46, 0xff, 0xf7, 0xd8, 0xff, 0x69, 0x46, 0x20, 0x46, 0x00, 0xf0, + 0x98, 0xf8, 0xff, 0xf7, 0x19, 0xff, 0x06, 0x46, 0xa0, 0x68, 0x42, 0x46, + 0x69, 0x46, 0xf9, 0xf7, 0x0f, 0xfd, 0xe8, 0x68, 0x40, 0x1c, 0xe8, 0x60, + 0x60, 0x7f, 0x10, 0xb1, 0x28, 0x69, 0x40, 0x1c, 0x28, 0x61, 0xa0, 0x68, + 0x61, 0x68, 0x40, 0x88, 0x89, 0x8a, 0x90, 0xfb, 0xf1, 0xf0, 0x64, 0x28, + 0x28, 0xbf, 0x63, 0x20, 0x68, 0x60, 0x61, 0x69, 0x09, 0xb3, 0x05, 0xf1, + 0x5c, 0x00, 0xff, 0xf7, 0x78, 0xff, 0x61, 0x69, 0x05, 0xf1, 0x44, 0x00, + 0xff, 0xf7, 0x73, 0xff, 0x61, 0x69, 0x05, 0xf1, 0x2c, 0x00, 0xff, 0xf7, + 0x6e, 0xff, 0x61, 0x69, 0x05, 0xf1, 0x14, 0x00, 0xff, 0xf7, 0x69, 0xff, + 0x60, 0x69, 0xc1, 0x06, 0x01, 0xd5, 0x03, 0x20, 0x07, 0xe0, 0x81, 0x07, + 0x02, 0xd5, 0x01, 0x20, 0x28, 0x60, 0x3c, 0xe0, 0xc0, 0x07, 0x3b, 0xd5, + 0x02, 0x20, 0x28, 0x60, 0x37, 0xe0, 0x20, 0x69, 0xa8, 0xb3, 0xa0, 0x7f, + 0x00, 0x28, 0x1c, 0xbf, 0xe0, 0x7f, 0x00, 0x28, 0x30, 0xd0, 0x20, 0x6a, + 0xa8, 0x60, 0x05, 0xf1, 0x14, 0x00, 0x21, 0x6a, 0xff, 0xf7, 0x50, 0xff, + 0x21, 0x6a, 0x05, 0xf1, 0x2c, 0x00, 0xff, 0xf7, 0x4b, 0xff, 0x21, 0x6a, + 0x05, 0xf1, 0x44, 0x00, 0xff, 0xf7, 0x46, 0xff, 0x21, 0x6a, 0x05, 0xf1, + 0x5c, 0x00, 0xff, 0xf7, 0x41, 0xff, 0x20, 0x78, 0xa9, 0x68, 0x32, 0x30, + 0xc0, 0xb2, 0xf7, 0xf7, 0x79, 0xfe, 0xe0, 0x7f, 0x02, 0x28, 0x10, 0xd1, + 0x05, 0xf1, 0x14, 0x00, 0xff, 0xf7, 0x3f, 0xff, 0x05, 0xf1, 0x2c, 0x00, + 0xff, 0xf7, 0x3b, 0xff, 0x05, 0xf1, 0x44, 0x00, 0xff, 0xf7, 0x37, 0xff, + 0x05, 0xf1, 0x5c, 0x00, 0xff, 0xf7, 0x33, 0xff, 0x00, 0xe0, 0x01, 0x27, + 0x05, 0xf1, 0x14, 0x00, 0xff, 0xf7, 0xa6, 0xfe, 0x05, 0xf1, 0x2c, 0x00, + 0xff, 0xf7, 0xa2, 0xfe, 0x05, 0xf1, 0x44, 0x00, 0xff, 0xf7, 0x9e, 0xfe, + 0x05, 0xf1, 0x5c, 0x00, 0xff, 0xf7, 0x9a, 0xfe, 0x60, 0x78, 0x08, 0xb9, + 0x01, 0x27, 0x00, 0xe0, 0x0f, 0xb1, 0x64, 0x20, 0x68, 0x60, 0x86, 0xf3, + 0x11, 0x88, 0x00, 0x2f, 0x3f, 0xf4, 0x66, 0xaf, 0x28, 0x68, 0x0d, 0xf5, + 0x7c, 0x7d, 0xbd, 0xe8, 0xf0, 0x81, 0xf8, 0xb5, 0x04, 0x46, 0x00, 0x20, + 0x60, 0x61, 0x20, 0x76, 0x60, 0x76, 0xa0, 0x76, 0xe0, 0x76, 0x20, 0x77, + 0x60, 0x77, 0x0d, 0x46, 0x04, 0xf1, 0x24, 0x00, 0x00, 0x21, 0x04, 0xf5, + 0x56, 0x76, 0x01, 0x70, 0x41, 0x60, 0x41, 0x70, 0xb1, 0x61, 0xf1, 0x61, + 0x20, 0x69, 0x88, 0xb1, 0x31, 0x68, 0x00, 0x29, 0x1c, 0xbf, 0x71, 0x79, + 0x01, 0x29, 0x0b, 0xd1, 0x61, 0x68, 0x2a, 0x88, 0x4b, 0x8a, 0x9a, 0x42, + 0x06, 0xd3, 0x6a, 0x88, 0x8b, 0x8a, 0x9a, 0x42, 0x89, 0x41, 0xc9, 0x43, + 0xc9, 0x0f, 0x00, 0xe0, 0x00, 0x21, 0xa1, 0x77, 0xa1, 0x7f, 0x01, 0xb9, + 0xe0, 0x68, 0x30, 0x84, 0x01, 0xf0, 0xfc, 0xfe, 0x30, 0x8c, 0x88, 0xb9, + 0x60, 0x69, 0x40, 0xf0, 0x10, 0x00, 0x60, 0x61, 0x0c, 0xe0, 0x20, 0x7e, + 0x03, 0x28, 0x56, 0xd0, 0x02, 0x28, 0x1c, 0xbf, 0x60, 0x7e, 0x01, 0x28, + 0x04, 0xd1, 0x60, 0x68, 0x80, 0x78, 0x08, 0xb1, 0xf2, 0xf7, 0x68, 0xfb, + 0x60, 0x69, 0x00, 0x28, 0x38, 0xd1, 0xdf, 0xf8, 0x74, 0x75, 0x20, 0x78, + 0x47, 0xf8, 0x20, 0x40, 0x00, 0x20, 0xf0, 0x61, 0x20, 0x76, 0x60, 0x76, + 0xa0, 0x76, 0x00, 0x21, 0xf3, 0xf7, 0x47, 0xf8, 0x20, 0x46, 0x00, 0xf0, + 0x4a, 0xf8, 0x20, 0x46, 0x00, 0xf0, 0xed, 0xf8, 0xf0, 0x69, 0x98, 0xb9, + 0x20, 0x46, 0x00, 0xf0, 0x8d, 0xf8, 0x20, 0x7e, 0x70, 0xb9, 0x20, 0x46, + 0x00, 0xf0, 0xaa, 0xf8, 0x28, 0xb3, 0x00, 0x20, 0x60, 0x76, 0x20, 0x46, + 0x00, 0xf0, 0x05, 0xf9, 0x30, 0x68, 0x31, 0x8c, 0x88, 0x42, 0xeb, 0xd3, + 0x01, 0x20, 0xa0, 0x76, 0x00, 0x20, 0x21, 0x78, 0x47, 0xf8, 0x21, 0x00, + 0x20, 0x46, 0x00, 0xf0, 0x5e, 0xf8, 0x00, 0x20, 0xf3, 0xf7, 0x7e, 0xf8, + 0xb0, 0x69, 0x00, 0x28, 0x04, 0xbf, 0xa0, 0x7e, 0x00, 0x28, 0xb6, 0xd0, + 0xa0, 0x7e, 0x70, 0xb1, 0x29, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x05, 0xfa, + 0xe0, 0x7e, 0x28, 0xb9, 0x01, 0x20, 0x20, 0x77, 0x07, 0xe0, 0x01, 0x20, + 0x60, 0x76, 0xe1, 0xe7, 0x00, 0x20, 0x20, 0x77, 0xf1, 0xbd, 0x20, 0x7f, + 0x60, 0xb1, 0x29, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x79, 0xfa, 0x08, 0xb1, + 0x01, 0x20, 0x04, 0xe0, 0x60, 0x69, 0x40, 0xf0, 0x04, 0x00, 0x60, 0x61, + 0x00, 0x20, 0x60, 0x77, 0xf1, 0xbd, 0x38, 0xb5, 0x04, 0x46, 0x60, 0x68, + 0x18, 0x30, 0xf4, 0xf7, 0xdd, 0xfc, 0x20, 0x78, 0x02, 0x28, 0x18, 0xbf, + 0x03, 0x28, 0x27, 0xd1, 0xf3, 0xf7, 0xdc, 0xfa, 0x03, 0x28, 0x23, 0xd1, + 0x20, 0x78, 0x02, 0x28, 0x02, 0xd1, 0xf3, 0xf7, 0x2c, 0xfb, 0x01, 0xe0, + 0xf3, 0xf7, 0x3d, 0xfb, 0x05, 0x46, 0x04, 0xf5, 0x59, 0x70, 0xf4, 0xf7, + 0xc4, 0xff, 0x20, 0x78, 0x03, 0x28, 0x0c, 0xbf, 0x01, 0x20, 0x00, 0x20, + 0xf4, 0xf7, 0xe5, 0xff, 0x05, 0x2d, 0x18, 0xbf, 0x06, 0x2d, 0x02, 0xd1, + 0xf5, 0xf7, 0x17, 0xf8, 0x01, 0xe0, 0xf5, 0xf7, 0x10, 0xf8, 0xf4, 0xf7, + 0xfb, 0xff, 0x28, 0x46, 0xbd, 0xe8, 0x32, 0x40, 0xfd, 0xf7, 0x68, 0xbf, + 0x31, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0xf4, 0xf7, 0xf5, 0xfc, 0x20, 0x78, + 0x02, 0x28, 0x18, 0xbf, 0x03, 0x28, 0x0c, 0xd1, 0xf3, 0xf7, 0xaa, 0xfa, + 0x03, 0x28, 0x08, 0xd1, 0xfd, 0xf7, 0xb0, 0xff, 0x04, 0xf5, 0x59, 0x70, + 0xbd, 0xe8, 0x10, 0x40, 0x00, 0x21, 0xf4, 0xf7, 0xa8, 0xbf, 0x10, 0xbd, + 0x10, 0xb5, 0x00, 0xf0, 0x52, 0xf8, 0xfe, 0xf7, 0x00, 0xff, 0x60, 0x68, + 0x23, 0x78, 0xa1, 0x7f, 0x00, 0xf1, 0x18, 0x02, 0x0f, 0xf2, 0xb4, 0x40, + 0x18, 0x5c, 0xf4, 0xf7, 0xdc, 0xfc, 0x01, 0x28, 0x03, 0xd0, 0xa1, 0x68, + 0xd1, 0xf8, 0xec, 0x13, 0x09, 0xb1, 0x01, 0x20, 0x08, 0xe0, 0x02, 0x28, + 0x18, 0xbf, 0x00, 0x28, 0x04, 0xd0, 0x61, 0x69, 0x41, 0xf0, 0x01, 0x01, + 0x03, 0x20, 0x61, 0x61, 0x20, 0x76, 0x10, 0xbd, 0xd0, 0xb5, 0x00, 0xf0, + 0x30, 0xf8, 0xfe, 0xf7, 0xf2, 0xfe, 0x01, 0x28, 0x20, 0xd0, 0x00, 0x26, + 0x00, 0x27, 0x01, 0x22, 0xdf, 0xf8, 0xd4, 0x03, 0x00, 0xf0, 0x1e, 0xf8, + 0xdf, 0xf8, 0xd0, 0x03, 0x00, 0xf0, 0x1a, 0xf8, 0xdf, 0xf8, 0xcc, 0x03, + 0x50, 0xf8, 0x22, 0x00, 0xc1, 0x17, 0x49, 0x00, 0x41, 0xea, 0xd0, 0x71, + 0x16, 0xeb, 0x40, 0x06, 0x4f, 0x41, 0x52, 0x1c, 0x18, 0x2a, 0xe9, 0xd3, + 0x60, 0x68, 0xd0, 0xe9, 0x02, 0x23, 0x9f, 0x42, 0x04, 0xdc, 0x01, 0xdb, + 0x96, 0x42, 0x01, 0xd2, 0x00, 0x20, 0xd0, 0xbd, 0x01, 0x20, 0xd0, 0xbd, + 0x50, 0xf8, 0x22, 0x00, 0x16, 0xeb, 0x00, 0x16, 0x57, 0xeb, 0x10, 0x77, + 0x70, 0x47, 0x04, 0x46, 0x0f, 0xf2, 0x20, 0x40, 0x21, 0x78, 0x08, 0x5c, + 0x70, 0x47, 0x70, 0xb5, 0x04, 0x46, 0xa5, 0x7f, 0x05, 0xb1, 0x01, 0x25, + 0x21, 0x78, 0x0f, 0xf2, 0x10, 0x40, 0x08, 0x5c, 0xff, 0xf7, 0x7d, 0xfb, + 0x04, 0xf5, 0x54, 0x76, 0xb1, 0x68, 0x29, 0xb1, 0x31, 0x7b, 0x81, 0x42, + 0x04, 0xbf, 0x71, 0x7b, 0xa9, 0x42, 0x08, 0xd0, 0x01, 0x46, 0x2a, 0x46, + 0x04, 0xf1, 0x30, 0x00, 0xf4, 0xf7, 0xd5, 0xfc, 0x00, 0x20, 0xc6, 0xe9, + 0x00, 0x00, 0xa1, 0x68, 0x00, 0x20, 0xc1, 0xf8, 0xec, 0x03, 0x70, 0xbd, + 0x00, 0x22, 0x00, 0x21, 0x30, 0x30, 0xf4, 0xf7, 0xc8, 0xbc, 0x10, 0xb5, + 0x04, 0x46, 0x04, 0xf1, 0x30, 0x00, 0xf4, 0xf7, 0x0a, 0xfd, 0xd4, 0xe9, + 0x0c, 0x01, 0xc4, 0xe9, 0x3e, 0x01, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, + 0x04, 0x46, 0xad, 0xf2, 0xfc, 0x5d, 0xe0, 0x68, 0x00, 0xf5, 0x4b, 0x71, + 0x91, 0xf8, 0x00, 0x80, 0x4f, 0x78, 0x01, 0x21, 0x21, 0x77, 0x04, 0xf1, + 0x24, 0x06, 0x00, 0x21, 0x61, 0x77, 0x71, 0x70, 0xa1, 0x68, 0x67, 0x90, + 0x5c, 0x31, 0x66, 0x91, 0x20, 0x68, 0xe0, 0x30, 0x68, 0x90, 0x60, 0x68, + 0x69, 0x90, 0x61, 0x69, 0x20, 0x69, 0x01, 0xf0, 0xf7, 0xfd, 0x6a, 0x90, + 0x20, 0x68, 0x90, 0xf8, 0xd0, 0x10, 0x88, 0x45, 0x03, 0xd1, 0xd0, 0xf8, + 0xf8, 0x12, 0x01, 0x29, 0x06, 0xd1, 0x68, 0x9a, 0x01, 0x21, 0xc2, 0xf8, + 0x10, 0x12, 0x00, 0x21, 0xc0, 0xf8, 0xf8, 0x12, 0x01, 0x2f, 0x1b, 0xd1, + 0x69, 0x46, 0x66, 0xa8, 0x01, 0xf0, 0x8e, 0xfc, 0x60, 0x77, 0x00, 0x20, + 0x27, 0x68, 0x78, 0x80, 0x65, 0x7f, 0x1d, 0xb9, 0x4f, 0xf0, 0xff, 0x30, + 0x20, 0x62, 0x09, 0xe0, 0x00, 0x98, 0xfd, 0xf7, 0x47, 0xfa, 0x02, 0x2d, + 0x20, 0x62, 0x03, 0xd1, 0x41, 0x46, 0x38, 0x46, 0xff, 0xf7, 0x0a, 0xfd, + 0x01, 0x20, 0x70, 0x70, 0x02, 0x20, 0xbd, 0xe0, 0x00, 0x20, 0x00, 0x90, + 0x68, 0x98, 0x00, 0xf5, 0x04, 0x70, 0x01, 0x68, 0x91, 0xb1, 0x69, 0x46, + 0x66, 0xa8, 0x00, 0xf0, 0xdc, 0xf9, 0x68, 0x99, 0x01, 0xf5, 0x04, 0x71, + 0x48, 0x60, 0x48, 0x68, 0x03, 0x28, 0x14, 0xd0, 0x48, 0x68, 0x01, 0x28, + 0x02, 0xd0, 0x00, 0x20, 0x08, 0x60, 0x0e, 0xe0, 0x00, 0x20, 0x0d, 0xe0, + 0x40, 0x68, 0x02, 0x28, 0x69, 0x46, 0x66, 0xa8, 0x02, 0xd1, 0x00, 0xf0, + 0xc6, 0xf9, 0x01, 0xe0, 0x00, 0xf0, 0x6e, 0xf9, 0x68, 0x99, 0xc1, 0xf8, + 0x14, 0x02, 0x01, 0x20, 0x70, 0x70, 0x00, 0x2f, 0x68, 0x98, 0xd0, 0xf8, + 0x14, 0x02, 0x69, 0x99, 0x48, 0x62, 0x40, 0xf0, 0x8e, 0x80, 0x00, 0x20, + 0x00, 0x90, 0x4f, 0xf0, 0x00, 0x09, 0x27, 0x68, 0x07, 0xf1, 0xe0, 0x05, + 0x05, 0xf1, 0xcc, 0x00, 0x29, 0x68, 0x40, 0x68, 0xf6, 0xf7, 0x62, 0xfa, + 0x33, 0x90, 0x33, 0xa8, 0x05, 0xeb, 0x89, 0x0b, 0x00, 0xeb, 0x89, 0x0a, + 0xdb, 0xf8, 0x04, 0x00, 0xd5, 0xf8, 0xcc, 0x10, 0xf6, 0xf7, 0xf2, 0xfa, + 0xca, 0xf8, 0x04, 0x00, 0x09, 0xf1, 0x01, 0x09, 0xdb, 0xf8, 0x68, 0x00, + 0xca, 0xf8, 0x68, 0x00, 0xb9, 0xf1, 0x19, 0x0f, 0xe9, 0xd3, 0x00, 0x25, + 0x33, 0xa8, 0x00, 0xeb, 0x85, 0x09, 0x74, 0x49, 0xd9, 0xf8, 0x04, 0x00, + 0xf6, 0xf7, 0x42, 0xfa, 0x82, 0x46, 0x33, 0x98, 0xd9, 0xf8, 0x68, 0x10, + 0xf6, 0xf7, 0x3c, 0xfa, 0x81, 0x46, 0x50, 0x46, 0x51, 0x46, 0xf6, 0xf7, + 0xd3, 0xfa, 0x82, 0x46, 0x48, 0x46, 0x49, 0x46, 0xf6, 0xf7, 0xce, 0xfa, + 0x51, 0x46, 0xf6, 0xf7, 0x2f, 0xfa, 0x4f, 0xf0, 0x7a, 0x51, 0xf6, 0xf7, + 0xc7, 0xfa, 0x01, 0x46, 0xa0, 0x68, 0xd0, 0xf8, 0x00, 0x01, 0xf6, 0xf7, + 0xaf, 0xfa, 0x08, 0xd2, 0x01, 0x20, 0x30, 0x70, 0x41, 0x46, 0x20, 0x68, + 0xff, 0xf7, 0x84, 0xfc, 0x01, 0x20, 0x70, 0x70, 0x38, 0xe0, 0x6d, 0x1c, + 0x19, 0x2d, 0xcd, 0xd3, 0x07, 0xf1, 0xd4, 0x00, 0x01, 0x7a, 0x49, 0xb9, + 0x34, 0x99, 0x01, 0x60, 0x33, 0x99, 0x41, 0x60, 0x01, 0x21, 0x01, 0x72, + 0x01, 0x20, 0x21, 0x68, 0x81, 0xf8, 0xdd, 0x00, 0x20, 0x68, 0x80, 0xf8, + 0xd0, 0x80, 0x20, 0x68, 0xff, 0xf7, 0x2b, 0xfc, 0x20, 0x68, 0x80, 0x1c, + 0xff, 0xf7, 0x27, 0xfc, 0xa0, 0x69, 0x98, 0xb9, 0x20, 0x68, 0xd4, 0x30, + 0x18, 0x26, 0x41, 0x68, 0x33, 0x91, 0x00, 0x68, 0x34, 0x99, 0xf6, 0xf7, + 0x03, 0xf9, 0x05, 0x46, 0x33, 0xa8, 0x00, 0xeb, 0x86, 0x07, 0x29, 0x46, + 0x78, 0x68, 0xf6, 0xf7, 0x89, 0xfa, 0x76, 0x1e, 0x78, 0x60, 0xf5, 0xd5, + 0x20, 0x68, 0x01, 0x1d, 0x6b, 0x46, 0x01, 0xaa, 0x33, 0xa8, 0x01, 0xf0, + 0x22, 0xfd, 0x00, 0x20, 0x20, 0x77, 0x0d, 0xf2, 0xfc, 0x5d, 0xbd, 0xe8, + 0xf0, 0x8f, 0x70, 0xb5, 0x82, 0xb0, 0x04, 0x46, 0x0e, 0x46, 0x6a, 0x46, + 0x00, 0x21, 0x00, 0x20, 0xf2, 0xf7, 0xb9, 0xff, 0x00, 0x98, 0x30, 0xb9, + 0x01, 0x20, 0xe0, 0x76, 0x60, 0x69, 0x40, 0xf0, 0x08, 0x00, 0x60, 0x61, + 0x73, 0xbd, 0x20, 0x78, 0x01, 0x46, 0x02, 0x29, 0x04, 0xf1, 0x24, 0x05, + 0x08, 0xd0, 0x03, 0x29, 0x09, 0xd1, 0xf3, 0xf7, 0x4e, 0xf9, 0x68, 0x70, + 0x68, 0x78, 0xfd, 0xf7, 0xb6, 0xff, 0x0b, 0xe0, 0xf3, 0xf7, 0x33, 0xf9, + 0xf7, 0xe7, 0x00, 0x28, 0x18, 0xbf, 0x01, 0x29, 0x08, 0xd1, 0x0f, 0xf2, + 0x3c, 0x10, 0x08, 0x5c, 0xfd, 0xf7, 0xa0, 0xff, 0x40, 0x1e, 0x80, 0x41, + 0xc0, 0x0f, 0x68, 0x60, 0x00, 0x98, 0x06, 0x60, 0x00, 0x99, 0xd4, 0xf8, + 0x60, 0x03, 0x48, 0x60, 0x00, 0x99, 0x60, 0x68, 0x88, 0x60, 0x04, 0xf1, + 0x30, 0x00, 0x00, 0x99, 0xc8, 0x60, 0x00, 0x99, 0x68, 0x68, 0x88, 0x61, + 0x21, 0x78, 0x1f, 0x48, 0x01, 0x29, 0x03, 0xd9, 0x89, 0x1e, 0x01, 0x29, + 0x05, 0xd9, 0x09, 0xe0, 0x00, 0x9a, 0x41, 0x6b, 0x11, 0x61, 0xc0, 0x6a, + 0x08, 0xe0, 0x00, 0x9a, 0x81, 0x6c, 0x11, 0x61, 0x00, 0x6c, 0x03, 0xe0, + 0x00, 0x9a, 0xc1, 0x6d, 0x11, 0x61, 0x40, 0x6d, 0x00, 0x99, 0x15, 0x4a, + 0x48, 0x61, 0x00, 0x21, 0x00, 0x20, 0xf2, 0xf7, 0xf0, 0xff, 0x00, 0x98, + 0x90, 0xf8, 0x25, 0x00, 0x10, 0xb1, 0x20, 0x46, 0xff, 0xf7, 0x7a, 0xfe, + 0x00, 0x98, 0x40, 0x7f, 0xe0, 0x77, 0x00, 0x98, 0x50, 0xf8, 0x20, 0x1f, + 0x21, 0x62, 0x00, 0x79, 0x28, 0x70, 0x00, 0x98, 0x00, 0x7f, 0xe0, 0x76, + 0x00, 0x20, 0xf2, 0xf7, 0x96, 0xff, 0x73, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xf3, 0x00, 0x20, 0x80, 0x16, 0x00, 0x41, 0x00, 0x16, 0x00, 0x41, + 0x80, 0x17, 0x00, 0x41, 0x00, 0x00, 0x80, 0xbf, 0x78, 0x29, 0x00, 0x20, + 0x89, 0x06, 0x01, 0x01, 0x2d, 0xe9, 0xf8, 0x43, 0x0d, 0x46, 0x04, 0x46, + 0x0f, 0xf2, 0x78, 0x00, 0x21, 0x78, 0x0f, 0x5c, 0x38, 0x46, 0xf4, 0xf7, + 0x04, 0xfc, 0x80, 0x46, 0xf1, 0xf7, 0xc8, 0xf9, 0x21, 0x78, 0x0f, 0xf2, + 0x70, 0x00, 0x08, 0x5c, 0x40, 0xf0, 0x02, 0x09, 0x29, 0x1d, 0x40, 0x46, + 0xf4, 0xf7, 0x96, 0xfb, 0x00, 0x26, 0x28, 0xb1, 0x49, 0x46, 0x38, 0x46, + 0xf4, 0xf7, 0xfd, 0xfb, 0x00, 0xb1, 0x01, 0x26, 0x95, 0xf8, 0xdd, 0x00, + 0x00, 0x28, 0x04, 0xbf, 0xa0, 0x6a, 0x00, 0x28, 0x0e, 0xd0, 0x02, 0x2f, + 0x06, 0xd3, 0x94, 0xf8, 0x25, 0x00, 0x00, 0x22, 0x00, 0x21, 0xfd, 0xf7, + 0xf4, 0xfe, 0x02, 0xe0, 0x20, 0x78, 0xfd, 0xf7, 0xc2, 0xfe, 0x00, 0x20, + 0x85, 0xf8, 0xdd, 0x00, 0xf1, 0xf7, 0xb3, 0xf9, 0x30, 0x46, 0xbd, 0xe8, + 0xf2, 0x83, 0x00, 0x21, 0x01, 0x80, 0x01, 0x21, 0xc0, 0xf8, 0xec, 0x13, + 0x70, 0x47, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x04, 0xf8, 0xb5, 0x04, 0x46, + 0x04, 0xf1, 0x14, 0x06, 0x06, 0xf5, 0xd0, 0x77, 0x0d, 0x46, 0x01, 0x20, + 0xb8, 0x62, 0x05, 0x20, 0xe1, 0x68, 0x08, 0x60, 0xa0, 0x68, 0x00, 0xf0, + 0x89, 0xf9, 0x00, 0x22, 0x31, 0x46, 0x20, 0x46, 0x00, 0xf0, 0xcc, 0xf9, + 0x28, 0x68, 0x20, 0xbb, 0x38, 0x68, 0x10, 0xb3, 0x31, 0x46, 0x20, 0x46, + 0x00, 0xf0, 0x1c, 0xf9, 0xe1, 0x68, 0x00, 0x20, 0x08, 0x62, 0x01, 0x22, + 0x20, 0x68, 0x00, 0x78, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x20, 0xf8, + 0x29, 0x68, 0x00, 0x29, 0x08, 0xbf, 0x00, 0x28, 0x0f, 0xd1, 0xa0, 0x68, + 0x00, 0x68, 0xc6, 0xf8, 0x34, 0x02, 0x02, 0x22, 0x20, 0x68, 0x00, 0x88, + 0xc0, 0xf3, 0x03, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x29, 0x68, 0x00, 0x29, + 0x08, 0xbf, 0x00, 0x28, 0x01, 0xd0, 0x00, 0x20, 0xf2, 0xbd, 0x20, 0x68, + 0x00, 0x88, 0xc0, 0xf3, 0x03, 0x20, 0xf8, 0x62, 0x03, 0x22, 0x00, 0xf0, + 0x03, 0xf8, 0xf4, 0xe7, 0x40, 0x1c, 0xf8, 0x62, 0x31, 0x46, 0x20, 0x46, + 0x00, 0xf0, 0x26, 0xbc, 0x51, 0x46, 0x70, 0x68, 0xf6, 0xf7, 0x5a, 0xb9, + 0x4f, 0xf0, 0x7e, 0x50, 0x29, 0x46, 0xf6, 0xf7, 0x45, 0xb8, 0x2d, 0xe9, + 0xf0, 0x47, 0x04, 0x46, 0x04, 0xf1, 0x14, 0x05, 0x05, 0xf5, 0xd0, 0x76, + 0x84, 0xb0, 0x01, 0x20, 0xb0, 0x62, 0x0f, 0x46, 0xe0, 0x68, 0x02, 0x21, + 0x01, 0x62, 0x02, 0x22, 0x05, 0x21, 0x01, 0x60, 0x20, 0x46, 0x29, 0x46, + 0x00, 0xf0, 0x76, 0xf9, 0x38, 0x68, 0x08, 0xb9, 0x30, 0x68, 0x38, 0xb9, + 0xa0, 0x68, 0xd0, 0xf8, 0x10, 0x02, 0x00, 0x28, 0x0c, 0xbf, 0x02, 0x20, + 0x03, 0x20, 0x3e, 0xe0, 0xa0, 0x68, 0xd0, 0xf8, 0x10, 0x02, 0x30, 0xb1, + 0x60, 0x68, 0xd0, 0xf8, 0x28, 0x03, 0x40, 0x28, 0xb6, 0x41, 0xf6, 0x0f, + 0x00, 0xe0, 0x00, 0x26, 0x01, 0x20, 0x00, 0x90, 0x02, 0xab, 0x01, 0xaa, + 0x29, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x2e, 0xf8, 0xa7, 0x68, 0x02, 0x98, + 0x39, 0x68, 0xf6, 0xf7, 0x0b, 0xf8, 0x04, 0x46, 0x07, 0xf1, 0xcc, 0x05, + 0x1e, 0xb1, 0x01, 0x98, 0x28, 0x60, 0x6c, 0x60, 0x1c, 0xe0, 0xdf, 0xf8, + 0xdc, 0x9d, 0x28, 0x68, 0xdf, 0xf8, 0xd8, 0x8d, 0x01, 0xf0, 0x02, 0xf8, + 0x82, 0x46, 0x01, 0x98, 0x01, 0xf0, 0x03, 0xf8, 0x51, 0x46, 0xf6, 0xf7, + 0x69, 0xf8, 0x28, 0x60, 0x49, 0x46, 0x68, 0x68, 0xf6, 0xf7, 0x00, 0xf9, + 0x81, 0x46, 0x20, 0x46, 0x00, 0xf0, 0xf7, 0xff, 0x00, 0xf0, 0xbc, 0xfb, + 0x68, 0x60, 0x38, 0x46, 0x00, 0xf0, 0xe4, 0xf8, 0x30, 0x46, 0x04, 0xb0, + 0xbd, 0xe8, 0xf0, 0x87, 0x2d, 0xe9, 0xf1, 0x4f, 0x84, 0xb0, 0x4f, 0xf0, + 0x7e, 0x50, 0x03, 0x90, 0x88, 0x46, 0x0e, 0x9f, 0x00, 0x20, 0x02, 0x90, + 0x00, 0x2f, 0x08, 0xf5, 0x13, 0x75, 0x14, 0xbf, 0x6c, 0x46, 0x03, 0xac, + 0x68, 0x60, 0x91, 0x46, 0x9a, 0x46, 0x28, 0x60, 0x01, 0x26, 0x04, 0x98, + 0x80, 0x68, 0x01, 0x90, 0x00, 0xeb, 0x86, 0x00, 0x40, 0x68, 0x00, 0x90, + 0xd8, 0xf8, 0x90, 0x01, 0xf0, 0x40, 0xc0, 0x07, 0x1a, 0xd5, 0x58, 0xf8, + 0x26, 0x10, 0x20, 0x68, 0x08, 0xeb, 0x86, 0x0b, 0xf6, 0xf7, 0xca, 0xf8, + 0xdb, 0xf8, 0xc8, 0x10, 0xf6, 0xf7, 0xc6, 0xf8, 0x69, 0x68, 0xf6, 0xf7, + 0x27, 0xf8, 0x68, 0x60, 0x21, 0x68, 0x08, 0x46, 0xf6, 0xf7, 0xbe, 0xf8, + 0xdb, 0xf8, 0xc8, 0x10, 0xf6, 0xf7, 0xba, 0xf8, 0x29, 0x68, 0xf6, 0xf7, + 0x1b, 0xf8, 0x28, 0x60, 0x76, 0x1c, 0x18, 0x2e, 0xd5, 0xdb, 0x68, 0x68, + 0x29, 0x68, 0xf5, 0xf7, 0x21, 0xff, 0xc9, 0xf8, 0x00, 0x00, 0x00, 0x2f, + 0x14, 0xbf, 0xe9, 0x46, 0x0d, 0xf1, 0x08, 0x09, 0x00, 0x20, 0x68, 0x60, + 0x28, 0x60, 0x01, 0x27, 0x01, 0x98, 0x00, 0xeb, 0x87, 0x00, 0x80, 0x6e, + 0x00, 0x90, 0xd8, 0xf8, 0x90, 0x01, 0xf8, 0x40, 0xc0, 0x07, 0x1b, 0xd5, + 0x08, 0xeb, 0x87, 0x04, 0x04, 0xf1, 0x64, 0x06, 0xd9, 0xf8, 0x00, 0x10, + 0x00, 0xf0, 0xc5, 0xf8, 0x01, 0x46, 0xd4, 0xf8, 0x2c, 0x01, 0xf5, 0xf7, + 0x7d, 0xff, 0x71, 0x6e, 0xf6, 0xf7, 0x8a, 0xf8, 0x69, 0x68, 0xf5, 0xf7, + 0xeb, 0xff, 0x68, 0x60, 0x70, 0x6e, 0x01, 0x46, 0xf6, 0xf7, 0x82, 0xf8, + 0x29, 0x68, 0xf5, 0xf7, 0xe3, 0xff, 0x28, 0x60, 0x7f, 0x1c, 0x18, 0x2f, + 0xd6, 0xdb, 0x68, 0x68, 0x29, 0x68, 0xf5, 0xf7, 0xe9, 0xfe, 0xca, 0xf8, + 0x00, 0x00, 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x2d, 0xe9, 0xf8, 0x4f, + 0x04, 0x46, 0x00, 0x26, 0x20, 0x69, 0x00, 0x90, 0x0d, 0x46, 0xb3, 0x46, + 0xb0, 0x46, 0xb1, 0x46, 0xb2, 0x46, 0x01, 0x27, 0x01, 0xe0, 0x03, 0x2f, + 0x0b, 0xda, 0x04, 0xeb, 0x87, 0x00, 0x00, 0xf5, 0x34, 0x70, 0x01, 0x68, + 0x40, 0x6e, 0xf5, 0xf7, 0xbf, 0xff, 0x00, 0xf0, 0x1e, 0xfb, 0x06, 0x46, + 0x0e, 0xe0, 0x00, 0xf0, 0x5b, 0xfe, 0x01, 0x46, 0x00, 0x98, 0xb8, 0x42, + 0x04, 0xda, 0x40, 0x46, 0xf5, 0xf7, 0xb2, 0xff, 0x80, 0x46, 0x03, 0xe0, + 0x58, 0x46, 0xf5, 0xf7, 0xad, 0xff, 0x83, 0x46, 0x00, 0xf0, 0x4c, 0xfe, + 0xd5, 0xf8, 0x9c, 0x11, 0xf9, 0x40, 0xc9, 0x07, 0x03, 0xd5, 0x00, 0xf0, + 0x01, 0xfb, 0x81, 0x46, 0x03, 0xe0, 0x51, 0x46, 0xf5, 0xf7, 0x9e, 0xff, + 0x82, 0x46, 0x7f, 0x1c, 0x18, 0x2f, 0xd0, 0xdb, 0x58, 0x46, 0x41, 0x46, + 0xf5, 0xf7, 0x96, 0xff, 0x02, 0x46, 0x50, 0x46, 0x49, 0x46, 0xf6, 0xf7, + 0x1b, 0xf8, 0x10, 0x46, 0x31, 0x46, 0x05, 0xd2, 0xf6, 0xf7, 0x16, 0xf8, + 0x2c, 0xbf, 0x01, 0x20, 0x04, 0x20, 0x0d, 0xe0, 0xf6, 0xf7, 0x10, 0xf8, + 0x38, 0xbf, 0x02, 0x20, 0x08, 0xd3, 0x58, 0x46, 0xf5, 0xf7, 0x80, 0xff, + 0x41, 0x46, 0xf6, 0xf7, 0x07, 0xf8, 0x34, 0xbf, 0x03, 0x20, 0x00, 0x20, + 0xe1, 0x68, 0x08, 0x60, 0xbd, 0xe8, 0xf2, 0x8f, 0x2d, 0xe9, 0xf0, 0x41, + 0x80, 0x46, 0x00, 0x27, 0x08, 0xf5, 0x01, 0x75, 0x08, 0xf1, 0xcc, 0x06, + 0x08, 0xeb, 0x87, 0x04, 0x30, 0x68, 0x61, 0x68, 0xf6, 0xf7, 0x04, 0xf8, + 0x60, 0x60, 0x28, 0x68, 0xf8, 0x40, 0xc0, 0x07, 0x05, 0xd5, 0xd4, 0xf8, + 0xd4, 0x10, 0x00, 0xf0, 0x2e, 0xf8, 0xc4, 0xf8, 0xd4, 0x00, 0x7f, 0x1c, + 0x18, 0x2f, 0xeb, 0xdb, 0x4f, 0xf0, 0x7e, 0x50, 0x30, 0x60, 0x00, 0x27, + 0xd8, 0xf8, 0x00, 0x10, 0x70, 0x68, 0xf5, 0xf7, 0x51, 0xff, 0xc8, 0xf8, + 0x00, 0x00, 0x08, 0xeb, 0x87, 0x00, 0x00, 0xf5, 0x9c, 0x74, 0x68, 0x68, + 0xf8, 0x40, 0xc0, 0x07, 0x04, 0xd5, 0x20, 0x68, 0x71, 0x68, 0xf5, 0xf7, + 0xcf, 0xfe, 0x20, 0x60, 0xa8, 0x68, 0xf8, 0x40, 0xc0, 0x07, 0x04, 0xd5, + 0x60, 0x6e, 0x71, 0x68, 0xf5, 0xf7, 0xc6, 0xfe, 0x60, 0x66, 0x7f, 0x1c, + 0x18, 0x2f, 0xe6, 0xdb, 0x00, 0x20, 0x70, 0x60, 0xbd, 0xe8, 0xf0, 0x81, + 0xf1, 0x68, 0x30, 0x68, 0xf5, 0xf7, 0xca, 0xbf, 0x2d, 0xe9, 0xf6, 0x4f, + 0x04, 0x46, 0x85, 0xb0, 0x60, 0x68, 0xd0, 0xf8, 0x28, 0x03, 0xf5, 0xf7, + 0x23, 0xfe, 0x05, 0x46, 0x4f, 0xf0, 0x8a, 0x40, 0x00, 0xf0, 0xd1, 0xff, + 0x83, 0x46, 0x82, 0x46, 0x4f, 0xf0, 0x8e, 0x40, 0x00, 0xf0, 0xcb, 0xff, + 0x05, 0x46, 0x06, 0x46, 0x4f, 0xf0, 0x00, 0x08, 0x00, 0xf0, 0x6e, 0xfa, + 0x04, 0xeb, 0x88, 0x07, 0xd2, 0xe9, 0x00, 0x01, 0xf5, 0xf7, 0xde, 0xfd, + 0x59, 0x46, 0x07, 0xf5, 0x34, 0x79, 0xf5, 0xf7, 0x17, 0xfe, 0xc9, 0xf8, + 0x00, 0x00, 0x07, 0xf5, 0x66, 0x77, 0x00, 0xf0, 0x5d, 0xfa, 0xd2, 0xe9, + 0x32, 0x01, 0xf5, 0xf7, 0xcf, 0xfd, 0x51, 0x46, 0xf5, 0xf7, 0x0a, 0xfe, + 0xc9, 0xf8, 0x64, 0x00, 0x00, 0xf0, 0x52, 0xfa, 0xd2, 0xe9, 0x64, 0x01, + 0xf5, 0xf7, 0xb6, 0xfd, 0x29, 0x46, 0xf5, 0xf7, 0xff, 0xfd, 0x38, 0x60, + 0x00, 0xf0, 0x48, 0xfa, 0x08, 0xf1, 0x01, 0x08, 0xd2, 0xe9, 0x96, 0x01, + 0xf5, 0xf7, 0xaa, 0xfd, 0x31, 0x46, 0xf5, 0xf7, 0xf3, 0xfd, 0xb8, 0xf1, + 0x19, 0x0f, 0x78, 0x66, 0xca, 0xd3, 0x62, 0x68, 0x01, 0x25, 0xd2, 0xe9, + 0xc8, 0x01, 0xf5, 0xf7, 0xab, 0xfd, 0x4f, 0xf0, 0x3a, 0x51, 0xf5, 0xf7, + 0x73, 0xff, 0xc4, 0xf8, 0x60, 0x04, 0xd4, 0xf8, 0xd0, 0x02, 0x01, 0x90, + 0x04, 0xeb, 0x85, 0x06, 0x06, 0xf5, 0x34, 0x71, 0x00, 0xf0, 0x72, 0xfd, + 0x07, 0x46, 0xd6, 0xf8, 0x98, 0x03, 0x4f, 0xf0, 0x80, 0x41, 0xf5, 0xf7, + 0x61, 0xff, 0x00, 0xf0, 0x9b, 0xfd, 0x07, 0x46, 0x01, 0x98, 0x39, 0x46, + 0xf5, 0xf7, 0x48, 0xff, 0x38, 0xbf, 0x01, 0x97, 0x6d, 0x1c, 0x15, 0x2d, + 0xe6, 0xd3, 0x01, 0x26, 0x05, 0x98, 0x00, 0xf5, 0xc8, 0x75, 0x00, 0x20, + 0x28, 0x60, 0x68, 0x60, 0xa8, 0x60, 0xe8, 0x60, 0x28, 0x61, 0xa8, 0x61, + 0x68, 0x61, 0xe8, 0x61, 0xe8, 0x62, 0x28, 0x63, 0x28, 0x62, 0x68, 0x62, + 0xa8, 0x62, 0xd4, 0xf8, 0x60, 0x14, 0xdf, 0xf8, 0x40, 0x0a, 0xf5, 0xf7, + 0x3d, 0xff, 0x03, 0x90, 0x04, 0xeb, 0x86, 0x00, 0x00, 0xf5, 0x34, 0x71, + 0x00, 0xf5, 0x66, 0x77, 0xd1, 0xf8, 0x00, 0xa0, 0x49, 0x6e, 0x00, 0x91, + 0x4f, 0xf0, 0x80, 0x41, 0x38, 0x68, 0xf5, 0xf7, 0x2d, 0xff, 0x81, 0x46, + 0x05, 0x98, 0x00, 0xeb, 0x86, 0x08, 0x78, 0x6e, 0xc8, 0xf8, 0x2c, 0x01, + 0x51, 0x46, 0x00, 0x98, 0xf5, 0xf7, 0x86, 0xfe, 0x83, 0x46, 0x00, 0xf0, + 0xe1, 0xf9, 0x02, 0x90, 0x00, 0x21, 0xf5, 0xf7, 0xfb, 0xfe, 0x07, 0x46, + 0x36, 0xd0, 0x58, 0x46, 0x49, 0x46, 0xf5, 0xf7, 0x05, 0xfe, 0x39, 0x46, + 0xf5, 0xf7, 0x84, 0xfd, 0x00, 0x21, 0xf6, 0xf7, 0x17, 0xf8, 0x81, 0x46, + 0x04, 0xd9, 0xdf, 0xf8, 0xdc, 0x09, 0x00, 0xf0, 0xff, 0xfd, 0x81, 0x46, + 0x48, 0x46, 0xf5, 0xf7, 0xab, 0xfe, 0x05, 0x99, 0x41, 0xf8, 0x26, 0x00, + 0x50, 0x46, 0x00, 0x99, 0xf5, 0xf7, 0xee, 0xfd, 0x81, 0x46, 0x4f, 0xf0, + 0x7c, 0x50, 0x49, 0x46, 0x08, 0xf1, 0x64, 0x0a, 0xf5, 0xf7, 0xf6, 0xfe, + 0xca, 0xf8, 0x00, 0x00, 0x39, 0x46, 0x4f, 0xf0, 0x3f, 0x40, 0xf5, 0xf7, + 0xef, 0xfe, 0xca, 0xf8, 0x64, 0x00, 0x00, 0x21, 0xda, 0xf8, 0x00, 0x00, + 0xf5, 0xf7, 0xf0, 0xff, 0x24, 0xbf, 0xdf, 0xf8, 0x90, 0x19, 0xf5, 0xf7, + 0xe3, 0xfe, 0x02, 0xe0, 0x4f, 0xf0, 0x7e, 0x59, 0xd6, 0xe7, 0x29, 0x6b, + 0xf5, 0xf7, 0xca, 0xfe, 0x38, 0xbf, 0x08, 0x46, 0x28, 0x63, 0xda, 0xf8, + 0x64, 0x10, 0xe8, 0x6a, 0xf5, 0xf7, 0xc2, 0xfe, 0x38, 0xbf, 0x01, 0x46, + 0xe9, 0x62, 0x38, 0x46, 0x01, 0x99, 0xd4, 0xf8, 0x00, 0xa0, 0xf5, 0xf7, + 0x3d, 0xfd, 0x0a, 0xf1, 0x08, 0x0b, 0x01, 0x46, 0xdb, 0xf8, 0x04, 0x00, + 0xf5, 0xf7, 0xb2, 0xfe, 0x08, 0xd2, 0xdb, 0xf8, 0x00, 0x00, 0x39, 0x46, + 0xf5, 0xf7, 0xac, 0xfe, 0x38, 0xbf, 0x4f, 0xf0, 0x01, 0x0b, 0x01, 0xd3, + 0x4f, 0xf0, 0x00, 0x0b, 0xa0, 0x68, 0xd0, 0xf8, 0x10, 0x02, 0x10, 0xb9, + 0x06, 0x98, 0x02, 0x28, 0x02, 0xd1, 0xda, 0xf8, 0x8c, 0x00, 0x78, 0xb1, + 0x0a, 0xeb, 0x86, 0x01, 0x03, 0x98, 0x89, 0x6a, 0xf5, 0xf7, 0xa8, 0xfe, + 0x00, 0x90, 0x39, 0x46, 0xdf, 0xf8, 0x10, 0x09, 0xf5, 0xf7, 0xa2, 0xfe, + 0x00, 0x99, 0xf5, 0xf7, 0x8d, 0xfe, 0x29, 0xd3, 0xbb, 0xf1, 0x00, 0x0f, + 0x1c, 0xbf, 0x06, 0x98, 0x01, 0x28, 0x25, 0xd0, 0x05, 0x98, 0xdf, 0xf8, + 0xf0, 0x18, 0x50, 0xf8, 0x26, 0x00, 0xf5, 0xf7, 0xf5, 0xfd, 0x83, 0x46, + 0xd8, 0xf8, 0x2c, 0x01, 0x39, 0x46, 0xf5, 0xf7, 0xfd, 0xfc, 0x80, 0x46, + 0x58, 0x46, 0x00, 0xf0, 0xb1, 0xfc, 0x07, 0x46, 0x40, 0x46, 0x00, 0xf0, + 0x7e, 0xfd, 0x00, 0xf0, 0xbd, 0xfc, 0x4f, 0xf0, 0x7a, 0x51, 0xf5, 0xf7, + 0x7d, 0xfe, 0x0a, 0xf1, 0x8c, 0x01, 0x49, 0x69, 0xf5, 0xf7, 0x66, 0xfe, + 0x38, 0xbf, 0x4f, 0xf0, 0x01, 0x0b, 0x01, 0xd3, 0x4f, 0xf0, 0x00, 0x0b, + 0x28, 0x69, 0x58, 0x44, 0x28, 0x61, 0x0b, 0xfa, 0x06, 0xf1, 0x28, 0x68, + 0x08, 0x43, 0x28, 0x60, 0x48, 0x46, 0x02, 0x99, 0xf5, 0xf7, 0xd8, 0xfc, + 0x01, 0x46, 0x20, 0x68, 0x07, 0x69, 0x38, 0x46, 0xf5, 0xf7, 0x4e, 0xfe, + 0x05, 0xd2, 0x01, 0x20, 0x5f, 0xea, 0x0b, 0x01, 0x0e, 0xd0, 0x01, 0x21, + 0x0c, 0xe0, 0xdf, 0xf8, 0x74, 0x08, 0xf5, 0xf7, 0x55, 0xfe, 0x01, 0x46, + 0x38, 0x46, 0xf5, 0xf7, 0x3f, 0xfe, 0x34, 0xbf, 0x4f, 0xf0, 0xff, 0x30, + 0x00, 0x20, 0x00, 0x21, 0xaa, 0x69, 0x8a, 0x18, 0xaa, 0x61, 0xb1, 0x40, + 0x6a, 0x68, 0x11, 0x43, 0xbb, 0xf1, 0x00, 0x0f, 0x69, 0x60, 0x04, 0xd0, + 0x10, 0xf1, 0x01, 0x0f, 0x08, 0xbf, 0x01, 0x21, 0x00, 0xd0, 0x00, 0x21, + 0x6a, 0x69, 0x8a, 0x18, 0x6a, 0x61, 0xb1, 0x40, 0xaa, 0x68, 0x11, 0x43, + 0xa9, 0x60, 0x40, 0x1e, 0x80, 0x41, 0xe9, 0x69, 0xc0, 0x0f, 0x41, 0x18, + 0xe9, 0x61, 0xb0, 0x40, 0xe9, 0x68, 0x76, 0x1c, 0x08, 0x43, 0x15, 0x2e, + 0xe8, 0x60, 0xff, 0xf4, 0xeb, 0xae, 0x4f, 0xf0, 0x7e, 0x50, 0x05, 0x99, + 0x08, 0x60, 0x00, 0x21, 0x05, 0x98, 0xc8, 0x30, 0x41, 0x66, 0x01, 0x60, + 0x00, 0x20, 0x05, 0x99, 0x48, 0x66, 0x15, 0x26, 0x05, 0x99, 0x4f, 0xf0, + 0x7e, 0x50, 0x41, 0xf8, 0x26, 0x00, 0x00, 0x21, 0x05, 0x98, 0x00, 0xeb, + 0x86, 0x00, 0x76, 0x1c, 0xc0, 0xf8, 0x2c, 0x11, 0x64, 0x30, 0x19, 0x2e, + 0x41, 0x66, 0x01, 0x60, 0xee, 0xd3, 0x06, 0x98, 0x01, 0x28, 0x25, 0xd1, + 0xe9, 0x6a, 0x4f, 0xf0, 0x40, 0x40, 0xf5, 0xf7, 0x01, 0xfe, 0x80, 0x46, + 0x01, 0x26, 0x04, 0xeb, 0x86, 0x07, 0x07, 0xf5, 0x34, 0x71, 0x00, 0xf0, + 0x03, 0xfc, 0x81, 0x46, 0xd7, 0xf8, 0x98, 0x03, 0x4f, 0xf0, 0x80, 0x41, + 0xf5, 0xf7, 0xf2, 0xfd, 0x00, 0xf0, 0xb2, 0xf8, 0x41, 0x46, 0xf5, 0xf7, + 0x5f, 0xfc, 0xdf, 0xf8, 0xa4, 0x17, 0xf5, 0xf7, 0xd7, 0xfd, 0x04, 0xd2, + 0x28, 0x68, 0x01, 0x21, 0xb1, 0x40, 0x88, 0x43, 0x28, 0x60, 0x76, 0x1c, + 0x18, 0x2e, 0xe0, 0xd3, 0x27, 0x68, 0xe9, 0x6a, 0x38, 0x6a, 0xf5, 0xf7, + 0xdb, 0xfd, 0x06, 0x46, 0x29, 0x6b, 0x78, 0x6a, 0xf5, 0xf7, 0xd6, 0xfd, + 0x80, 0x46, 0x01, 0x27, 0x05, 0x98, 0x00, 0xeb, 0x87, 0x00, 0x00, 0xf1, + 0x64, 0x09, 0x28, 0x68, 0xf8, 0x40, 0xc0, 0x07, 0x07, 0xd5, 0xd9, 0xf8, + 0x64, 0x00, 0x31, 0x46, 0xf5, 0xf7, 0xb4, 0xfd, 0x38, 0xbf, 0x01, 0x20, + 0x00, 0xd3, 0x00, 0x20, 0x29, 0x6a, 0xb8, 0x40, 0x08, 0x43, 0x28, 0x62, + 0x68, 0x68, 0xf8, 0x40, 0xc0, 0x07, 0x07, 0xd5, 0xd9, 0xf8, 0x00, 0x10, + 0x40, 0x46, 0xf5, 0xf7, 0xa3, 0xfd, 0x38, 0xbf, 0x01, 0x20, 0x00, 0xd3, + 0x00, 0x20, 0x69, 0x6a, 0xb8, 0x40, 0x08, 0x43, 0x68, 0x62, 0xa8, 0x68, + 0xf8, 0x40, 0xc0, 0x07, 0x0b, 0xd5, 0xdf, 0xf8, 0x14, 0x07, 0x00, 0xf0, + 0xa0, 0xfc, 0x01, 0x46, 0xd9, 0xf8, 0x00, 0x00, 0xf5, 0xf7, 0x8e, 0xfd, + 0x38, 0xbf, 0x01, 0x20, 0x00, 0xd3, 0x00, 0x20, 0xa9, 0x6a, 0xb8, 0x40, + 0x7f, 0x1c, 0x08, 0x43, 0x18, 0x2f, 0xa8, 0x62, 0xc0, 0xd3, 0x04, 0xf5, + 0x34, 0x70, 0xd4, 0xf8, 0x9c, 0x63, 0xd4, 0xf8, 0xd0, 0x12, 0x40, 0x68, + 0xf5, 0xf7, 0xf0, 0xfc, 0x04, 0xf5, 0x34, 0x71, 0x4f, 0xf0, 0x02, 0x08, + 0x89, 0x6e, 0xf5, 0xf7, 0xe9, 0xfc, 0x00, 0xf0, 0x48, 0xf8, 0x00, 0xf0, + 0x46, 0xf8, 0x06, 0x46, 0x00, 0x20, 0x04, 0xeb, 0x88, 0x01, 0x01, 0xf5, + 0x34, 0x79, 0xd1, 0xf8, 0x98, 0x73, 0xd9, 0xf8, 0x00, 0x10, 0xf5, 0xf7, + 0xd9, 0xfc, 0xd9, 0xf8, 0x64, 0x10, 0xf5, 0xf7, 0xd5, 0xfc, 0x00, 0xf0, + 0xab, 0xfb, 0x00, 0xf0, 0xa9, 0xfb, 0x08, 0xf1, 0x01, 0x08, 0xb8, 0xf1, + 0x18, 0x0f, 0xe8, 0xd3, 0xa7, 0x68, 0xdf, 0xf8, 0x3c, 0x1d, 0xf5, 0xf7, + 0x63, 0xfd, 0x01, 0x46, 0x30, 0x46, 0xf5, 0xf7, 0x4d, 0xfd, 0x34, 0xbf, + 0x01, 0x20, 0x00, 0x20, 0x87, 0xf8, 0x08, 0x03, 0xe1, 0x68, 0x28, 0x68, + 0x48, 0x60, 0xe1, 0x68, 0x68, 0x68, 0x88, 0x60, 0xe1, 0x68, 0xa8, 0x68, + 0xc8, 0x60, 0xe1, 0x68, 0xe8, 0x68, 0x08, 0x61, 0xe1, 0x68, 0x28, 0x6a, + 0x48, 0x61, 0xe1, 0x68, 0x68, 0x6a, 0x88, 0x61, 0xe1, 0x68, 0xa8, 0x6a, + 0xc8, 0x61, 0x07, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x60, 0x68, 0x00, 0xeb, + 0xc8, 0x02, 0x70, 0x47, 0x49, 0x46, 0xf5, 0xf7, 0x9f, 0xbc, 0x31, 0x46, + 0xf5, 0xf7, 0x9c, 0xbc, 0x2d, 0xe9, 0xf7, 0x4f, 0x86, 0xb0, 0x80, 0x68, + 0xd0, 0xf8, 0x00, 0x02, 0x40, 0x08, 0x00, 0xf0, 0x01, 0x00, 0x03, 0x90, + 0x07, 0x98, 0x00, 0xf5, 0xc8, 0x74, 0x20, 0x69, 0x00, 0x28, 0x00, 0xf0, + 0xae, 0x81, 0x07, 0x98, 0xdf, 0xf8, 0x0c, 0xb6, 0x00, 0xf5, 0xe8, 0x70, + 0x04, 0x90, 0x64, 0x21, 0xf6, 0xf7, 0xce, 0xfb, 0x07, 0x98, 0x00, 0xf5, + 0x0d, 0x76, 0x14, 0x21, 0x30, 0x46, 0xf6, 0xf7, 0xc7, 0xfb, 0x07, 0x98, + 0x00, 0xf5, 0xe2, 0x70, 0x00, 0x90, 0x4f, 0xf0, 0x7e, 0x58, 0x08, 0x98, + 0x01, 0x28, 0x46, 0xd1, 0x00, 0xf0, 0xdd, 0xfa, 0x0a, 0xe0, 0xf5, 0xf7, + 0x09, 0xfd, 0x03, 0x2d, 0x30, 0x62, 0x02, 0xd2, 0x00, 0xf0, 0xda, 0xfa, + 0x30, 0x62, 0x6d, 0x1c, 0x00, 0xf0, 0xe9, 0xfa, 0x18, 0x2d, 0x47, 0xd2, + 0x20, 0x68, 0x22, 0x6a, 0x65, 0x63, 0xe8, 0x40, 0x00, 0xf0, 0x01, 0x09, + 0x06, 0x98, 0x81, 0x68, 0xd1, 0xf8, 0x04, 0x02, 0xc6, 0xf8, 0x14, 0x80, + 0xe8, 0x40, 0xea, 0x40, 0xc6, 0xf8, 0x18, 0x80, 0x01, 0x23, 0x00, 0xf0, + 0x01, 0x00, 0x02, 0xf0, 0x01, 0x02, 0xa3, 0x63, 0x4a, 0xb9, 0x28, 0xb1, + 0x00, 0xf0, 0x11, 0xfb, 0x06, 0x99, 0x09, 0x68, 0x49, 0x69, 0xd4, 0xe7, + 0xb9, 0xf1, 0x00, 0x0f, 0x0a, 0xd0, 0x07, 0x98, 0x50, 0xf8, 0x25, 0x00, + 0xf0, 0x61, 0x59, 0x46, 0x07, 0x98, 0x00, 0xeb, 0x85, 0x00, 0xd0, 0xf8, + 0xc8, 0x00, 0xc6, 0xe7, 0x00, 0xf0, 0xfd, 0xfa, 0x01, 0x46, 0x06, 0x98, + 0x03, 0x9a, 0x00, 0x68, 0x00, 0x2a, 0x14, 0xbf, 0x80, 0x69, 0xc0, 0x69, + 0xbb, 0xe7, 0x02, 0x28, 0x72, 0xd1, 0x00, 0xf0, 0x94, 0xfa, 0x0a, 0xe0, + 0xf5, 0xf7, 0xc0, 0xfc, 0x03, 0x2d, 0x30, 0x62, 0x02, 0xd2, 0x00, 0xf0, + 0x91, 0xfa, 0x30, 0x62, 0x00, 0xf0, 0xa1, 0xfa, 0x6d, 0x1c, 0x18, 0x2d, + 0x80, 0xf0, 0xf4, 0x80, 0x60, 0x68, 0x65, 0x63, 0xe8, 0x40, 0xc0, 0x07, + 0x5d, 0xbf, 0xa0, 0x68, 0xe8, 0x40, 0x00, 0xf0, 0x01, 0x09, 0x4f, 0xf0, + 0x01, 0x09, 0x00, 0xf0, 0x99, 0xfa, 0x29, 0xd4, 0xa1, 0x6a, 0xe9, 0x40, + 0xc9, 0x07, 0x25, 0xd4, 0x6f, 0xb1, 0x00, 0xeb, 0x85, 0x00, 0xc6, 0xf8, + 0x14, 0x80, 0xc6, 0xf8, 0x18, 0xb0, 0xd0, 0xf8, 0x38, 0x01, 0x00, 0xf0, + 0xdd, 0xfa, 0x00, 0xf0, 0xb8, 0xfa, 0x00, 0xf0, 0x7b, 0xfa, 0x01, 0x98, + 0x60, 0xb1, 0x00, 0xf0, 0x52, 0xfa, 0x80, 0x68, 0x00, 0xeb, 0x85, 0x00, + 0xd0, 0xf8, 0x9c, 0x01, 0x00, 0xf0, 0xce, 0xfa, 0x00, 0xf0, 0xa9, 0xfa, + 0x00, 0xf0, 0x6c, 0xfa, 0x01, 0x98, 0x38, 0x43, 0xc0, 0xb2, 0x00, 0x28, + 0xc6, 0xd1, 0xb9, 0xf1, 0x00, 0x0f, 0x12, 0xd0, 0x00, 0xf0, 0x43, 0xfa, + 0x06, 0x98, 0x80, 0x68, 0x49, 0x6e, 0x00, 0xeb, 0x85, 0x00, 0x40, 0x68, + 0xf5, 0xf7, 0x72, 0xfc, 0xb0, 0x61, 0xd9, 0xf8, 0x2c, 0x01, 0xf0, 0x61, + 0x01, 0x20, 0xa0, 0x63, 0xc6, 0xf8, 0x20, 0x80, 0xae, 0xe7, 0x70, 0x61, + 0xc6, 0xf8, 0x18, 0xb0, 0x00, 0xf0, 0x4f, 0xfa, 0x00, 0xf0, 0x6c, 0xfa, + 0x4f, 0xf0, 0x7c, 0x51, 0xf5, 0xf7, 0x5e, 0xfc, 0x00, 0xf0, 0xa2, 0xfa, + 0x01, 0x46, 0x31, 0x62, 0x06, 0x98, 0x03, 0x9a, 0x00, 0x68, 0x00, 0x2a, + 0x14, 0xbf, 0x80, 0x69, 0xc0, 0x69, 0x8f, 0xe7, 0x60, 0x6a, 0x00, 0x28, + 0x04, 0xbf, 0xa0, 0x6a, 0x00, 0x28, 0x05, 0xd0, 0x21, 0x6b, 0x08, 0x46, + 0xf5, 0xf7, 0x48, 0xfc, 0x02, 0x90, 0x01, 0xe0, 0xcd, 0xf8, 0x08, 0x80, + 0x00, 0xf0, 0x13, 0xfa, 0x0c, 0xe0, 0x02, 0x98, 0x51, 0x46, 0xf5, 0xf7, + 0x3d, 0xfc, 0x03, 0x2d, 0x30, 0x62, 0x02, 0xd2, 0x00, 0xf0, 0x0f, 0xfa, + 0x30, 0x62, 0x00, 0xf0, 0x1e, 0xfa, 0x6d, 0x1c, 0x18, 0x2d, 0x71, 0xd2, + 0x60, 0x68, 0x65, 0x63, 0xe8, 0x40, 0xc0, 0x07, 0x5d, 0xbf, 0xa0, 0x68, + 0xe8, 0x40, 0x00, 0xf0, 0x01, 0x09, 0x4f, 0xf0, 0x01, 0x09, 0x00, 0xf0, + 0x17, 0xfa, 0x2f, 0xd4, 0xa1, 0x6a, 0xe9, 0x40, 0xc9, 0x07, 0x2b, 0xd4, + 0x06, 0x99, 0x09, 0x68, 0xd1, 0xf8, 0x14, 0xa0, 0x77, 0xb1, 0x00, 0xeb, + 0x85, 0x01, 0xc6, 0xf8, 0x14, 0x80, 0xc6, 0xf8, 0x18, 0x80, 0xd1, 0xf8, + 0x38, 0x11, 0x00, 0x68, 0xf5, 0xf7, 0x74, 0xfb, 0x00, 0xf0, 0x2b, 0xfa, + 0x00, 0xf0, 0xf4, 0xf9, 0x01, 0x98, 0x68, 0xb1, 0x00, 0xf0, 0xcb, 0xf9, + 0x81, 0x68, 0x01, 0xeb, 0x85, 0x00, 0x09, 0x68, 0xd0, 0xf8, 0x9c, 0x01, + 0xf5, 0xf7, 0x64, 0xfb, 0x00, 0xf0, 0x1b, 0xfa, 0x00, 0xf0, 0xe4, 0xf9, + 0x01, 0x98, 0x38, 0x43, 0xc0, 0xb2, 0x00, 0x28, 0xc1, 0xd1, 0xb9, 0xf1, + 0x00, 0x0f, 0x19, 0xd0, 0x00, 0xf0, 0xbb, 0xf9, 0xb0, 0x61, 0x06, 0x98, + 0xd0, 0xf8, 0x08, 0xa0, 0x49, 0x6e, 0x0a, 0xeb, 0x85, 0x00, 0x40, 0x68, + 0xf5, 0xf7, 0xe8, 0xfb, 0xda, 0xf8, 0x00, 0x10, 0xf5, 0xf7, 0xe4, 0xfb, + 0x01, 0x46, 0xd9, 0xf8, 0x2c, 0x01, 0xf5, 0xf7, 0xcf, 0xfa, 0xf0, 0x61, + 0xa5, 0x63, 0xc6, 0xf8, 0x20, 0x80, 0xa2, 0xe7, 0xc6, 0xf8, 0x14, 0x80, + 0xc6, 0xf8, 0x18, 0x80, 0x00, 0xf0, 0xbf, 0xf9, 0x08, 0x68, 0x49, 0x6e, + 0xf5, 0xf7, 0xc0, 0xfa, 0x4f, 0xf0, 0x7c, 0x51, 0xf5, 0xf7, 0xcc, 0xfb, + 0xf0, 0x61, 0xa5, 0x63, 0x06, 0x98, 0x03, 0x99, 0x00, 0x68, 0x00, 0x29, + 0x14, 0xbf, 0xd0, 0xf8, 0x18, 0xa0, 0xd0, 0xf8, 0x1c, 0xa0, 0x7e, 0xe7, + 0xe0, 0x6b, 0x01, 0x28, 0x05, 0xd1, 0x30, 0x68, 0x21, 0x6c, 0xf5, 0xf7, + 0x2b, 0xfa, 0x30, 0x60, 0x04, 0xe0, 0x02, 0x46, 0x04, 0x98, 0x31, 0x46, + 0x00, 0xf0, 0x14, 0xfb, 0x08, 0x98, 0x02, 0x28, 0x26, 0xd1, 0x34, 0x68, + 0x20, 0x46, 0x21, 0x46, 0xf5, 0xf7, 0x8a, 0xfb, 0x2f, 0xd1, 0x06, 0x98, + 0x85, 0x68, 0x95, 0xf8, 0x00, 0x02, 0xc0, 0x07, 0x12, 0xd5, 0x06, 0x98, + 0x00, 0x68, 0x46, 0x68, 0x40, 0x46, 0x31, 0x46, 0xf5, 0xf7, 0x8c, 0xfa, + 0x29, 0x68, 0xf5, 0xf7, 0x99, 0xfb, 0x07, 0x46, 0x20, 0x46, 0x31, 0x46, + 0xf5, 0xf7, 0x94, 0xfb, 0x00, 0xf0, 0xce, 0xf9, 0x28, 0x60, 0x00, 0xe0, + 0x2c, 0x60, 0xd5, 0xf8, 0x00, 0x02, 0x40, 0xf0, 0x01, 0x00, 0xc5, 0xf8, + 0x00, 0x02, 0x46, 0xe1, 0x00, 0x25, 0x00, 0xe0, 0x6d, 0x1c, 0xe0, 0x6b, + 0x85, 0x42, 0x0a, 0xd2, 0x07, 0x98, 0x00, 0xeb, 0x85, 0x00, 0xd0, 0xf8, + 0x34, 0x02, 0x01, 0x46, 0xf5, 0xf7, 0x5a, 0xfb, 0xf2, 0xd0, 0x01, 0x20, + 0x36, 0xe1, 0x08, 0x98, 0x01, 0x28, 0x0c, 0xbf, 0x02, 0x20, 0x01, 0x20, + 0x00, 0x90, 0x31, 0x46, 0x06, 0x98, 0x03, 0x69, 0x07, 0x98, 0xe2, 0x6b, + 0x00, 0xf5, 0x16, 0x70, 0x00, 0xf0, 0x84, 0xfa, 0x08, 0x98, 0x01, 0x28, + 0x10, 0xd1, 0x00, 0x25, 0x09, 0xe0, 0x07, 0x99, 0x01, 0xeb, 0x80, 0x00, + 0x01, 0xeb, 0x85, 0x01, 0xd0, 0xf8, 0x5c, 0x02, 0xc1, 0xf8, 0x58, 0x02, + 0x6d, 0x1c, 0x06, 0x98, 0x07, 0x68, 0x78, 0x88, 0xa8, 0x42, 0xf0, 0xd2, + 0x00, 0x25, 0x07, 0x98, 0x00, 0xeb, 0x85, 0x0b, 0x08, 0x98, 0x01, 0x28, + 0x1f, 0xd1, 0x06, 0x98, 0x81, 0x68, 0xdb, 0xf8, 0x58, 0x62, 0xd1, 0xf8, + 0x04, 0x02, 0x01, 0xeb, 0x85, 0x08, 0x98, 0xb1, 0x06, 0x98, 0x07, 0x68, + 0x7f, 0x68, 0x00, 0xf0, 0x57, 0xfb, 0x01, 0x46, 0xd8, 0xf8, 0x04, 0x00, + 0xf5, 0xf7, 0x3a, 0xfb, 0x83, 0x46, 0x30, 0x46, 0x39, 0x46, 0xf5, 0xf7, + 0x35, 0xfb, 0x00, 0xf0, 0x36, 0xf9, 0xc8, 0xf8, 0x04, 0x00, 0x2a, 0xe0, + 0xc8, 0xf8, 0x04, 0x60, 0x27, 0xe0, 0x03, 0x28, 0x25, 0xd1, 0x06, 0x98, + 0x82, 0x68, 0x02, 0xf5, 0x01, 0x76, 0x70, 0x68, 0x00, 0x28, 0x04, 0xbf, + 0xb0, 0x68, 0x00, 0x28, 0x16, 0xd0, 0x06, 0x98, 0x07, 0x68, 0x7f, 0x68, + 0x02, 0xeb, 0x85, 0x08, 0x00, 0xf0, 0x32, 0xfb, 0x01, 0x46, 0xd8, 0xf8, + 0x68, 0x00, 0xf5, 0xf7, 0x15, 0xfb, 0x06, 0x46, 0xdb, 0xf8, 0x58, 0x02, + 0x39, 0x46, 0xf5, 0xf7, 0x0f, 0xfb, 0xff, 0xf7, 0xd2, 0xfd, 0xc8, 0xf8, + 0x68, 0x00, 0x04, 0xe0, 0xdb, 0xf8, 0x58, 0x02, 0x02, 0xeb, 0x85, 0x01, + 0x88, 0x66, 0x6d, 0x1c, 0x19, 0x2d, 0xae, 0xd3, 0x00, 0x25, 0x01, 0x20, + 0xa8, 0x40, 0x00, 0x90, 0x07, 0x98, 0x00, 0xeb, 0x85, 0x08, 0x08, 0x98, + 0x01, 0x28, 0x38, 0xd1, 0x06, 0x98, 0x82, 0x68, 0x21, 0x6a, 0x02, 0xf5, + 0x01, 0x76, 0xe9, 0x40, 0x30, 0x68, 0xe8, 0x40, 0xc9, 0x07, 0x00, 0xf0, + 0x01, 0x00, 0x18, 0xd5, 0xd8, 0xf8, 0x58, 0x82, 0x02, 0xeb, 0x85, 0x01, + 0x01, 0xf1, 0xd4, 0x0b, 0x50, 0xb1, 0x00, 0xf0, 0x22, 0xf9, 0x00, 0xf0, + 0xf9, 0xf8, 0x00, 0xf0, 0xd8, 0xf9, 0xff, 0xf7, 0x9f, 0xfd, 0xcb, 0xf8, + 0x00, 0x00, 0x01, 0xe0, 0xcb, 0xf8, 0x00, 0x80, 0x30, 0x68, 0x00, 0x99, + 0x08, 0x43, 0x30, 0x60, 0x8d, 0xe0, 0x00, 0x28, 0xfc, 0xd1, 0x02, 0xeb, + 0x85, 0x00, 0x00, 0xf1, 0xd4, 0x0b, 0x00, 0xf0, 0x0a, 0xf9, 0x00, 0xf0, + 0xe1, 0xf8, 0x06, 0x46, 0xd8, 0xf8, 0x58, 0x02, 0x00, 0xf0, 0xe8, 0xfc, + 0xff, 0xf7, 0x87, 0xfd, 0xcb, 0xf8, 0x00, 0x00, 0x79, 0xe0, 0x08, 0x98, + 0x03, 0x28, 0x76, 0xd1, 0x06, 0x98, 0xd0, 0xf8, 0x08, 0xa0, 0x0a, 0xf5, + 0x01, 0x76, 0x70, 0x68, 0xe8, 0x40, 0x00, 0xf0, 0x01, 0x07, 0xb0, 0x68, + 0xe8, 0x40, 0x00, 0xf0, 0x01, 0x00, 0x01, 0x90, 0x60, 0x6a, 0xe8, 0x40, + 0xc0, 0x07, 0x19, 0xd5, 0x00, 0xf0, 0xde, 0xf8, 0x80, 0x46, 0x0a, 0xeb, + 0x85, 0x00, 0x00, 0xf1, 0xd4, 0x0b, 0x57, 0xb1, 0x00, 0xf0, 0xdf, 0xf8, + 0x00, 0xf0, 0xb1, 0xf8, 0x00, 0xf0, 0x95, 0xf9, 0xff, 0xf7, 0x5c, 0xfd, + 0xcb, 0xf8, 0x64, 0x00, 0x01, 0xe0, 0xcb, 0xf8, 0x64, 0x80, 0x70, 0x68, + 0x00, 0x99, 0x08, 0x43, 0x70, 0x60, 0x4a, 0xe0, 0xa0, 0x6a, 0xe8, 0x40, + 0xc0, 0x07, 0x1b, 0xd5, 0x00, 0xf0, 0xb0, 0xfb, 0x83, 0x46, 0x01, 0x98, + 0x0a, 0xeb, 0x85, 0x09, 0x68, 0xb1, 0x00, 0xf0, 0xc2, 0xf8, 0x00, 0xf0, + 0x8f, 0xf8, 0x80, 0x46, 0x78, 0x68, 0x00, 0xf0, 0xa7, 0xf8, 0x41, 0x46, + 0xf5, 0xf7, 0xde, 0xf9, 0xc9, 0xf8, 0x9c, 0x01, 0x01, 0xe0, 0xc9, 0xf8, + 0x9c, 0xb1, 0xb0, 0x68, 0x00, 0x99, 0x08, 0x43, 0xb0, 0x60, 0x2a, 0xe0, + 0x01, 0x98, 0x38, 0x43, 0x27, 0xd1, 0x06, 0x98, 0x07, 0x68, 0x79, 0x68, + 0x4f, 0xf0, 0x7e, 0x50, 0x0a, 0xeb, 0x85, 0x09, 0xf5, 0xf7, 0x54, 0xf9, + 0x09, 0xf1, 0xd4, 0x0b, 0x00, 0xf0, 0x73, 0xf8, 0x06, 0x46, 0x00, 0xf0, + 0x93, 0xf8, 0x00, 0xf0, 0x7f, 0xfc, 0xff, 0xf7, 0x1e, 0xfd, 0xcb, 0xf8, + 0x64, 0x00, 0x4f, 0xf0, 0x7e, 0x50, 0x7e, 0x68, 0x31, 0x46, 0xf5, 0xf7, + 0x41, 0xf9, 0x00, 0xf0, 0x5d, 0xf8, 0x07, 0x46, 0x00, 0xf0, 0x72, 0xfb, + 0x31, 0x46, 0xf5, 0xf7, 0x49, 0xfa, 0x00, 0xf0, 0x83, 0xf8, 0xc9, 0xf8, + 0x9c, 0x01, 0x6d, 0x1c, 0x19, 0x2d, 0xff, 0xf4, 0x40, 0xaf, 0x00, 0x20, + 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0xc6, 0xf8, 0x14, 0xb0, 0xc6, 0xf8, + 0x18, 0xb0, 0x06, 0x98, 0x70, 0x47, 0x07, 0x98, 0x00, 0xeb, 0x85, 0x09, + 0x09, 0xf1, 0x64, 0x01, 0x08, 0x68, 0x70, 0x61, 0x70, 0x47, 0x06, 0x98, + 0x00, 0x68, 0x40, 0x88, 0x45, 0x1c, 0x70, 0x47, 0x30, 0x6a, 0xdf, 0xf8, + 0x88, 0x18, 0xf5, 0xf7, 0x97, 0xb8, 0x00, 0x00, 0x77, 0xbe, 0x7f, 0x3f, + 0x6f, 0x12, 0x83, 0x3a, 0x80, 0x61, 0x0c, 0x4a, 0x00, 0x00, 0x80, 0xbf, + 0xac, 0xc5, 0x27, 0x37, 0x52, 0x49, 0x9d, 0x39, 0x30, 0x62, 0x00, 0x98, + 0x61, 0xe0, 0x06, 0x98, 0x80, 0x68, 0x00, 0xeb, 0x85, 0x00, 0x00, 0xf5, + 0x9c, 0x71, 0x70, 0x47, 0x06, 0x98, 0x80, 0x68, 0x00, 0xf5, 0x02, 0x71, + 0x0a, 0x68, 0x49, 0x68, 0xe9, 0x40, 0x01, 0xf0, 0x01, 0x01, 0x01, 0x91, + 0xea, 0x40, 0x61, 0x6a, 0xe9, 0x40, 0xc9, 0x07, 0x02, 0xf0, 0x01, 0x07, + 0x70, 0x47, 0x59, 0x46, 0xf5, 0xf7, 0x5e, 0xb9, 0x04, 0xeb, 0x87, 0x00, + 0x00, 0xf5, 0x34, 0x71, 0x08, 0x68, 0x49, 0x6e, 0xf5, 0xf7, 0x56, 0xb9, + 0x01, 0x46, 0xd9, 0xf8, 0x9c, 0x01, 0xf5, 0xf7, 0xed, 0xb9, 0x01, 0x46, + 0xdb, 0xf8, 0x64, 0x00, 0xf5, 0xf7, 0xe8, 0xb9, 0x01, 0x46, 0xdb, 0xf8, + 0x00, 0x00, 0xf5, 0xf7, 0xe3, 0xb9, 0xf0, 0x61, 0xa5, 0x63, 0x51, 0x46, + 0x02, 0x98, 0xf5, 0xf7, 0xdd, 0xb9, 0x01, 0x46, 0x31, 0x62, 0x06, 0x98, + 0x00, 0x68, 0x40, 0x69, 0xf5, 0xf7, 0xd6, 0xb9, 0x59, 0x46, 0xf5, 0xf7, + 0xd3, 0xb9, 0x01, 0xeb, 0x85, 0x00, 0x59, 0x46, 0xd0, 0xf8, 0xd4, 0x00, + 0xf0, 0x61, 0xe0, 0x6a, 0xf5, 0xf7, 0xca, 0xb9, 0xd8, 0xf8, 0x58, 0x02, + 0xda, 0xf8, 0x00, 0x10, 0xf5, 0xf7, 0xb4, 0xb8, 0x39, 0x46, 0xf5, 0xf7, + 0x25, 0xb9, 0x06, 0x98, 0x07, 0x68, 0x79, 0x68, 0x4f, 0xf0, 0x7e, 0x50, + 0xf5, 0xf7, 0xaa, 0xb8, 0xf0, 0x61, 0x01, 0x20, 0xa0, 0x63, 0x20, 0x6b, + 0x01, 0x46, 0xf5, 0xf7, 0xb3, 0xb9, 0x2d, 0xe9, 0xf8, 0x4f, 0x05, 0x46, + 0x05, 0xf1, 0x84, 0x06, 0xf1, 0x68, 0xff, 0xf7, 0x4e, 0xf8, 0xb1, 0x68, + 0xf5, 0xf7, 0xa8, 0xf9, 0x04, 0x46, 0x68, 0x68, 0xf5, 0xf7, 0x06, 0xf8, + 0x00, 0xf0, 0x01, 0xf9, 0x29, 0x6f, 0xf5, 0xf7, 0x03, 0xf9, 0x28, 0x67, + 0x4f, 0xf0, 0x01, 0x0b, 0x68, 0x68, 0x29, 0x68, 0x48, 0x43, 0xf4, 0xf7, + 0xf9, 0xff, 0x80, 0x46, 0xff, 0xf7, 0xc6, 0xf9, 0xb1, 0x68, 0xf5, 0xf7, + 0x91, 0xf9, 0x07, 0x46, 0x10, 0xe0, 0x40, 0x46, 0x39, 0x46, 0x05, 0xeb, + 0x8b, 0x04, 0xf5, 0xf7, 0x89, 0xf9, 0x21, 0x6f, 0xf5, 0xf7, 0xea, 0xf8, + 0x20, 0x67, 0x0b, 0xf1, 0x01, 0x0b, 0x00, 0xf0, 0x7f, 0xf8, 0x00, 0xf0, + 0x7a, 0xf8, 0x80, 0x46, 0xa8, 0x68, 0x83, 0x45, 0xeb, 0xd3, 0x68, 0x68, + 0x40, 0x43, 0xf4, 0xf7, 0xd9, 0xff, 0x83, 0x46, 0x74, 0x68, 0x00, 0xf0, + 0xd1, 0xf8, 0x00, 0xf0, 0xd0, 0xf8, 0xff, 0xf7, 0x99, 0xff, 0xe9, 0x68, + 0xf5, 0xf7, 0xd0, 0xf8, 0xe8, 0x60, 0x01, 0x24, 0x00, 0xf0, 0x66, 0xf8, + 0xff, 0xf7, 0x90, 0xff, 0x81, 0x46, 0xff, 0xf7, 0x95, 0xf9, 0x71, 0x68, + 0xf5, 0xf7, 0x60, 0xf9, 0x00, 0x90, 0xd5, 0xf8, 0x08, 0xa0, 0x19, 0xe0, + 0x00, 0x98, 0x00, 0xf0, 0x4f, 0xf8, 0x05, 0xeb, 0x84, 0x07, 0x80, 0x46, + 0xf8, 0x68, 0x41, 0x46, 0xf5, 0xf7, 0xb6, 0xf8, 0xf8, 0x60, 0x05, 0xeb, + 0x8a, 0x07, 0x41, 0x46, 0xf8, 0x68, 0xf5, 0xf7, 0xaf, 0xf8, 0xf8, 0x60, + 0x64, 0x1c, 0xa8, 0x68, 0x82, 0x44, 0x00, 0xf0, 0x43, 0xf8, 0x00, 0xf0, + 0x39, 0xf8, 0x81, 0x46, 0xd5, 0xf8, 0x08, 0x80, 0x44, 0x45, 0xe1, 0xd3, + 0x34, 0x68, 0x00, 0xf0, 0x99, 0xf8, 0x00, 0xf0, 0x98, 0xf8, 0x06, 0x46, + 0x00, 0xf0, 0x34, 0xf8, 0xff, 0xf7, 0x5e, 0xff, 0x83, 0x46, 0x4f, 0xf0, + 0x01, 0x0a, 0x16, 0xe0, 0x48, 0x46, 0x31, 0x46, 0x05, 0xeb, 0x88, 0x07, + 0xf5, 0xf7, 0x2a, 0xf9, 0xf9, 0x68, 0xf5, 0xf7, 0x8b, 0xf8, 0xf8, 0x60, + 0x08, 0xf1, 0x01, 0x08, 0x00, 0xf0, 0x20, 0xf8, 0x00, 0xf0, 0x16, 0xf8, + 0x81, 0x46, 0x64, 0x1c, 0xa8, 0x68, 0x84, 0x42, 0xea, 0xd3, 0x0a, 0xf1, + 0x01, 0x0a, 0xa8, 0x68, 0x82, 0x45, 0x09, 0xd2, 0x00, 0xf0, 0x12, 0xf8, + 0xff, 0xf7, 0x3c, 0xff, 0x83, 0x46, 0xd9, 0x46, 0x08, 0xf1, 0x01, 0x08, + 0x01, 0x24, 0xed, 0xe7, 0xbd, 0xe8, 0xf1, 0x8f, 0x49, 0x46, 0xf5, 0xf7, + 0x07, 0xb9, 0x81, 0x46, 0x78, 0x68, 0x41, 0x46, 0xf5, 0xf7, 0x02, 0xb9, + 0x28, 0x68, 0xf4, 0xf7, 0x61, 0xbf, 0x2d, 0xe9, 0xf8, 0x43, 0x80, 0x46, + 0x0d, 0x46, 0x16, 0x46, 0x99, 0x46, 0x00, 0x24, 0x00, 0x27, 0x0c, 0xe0, + 0x30, 0x46, 0xf4, 0xf7, 0x55, 0xff, 0x58, 0xf8, 0x27, 0x10, 0xf5, 0xf7, + 0xef, 0xf8, 0x21, 0x46, 0xf5, 0xf7, 0x50, 0xf8, 0x04, 0x46, 0x6e, 0x43, + 0x7f, 0x1c, 0x4f, 0x45, 0xf0, 0xd3, 0x20, 0x46, 0xbd, 0xe8, 0xf2, 0x83, + 0x2d, 0xe9, 0xf8, 0x43, 0x08, 0x9c, 0x80, 0x46, 0x0e, 0x46, 0x17, 0x46, + 0x99, 0x46, 0x00, 0x25, 0xa0, 0x07, 0x4c, 0xbf, 0x01, 0x22, 0x2a, 0x46, + 0x3b, 0x46, 0x29, 0x46, 0x30, 0x46, 0xff, 0xf7, 0xd4, 0xff, 0x48, 0xf8, + 0x25, 0x00, 0x6d, 0x1c, 0x19, 0x2d, 0xf1, 0xd3, 0xe0, 0x07, 0x4c, 0xbf, + 0x00, 0x26, 0x58, 0xf8, 0x29, 0x60, 0x4f, 0x46, 0x20, 0xe0, 0xc7, 0xf1, + 0x18, 0x00, 0xf4, 0xf7, 0x25, 0xff, 0x04, 0x46, 0xc9, 0xf1, 0x18, 0x00, + 0xf4, 0xf7, 0x20, 0xff, 0x01, 0x46, 0x20, 0x46, 0xf4, 0xf7, 0x2c, 0xff, + 0x04, 0x46, 0x58, 0xf8, 0x27, 0x00, 0x00, 0xf0, 0x14, 0xf8, 0x05, 0x46, + 0x4f, 0xf0, 0x7e, 0x50, 0x21, 0x46, 0xf4, 0xf7, 0x9f, 0xff, 0x31, 0x46, + 0xf5, 0xf7, 0xac, 0xf8, 0x29, 0x46, 0xf5, 0xf7, 0x0d, 0xf8, 0x48, 0xf8, + 0x27, 0x00, 0x7f, 0x1c, 0x19, 0x2f, 0xdc, 0xd3, 0xbd, 0xe8, 0xf1, 0x83, + 0xf0, 0x68, 0x21, 0x46, 0xf5, 0xf7, 0x9e, 0xb8, 0x2d, 0xe9, 0xf2, 0x4f, + 0x8a, 0xb0, 0x80, 0x46, 0x91, 0x46, 0x00, 0x26, 0x00, 0xe0, 0x76, 0x1c, + 0x4e, 0x45, 0x47, 0xd2, 0x00, 0x25, 0x12, 0xe0, 0x04, 0xeb, 0x0a, 0x00, + 0x00, 0xf0, 0x9a, 0xf8, 0xff, 0xf7, 0xc8, 0xfe, 0x07, 0x46, 0x64, 0x1c, + 0xac, 0x42, 0xf5, 0xd3, 0x06, 0xeb, 0x0a, 0x04, 0x58, 0xf8, 0x24, 0x00, + 0x00, 0xf0, 0x9c, 0xf8, 0x48, 0xf8, 0x24, 0x00, 0x6d, 0x1c, 0xae, 0x42, + 0x04, 0xd3, 0x00, 0x27, 0x00, 0x24, 0x05, 0xfb, 0x09, 0xfa, 0xed, 0xe7, + 0x06, 0xfb, 0x09, 0x61, 0x58, 0xf8, 0x21, 0x10, 0x4f, 0xf0, 0x7e, 0x50, + 0xf4, 0xf7, 0xe2, 0xfe, 0x05, 0x46, 0x05, 0xa8, 0x06, 0xf1, 0x01, 0x0a, + 0x40, 0xf8, 0x26, 0x50, 0x15, 0xe0, 0x04, 0xeb, 0x0b, 0x00, 0x00, 0xf0, + 0x71, 0xf8, 0xff, 0xf7, 0x9f, 0xfe, 0x07, 0x46, 0x64, 0x1c, 0xb4, 0x42, + 0xf5, 0xd3, 0x06, 0xeb, 0x0b, 0x04, 0x58, 0xf8, 0x24, 0x00, 0x00, 0xf0, + 0x73, 0xf8, 0x00, 0xf0, 0x6c, 0xf8, 0x48, 0xf8, 0x24, 0x00, 0x0a, 0xf1, + 0x01, 0x0a, 0xca, 0x45, 0xb9, 0xd2, 0x00, 0x27, 0x00, 0x24, 0x0a, 0xfb, + 0x09, 0xfb, 0xea, 0xe7, 0x0a, 0x98, 0x00, 0x68, 0x00, 0x90, 0x01, 0x25, + 0x15, 0xe0, 0x05, 0xfb, 0x09, 0x60, 0x58, 0xf8, 0x20, 0x00, 0x5d, 0xf8, + 0x26, 0x10, 0xf5, 0xf7, 0x3f, 0xf8, 0xff, 0xf7, 0x79, 0xfe, 0x07, 0x46, + 0x76, 0x1c, 0xae, 0x42, 0xf1, 0xd3, 0x0a, 0x98, 0x50, 0xf8, 0x25, 0x00, + 0x00, 0xf0, 0x4e, 0xf8, 0x4d, 0xf8, 0x25, 0x00, 0x6d, 0x1c, 0x4d, 0x45, + 0x02, 0xd2, 0x00, 0x27, 0x00, 0x26, 0xf0, 0xe7, 0x68, 0x46, 0x00, 0xeb, + 0x89, 0x00, 0xa9, 0xf1, 0x02, 0x05, 0x50, 0xf8, 0x04, 0x1c, 0x05, 0xa8, + 0x00, 0xeb, 0x89, 0x00, 0x50, 0xf8, 0x04, 0x0c, 0xf5, 0xf7, 0x1e, 0xf8, + 0x0a, 0x99, 0x01, 0xeb, 0x89, 0x01, 0x41, 0xf8, 0x04, 0x0c, 0x1b, 0xe0, + 0x0a, 0x99, 0x51, 0xf8, 0x26, 0x10, 0x05, 0xfb, 0x09, 0x60, 0x58, 0xf8, + 0x20, 0x00, 0xf5, 0xf7, 0x0f, 0xf8, 0xff, 0xf7, 0x49, 0xfe, 0x07, 0x46, + 0x76, 0x1c, 0x4e, 0x45, 0xf0, 0xd3, 0x5d, 0xf8, 0x25, 0x00, 0x00, 0xf0, + 0x1f, 0xf8, 0x05, 0xa9, 0x51, 0xf8, 0x25, 0x10, 0xf5, 0xf7, 0x00, 0xf8, + 0x0a, 0x99, 0x41, 0xf8, 0x25, 0x00, 0x6d, 0x1e, 0x00, 0x2d, 0x02, 0xd4, + 0x00, 0x27, 0x6e, 0x1c, 0xeb, 0xe7, 0x0b, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, + 0x04, 0xfb, 0x09, 0x61, 0x58, 0xf8, 0x20, 0x00, 0x58, 0xf8, 0x21, 0x10, + 0xf4, 0xf7, 0xec, 0xbf, 0x02, 0x98, 0x29, 0x46, 0xf4, 0xf7, 0xe8, 0xbf, + 0x4f, 0xf0, 0x7e, 0x50, 0x39, 0x46, 0xf4, 0xf7, 0xd3, 0xbe, 0x2d, 0xe9, + 0xf2, 0x4f, 0x04, 0x46, 0x04, 0xf5, 0x00, 0x75, 0x50, 0x08, 0x03, 0x22, + 0x59, 0x08, 0x2a, 0x60, 0x40, 0x00, 0x49, 0x00, 0x41, 0xea, 0x00, 0x02, + 0xa8, 0x60, 0x6a, 0x60, 0xe9, 0x60, 0x4f, 0xf0, 0x00, 0x09, 0x68, 0x68, + 0xc0, 0x08, 0xc0, 0x00, 0x68, 0x60, 0xa8, 0x68, 0xc0, 0x08, 0xc0, 0x00, + 0xa8, 0x60, 0xe8, 0x68, 0xc0, 0x08, 0xc0, 0x00, 0xe8, 0x60, 0x68, 0x68, + 0xc0, 0x02, 0xc0, 0x0a, 0x68, 0x60, 0xa8, 0x68, 0xc0, 0x02, 0xc0, 0x0a, + 0xa8, 0x60, 0xe8, 0x68, 0xc0, 0x02, 0xc0, 0x0a, 0xe8, 0x60, 0x18, 0x20, + 0x69, 0x68, 0xc1, 0x40, 0xc9, 0x07, 0x07, 0xd4, 0xa9, 0x68, 0xc1, 0x40, + 0xc9, 0x07, 0x03, 0xd4, 0xe9, 0x68, 0xc1, 0x40, 0xc9, 0x07, 0x01, 0xd5, + 0x81, 0x46, 0x01, 0xe0, 0x40, 0x1e, 0xef, 0xd5, 0x4f, 0xf0, 0x00, 0x0a, + 0x50, 0x46, 0xca, 0x45, 0xc8, 0xbf, 0x48, 0x46, 0x04, 0xeb, 0x80, 0x07, + 0x04, 0xeb, 0x8a, 0x08, 0x08, 0xf1, 0x04, 0x06, 0x78, 0x68, 0x30, 0x60, + 0x08, 0xf1, 0xd4, 0x0b, 0x78, 0x68, 0xcb, 0xf8, 0x00, 0x00, 0x0a, 0xf1, + 0x01, 0x0a, 0xb8, 0x6e, 0x70, 0x66, 0x21, 0x68, 0xb8, 0x6e, 0xf4, 0xf7, + 0x7d, 0xfe, 0xcb, 0xf8, 0x64, 0x00, 0xb8, 0x6e, 0x21, 0x68, 0x00, 0xf0, + 0xb1, 0xf8, 0xc8, 0xf8, 0x9c, 0x01, 0x08, 0xf5, 0x0b, 0x70, 0x31, 0x68, + 0x01, 0x60, 0xba, 0xf1, 0x19, 0x0f, 0x71, 0x6e, 0x41, 0x66, 0x20, 0x68, + 0xa8, 0x62, 0xd3, 0xdb, 0x20, 0x68, 0xa8, 0x62, 0x04, 0xf5, 0x3d, 0x70, + 0x9d, 0xf8, 0x00, 0x10, 0x00, 0xf0, 0x02, 0xf8, 0xbd, 0xe8, 0xf1, 0x8f, + 0x01, 0x70, 0x29, 0x68, 0x41, 0x60, 0x69, 0x68, 0x81, 0x60, 0xa9, 0x68, + 0xc1, 0x60, 0xe9, 0x68, 0x01, 0x61, 0x70, 0x47, 0x38, 0xb5, 0x04, 0x46, + 0x00, 0xf0, 0x89, 0xfa, 0x04, 0xf1, 0xcc, 0x01, 0x4f, 0xf0, 0x7e, 0x50, + 0x00, 0x22, 0x08, 0x60, 0x4a, 0x60, 0x00, 0x21, 0x00, 0x25, 0x04, 0xeb, + 0x81, 0x02, 0x02, 0xf1, 0xd4, 0x03, 0x49, 0x1c, 0x18, 0x60, 0xc2, 0xf8, + 0x9c, 0x51, 0x00, 0x22, 0x19, 0x29, 0x5a, 0x66, 0xf3, 0xd3, 0x04, 0xf5, + 0x00, 0x75, 0x01, 0x21, 0x29, 0x60, 0x6f, 0xf0, 0x01, 0x01, 0x69, 0x60, + 0xa9, 0x60, 0xe9, 0x60, 0x69, 0x68, 0xc9, 0x08, 0xc9, 0x00, 0x69, 0x60, + 0xa9, 0x68, 0xc9, 0x08, 0xc9, 0x00, 0xa9, 0x60, 0xe9, 0x68, 0xc9, 0x08, + 0xc9, 0x00, 0xe9, 0x60, 0x69, 0x68, 0xc9, 0x02, 0xc9, 0x0a, 0x69, 0x60, + 0xa9, 0x68, 0xc9, 0x02, 0xc9, 0x0a, 0xa9, 0x60, 0xe9, 0x68, 0xc9, 0x02, + 0xc9, 0x0a, 0xe9, 0x60, 0x2a, 0x61, 0x6a, 0x61, 0x28, 0x62, 0xaa, 0x61, + 0xea, 0x61, 0x6a, 0x62, 0x04, 0xf5, 0x0a, 0x70, 0x00, 0xf0, 0x49, 0xfa, + 0x04, 0xf5, 0x3d, 0x70, 0x00, 0x21, 0xff, 0xf7, 0xad, 0xff, 0x01, 0x21, + 0x01, 0x75, 0x31, 0xbd, 0x2d, 0xe9, 0xf8, 0x43, 0x80, 0x46, 0x08, 0xf5, + 0x00, 0x75, 0x00, 0x26, 0xa8, 0x6a, 0xc8, 0xf8, 0x00, 0x00, 0x08, 0xeb, + 0x86, 0x09, 0x09, 0xf5, 0x0b, 0x74, 0x09, 0xf1, 0x04, 0x00, 0x21, 0x68, + 0x01, 0x60, 0x09, 0xf1, 0xd4, 0x07, 0x21, 0x68, 0x39, 0x60, 0x76, 0x1c, + 0x61, 0x6e, 0x41, 0x66, 0x60, 0x6e, 0xa9, 0x6a, 0xf4, 0xf7, 0xee, 0xfd, + 0x78, 0x66, 0x60, 0x6e, 0xa9, 0x6a, 0x00, 0xf0, 0x23, 0xf8, 0x19, 0x2e, + 0xc9, 0xf8, 0x9c, 0x01, 0xe3, 0xd3, 0x08, 0xf1, 0xcc, 0x00, 0x4f, 0xf0, + 0x7e, 0x51, 0x00, 0x22, 0x01, 0x60, 0x42, 0x60, 0x08, 0xf5, 0x3e, 0x70, + 0x02, 0x68, 0x2a, 0x60, 0x42, 0x68, 0x6a, 0x60, 0x82, 0x68, 0xaa, 0x60, + 0xc0, 0x68, 0xe8, 0x60, 0x00, 0x20, 0x68, 0x61, 0x29, 0x62, 0x01, 0x20, + 0xa8, 0x61, 0x00, 0x20, 0xe8, 0x61, 0x68, 0x62, 0xbd, 0xe8, 0xf1, 0x83, + 0xd8, 0xf8, 0x58, 0x02, 0xda, 0xf8, 0x00, 0x10, 0x80, 0xf0, 0x00, 0x40, + 0xf4, 0xf7, 0xc2, 0xbd, 0x80, 0xb5, 0x01, 0x21, 0xfb, 0xf7, 0xd8, 0xff, + 0xbd, 0xe8, 0x04, 0x40, 0x74, 0x49, 0xf4, 0xf7, 0xc9, 0xbe, 0x00, 0x00, + 0x0a, 0xd7, 0x23, 0x3c, 0x2d, 0xe9, 0xfe, 0x4f, 0x04, 0x46, 0x04, 0xf1, + 0x14, 0x07, 0x07, 0xf5, 0xd0, 0x76, 0x01, 0x20, 0xb0, 0x62, 0x88, 0x46, + 0xe0, 0x68, 0x03, 0x21, 0x01, 0x62, 0x01, 0x22, 0x05, 0x21, 0x01, 0x60, + 0x20, 0x46, 0x39, 0x46, 0xfe, 0xf7, 0xe8, 0xfe, 0x30, 0x68, 0x00, 0x28, + 0x00, 0xf0, 0xc7, 0x80, 0x39, 0x46, 0x20, 0x46, 0xfe, 0xf7, 0x38, 0xfe, + 0x06, 0x46, 0x00, 0x20, 0x00, 0x90, 0x01, 0xab, 0x02, 0xaa, 0x39, 0x46, + 0x20, 0x46, 0xfe, 0xf7, 0xaf, 0xfd, 0xa0, 0x68, 0x00, 0xf5, 0x07, 0x77, + 0x3d, 0x68, 0x1d, 0xb9, 0x02, 0x98, 0x78, 0x60, 0x01, 0x98, 0x46, 0xe0, + 0x20, 0x68, 0x00, 0xf1, 0x88, 0x09, 0xd9, 0xf8, 0x0c, 0x00, 0x85, 0x42, + 0x23, 0xd2, 0x28, 0x46, 0xf4, 0xf7, 0xf0, 0xfc, 0x00, 0xf0, 0xb0, 0xf8, + 0x02, 0x99, 0xf4, 0xf7, 0xed, 0xfd, 0x81, 0x46, 0x68, 0x1c, 0xf4, 0xf7, + 0xe7, 0xfc, 0x01, 0x46, 0x48, 0x46, 0xf4, 0xf7, 0xf3, 0xfc, 0x78, 0x60, + 0x3d, 0x68, 0x28, 0x46, 0xf4, 0xf7, 0xde, 0xfc, 0xb9, 0x68, 0xf4, 0xf7, + 0x79, 0xfe, 0x01, 0x99, 0xf4, 0xf7, 0xda, 0xfd, 0x81, 0x46, 0x68, 0x1c, + 0xf4, 0xf7, 0xd4, 0xfc, 0x01, 0x46, 0x48, 0x46, 0xf4, 0xf7, 0xe0, 0xfc, + 0x1b, 0xe0, 0xd9, 0xf8, 0x08, 0x50, 0xfe, 0xf7, 0x0f, 0xfd, 0x00, 0xf0, + 0x8b, 0xf8, 0x82, 0x46, 0xff, 0xf7, 0x78, 0xfe, 0x51, 0x46, 0xf4, 0xf7, + 0xc5, 0xfd, 0x78, 0x60, 0x4f, 0xf0, 0x7e, 0x50, 0xd9, 0xf8, 0x08, 0x50, + 0xfe, 0xf7, 0x02, 0xfd, 0xb9, 0x68, 0xf4, 0xf7, 0x57, 0xfe, 0x81, 0x46, + 0x01, 0x98, 0xff, 0xf7, 0x68, 0xfe, 0xff, 0xf7, 0x13, 0xf9, 0xb8, 0x60, + 0x01, 0x2e, 0x18, 0xbf, 0x04, 0x2e, 0x07, 0xd1, 0x20, 0x68, 0xd0, 0xf8, + 0x88, 0x10, 0x34, 0x48, 0xf4, 0xf7, 0x46, 0xfe, 0x05, 0x46, 0x02, 0xe0, + 0x20, 0x68, 0xd0, 0xf8, 0x88, 0x50, 0x79, 0x68, 0x30, 0x48, 0xf4, 0xf7, + 0xa1, 0xfd, 0xd7, 0xf8, 0x08, 0x90, 0x01, 0x46, 0xf4, 0xf7, 0x38, 0xfe, + 0x83, 0x46, 0x48, 0x46, 0xff, 0xf7, 0x2a, 0xfd, 0xff, 0xf7, 0x35, 0xfc, + 0x4f, 0xf0, 0x7a, 0x5a, 0x51, 0x46, 0xf4, 0xf7, 0x2d, 0xfe, 0x81, 0x46, + 0x01, 0x20, 0x01, 0x2e, 0x18, 0xbf, 0x04, 0x2e, 0x03, 0xd1, 0x21, 0x68, + 0x88, 0x31, 0x49, 0x69, 0x02, 0xe0, 0x21, 0x68, 0x88, 0x31, 0x09, 0x69, + 0x88, 0x40, 0xf4, 0xf7, 0x75, 0xfc, 0xff, 0xf7, 0x30, 0xfe, 0x06, 0x46, + 0x02, 0x99, 0x1d, 0x48, 0xf4, 0xf7, 0x7a, 0xfd, 0x01, 0x46, 0xf4, 0xf7, + 0x13, 0xfe, 0x01, 0x99, 0x83, 0x46, 0x08, 0x46, 0xf4, 0xf7, 0x0e, 0xfe, + 0xff, 0xf7, 0x0f, 0xfc, 0x51, 0x46, 0xf4, 0xf7, 0x09, 0xfe, 0x01, 0x46, + 0x30, 0x46, 0xf4, 0xf7, 0xf3, 0xfd, 0x05, 0xd2, 0x08, 0x46, 0xff, 0xf7, + 0x2f, 0xff, 0xc8, 0xf8, 0x00, 0x00, 0x15, 0xe0, 0x21, 0x68, 0x38, 0x68, + 0x88, 0x31, 0xc9, 0x68, 0x88, 0x42, 0x03, 0xd2, 0x40, 0x1c, 0x38, 0x60, + 0x00, 0x20, 0x0c, 0xe0, 0x48, 0x46, 0xff, 0xf7, 0x1f, 0xff, 0xc8, 0xf8, + 0x00, 0x00, 0x29, 0x46, 0x48, 0x46, 0xf4, 0xf7, 0xd9, 0xfd, 0x38, 0xbf, + 0x01, 0x20, 0x00, 0xd3, 0x02, 0x20, 0xbd, 0xe8, 0xfe, 0x8f, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x42, 0x00, 0x00, 0x20, 0xc1, 0x71, 0x1d, 0x9e, 0x43, + 0x00, 0x00, 0x80, 0xbf, 0x79, 0x68, 0xf4, 0xf7, 0xd9, 0xbd, 0x00, 0x00, + 0x1a, 0x48, 0x01, 0x78, 0x09, 0x06, 0x00, 0xd4, 0x70, 0x47, 0x2d, 0xe9, + 0xf0, 0x41, 0x00, 0x78, 0x17, 0x4d, 0x00, 0xf0, 0x07, 0x04, 0x68, 0x78, + 0x84, 0x42, 0x01, 0xd1, 0x28, 0x78, 0x18, 0xbb, 0x0f, 0xf2, 0x5c, 0x00, + 0x13, 0x4f, 0x50, 0xf8, 0x24, 0x80, 0x4f, 0xf6, 0xff, 0x70, 0x38, 0x80, + 0x01, 0x26, 0x30, 0x46, 0xf4, 0xf7, 0x1e, 0xfc, 0x41, 0x46, 0xf4, 0xf7, + 0xb9, 0xfd, 0x0e, 0x49, 0xf4, 0xf7, 0x28, 0xfc, 0x01, 0x46, 0x0d, 0x48, + 0xf5, 0xf7, 0x29, 0xf8, 0x4f, 0xf0, 0x8f, 0x41, 0xf4, 0xf7, 0xae, 0xfd, + 0xf4, 0xf7, 0x18, 0xfe, 0x27, 0xf8, 0x16, 0x00, 0x76, 0x1c, 0x40, 0x2e, + 0xe7, 0xd3, 0x01, 0x20, 0x6c, 0x70, 0x28, 0x70, 0xbd, 0xe8, 0xf0, 0x81, + 0x13, 0x07, 0x00, 0x46, 0x96, 0xf3, 0x00, 0x20, 0x30, 0xf0, 0x00, 0x20, + 0x00, 0x00, 0xa0, 0x41, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0x80, 0xbe, + 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0xa0, 0xc0, + 0x00, 0x00, 0xc0, 0xc0, 0x80, 0xb5, 0x4f, 0xf0, 0x9e, 0x41, 0xf4, 0xf7, + 0x8b, 0xfe, 0x02, 0xd8, 0x6f, 0xf0, 0x00, 0x40, 0x02, 0xbd, 0x4d, 0x49, + 0xf4, 0xf7, 0x6a, 0xfd, 0x24, 0xbf, 0xbd, 0xe8, 0x02, 0x40, 0xf4, 0xf7, + 0xe3, 0xbd, 0x4f, 0xf0, 0x00, 0x40, 0x02, 0xbd, 0x38, 0xb5, 0x0c, 0x46, + 0xf4, 0xf7, 0xd2, 0xfb, 0x46, 0x49, 0xf4, 0xf7, 0x6d, 0xfd, 0x05, 0x46, + 0x20, 0x46, 0xf4, 0xf7, 0xcb, 0xfb, 0x01, 0x46, 0x28, 0x46, 0xf4, 0xf7, + 0xd7, 0xfb, 0x4f, 0xf0, 0x7e, 0x51, 0xf4, 0xf7, 0xc5, 0xfc, 0xbd, 0xe8, + 0x32, 0x40, 0xfb, 0xf7, 0x5d, 0xbc, 0x2d, 0xe9, 0xfe, 0x4f, 0x04, 0x46, + 0x0f, 0x46, 0x25, 0x68, 0x4f, 0xf0, 0x7c, 0x50, 0x29, 0x46, 0xf4, 0xf7, + 0x53, 0xfd, 0x29, 0x46, 0xf4, 0xf7, 0x50, 0xfd, 0x00, 0xf0, 0x70, 0xf8, + 0x81, 0x46, 0x28, 0x46, 0x49, 0x46, 0xf4, 0xf7, 0xbb, 0xfb, 0x4f, 0xf0, + 0x9d, 0x4b, 0x59, 0x46, 0xf4, 0xf7, 0x44, 0xfd, 0xff, 0xf7, 0xba, 0xff, + 0x38, 0x60, 0x4f, 0xf0, 0x7e, 0x58, 0x38, 0x1d, 0x00, 0x90, 0x68, 0x37, + 0x00, 0x25, 0xdf, 0xf8, 0xb4, 0xa0, 0x04, 0xeb, 0x85, 0x06, 0x4f, 0xf0, + 0x7c, 0x51, 0xb0, 0x6e, 0xf4, 0xf7, 0x32, 0xfd, 0xb1, 0x6e, 0xf4, 0xf7, + 0x2f, 0xfd, 0x00, 0xf0, 0x4f, 0xf8, 0x71, 0x68, 0xf4, 0xf7, 0x9c, 0xfb, + 0x59, 0x46, 0xf4, 0xf7, 0x27, 0xfd, 0x49, 0x46, 0xf4, 0xf7, 0x96, 0xfb, + 0x41, 0x46, 0xf4, 0xf7, 0x21, 0xfd, 0xff, 0xf7, 0x97, 0xff, 0x00, 0x99, + 0x41, 0xf8, 0x25, 0x00, 0x51, 0x46, 0xb0, 0x6e, 0xf4, 0xf7, 0x18, 0xfd, + 0x71, 0x68, 0xf4, 0xf7, 0x87, 0xfb, 0x59, 0x46, 0xf4, 0xf7, 0x12, 0xfd, + 0x49, 0x46, 0xf4, 0xf7, 0x81, 0xfb, 0x41, 0x46, 0xf4, 0xf7, 0x0c, 0xfd, + 0xff, 0xf7, 0x82, 0xff, 0x47, 0xf8, 0x25, 0x00, 0x51, 0x46, 0x40, 0x46, + 0xf4, 0xf7, 0x04, 0xfd, 0x6d, 0x1c, 0x18, 0x2d, 0x80, 0x46, 0xc6, 0xdb, + 0x60, 0x6e, 0x49, 0x46, 0xf4, 0xf7, 0xfc, 0xfc, 0x01, 0x46, 0x58, 0x46, + 0xf4, 0xf7, 0x6a, 0xfb, 0xff, 0xf7, 0x6e, 0xff, 0x00, 0x99, 0x08, 0x66, + 0x00, 0x20, 0x38, 0x66, 0x02, 0x98, 0x00, 0x68, 0x30, 0xb9, 0x01, 0x99, + 0x00, 0x98, 0x03, 0xb0, 0xbd, 0xe8, 0xf0, 0x4f, 0x00, 0xf0, 0x42, 0xb9, + 0xbd, 0xe8, 0xf7, 0x8f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xce, + 0x00, 0x00, 0xc0, 0x41, 0x00, 0x00, 0x80, 0xbf, 0x01, 0x46, 0x4f, 0xf0, + 0x7e, 0x50, 0xf4, 0xf7, 0xc9, 0xbb, 0x00, 0x21, 0x01, 0x60, 0x00, 0xeb, + 0x81, 0x02, 0x4f, 0xf0, 0x7e, 0x53, 0x53, 0x60, 0x49, 0x1c, 0x00, 0x23, + 0x19, 0x29, 0x93, 0x66, 0xf5, 0xd3, 0x70, 0x47, 0xf8, 0xb5, 0x0f, 0x46, + 0xd7, 0xf8, 0x00, 0xe0, 0xd7, 0xf8, 0x04, 0xc0, 0x06, 0x46, 0x82, 0xfb, + 0x0e, 0x45, 0x83, 0xfb, 0x0c, 0x01, 0x20, 0x1a, 0x65, 0xeb, 0x01, 0x01, + 0x82, 0xfb, 0x0c, 0x45, 0xc3, 0xfb, 0x0e, 0x45, 0x32, 0x68, 0x73, 0x68, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0x81, 0x18, 0x31, 0x60, 0xe4, 0x0d, + 0x44, 0xea, 0x45, 0x24, 0xe1, 0x18, 0x71, 0x60, 0x10, 0x1a, 0x38, 0x60, + 0x18, 0x1b, 0x78, 0x60, 0xf1, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0x00, 0xf0, + 0x5b, 0xf8, 0x04, 0xf1, 0x08, 0x01, 0xff, 0xf7, 0xd5, 0xff, 0x00, 0xf0, + 0x55, 0xf8, 0x04, 0xf1, 0x18, 0x01, 0x04, 0xf1, 0x10, 0x00, 0xff, 0xf7, + 0xcd, 0xff, 0x00, 0xf0, 0x4d, 0xf8, 0x04, 0xf1, 0x10, 0x01, 0x20, 0x46, + 0xff, 0xf7, 0xc6, 0xff, 0x04, 0xf1, 0x18, 0x01, 0x04, 0xf1, 0x08, 0x00, + 0xbd, 0xe8, 0x10, 0x40, 0x4f, 0xf4, 0x00, 0x03, 0x00, 0x22, 0xbb, 0xe7, + 0x30, 0xb5, 0x85, 0xb0, 0x04, 0x46, 0x0d, 0x46, 0x68, 0x46, 0x0f, 0xf2, + 0x1c, 0x31, 0x10, 0x22, 0xf7, 0xf7, 0xf8, 0xfb, 0x00, 0x20, 0x10, 0xf8, + 0x0d, 0x10, 0x54, 0xf8, 0x21, 0x10, 0x45, 0xf8, 0x20, 0x10, 0x40, 0x1c, + 0x10, 0x28, 0xf6, 0xd3, 0x28, 0x46, 0xff, 0xf7, 0xc8, 0xff, 0x05, 0xf1, + 0x20, 0x00, 0xff, 0xf7, 0xc4, 0xff, 0x00, 0xf0, 0x21, 0xf8, 0x05, 0xf1, + 0x20, 0x01, 0x28, 0x46, 0xff, 0xf7, 0x9a, 0xff, 0xb1, 0x4c, 0x23, 0x46, + 0x22, 0x46, 0x05, 0xf1, 0x28, 0x01, 0x05, 0xf1, 0x08, 0x00, 0xff, 0xf7, + 0x91, 0xff, 0x4f, 0xf4, 0x00, 0x03, 0x00, 0x22, 0x05, 0xf1, 0x30, 0x01, + 0x05, 0xf1, 0x10, 0x00, 0xff, 0xf7, 0x88, 0xff, 0x23, 0x46, 0xa9, 0x4a, + 0x05, 0xf1, 0x38, 0x01, 0x05, 0xf1, 0x18, 0x00, 0xff, 0xf7, 0x80, 0xff, + 0x05, 0xb0, 0x30, 0xbd, 0x00, 0x23, 0x4f, 0xf4, 0x00, 0x02, 0x70, 0x47, + 0x2d, 0xe9, 0xf3, 0x43, 0x87, 0xb0, 0xff, 0xf7, 0xb9, 0xff, 0x08, 0x98, + 0x00, 0xf1, 0x40, 0x01, 0x07, 0x98, 0x08, 0x30, 0xff, 0xf7, 0xb2, 0xff, + 0x08, 0x98, 0x00, 0xf1, 0x80, 0x01, 0x07, 0x98, 0x10, 0x30, 0xff, 0xf7, + 0xab, 0xff, 0x00, 0x22, 0x08, 0x98, 0x07, 0x99, 0x50, 0xf8, 0x22, 0x00, + 0x41, 0xf8, 0x22, 0x00, 0x52, 0x1c, 0x30, 0x2a, 0xf6, 0xd3, 0x03, 0x20, + 0x4f, 0xf4, 0x00, 0x0e, 0x4f, 0xf0, 0x00, 0x08, 0x00, 0x27, 0x02, 0x90, + 0x00, 0x22, 0x07, 0x98, 0x50, 0xf8, 0x22, 0xc0, 0x00, 0xeb, 0x82, 0x01, + 0x08, 0x1d, 0x03, 0x68, 0xc4, 0x6b, 0x05, 0x6c, 0xc6, 0x6f, 0x01, 0x96, + 0xd1, 0xf8, 0x84, 0x10, 0x00, 0x91, 0x2f, 0xb9, 0x01, 0x98, 0x00, 0x19, + 0x00, 0xeb, 0x0c, 0x06, 0x48, 0x19, 0x52, 0xe0, 0x86, 0x48, 0x80, 0xfb, + 0x0e, 0x01, 0xcd, 0xe9, 0x04, 0x01, 0x85, 0x48, 0x80, 0xfb, 0x0e, 0x69, + 0x82, 0x48, 0x80, 0xfb, 0x08, 0x01, 0x30, 0x1a, 0x69, 0xeb, 0x01, 0x01, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x2e, 0xdd, 0xe9, 0x04, 0x01, 0x7e, 0x4e, + 0xc6, 0xfb, 0x08, 0x01, 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x28, 0x84, 0xfb, + 0x0e, 0x69, 0x85, 0xfb, 0x08, 0x01, 0x30, 0x1a, 0x69, 0xeb, 0x01, 0x01, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0x84, 0x44, 0x85, 0xfb, 0x0e, 0x01, + 0xc4, 0xfb, 0x08, 0x01, 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0xc3, 0x18, + 0x8e, 0xfb, 0x0e, 0x45, 0x88, 0xfb, 0x08, 0x01, 0x20, 0x1a, 0x65, 0xeb, + 0x01, 0x01, 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x24, 0x88, 0xfb, 0x0e, 0x01, + 0x80, 0x0d, 0x40, 0xea, 0x81, 0x25, 0x01, 0x98, 0x80, 0xfb, 0x04, 0x69, + 0x00, 0x98, 0x80, 0xfb, 0x05, 0x01, 0x30, 0x1a, 0x69, 0xeb, 0x01, 0x01, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0x00, 0xeb, 0x0c, 0x06, 0x00, 0x98, + 0xdd, 0xf8, 0x04, 0x90, 0x80, 0xfb, 0x04, 0x01, 0xc9, 0xfb, 0x05, 0x01, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0x08, 0x99, 0x41, 0xf8, 0x27, 0x60, + 0x92, 0x1c, 0x08, 0x99, 0x01, 0xeb, 0x87, 0x01, 0xbf, 0x1c, 0xc0, 0x18, + 0x10, 0x2a, 0x48, 0x60, 0x8b, 0xd3, 0x02, 0x98, 0x40, 0x1e, 0x02, 0x90, + 0x86, 0xd1, 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x83, 0x2d, 0xe9, 0xf3, 0x4f, + 0x87, 0xb0, 0x4f, 0xf4, 0x00, 0x02, 0x4f, 0xf0, 0x00, 0x0e, 0x00, 0x23, + 0x07, 0x98, 0x4f, 0xea, 0xee, 0x79, 0xde, 0xf5, 0x00, 0x0a, 0x50, 0xf8, + 0x23, 0x00, 0x69, 0xeb, 0x49, 0x07, 0xc1, 0x17, 0xaa, 0xfb, 0x00, 0x45, + 0x0a, 0xfb, 0x01, 0x55, 0x07, 0xfb, 0x00, 0x55, 0xcd, 0xe9, 0x04, 0x45, + 0x07, 0x99, 0x03, 0xf1, 0x19, 0x06, 0x51, 0xf8, 0x26, 0x60, 0x04, 0x46, + 0x50, 0x46, 0x39, 0x46, 0xf5, 0x17, 0xa0, 0xfb, 0x06, 0xa7, 0x00, 0xfb, + 0x05, 0x77, 0x1e, 0xf5, 0x00, 0x00, 0x01, 0xfb, 0x06, 0x77, 0x49, 0xf1, + 0x00, 0x01, 0xcd, 0xe9, 0x02, 0x01, 0xc2, 0xfb, 0x04, 0xa7, 0x07, 0x98, + 0x59, 0x42, 0x00, 0xeb, 0x81, 0x00, 0x50, 0xf8, 0x60, 0xcf, 0x40, 0x6e, + 0xcc, 0xf1, 0x00, 0x01, 0xdd, 0xe9, 0x02, 0x45, 0xc2, 0xfb, 0x01, 0xa7, + 0x40, 0x42, 0xd0, 0x46, 0xb9, 0x46, 0xc1, 0x17, 0xa4, 0xfb, 0x00, 0xa7, + 0x04, 0xfb, 0x01, 0x77, 0x05, 0xfb, 0x00, 0x77, 0x4d, 0x46, 0x18, 0xeb, + 0x0a, 0x04, 0x7d, 0x41, 0xdd, 0xe9, 0x04, 0xa7, 0x71, 0x42, 0xc2, 0xfb, + 0x01, 0xa7, 0xcd, 0xe9, 0x00, 0xa7, 0x4f, 0xea, 0xec, 0x71, 0xdd, 0xe9, + 0x02, 0xa7, 0xaa, 0xfb, 0x0c, 0x6b, 0x0a, 0xfb, 0x01, 0xbb, 0x07, 0xfb, + 0x0c, 0xbb, 0xdd, 0xe9, 0x00, 0x17, 0x11, 0xeb, 0x06, 0x0a, 0x47, 0xeb, + 0x0b, 0x07, 0xc2, 0xfb, 0x00, 0xa7, 0x4f, 0xea, 0xda, 0x50, 0x40, 0xea, + 0x47, 0x21, 0x21, 0x48, 0xff, 0x15, 0xa0, 0xfb, 0x01, 0x89, 0x00, 0xfb, + 0x07, 0x99, 0x4f, 0xea, 0xd8, 0x50, 0x40, 0xea, 0x49, 0x21, 0x08, 0x98, + 0xdf, 0xf8, 0x6c, 0xa0, 0x40, 0xf8, 0x33, 0x10, 0xe4, 0x0d, 0x44, 0xea, + 0x45, 0x24, 0xed, 0x15, 0xaa, 0xfb, 0x04, 0x01, 0x0a, 0xfb, 0x05, 0x11, + 0xc0, 0x0d, 0x40, 0xea, 0x41, 0x20, 0x08, 0x99, 0x01, 0xeb, 0xc3, 0x01, + 0x5b, 0x1c, 0x48, 0x60, 0x12, 0x49, 0x13, 0x48, 0x81, 0xfb, 0x02, 0x45, + 0xc0, 0xfb, 0x0e, 0x45, 0x06, 0x46, 0xce, 0xf1, 0x00, 0x00, 0x81, 0xfb, + 0x00, 0x01, 0xc6, 0xfb, 0x02, 0x01, 0xc0, 0x0d, 0xe4, 0x0d, 0x18, 0x2b, + 0x40, 0xea, 0x41, 0x22, 0x44, 0xea, 0x45, 0x2e, 0xff, 0xf4, 0x6a, 0xaf, + 0x07, 0x99, 0x08, 0x98, 0x09, 0xb0, 0xbd, 0xe8, 0xf0, 0x4f, 0xbb, 0xe6, + 0x7a, 0x82, 0x5a, 0x00, 0x86, 0x7d, 0xa5, 0xff, 0xfc, 0x20, 0x21, 0x00, + 0x75, 0xa3, 0x7b, 0x00, 0xab, 0xaa, 0x02, 0x00, 0x15, 0xb5, 0x10, 0x00, + 0xaa, 0xe7, 0x7e, 0x00, 0x00, 0x01, 0x18, 0x19, 0x0c, 0x0d, 0x24, 0x25, + 0x06, 0x07, 0x1e, 0x1f, 0x12, 0x13, 0x2a, 0x2b, 0x2d, 0xe9, 0xf0, 0x4f, + 0x04, 0x46, 0x8b, 0xb0, 0x00, 0x20, 0x20, 0x77, 0x04, 0xf1, 0x1d, 0x05, + 0x60, 0x69, 0x00, 0xf1, 0x68, 0x01, 0x00, 0x1d, 0x07, 0x90, 0x06, 0x91, + 0x04, 0xf5, 0xe8, 0x70, 0x02, 0x90, 0x04, 0xf5, 0x24, 0x70, 0x01, 0x90, + 0x04, 0xf1, 0x50, 0x00, 0x0a, 0x90, 0x01, 0x20, 0xa1, 0x68, 0x46, 0x42, + 0x01, 0xeb, 0x80, 0x02, 0x01, 0xeb, 0x86, 0x01, 0x13, 0x6e, 0xd1, 0xf8, + 0xc0, 0x60, 0x16, 0x66, 0xc1, 0xf8, 0xc0, 0x30, 0x40, 0x1c, 0xd2, 0xf8, + 0x20, 0x31, 0xd1, 0xf8, 0x80, 0x61, 0xc2, 0xf8, 0x20, 0x61, 0x0c, 0x28, + 0xc1, 0xf8, 0x80, 0x31, 0xe8, 0xdb, 0x00, 0x20, 0x28, 0x70, 0x01, 0x26, + 0x02, 0x99, 0x08, 0x60, 0x4f, 0xf0, 0x42, 0x58, 0x01, 0x99, 0x08, 0x60, + 0x20, 0x69, 0xf0, 0x40, 0x00, 0xf0, 0x01, 0x00, 0x70, 0x55, 0xa7, 0x68, + 0x57, 0xf8, 0x26, 0x00, 0xf4, 0xf7, 0x02, 0xf9, 0x00, 0xf0, 0x42, 0xfa, + 0x02, 0x99, 0x41, 0xf8, 0x26, 0x00, 0x07, 0xeb, 0x86, 0x00, 0xd0, 0xf8, + 0xc0, 0x00, 0xf4, 0xf7, 0xf7, 0xf8, 0x00, 0xf0, 0x37, 0xfa, 0x01, 0x99, + 0x41, 0xf8, 0x26, 0x00, 0xa9, 0x1b, 0xe0, 0x68, 0xf0, 0x40, 0x00, 0xf0, + 0x01, 0x00, 0x81, 0xf8, 0x30, 0x00, 0xa0, 0x68, 0x00, 0xeb, 0x86, 0x07, + 0x38, 0x6e, 0xf4, 0xf7, 0xe5, 0xf8, 0x00, 0xf0, 0x25, 0xfa, 0x02, 0x99, + 0x01, 0xeb, 0x86, 0x01, 0x08, 0x66, 0xd7, 0xf8, 0x20, 0x01, 0xf4, 0xf7, + 0xdb, 0xf8, 0x00, 0xf0, 0x1b, 0xfa, 0x01, 0x99, 0x01, 0xeb, 0x86, 0x01, + 0x76, 0x1c, 0x18, 0x2e, 0x08, 0x66, 0xc5, 0xdb, 0x01, 0x22, 0xdf, 0xf8, + 0x00, 0x08, 0x01, 0x46, 0x40, 0x08, 0x49, 0x08, 0xc3, 0x07, 0x5c, 0xbf, + 0x00, 0x23, 0x53, 0x55, 0xcb, 0x07, 0x03, 0xd4, 0xae, 0x1a, 0x00, 0x23, + 0x86, 0xf8, 0x30, 0x30, 0x52, 0x1c, 0x18, 0x2a, 0xf0, 0xdb, 0x00, 0x27, + 0x03, 0xe0, 0x00, 0x2f, 0x18, 0xbf, 0x18, 0x2f, 0x02, 0xd1, 0x4f, 0xf0, + 0xff, 0x39, 0x65, 0xe0, 0x78, 0x5d, 0x00, 0x28, 0x62, 0xd0, 0x01, 0x98, + 0x50, 0xf8, 0x27, 0xa0, 0x02, 0x98, 0x50, 0xf8, 0x27, 0xb0, 0x58, 0x46, + 0x59, 0x46, 0xf4, 0xf7, 0x51, 0xfa, 0x00, 0x90, 0x51, 0x46, 0x50, 0x46, + 0xf4, 0xf7, 0x4c, 0xfa, 0x00, 0x99, 0xf4, 0xf7, 0xad, 0xf9, 0xb9, 0xf1, + 0x00, 0x0f, 0x0e, 0xd5, 0x06, 0x46, 0x58, 0x46, 0x00, 0x21, 0xf4, 0xf7, + 0x21, 0xfa, 0xb9, 0x46, 0x08, 0xbf, 0x88, 0x46, 0x44, 0xd0, 0x50, 0x46, + 0x59, 0x46, 0xf4, 0xf7, 0xab, 0xf8, 0x80, 0x46, 0x3e, 0xe0, 0x00, 0x90, + 0x00, 0x21, 0x58, 0x46, 0xf4, 0xf7, 0x12, 0xfa, 0x08, 0xbf, 0x8a, 0x46, + 0x04, 0xd0, 0x50, 0x46, 0x59, 0x46, 0xf4, 0xf7, 0x9d, 0xf8, 0x82, 0x46, + 0x00, 0x98, 0x31, 0x46, 0xf4, 0xf7, 0x98, 0xf8, 0xf4, 0xf7, 0xca, 0xf9, + 0xdf, 0xf8, 0x58, 0x17, 0xf4, 0xf7, 0x84, 0xf9, 0x06, 0x46, 0x50, 0x46, + 0x41, 0x46, 0xf4, 0xf7, 0x0b, 0xf9, 0x80, 0x46, 0x30, 0x46, 0x31, 0x46, + 0xf4, 0xf7, 0x16, 0xfa, 0x06, 0x46, 0x40, 0x46, 0x00, 0xf0, 0xac, 0xf9, + 0x31, 0x46, 0xf4, 0xf7, 0x73, 0xf9, 0xa7, 0xeb, 0x09, 0x0b, 0x06, 0x46, + 0x0b, 0xfb, 0x0b, 0xf0, 0xf4, 0xf7, 0x60, 0xf8, 0x01, 0x46, 0x30, 0x46, + 0xf4, 0xf7, 0x76, 0xf8, 0xdf, 0xf8, 0x1c, 0x17, 0xf4, 0xf7, 0x08, 0xfb, + 0x03, 0xd8, 0x00, 0x20, 0x09, 0xf8, 0x05, 0x00, 0x78, 0x55, 0xb9, 0x46, + 0x00, 0x9e, 0xd0, 0x46, 0x7f, 0x1c, 0x30, 0x2f, 0x8f, 0xdb, 0x00, 0x20, + 0x00, 0x21, 0x4a, 0x5d, 0x01, 0x2a, 0x08, 0xbf, 0x40, 0x1c, 0x49, 0x1c, + 0x30, 0x29, 0xf8, 0xdb, 0xa1, 0x69, 0x89, 0x78, 0x88, 0x42, 0x03, 0xd2, + 0x20, 0x7f, 0x40, 0xf0, 0x02, 0x00, 0x20, 0x77, 0x00, 0x26, 0x00, 0x20, + 0x02, 0x21, 0x4a, 0x5d, 0x00, 0x2a, 0x1e, 0xbf, 0x6a, 0x1a, 0x92, 0xf8, + 0x30, 0x20, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x22, 0x8a, 0x40, 0x10, 0x43, + 0x49, 0x1c, 0x18, 0x29, 0xf1, 0xdb, 0x00, 0x21, 0x4f, 0xf4, 0x80, 0x72, + 0x80, 0x23, 0x4f, 0xf0, 0x17, 0x08, 0x18, 0x42, 0x1c, 0xbf, 0x1e, 0x43, + 0x49, 0x1c, 0x0c, 0x29, 0x07, 0xd0, 0x10, 0x42, 0x03, 0xd0, 0x16, 0x43, + 0x49, 0x1c, 0x0c, 0x29, 0x01, 0xd0, 0x5b, 0x10, 0x52, 0x00, 0xb8, 0xf1, + 0x01, 0x08, 0xee, 0xd1, 0x04, 0x29, 0x07, 0xda, 0x68, 0x78, 0x00, 0x28, + 0x1e, 0xbf, 0x95, 0xf8, 0x2f, 0x00, 0x00, 0x28, 0x46, 0xf0, 0x01, 0x06, + 0x00, 0x27, 0x4f, 0xf0, 0x01, 0x09, 0x19, 0xf8, 0x05, 0x00, 0x00, 0x28, + 0x1e, 0xbf, 0xa5, 0xeb, 0x09, 0x00, 0x90, 0xf8, 0x30, 0x00, 0x00, 0x28, + 0xc9, 0xf1, 0x30, 0x0a, 0x00, 0xf0, 0x93, 0x80, 0x01, 0x98, 0x02, 0x99, + 0x50, 0xf8, 0x29, 0x00, 0x51, 0xf8, 0x29, 0x10, 0xf4, 0xf7, 0x0c, 0xf8, + 0x00, 0x90, 0x02, 0x99, 0x01, 0x98, 0x51, 0xf8, 0x2a, 0x10, 0x50, 0xf8, + 0x2a, 0x00, 0xf4, 0xf7, 0x03, 0xf8, 0x83, 0x46, 0x4f, 0xf4, 0x80, 0x10, + 0x05, 0x90, 0x4f, 0xf0, 0x93, 0x40, 0x00, 0x99, 0xf4, 0xf7, 0x88, 0xf9, + 0xf4, 0xf7, 0xf2, 0xf9, 0x00, 0xf0, 0x14, 0xf9, 0x00, 0xf0, 0x1f, 0xf9, + 0x00, 0xf0, 0x20, 0xf9, 0x00, 0xf0, 0x22, 0xf9, 0x09, 0x90, 0x59, 0x46, + 0x00, 0xf0, 0x03, 0xf9, 0xf4, 0xf7, 0xe4, 0xf9, 0x00, 0xf0, 0x06, 0xf9, + 0x00, 0xf0, 0x11, 0xf9, 0x00, 0xf0, 0x12, 0xf9, 0x00, 0xf0, 0x14, 0xf9, + 0x08, 0x90, 0x01, 0x98, 0x50, 0xf8, 0x29, 0xb0, 0x02, 0x98, 0x50, 0xf8, + 0x29, 0x10, 0x08, 0x46, 0xf4, 0xf7, 0x66, 0xf9, 0x00, 0x90, 0x59, 0x46, + 0x58, 0x46, 0xf4, 0xf7, 0x61, 0xf9, 0x00, 0x99, 0xf4, 0xf7, 0xc2, 0xf8, + 0x00, 0x90, 0x01, 0x98, 0x50, 0xf8, 0x2a, 0xb0, 0x02, 0x98, 0x50, 0xf8, + 0x2a, 0x10, 0x08, 0x46, 0xf4, 0xf7, 0x54, 0xf9, 0x82, 0x46, 0x58, 0x46, + 0x59, 0x46, 0xf4, 0xf7, 0x4f, 0xf9, 0x51, 0x46, 0xf4, 0xf7, 0xb0, 0xf8, + 0x82, 0x46, 0x00, 0x98, 0xf4, 0xf7, 0xee, 0xf8, 0x50, 0x46, 0xf4, 0xf7, + 0xeb, 0xf8, 0x08, 0x98, 0x09, 0x99, 0xf4, 0xf7, 0x31, 0xf8, 0x4f, 0xf0, + 0x7c, 0x51, 0xf4, 0xf7, 0x3d, 0xf9, 0x06, 0x99, 0x41, 0xf8, 0x29, 0x00, + 0x51, 0x46, 0x00, 0x98, 0xf4, 0xf7, 0x36, 0xf9, 0xf4, 0xf7, 0xda, 0xf8, + 0xf4, 0xf7, 0xd8, 0xf8, 0x83, 0x46, 0x00, 0x98, 0xf4, 0xf7, 0xd4, 0xf8, + 0x50, 0x46, 0xf4, 0xf7, 0xd1, 0xf8, 0x07, 0x98, 0x40, 0xf8, 0x29, 0xb0, + 0x08, 0x99, 0x09, 0x98, 0xf4, 0xf7, 0x88, 0xf8, 0x4f, 0xf0, 0x7c, 0x51, + 0xf4, 0xf7, 0x20, 0xf9, 0x0a, 0x99, 0x41, 0xf8, 0x29, 0x00, 0x26, 0xfa, + 0x09, 0xf1, 0xc9, 0x07, 0x09, 0xd5, 0x41, 0x46, 0xf4, 0xf7, 0x7a, 0xf8, + 0x80, 0x46, 0x4f, 0xf0, 0x7e, 0x50, 0x39, 0x46, 0xf4, 0xf7, 0x74, 0xf8, + 0x07, 0x46, 0x09, 0xf1, 0x01, 0x09, 0xb9, 0xf1, 0x18, 0x0f, 0xff, 0xf6, + 0x5a, 0xaf, 0x38, 0x46, 0x00, 0x21, 0xf4, 0xf7, 0xe5, 0xf8, 0x08, 0xbf, + 0x00, 0x26, 0x04, 0xd0, 0x40, 0x46, 0x39, 0x46, 0xf3, 0xf7, 0x70, 0xff, + 0x06, 0x46, 0x60, 0x69, 0x06, 0x60, 0x4f, 0xf0, 0x01, 0x08, 0xc8, 0xf1, + 0x30, 0x0a, 0x18, 0xf8, 0x05, 0x00, 0x1a, 0xf8, 0x05, 0x10, 0x00, 0x28, + 0x02, 0xd0, 0x00, 0x29, 0x4d, 0xd1, 0x01, 0xe0, 0x00, 0x29, 0x4a, 0xd0, + 0x40, 0xb1, 0x02, 0x98, 0x50, 0xf8, 0x28, 0x70, 0x01, 0x98, 0x50, 0xf8, + 0x28, 0x00, 0x80, 0xf0, 0x00, 0x49, 0x07, 0xe0, 0x08, 0x00, 0x05, 0xd0, + 0x02, 0x98, 0x50, 0xf8, 0x2a, 0x70, 0x01, 0x98, 0x50, 0xf8, 0x2a, 0x90, + 0x48, 0x46, 0x39, 0x46, 0xf3, 0xf7, 0x48, 0xff, 0x01, 0x46, 0x06, 0x98, + 0x40, 0xf8, 0x28, 0x10, 0x00, 0xf0, 0x59, 0xf8, 0xf4, 0xf7, 0x3a, 0xf9, + 0x00, 0xf0, 0x5c, 0xf8, 0x00, 0xf0, 0x67, 0xf8, 0x00, 0xf0, 0x68, 0xf8, + 0x00, 0xf0, 0x6a, 0xf8, 0x01, 0x46, 0x06, 0x98, 0x40, 0xf8, 0x28, 0x10, + 0x18, 0xf8, 0x05, 0x00, 0x18, 0xb1, 0x30, 0x46, 0xf4, 0xf7, 0x20, 0xf8, + 0x06, 0xe0, 0x1a, 0xf8, 0x05, 0x00, 0x30, 0xb1, 0x08, 0x46, 0x31, 0x46, + 0xf3, 0xf7, 0xa4, 0xff, 0x06, 0x99, 0x41, 0xf8, 0x28, 0x00, 0x38, 0x46, + 0x00, 0xf0, 0x45, 0xf8, 0x82, 0x46, 0x48, 0x46, 0x49, 0x46, 0xf4, 0xf7, + 0xa9, 0xf8, 0x51, 0x46, 0xf4, 0xf7, 0x0a, 0xf8, 0xf4, 0xf7, 0x4a, 0xf8, + 0x07, 0x99, 0x41, 0xf8, 0x28, 0x00, 0x08, 0xf1, 0x01, 0x08, 0xb8, 0xf1, + 0x18, 0x0f, 0xa2, 0xdb, 0xa0, 0x69, 0x01, 0x90, 0x04, 0xf5, 0x88, 0x73, + 0x04, 0xf5, 0x54, 0x70, 0x00, 0x90, 0x04, 0xf1, 0x50, 0x02, 0x60, 0x69, + 0x04, 0xf1, 0x1d, 0x01, 0x00, 0xf0, 0x36, 0xf8, 0x00, 0x24, 0x07, 0x98, + 0x50, 0xf8, 0x24, 0x20, 0x10, 0x46, 0x00, 0x21, 0xf4, 0xf7, 0x66, 0xf8, + 0x4f, 0xf0, 0x7e, 0x50, 0x1c, 0xbf, 0x11, 0x46, 0xf3, 0xf7, 0xf2, 0xfe, + 0x07, 0x99, 0x41, 0xf8, 0x24, 0x00, 0x64, 0x1c, 0x19, 0x2c, 0xec, 0xdb, + 0x0b, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x4f, 0xf4, 0x80, 0x10, 0x05, 0x90, + 0x4f, 0xf0, 0x93, 0x40, 0xf4, 0xf7, 0x70, 0xb8, 0x04, 0x90, 0x03, 0xab, + 0x00, 0x20, 0x03, 0x90, 0x05, 0xaa, 0x04, 0xa9, 0x8b, 0xe1, 0x39, 0x46, + 0xf4, 0xf7, 0x66, 0xb8, 0x41, 0x46, 0xf4, 0xf7, 0x63, 0xb8, 0x03, 0x98, + 0xf3, 0xf7, 0xb8, 0xbe, 0x4f, 0xf0, 0x56, 0x51, 0xf4, 0xf7, 0x5c, 0xb8, + 0xdf, 0xf8, 0xd0, 0x13, 0xf4, 0xf7, 0x58, 0xb8, 0x2d, 0xe9, 0xf0, 0x4f, + 0x9d, 0xb0, 0x0c, 0x46, 0x00, 0xf1, 0x68, 0x01, 0x00, 0x1d, 0x02, 0x91, + 0x01, 0x90, 0x90, 0x46, 0x9a, 0x46, 0x00, 0x20, 0x00, 0x21, 0x48, 0xf8, + 0x20, 0x10, 0x4a, 0xf8, 0x20, 0x10, 0x40, 0x1c, 0x30, 0x28, 0xf8, 0xdb, + 0x01, 0x20, 0x02, 0x99, 0x51, 0xf8, 0x20, 0x10, 0x81, 0xf0, 0x00, 0x41, + 0x48, 0xf8, 0x20, 0x10, 0x41, 0x42, 0x02, 0x9a, 0x52, 0xf8, 0x20, 0x20, + 0x08, 0xeb, 0x81, 0x03, 0x0a, 0xeb, 0x81, 0x01, 0xc3, 0xf8, 0xc0, 0x20, + 0x01, 0x9a, 0x52, 0xf8, 0x20, 0x20, 0x4a, 0xf8, 0x20, 0x20, 0x01, 0x9a, + 0x52, 0xf8, 0x20, 0x20, 0xc1, 0xf8, 0xc0, 0x20, 0x40, 0x1c, 0x18, 0x28, + 0xe1, 0xdb, 0x4f, 0xf0, 0x18, 0x0b, 0x01, 0x20, 0x01, 0x5d, 0x01, 0x29, + 0x1e, 0xbf, 0x21, 0x1a, 0x91, 0xf8, 0x30, 0x10, 0x01, 0x29, 0x01, 0xd1, + 0x83, 0x46, 0x02, 0xe0, 0x40, 0x1c, 0x18, 0x28, 0xf2, 0xdb, 0x60, 0x78, + 0x00, 0x28, 0x1c, 0xbf, 0x94, 0xf8, 0x2f, 0x10, 0x00, 0x29, 0x21, 0xd1, + 0x01, 0x28, 0x04, 0xbf, 0x94, 0xf8, 0x2f, 0x10, 0x00, 0x29, 0x03, 0xd1, + 0x02, 0x20, 0x84, 0xf8, 0x2f, 0x00, 0x17, 0xe0, 0x00, 0x28, 0x04, 0xbf, + 0x94, 0xf8, 0x2f, 0x00, 0x01, 0x28, 0x02, 0xd1, 0x02, 0x20, 0x60, 0x70, + 0x0e, 0xe0, 0x02, 0x20, 0x60, 0x70, 0x01, 0x98, 0x50, 0xf8, 0x2b, 0x00, + 0xca, 0xf8, 0x04, 0x00, 0x02, 0x20, 0x84, 0xf8, 0x2f, 0x00, 0x01, 0x98, + 0x50, 0xf8, 0x2b, 0x00, 0xca, 0xf8, 0xbc, 0x00, 0x05, 0x20, 0x26, 0x9f, + 0x00, 0xf0, 0x00, 0xf9, 0x00, 0xf0, 0xf9, 0xf8, 0x00, 0x26, 0x07, 0xf1, + 0x84, 0x05, 0x4f, 0xf0, 0x7e, 0x59, 0x03, 0xe0, 0x18, 0x2e, 0x18, 0xd0, + 0x18, 0x2e, 0x01, 0xda, 0x3e, 0x60, 0x02, 0xe0, 0xc6, 0xf1, 0x30, 0x00, + 0x38, 0x60, 0xc5, 0xf8, 0x00, 0x90, 0xc5, 0xf8, 0x04, 0x90, 0x30, 0x5d, + 0x28, 0xb1, 0x5a, 0xf8, 0x26, 0x00, 0xa8, 0x60, 0xc5, 0xf8, 0x0c, 0x90, + 0x03, 0xe0, 0xc5, 0xf8, 0x08, 0x90, 0xac, 0x48, 0xe8, 0x60, 0x00, 0xf0, + 0xe3, 0xf8, 0x76, 0x1c, 0x30, 0x2e, 0xe1, 0xdb, 0xdd, 0xf8, 0x9c, 0xa0, + 0x9a, 0xf9, 0x00, 0x60, 0xba, 0x68, 0x00, 0x2e, 0x3a, 0xd4, 0x96, 0x42, + 0x38, 0xd2, 0x00, 0x20, 0x00, 0x21, 0x0d, 0xf1, 0x0c, 0x0c, 0x10, 0xe0, + 0xb1, 0x42, 0x18, 0xbf, 0xb2, 0x42, 0x07, 0xd0, 0x03, 0xfb, 0x01, 0x23, + 0x07, 0xeb, 0x83, 0x03, 0xdb, 0x68, 0x4c, 0xf8, 0x20, 0x30, 0x40, 0x1c, + 0x52, 0x1c, 0xbb, 0x68, 0x9a, 0x42, 0xef, 0xd3, 0x49, 0x1c, 0xba, 0x68, + 0x91, 0x42, 0x38, 0xbf, 0x00, 0x22, 0xf6, 0xd3, 0x70, 0x1c, 0x04, 0xe0, + 0x07, 0xeb, 0x80, 0x01, 0x40, 0x1c, 0x0a, 0x6f, 0xca, 0x66, 0xb9, 0x68, + 0x88, 0x42, 0xf7, 0xd3, 0x4a, 0x1e, 0x07, 0xf1, 0x70, 0x01, 0x03, 0xa8, + 0xfe, 0xf7, 0xf0, 0xfe, 0xb8, 0x68, 0x03, 0xe0, 0x07, 0xeb, 0x80, 0x01, + 0xca, 0x6e, 0x0a, 0x67, 0x40, 0x1e, 0x86, 0x42, 0xf8, 0xd3, 0x07, 0xeb, + 0x86, 0x01, 0x00, 0x20, 0x08, 0x67, 0x01, 0xe0, 0x00, 0xf0, 0x8b, 0xf8, + 0x02, 0x20, 0x00, 0x90, 0x9a, 0xf8, 0x01, 0x30, 0xba, 0x68, 0x01, 0x98, + 0x07, 0xf1, 0x70, 0x01, 0xfe, 0xf7, 0x90, 0xfe, 0x00, 0x26, 0x0d, 0xe0, + 0x30, 0x5d, 0x02, 0x28, 0x04, 0xbf, 0x00, 0x20, 0x30, 0x55, 0xa0, 0x1b, + 0x90, 0xf8, 0x30, 0x10, 0x02, 0x29, 0x04, 0xbf, 0x00, 0x21, 0x80, 0xf8, + 0x30, 0x10, 0x76, 0x1c, 0x5e, 0x45, 0xef, 0xdb, 0x60, 0x78, 0x00, 0x28, + 0x1c, 0xbf, 0x94, 0xf8, 0x2f, 0x00, 0x00, 0x28, 0x1d, 0xd1, 0xab, 0xf1, + 0x01, 0x06, 0x18, 0xe0, 0x96, 0xfb, 0xfb, 0xf0, 0xf3, 0xf7, 0xac, 0xfd, + 0x02, 0x99, 0x51, 0xf8, 0x2b, 0x10, 0xf3, 0xf7, 0x4f, 0xff, 0x02, 0x21, + 0x31, 0x55, 0x02, 0x22, 0x80, 0xf0, 0x00, 0x41, 0x48, 0xf8, 0x26, 0x10, + 0x71, 0x42, 0x0b, 0x19, 0x08, 0xeb, 0x81, 0x01, 0x83, 0xf8, 0x30, 0x20, + 0xc1, 0xf8, 0xc0, 0x00, 0x76, 0x1e, 0x01, 0x2e, 0xe4, 0xda, 0x05, 0x20, + 0x00, 0xf0, 0x52, 0xf8, 0x00, 0xf0, 0x4b, 0xf8, 0x00, 0x26, 0x03, 0xe0, + 0x18, 0x2e, 0x19, 0xd0, 0x18, 0x2e, 0x03, 0xda, 0x3e, 0x60, 0x5d, 0x48, + 0x28, 0x60, 0x04, 0xe0, 0xc6, 0xf1, 0x30, 0x00, 0x38, 0x60, 0xc5, 0xf8, + 0x00, 0x90, 0xc5, 0xf8, 0x04, 0x90, 0x30, 0x5d, 0x28, 0xb1, 0x58, 0xf8, + 0x26, 0x00, 0xa8, 0x60, 0xc5, 0xf8, 0x0c, 0x90, 0x02, 0xe0, 0xa8, 0x60, + 0x56, 0x48, 0xe8, 0x60, 0x00, 0xf0, 0x38, 0xf8, 0x76, 0x1c, 0x30, 0x2e, + 0xe0, 0xdb, 0xba, 0x68, 0x00, 0xf0, 0x21, 0xf8, 0x00, 0x20, 0x38, 0x67, + 0x07, 0xf1, 0x70, 0x01, 0x03, 0x20, 0x00, 0x90, 0x9a, 0xf8, 0x01, 0x30, + 0xba, 0x68, 0x02, 0x98, 0xfe, 0xf7, 0x24, 0xfe, 0x00, 0x20, 0x0d, 0xe0, + 0x01, 0x5d, 0x02, 0x29, 0x04, 0xbf, 0x00, 0x21, 0x01, 0x55, 0x21, 0x1a, + 0x91, 0xf8, 0x30, 0x20, 0x02, 0x2a, 0x04, 0xbf, 0x00, 0x22, 0x81, 0xf8, + 0x30, 0x20, 0x40, 0x1c, 0x58, 0x45, 0xef, 0xdb, 0x1d, 0xb0, 0xbd, 0xe8, + 0xf0, 0x8f, 0x07, 0xf1, 0x70, 0x01, 0x07, 0xf1, 0x0c, 0x00, 0xfe, 0xf7, + 0x4f, 0xbe, 0x14, 0x21, 0x07, 0xf1, 0x70, 0x00, 0xf4, 0xf7, 0x98, 0xbd, + 0xb8, 0x60, 0x64, 0x21, 0x07, 0xf1, 0x0c, 0x00, 0xf4, 0xf7, 0x92, 0xbd, + 0x01, 0x20, 0x78, 0x60, 0x38, 0x46, 0xfe, 0xf7, 0x2a, 0xbd, 0x2d, 0xe9, + 0xf0, 0x43, 0x01, 0x24, 0x01, 0x26, 0x4f, 0xf0, 0xff, 0x39, 0xa8, 0xb1, + 0x1f, 0x68, 0xb7, 0xf5, 0x80, 0x2f, 0xc8, 0xbf, 0xa7, 0xf5, 0x00, 0x26, + 0x04, 0xdc, 0x17, 0xf5, 0x80, 0x2f, 0x03, 0xda, 0x07, 0xf5, 0x00, 0x26, + 0x1e, 0x60, 0x4e, 0x46, 0x2c, 0x4f, 0x17, 0x60, 0x00, 0x27, 0x0f, 0x60, + 0x1f, 0x68, 0x00, 0x2f, 0x13, 0xd5, 0x11, 0xe0, 0x00, 0x26, 0x1e, 0x60, + 0x17, 0x68, 0x00, 0x2f, 0x09, 0xd5, 0x0e, 0x68, 0x00, 0x2e, 0x54, 0xbf, + 0x01, 0x26, 0x4e, 0x46, 0x7f, 0x42, 0x17, 0x60, 0x0f, 0x68, 0x7f, 0x42, + 0x0f, 0x60, 0x0f, 0x68, 0x00, 0x2f, 0x00, 0xd4, 0x4c, 0x46, 0x00, 0x27, + 0x0f, 0xf2, 0x7c, 0x0c, 0xd2, 0xf8, 0x00, 0xe0, 0x0d, 0x68, 0x4e, 0xfa, + 0x07, 0xf8, 0x3d, 0x41, 0x05, 0xfb, 0x14, 0xee, 0xc2, 0xf8, 0x00, 0xe0, + 0xd1, 0xf8, 0x00, 0xe0, 0x08, 0xfb, 0x04, 0xee, 0xc1, 0xf8, 0x00, 0xe0, + 0x5c, 0xf8, 0x27, 0x50, 0xd3, 0xf8, 0x00, 0xe0, 0x05, 0xfb, 0x14, 0xee, + 0xc3, 0xf8, 0x00, 0xe0, 0x01, 0x24, 0x18, 0xb1, 0xbe, 0xf1, 0x00, 0x0f, + 0x04, 0xd5, 0x02, 0xe0, 0x0d, 0x68, 0x00, 0x2d, 0x00, 0xd4, 0x4c, 0x46, + 0x7f, 0x1c, 0x13, 0x2f, 0xda, 0xdb, 0x10, 0x68, 0x70, 0x43, 0x10, 0x60, + 0x08, 0x68, 0x70, 0x43, 0x08, 0x60, 0x18, 0x68, 0x00, 0xeb, 0xc6, 0x40, + 0x18, 0x60, 0xbd, 0xe8, 0xf0, 0x83, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x80, 0xbf, 0xad, 0xc5, 0x27, 0x38, 0xdb, 0x0f, 0xc9, 0x40, + 0x95, 0xbf, 0xd6, 0x33, 0x4f, 0xb7, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x40, 0x2e, 0x01, 0x00, 0xb4, 0x9f, 0x00, 0x00, 0x11, 0x51, 0x00, 0x00, + 0xb1, 0x28, 0x00, 0x00, 0x5d, 0x14, 0x00, 0x00, 0x2f, 0x0a, 0x00, 0x00, + 0x18, 0x05, 0x00, 0x00, 0x8c, 0x02, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, + 0xa3, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x70, 0x47, 0x38, 0xb5, 0xdf, 0xf8, 0x34, 0x04, 0x40, 0x89, 0xc0, 0xf3, + 0x81, 0x04, 0xc0, 0xf3, 0x01, 0x10, 0x08, 0xb1, 0x44, 0xf0, 0x04, 0x04, + 0x0c, 0xb9, 0x00, 0x20, 0x32, 0xbd, 0xdf, 0xf8, 0x20, 0x04, 0x05, 0x78, + 0x01, 0x21, 0x4f, 0xf4, 0x82, 0x70, 0xf2, 0xf7, 0x26, 0xf9, 0x20, 0x46, + 0xef, 0xf7, 0xca, 0xff, 0x08, 0xb9, 0x04, 0x20, 0x32, 0xbd, 0x20, 0x46, + 0x00, 0xf0, 0xbd, 0xf8, 0x04, 0x46, 0x29, 0x46, 0x4f, 0xf4, 0x82, 0x70, + 0xf2, 0xf7, 0x17, 0xf9, 0x20, 0x46, 0x32, 0xbd, 0x2d, 0xe9, 0xf0, 0x4c, + 0x06, 0x46, 0x15, 0xb2, 0x6f, 0xf0, 0x02, 0x00, 0x85, 0x42, 0x0c, 0x46, + 0x1f, 0x46, 0xb8, 0xbf, 0x05, 0x46, 0x02, 0xdb, 0x04, 0x2d, 0xa8, 0xbf, + 0x03, 0x25, 0xd7, 0xe9, 0x00, 0xab, 0x0f, 0x20, 0x00, 0x21, 0xa2, 0x00, + 0xf4, 0xf7, 0x82, 0xf8, 0x5b, 0x46, 0x2a, 0xea, 0x00, 0x0a, 0x23, 0xea, + 0x01, 0x0b, 0xe8, 0x1c, 0xc1, 0x17, 0xa2, 0x00, 0xf4, 0xf7, 0x78, 0xf8, + 0x4a, 0xea, 0x00, 0x00, 0x4b, 0xea, 0x01, 0x01, 0xc7, 0xe9, 0x00, 0x01, + 0x72, 0xb6, 0xdf, 0xf8, 0xa4, 0x03, 0x4f, 0xf6, 0xfe, 0x61, 0x01, 0x60, + 0x01, 0x60, 0x86, 0xf0, 0x01, 0x03, 0xdf, 0xf8, 0x98, 0x13, 0x0a, 0x78, + 0x1b, 0x01, 0x02, 0xf0, 0x8f, 0x02, 0x03, 0xf0, 0x70, 0x03, 0x1a, 0x43, + 0x0a, 0x70, 0x04, 0xf0, 0x0f, 0x03, 0x4a, 0x78, 0x02, 0xf0, 0xf0, 0x02, + 0x1a, 0x43, 0x4a, 0x70, 0x8d, 0x70, 0x00, 0x21, 0x01, 0x60, 0x62, 0xb6, + 0xbd, 0xe8, 0xf0, 0x8c, 0x2d, 0xe9, 0xf8, 0x4f, 0x90, 0x46, 0x01, 0xf0, + 0x04, 0x05, 0x72, 0xb6, 0xdf, 0xf8, 0x58, 0xa3, 0x4f, 0xf6, 0xfe, 0x69, + 0x80, 0x00, 0xca, 0xf8, 0x00, 0x90, 0x00, 0xf0, 0x1c, 0x00, 0xd4, 0x4f, + 0xd4, 0x4c, 0xca, 0xf8, 0x00, 0x90, 0x01, 0xf0, 0x03, 0x01, 0x01, 0x43, + 0x39, 0x70, 0x40, 0xea, 0x95, 0x00, 0x20, 0x70, 0x00, 0x20, 0xca, 0xf8, + 0x00, 0x00, 0x62, 0xb6, 0xce, 0x49, 0xf3, 0xf7, 0x91, 0xfb, 0x97, 0xf8, + 0x00, 0xb0, 0x26, 0x78, 0xf1, 0xf7, 0xc9, 0xf9, 0x08, 0xb1, 0x01, 0x26, + 0x0d, 0xe0, 0x03, 0x21, 0x1b, 0xea, 0x01, 0x0f, 0x03, 0xd1, 0xf0, 0x07, + 0x01, 0xd4, 0x00, 0x26, 0x05, 0xe0, 0x00, 0x20, 0xf3, 0xf7, 0x96, 0xfb, + 0x00, 0x28, 0xea, 0xd0, 0x02, 0x26, 0x00, 0x20, 0xf3, 0xf7, 0x08, 0xfb, + 0x86, 0xbb, 0x72, 0xb6, 0xca, 0xf8, 0x00, 0x90, 0xca, 0xf8, 0x00, 0x90, + 0x00, 0x20, 0x41, 0x01, 0x39, 0x70, 0x39, 0x79, 0xfa, 0x78, 0xbb, 0x78, + 0x97, 0xf8, 0x01, 0xc0, 0x42, 0xea, 0x01, 0x21, 0x43, 0xea, 0x01, 0x21, + 0x4c, 0xea, 0x01, 0x21, 0x48, 0xf8, 0x20, 0x10, 0x40, 0x1c, 0x08, 0x28, + 0xed, 0xd3, 0x9d, 0xb1, 0x00, 0x21, 0x08, 0x20, 0x4a, 0x01, 0x22, 0x70, + 0x49, 0x1c, 0x22, 0x79, 0xe3, 0x78, 0xa5, 0x78, 0x67, 0x78, 0x43, 0xea, + 0x02, 0x22, 0x45, 0xea, 0x02, 0x22, 0x47, 0xea, 0x02, 0x22, 0x48, 0xf8, + 0x20, 0x20, 0x40, 0x1c, 0x0c, 0x28, 0xed, 0xd3, 0x00, 0x20, 0xca, 0xf8, + 0x00, 0x00, 0x62, 0xb6, 0x30, 0x46, 0xbd, 0xe8, 0xf2, 0x8f, 0x2d, 0xe9, + 0xf0, 0x4f, 0xa9, 0xb0, 0x80, 0x46, 0x0b, 0xa8, 0x0f, 0xf2, 0xc0, 0x21, + 0x10, 0x22, 0xf6, 0xf7, 0xd9, 0xfc, 0x00, 0x20, 0x00, 0xf0, 0xe2, 0xf9, + 0x00, 0x21, 0x00, 0x20, 0xf0, 0xf7, 0xef, 0xf8, 0x00, 0xf0, 0xec, 0xf9, + 0x00, 0x25, 0x07, 0xae, 0xad, 0x55, 0x6d, 0x1c, 0x10, 0x2d, 0xfb, 0xd3, + 0x00, 0xf0, 0x44, 0xfa, 0x5f, 0xea, 0x00, 0x09, 0xfa, 0xd0, 0x00, 0x24, + 0xdf, 0xf8, 0x5c, 0xa2, 0x00, 0xf0, 0x39, 0xf9, 0x0a, 0xd5, 0x00, 0x25, + 0x0a, 0xf1, 0x30, 0x00, 0x00, 0xeb, 0xc4, 0x03, 0x00, 0x22, 0x00, 0xf0, + 0x37, 0xf9, 0x6d, 0x1c, 0x10, 0x2d, 0xf5, 0xd3, 0x0a, 0xeb, 0x84, 0x01, + 0x64, 0x1c, 0x6f, 0xf0, 0x00, 0x40, 0x06, 0x2c, 0x08, 0x66, 0xe9, 0xdb, + 0x00, 0xf0, 0x1f, 0xf9, 0x04, 0x00, 0x55, 0xd1, 0x01, 0x90, 0x0d, 0xf1, + 0x3c, 0x0b, 0x00, 0x20, 0x00, 0x90, 0x01, 0x98, 0x30, 0xb9, 0x00, 0x99, + 0x0f, 0xf2, 0x54, 0x20, 0x00, 0xeb, 0x41, 0x10, 0x03, 0x90, 0x24, 0xe0, + 0x15, 0xa8, 0x03, 0x90, 0x02, 0x20, 0x09, 0xf0, 0x01, 0x01, 0x49, 0x42, + 0x80, 0x4a, 0x11, 0x40, 0x81, 0xea, 0x59, 0x09, 0x00, 0x27, 0x3a, 0x1d, + 0x29, 0xfa, 0x07, 0xf1, 0x29, 0xfa, 0x02, 0xf3, 0x01, 0xf0, 0x0f, 0x01, + 0x03, 0xf0, 0x0f, 0x03, 0x8a, 0x5d, 0x9c, 0x5d, 0x8c, 0x55, 0x08, 0x37, + 0x9a, 0x55, 0x20, 0x2f, 0xef, 0xd3, 0x40, 0x1e, 0xe5, 0xd1, 0x00, 0x25, + 0x15, 0xa9, 0xa8, 0x5d, 0x21, 0xf8, 0x15, 0x00, 0x6d, 0x1c, 0x10, 0x2d, + 0xf9, 0xd3, 0x00, 0x25, 0x03, 0x98, 0x30, 0xf9, 0x15, 0x00, 0x02, 0x90, + 0x04, 0xaa, 0x00, 0x20, 0x6f, 0xf0, 0x00, 0x41, 0x4b, 0xf8, 0x20, 0x10, + 0x00, 0x21, 0x22, 0xf8, 0x10, 0x10, 0x40, 0x1c, 0x06, 0x28, 0xf5, 0xdb, + 0x00, 0x27, 0x00, 0x24, 0x00, 0xf0, 0xd9, 0xf8, 0x05, 0xd5, 0x00, 0xf0, + 0xcd, 0xf8, 0x02, 0x99, 0xfa, 0x1e, 0x00, 0xf0, 0xda, 0xf8, 0x64, 0x1c, + 0x06, 0x2c, 0xf3, 0xdb, 0x00, 0xf0, 0xc9, 0xf8, 0x04, 0x00, 0x06, 0xd0, + 0x00, 0xf0, 0x96, 0xf9, 0x00, 0x20, 0xf0, 0xf7, 0xc7, 0xf8, 0x20, 0x46, + 0xa4, 0xe0, 0x00, 0xeb, 0xd0, 0x71, 0x49, 0x10, 0x28, 0xfa, 0x01, 0xf2, + 0xd1, 0x07, 0x0b, 0xd5, 0x1d, 0xa9, 0x5b, 0xf8, 0x20, 0x20, 0x51, 0xf8, + 0x30, 0x10, 0x91, 0x42, 0x04, 0xda, 0x4b, 0xf8, 0x20, 0x10, 0x04, 0xa9, + 0x21, 0xf8, 0x10, 0x70, 0x40, 0x1c, 0x06, 0x28, 0xe9, 0xdb, 0x7f, 0x1c, + 0x07, 0x2f, 0xce, 0xd3, 0x00, 0xf0, 0xa9, 0xf8, 0x16, 0xd5, 0x04, 0xa8, + 0x0a, 0xeb, 0xc4, 0x07, 0x30, 0xf9, 0x14, 0x00, 0x02, 0x99, 0xc2, 0x1e, + 0x07, 0xf1, 0x30, 0x03, 0x00, 0xf0, 0xa5, 0xf8, 0x0a, 0xeb, 0x84, 0x03, + 0x5b, 0xf8, 0x24, 0x20, 0x18, 0x6e, 0x82, 0x42, 0x04, 0xda, 0xd7, 0xe9, + 0x0c, 0x01, 0xc7, 0xe9, 0x00, 0x01, 0x1a, 0x66, 0x64, 0x1c, 0x06, 0x2c, + 0xe2, 0xdb, 0x6d, 0x1c, 0x10, 0x2d, 0x9d, 0xd3, 0x00, 0x98, 0x40, 0x1c, + 0x04, 0x28, 0x00, 0x90, 0xff, 0xf4, 0x69, 0xaf, 0x01, 0x98, 0x07, 0x28, + 0x41, 0xd2, 0x40, 0x1c, 0x01, 0x90, 0x0b, 0xa8, 0x01, 0x99, 0x00, 0xeb, + 0x41, 0x00, 0x00, 0x25, 0x00, 0x90, 0x00, 0x24, 0x00, 0xf0, 0x77, 0xf8, + 0x2d, 0xd5, 0x0a, 0xeb, 0xc4, 0x02, 0xd2, 0xe9, 0x00, 0x01, 0xaa, 0x00, + 0xfb, 0xf7, 0xfa, 0xfd, 0x00, 0xf0, 0x0f, 0x00, 0xc7, 0x1e, 0x3f, 0xb2, + 0x00, 0x2f, 0x09, 0xd4, 0x01, 0x2f, 0x0c, 0xda, 0x00, 0xf0, 0x68, 0xf9, + 0x00, 0xeb, 0xd0, 0x71, 0x49, 0x10, 0xb0, 0xeb, 0x41, 0x00, 0x04, 0xd0, + 0x00, 0x98, 0x30, 0xf8, 0x02, 0x0c, 0xc2, 0x19, 0x03, 0xe0, 0x00, 0x98, + 0x30, 0xf8, 0x02, 0x0c, 0x3a, 0x1a, 0x12, 0xb2, 0x04, 0x2a, 0xa8, 0xbf, + 0x03, 0x22, 0x04, 0xda, 0x12, 0xf1, 0x03, 0x0f, 0xb8, 0xbf, 0x6f, 0xf0, + 0x02, 0x02, 0x00, 0xf0, 0x41, 0xf8, 0x00, 0xf0, 0x4f, 0xf8, 0x64, 0x1c, + 0x06, 0x2c, 0xcb, 0xdb, 0x6d, 0x1c, 0x10, 0x2d, 0xbf, 0xf4, 0x23, 0xaf, + 0xc5, 0xe7, 0x00, 0x25, 0x00, 0x24, 0x00, 0xf0, 0x3c, 0xf8, 0x0f, 0xd5, + 0x0a, 0xeb, 0xc4, 0x02, 0x00, 0xf0, 0x2e, 0xf8, 0xd2, 0xe9, 0x00, 0x01, + 0x1e, 0x46, 0xaa, 0x00, 0xfb, 0xf7, 0xbc, 0xfd, 0x00, 0xf0, 0x0f, 0x00, + 0xc2, 0x1e, 0x33, 0x46, 0x00, 0xf0, 0x32, 0xf8, 0x64, 0x1c, 0x06, 0x2c, + 0xe9, 0xdb, 0x6d, 0x1c, 0x10, 0x2d, 0xe5, 0xd3, 0x00, 0xf0, 0xf0, 0xf8, + 0x00, 0x20, 0xf0, 0xf7, 0x21, 0xf8, 0x00, 0x20, 0x29, 0xb0, 0xbd, 0xe8, + 0xf0, 0x8f, 0x00, 0x00, 0x78, 0x29, 0x00, 0x20, 0x04, 0x01, 0x00, 0x46, + 0x48, 0x00, 0x00, 0x50, 0xb0, 0x05, 0x00, 0x46, 0xb8, 0x05, 0x00, 0x46, + 0x48, 0x08, 0x00, 0x46, 0x20, 0xa1, 0x07, 0x00, 0xb0, 0xf0, 0x00, 0x20, + 0x01, 0x00, 0x00, 0xd0, 0x0a, 0xeb, 0xc4, 0x00, 0x00, 0xf1, 0x30, 0x03, + 0x70, 0x47, 0x1d, 0xaa, 0x41, 0x46, 0x04, 0x20, 0x34, 0xe6, 0x04, 0xeb, + 0xd4, 0x70, 0x40, 0x10, 0x28, 0xfa, 0x00, 0xf1, 0xc8, 0x07, 0x70, 0x47, + 0x29, 0x46, 0x20, 0x46, 0xe4, 0xe5, 0x00, 0x00, 0x04, 0x00, 0xfc, 0xff, + 0xfe, 0xff, 0x02, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, + 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0e, 0x00, + 0x0d, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x08, 0x00, + 0x07, 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, + 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0c, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0b, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x09, 0x00, + 0x07, 0x00, 0x05, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x0c, 0x00, + 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0b, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0c, 0x00, + 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x07, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x10, 0xb5, 0x04, 0x46, 0x04, 0x48, 0xc0, 0x46, + 0xc0, 0x46, 0x00, 0x21, 0x01, 0x70, 0x03, 0x48, 0xc0, 0x46, 0xc0, 0x46, + 0x04, 0x60, 0x10, 0xbd, 0x90, 0xbc, 0x00, 0x20, 0x94, 0xbc, 0x00, 0x20, + 0x38, 0xb5, 0x2c, 0x48, 0x01, 0x78, 0x80, 0x7d, 0xc0, 0x07, 0x03, 0xd5, + 0x48, 0x07, 0x58, 0xbf, 0x08, 0x22, 0x00, 0xd5, 0x04, 0x22, 0x0c, 0x21, + 0x4f, 0xf4, 0xb6, 0x60, 0xef, 0xf7, 0xa6, 0xfc, 0x40, 0x22, 0x00, 0xf0, + 0x41, 0xf8, 0x40, 0x22, 0x00, 0xf0, 0x39, 0xf8, 0x40, 0x22, 0x00, 0xf0, + 0x31, 0xf8, 0x21, 0x4c, 0x21, 0x4d, 0x20, 0x78, 0x28, 0x70, 0x40, 0x22, + 0x00, 0xf0, 0x25, 0xf8, 0x60, 0x78, 0x68, 0x70, 0x40, 0x22, 0xbd, 0xe8, + 0x38, 0x40, 0x40, 0x21, 0x40, 0xf2, 0xe1, 0x50, 0xef, 0xf7, 0x8c, 0xbc, + 0x80, 0xb5, 0x00, 0x22, 0x00, 0xf0, 0x26, 0xf8, 0x00, 0x22, 0x00, 0xf0, + 0x1e, 0xf8, 0x00, 0x22, 0x00, 0xf0, 0x16, 0xf8, 0x00, 0x22, 0x00, 0xf0, + 0x0e, 0xf8, 0x00, 0x22, 0x40, 0x21, 0x40, 0xf2, 0xe1, 0x50, 0xef, 0xf7, + 0x79, 0xfc, 0xbd, 0xe8, 0x08, 0x40, 0x00, 0x22, 0x0c, 0x21, 0x4f, 0xf4, + 0xb6, 0x60, 0xef, 0xf7, 0x71, 0xbc, 0x40, 0x21, 0x4f, 0xf4, 0xbc, 0x60, + 0xef, 0xf7, 0x6c, 0xbc, 0x40, 0x21, 0x40, 0xf2, 0xdf, 0x50, 0xef, 0xf7, + 0x67, 0xbc, 0x40, 0x21, 0x40, 0xf2, 0xde, 0x50, 0xef, 0xf7, 0x62, 0xbc, + 0x40, 0x21, 0x40, 0xf2, 0xdd, 0x50, 0xef, 0xf7, 0x5d, 0xbc, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x46, 0xe0, 0x05, 0x00, 0x46, 0x9a, 0xf3, 0x00, 0x20, + 0xf8, 0xb5, 0x34, 0x4f, 0x38, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0x04, 0x46, + 0x38, 0x1d, 0xc0, 0x46, 0xc0, 0x46, 0x05, 0x46, 0x07, 0xf1, 0x08, 0x00, + 0xc0, 0x46, 0xc0, 0x46, 0x06, 0x46, 0x07, 0xf1, 0x0c, 0x00, 0xc0, 0x46, + 0xc0, 0x46, 0x23, 0x78, 0x2b, 0x49, 0x2c, 0x4a, 0x00, 0x2b, 0x40, 0xd1, + 0x2b, 0x68, 0x02, 0xfb, 0x03, 0x13, 0x2b, 0x60, 0x08, 0x27, 0x02, 0xfb, + 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, + 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, + 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, 0x03, 0x13, 0x2b, 0x60, 0x02, 0xfb, + 0x03, 0x13, 0x2b, 0x60, 0x03, 0x46, 0xd5, 0xf8, 0x00, 0xc0, 0x02, 0xfb, + 0x0c, 0x1c, 0xc5, 0xf8, 0x00, 0xc0, 0x43, 0xf8, 0x04, 0xcb, 0x7f, 0x1e, + 0xd5, 0xf8, 0x00, 0xc0, 0x02, 0xfb, 0x0c, 0x1c, 0xc5, 0xf8, 0x00, 0xc0, + 0x43, 0xf8, 0x04, 0xcb, 0xd5, 0xf8, 0x00, 0xc0, 0x02, 0xfb, 0x0c, 0x1c, + 0xc5, 0xf8, 0x00, 0xc0, 0x43, 0xf8, 0x04, 0xcb, 0xd5, 0xf8, 0x00, 0xc0, + 0x02, 0xfb, 0x0c, 0x1c, 0xc5, 0xf8, 0x00, 0xc0, 0x43, 0xf8, 0x04, 0xcb, + 0xdd, 0xd1, 0xc3, 0x6f, 0x33, 0x60, 0x01, 0x23, 0x23, 0x70, 0x2b, 0x68, + 0x02, 0xfb, 0x03, 0x11, 0x29, 0x60, 0x31, 0x78, 0x01, 0xf0, 0x1f, 0x01, + 0x50, 0xf8, 0x21, 0x20, 0x32, 0x60, 0x2a, 0x68, 0x40, 0xf8, 0x21, 0x20, + 0x30, 0x68, 0x80, 0x00, 0x80, 0x08, 0xf2, 0xbd, 0x90, 0xbc, 0x00, 0x20, + 0x5f, 0xf3, 0x6e, 0x3c, 0x0d, 0x66, 0x19, 0x00, 0x00, 0xb5, 0x32, 0x38, + 0xa1, 0xfb, 0x00, 0x01, 0xdf, 0xf8, 0x98, 0x24, 0x00, 0x23, 0xf3, 0xf7, + 0x01, 0xfe, 0x80, 0xb2, 0x00, 0xbd, 0x10, 0xb5, 0xdf, 0xf8, 0x8c, 0x44, + 0x61, 0x89, 0x00, 0x20, 0xc1, 0xf3, 0x81, 0x01, 0x11, 0xb1, 0x00, 0xf0, + 0x1b, 0xf8, 0x28, 0xb9, 0x61, 0x89, 0xc1, 0xf3, 0x82, 0x11, 0x11, 0xb1, + 0x00, 0xf0, 0x85, 0xf9, 0x88, 0xb9, 0x61, 0x89, 0xc1, 0xf3, 0x01, 0x11, + 0x69, 0xb1, 0xf1, 0xf7, 0x0a, 0xf9, 0x21, 0x6c, 0xff, 0xf7, 0xda, 0xff, + 0xdf, 0xf8, 0x5c, 0x14, 0x08, 0x80, 0x08, 0x20, 0xf4, 0xf7, 0xae, 0xfa, + 0xbd, 0xe8, 0x10, 0x40, 0xb5, 0xe0, 0x10, 0xbd, 0x00, 0x21, 0x00, 0x20, + 0x2d, 0xe9, 0xf8, 0x4f, 0xef, 0xf7, 0xfb, 0xfd, 0x00, 0x22, 0x03, 0x21, + 0x40, 0xf6, 0x84, 0x50, 0xef, 0xf7, 0xaa, 0xfb, 0x10, 0x21, 0x4f, 0xf4, + 0xc6, 0x60, 0xef, 0xf7, 0x9b, 0xfb, 0x40, 0x21, 0x40, 0xf2, 0x31, 0x60, + 0xef, 0xf7, 0x96, 0xfb, 0x00, 0x21, 0x40, 0xf2, 0x32, 0x60, 0xef, 0xf7, + 0x91, 0xfb, 0x33, 0x21, 0x40, 0xf2, 0x33, 0x60, 0xef, 0xf7, 0x8c, 0xfb, + 0x00, 0xf0, 0x81, 0xf8, 0x00, 0xf0, 0x7a, 0xf8, 0x00, 0xf0, 0x73, 0xf8, + 0x32, 0x21, 0x40, 0xf2, 0x34, 0x60, 0xef, 0xf7, 0x81, 0xfb, 0x40, 0xf2, + 0x35, 0x65, 0x1b, 0x22, 0x1f, 0x21, 0x28, 0x46, 0xef, 0xf7, 0x84, 0xfb, + 0x40, 0xf2, 0x36, 0x66, 0x13, 0x21, 0x00, 0xf0, 0x16, 0xfa, 0x40, 0xf2, + 0x37, 0x6b, 0x0a, 0x21, 0x00, 0xf0, 0x1d, 0xfa, 0x40, 0xf2, 0x3a, 0x68, + 0x00, 0xf0, 0x14, 0xfa, 0x40, 0xf2, 0x3b, 0x69, 0x00, 0xf0, 0x68, 0xf8, + 0x40, 0xf2, 0x39, 0x6a, 0x00, 0xf0, 0x60, 0xf8, 0xdf, 0xf8, 0xbc, 0x03, + 0x00, 0x78, 0x8d, 0xf8, 0x00, 0x00, 0x40, 0xf2, 0x76, 0x67, 0x00, 0x21, + 0x38, 0x46, 0xef, 0xf7, 0x59, 0xfb, 0x02, 0x22, 0x00, 0xf0, 0x5a, 0xf8, + 0xe9, 0x4b, 0x00, 0x22, 0x02, 0x21, 0x4f, 0xf4, 0xd9, 0x70, 0xf6, 0xf7, + 0x13, 0xf8, 0x00, 0x24, 0x18, 0xb1, 0x00, 0x22, 0x00, 0xf0, 0x4e, 0xf8, + 0x01, 0x24, 0x9d, 0xf8, 0x00, 0x10, 0x38, 0x46, 0xef, 0xf7, 0x44, 0xfb, + 0xf1, 0xf7, 0x97, 0xf8, 0xdc, 0x49, 0xc9, 0x6a, 0xff, 0xf7, 0x62, 0xff, + 0x07, 0x46, 0xf9, 0xb2, 0x40, 0xf2, 0x31, 0x60, 0xef, 0xf7, 0x38, 0xfb, + 0x39, 0x0a, 0x40, 0xf2, 0x32, 0x60, 0xef, 0xf7, 0x33, 0xfb, 0x00, 0x21, + 0x40, 0xf2, 0x33, 0x60, 0xef, 0xf7, 0x2e, 0xfb, 0x61, 0x21, 0x00, 0xf0, + 0xcc, 0xf9, 0x0a, 0x21, 0x00, 0xf0, 0xd5, 0xf9, 0x00, 0xf0, 0x22, 0xf8, + 0x00, 0xf0, 0xcc, 0xf9, 0x00, 0xf0, 0x22, 0xf8, 0x00, 0xf0, 0x17, 0xf8, + 0x00, 0xf0, 0x10, 0xf8, 0x00, 0xf0, 0x09, 0xf8, 0x7b, 0x21, 0x00, 0xf0, + 0xbe, 0xf9, 0x00, 0x20, 0xef, 0xf7, 0xc8, 0xfd, 0x20, 0x46, 0xbd, 0xe8, + 0xf2, 0x8f, 0x11, 0x21, 0x40, 0xf2, 0x41, 0x60, 0xef, 0xf7, 0x0e, 0xbb, + 0x00, 0x21, 0x4f, 0xf4, 0xc8, 0x60, 0xef, 0xf7, 0x09, 0xbb, 0x00, 0x21, + 0x40, 0xf2, 0x3f, 0x60, 0xef, 0xf7, 0x04, 0xbb, 0x3f, 0x21, 0x50, 0x46, + 0xef, 0xf7, 0x00, 0xbb, 0x00, 0x21, 0x48, 0x46, 0xef, 0xf7, 0xfc, 0xba, + 0x02, 0x21, 0x4f, 0xf4, 0xd9, 0x70, 0xef, 0xf7, 0x01, 0xbb, 0x2d, 0xe9, + 0xf0, 0x4f, 0x87, 0xb0, 0x00, 0x21, 0x00, 0x20, 0xef, 0xf7, 0x45, 0xfd, + 0x10, 0x22, 0x00, 0xf0, 0xad, 0xf8, 0x00, 0xf0, 0xa0, 0xf9, 0x10, 0x21, + 0x40, 0xf2, 0x4f, 0x60, 0xef, 0xf7, 0xe6, 0xfa, 0x40, 0x21, 0x4f, 0xf4, + 0xca, 0x60, 0xef, 0xf7, 0xe1, 0xfa, 0x00, 0x21, 0x40, 0xf2, 0x51, 0x60, + 0xef, 0xf7, 0xdc, 0xfa, 0x40, 0xf2, 0x52, 0x64, 0x33, 0x21, 0x20, 0x46, + 0xef, 0xf7, 0xd6, 0xfa, 0x32, 0x21, 0x40, 0xf2, 0x53, 0x60, 0xef, 0xf7, + 0xd1, 0xfa, 0x7b, 0x22, 0x7f, 0x21, 0x40, 0xf2, 0x54, 0x60, 0xef, 0xf7, + 0xd5, 0xfa, 0x01, 0x21, 0x40, 0xf2, 0x55, 0x60, 0xef, 0xf7, 0xc6, 0xfa, + 0x40, 0xf2, 0x56, 0x65, 0x00, 0xf0, 0x66, 0xf9, 0x40, 0xf2, 0x57, 0x6a, + 0x3c, 0x21, 0xff, 0xf7, 0xba, 0xff, 0x40, 0xf2, 0x59, 0x6b, 0x00, 0xf0, + 0x65, 0xf9, 0x40, 0xf2, 0x5a, 0x68, 0x00, 0x21, 0x00, 0xf0, 0x5d, 0xf9, + 0x00, 0xf0, 0x6d, 0xf8, 0x98, 0x48, 0x97, 0x4f, 0x00, 0x78, 0x01, 0x90, + 0x40, 0xf2, 0x42, 0x69, 0x04, 0xa8, 0xf1, 0xf7, 0xe4, 0xfc, 0x00, 0x20, + 0xf1, 0xf7, 0x09, 0xfd, 0x93, 0x48, 0x00, 0x78, 0x00, 0x90, 0x02, 0x21, + 0xff, 0xf7, 0xa1, 0xff, 0x3b, 0x46, 0x00, 0x22, 0x02, 0x21, 0x48, 0x46, + 0xf5, 0xf7, 0x5e, 0xff, 0x06, 0x46, 0x00, 0x21, 0x04, 0xa8, 0xf1, 0xf7, + 0xe2, 0xfc, 0x1e, 0xb1, 0xff, 0xf7, 0x92, 0xff, 0x02, 0x26, 0x16, 0xe0, + 0x02, 0xa8, 0xf1, 0xf7, 0x3a, 0xff, 0x01, 0x21, 0x00, 0x20, 0xf1, 0xf7, + 0x37, 0xfe, 0x04, 0x21, 0xff, 0xf7, 0x87, 0xff, 0x3b, 0x46, 0x00, 0x22, + 0x04, 0x21, 0x48, 0x46, 0xf5, 0xf7, 0x44, 0xff, 0x10, 0xb1, 0xff, 0xf7, + 0x7d, 0xff, 0x03, 0x26, 0x02, 0xa8, 0xf1, 0xf7, 0x33, 0xff, 0x00, 0xf0, + 0x02, 0xf9, 0x00, 0x22, 0x00, 0xf0, 0x34, 0xf8, 0xff, 0x21, 0x40, 0xf2, + 0x4f, 0x60, 0xef, 0xf7, 0x6f, 0xfa, 0x74, 0x4f, 0x39, 0x88, 0xc9, 0xb2, + 0x4f, 0xf4, 0xca, 0x60, 0xef, 0xf7, 0x68, 0xfa, 0x38, 0x88, 0x01, 0x0a, + 0x40, 0xf2, 0x51, 0x60, 0xef, 0xf7, 0x62, 0xfa, 0x00, 0x21, 0x20, 0x46, + 0xef, 0xf7, 0x5e, 0xfa, 0x00, 0xf0, 0x00, 0xf9, 0x3c, 0x21, 0xff, 0xf7, + 0x56, 0xff, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0xf0, 0x01, 0xf9, 0x00, 0x21, + 0x00, 0xf0, 0xfb, 0xf8, 0x00, 0x98, 0x40, 0xf0, 0x10, 0x01, 0xc9, 0xb2, + 0xff, 0xf7, 0x4d, 0xff, 0x00, 0x20, 0xef, 0xf7, 0xfb, 0xfc, 0x30, 0x46, + 0x07, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x3f, 0x21, 0x4f, 0xf4, 0xcb, 0x60, + 0xef, 0xf7, 0x40, 0xba, 0x10, 0x21, 0x40, 0xf6, 0x82, 0x50, 0xef, 0xf7, + 0x45, 0xba, 0x00, 0x20, 0x2d, 0xe9, 0xfe, 0x4f, 0x00, 0x21, 0xef, 0xf7, + 0x8a, 0xfc, 0x00, 0xf0, 0xe8, 0xf8, 0x5b, 0x48, 0x00, 0x78, 0x8d, 0xf8, + 0x08, 0x00, 0x03, 0x21, 0x40, 0xf6, 0x1a, 0x00, 0xef, 0xf7, 0x2a, 0xfa, + 0x00, 0xf0, 0xd8, 0xf8, 0x40, 0x21, 0x40, 0xf2, 0x44, 0x60, 0xef, 0xf7, + 0x23, 0xfa, 0x30, 0x21, 0x40, 0xf2, 0x45, 0x60, 0xef, 0xf7, 0x1e, 0xfa, + 0x00, 0xf0, 0xb7, 0xf8, 0x32, 0x21, 0x40, 0xf2, 0x47, 0x60, 0xef, 0xf7, + 0x17, 0xfa, 0x1b, 0x22, 0x1f, 0x21, 0x4f, 0xf4, 0xc9, 0x60, 0xef, 0xf7, + 0x1b, 0xfa, 0x00, 0xf0, 0xa5, 0xf8, 0x00, 0xf0, 0x9e, 0xf8, 0x40, 0xf2, + 0x4b, 0x65, 0x08, 0x21, 0x00, 0xf0, 0xad, 0xf8, 0x40, 0xf2, 0x4d, 0x66, + 0x00, 0xf0, 0xa4, 0xf8, 0x40, 0xf2, 0x4e, 0x69, 0xff, 0xf7, 0x00, 0xff, + 0x40, 0xf2, 0x4c, 0x68, 0x14, 0x21, 0x00, 0xf0, 0xa4, 0xf8, 0x00, 0x22, + 0x00, 0xf0, 0x7e, 0xf8, 0x40, 0xf6, 0x1f, 0x07, 0x00, 0x22, 0xc0, 0x21, + 0x38, 0x46, 0xf1, 0xf7, 0xcd, 0xfb, 0x38, 0x48, 0x00, 0x78, 0x01, 0x90, + 0x04, 0x21, 0x4f, 0xf4, 0x82, 0x70, 0xf1, 0xf7, 0x9e, 0xfb, 0x40, 0xf6, + 0x15, 0x0a, 0x20, 0x22, 0x20, 0x21, 0x50, 0x46, 0xf1, 0xf7, 0xbe, 0xfb, + 0x31, 0x48, 0x00, 0x78, 0x00, 0x90, 0x40, 0xf2, 0x42, 0x6b, 0x01, 0x21, + 0x00, 0xf0, 0x87, 0xf8, 0x2b, 0x4b, 0x00, 0x22, 0x01, 0x21, 0x58, 0x46, + 0xf5, 0xf7, 0x98, 0xfe, 0x00, 0x24, 0x10, 0xb1, 0x00, 0xf0, 0x7c, 0xf8, + 0x04, 0x24, 0x00, 0x22, 0x20, 0x21, 0x50, 0x46, 0xf1, 0xf7, 0xa6, 0xfb, + 0x00, 0xf0, 0x53, 0xf8, 0x80, 0x22, 0x00, 0xf0, 0x4b, 0xf8, 0xc0, 0x22, + 0xc0, 0x21, 0x38, 0x46, 0xf1, 0xf7, 0x9c, 0xfb, 0x9d, 0xf8, 0x08, 0x10, + 0x40, 0xf6, 0x1a, 0x00, 0xef, 0xf7, 0xba, 0xf9, 0x00, 0xf0, 0x68, 0xf8, + 0xf0, 0xf7, 0x03, 0xff, 0x16, 0x49, 0x49, 0x6d, 0xff, 0xf7, 0xd6, 0xfd, + 0x07, 0x46, 0xf9, 0xb2, 0x40, 0xf2, 0x44, 0x60, 0xef, 0xf7, 0xac, 0xf9, + 0x39, 0x0a, 0x40, 0xf2, 0x45, 0x60, 0xef, 0xf7, 0xa7, 0xf9, 0x00, 0xf0, + 0x40, 0xf8, 0x00, 0xf0, 0x39, 0xf8, 0x00, 0xf0, 0x32, 0xf8, 0x08, 0x21, + 0x00, 0xf0, 0x43, 0xf8, 0x14, 0x21, 0x00, 0xf0, 0x44, 0xf8, 0x00, 0xf0, + 0x39, 0xf8, 0xff, 0xf7, 0x97, 0xfe, 0x00, 0x98, 0x40, 0xf0, 0x08, 0x01, + 0xc9, 0xb2, 0x00, 0xf0, 0x3e, 0xf8, 0x00, 0x20, 0xef, 0xf7, 0x40, 0xfc, + 0x20, 0x46, 0xbd, 0xe8, 0xfe, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x09, 0x3d, + 0x78, 0x29, 0x00, 0x20, 0x94, 0xf3, 0x00, 0x20, 0x76, 0x06, 0x00, 0x46, + 0x40, 0x42, 0x0f, 0x00, 0x04, 0x01, 0x00, 0x46, 0x42, 0x06, 0x00, 0x46, + 0x1a, 0x08, 0x00, 0x46, 0x80, 0x21, 0x4f, 0xf4, 0x02, 0x60, 0xf1, 0xf7, + 0x51, 0xbb, 0x01, 0x99, 0xc9, 0xb2, 0x4f, 0xf4, 0x82, 0x70, 0xf1, 0xf7, + 0x24, 0xbb, 0x0a, 0x21, 0x40, 0xf2, 0x4a, 0x60, 0xef, 0xf7, 0x6a, 0xb9, + 0x13, 0x21, 0x40, 0xf2, 0x49, 0x60, 0xef, 0xf7, 0x65, 0xb9, 0x00, 0x21, + 0x40, 0xf2, 0x46, 0x60, 0xef, 0xf7, 0x60, 0xb9, 0x00, 0x21, 0x30, 0x46, + 0xef, 0xf7, 0x5c, 0xb9, 0x0a, 0x21, 0x28, 0x46, 0xef, 0xf7, 0x58, 0xb9, + 0x01, 0x21, 0x40, 0x46, 0xef, 0xf7, 0x54, 0xb9, 0x00, 0x21, 0x58, 0x46, + 0xef, 0xf7, 0x50, 0xb9, 0x10, 0x21, 0x40, 0xf2, 0x43, 0x60, 0xef, 0xf7, + 0x4b, 0xb9, 0x00, 0x22, 0x01, 0x21, 0x40, 0xf6, 0x87, 0x50, 0xef, 0xf7, + 0x4f, 0xb9, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4f, 0x00, 0xf1, 0x58, 0x06, + 0x83, 0xb0, 0x00, 0xf1, 0x08, 0x05, 0x30, 0x78, 0x0c, 0x46, 0x60, 0xb1, + 0xf1, 0x78, 0xb0, 0x78, 0x22, 0x46, 0xf0, 0xf7, 0x44, 0xff, 0x30, 0xb9, + 0x01, 0x20, 0x68, 0x64, 0x28, 0x64, 0xe8, 0x68, 0x40, 0xf0, 0x02, 0x00, + 0xe8, 0x60, 0x00, 0x2c, 0xc4, 0xf1, 0x00, 0x0b, 0x4f, 0xf0, 0x82, 0x40, + 0x4f, 0xf0, 0x01, 0x0a, 0x04, 0xd5, 0x0a, 0xfa, 0x0b, 0xf1, 0x01, 0x60, + 0x00, 0x21, 0x03, 0xe0, 0x00, 0x21, 0x01, 0x60, 0x0a, 0xfa, 0x04, 0xf1, + 0x41, 0x60, 0x68, 0x6c, 0x00, 0x28, 0x71, 0xd1, 0x70, 0x78, 0x00, 0x21, + 0xf0, 0xf7, 0xef, 0xff, 0x00, 0x28, 0x5f, 0xd1, 0x6a, 0x46, 0x01, 0xa9, + 0x20, 0x46, 0xf1, 0xf7, 0x35, 0xf8, 0xd6, 0xe9, 0x02, 0x23, 0x01, 0x98, + 0x12, 0xeb, 0x00, 0x08, 0x43, 0xeb, 0xe0, 0x79, 0xc6, 0xe9, 0x02, 0x89, + 0xd6, 0xe9, 0x04, 0x23, 0x00, 0x98, 0xc1, 0x17, 0x10, 0x18, 0x59, 0x41, + 0xc6, 0xe9, 0x04, 0x01, 0x72, 0x68, 0x52, 0x1c, 0x72, 0x60, 0x2b, 0x68, + 0x5b, 0x88, 0x9a, 0x42, 0xd9, 0xd3, 0x6f, 0x68, 0x00, 0x2c, 0x1d, 0xd4, + 0xa3, 0x46, 0x77, 0xb1, 0x00, 0x23, 0xf3, 0xf7, 0xf9, 0xfa, 0x07, 0xeb, + 0x8b, 0x01, 0x00, 0x23, 0xc1, 0xf8, 0xc0, 0x00, 0x40, 0x46, 0x72, 0x68, + 0x49, 0x46, 0xf3, 0xf7, 0xef, 0xfa, 0x47, 0xf8, 0x2b, 0x00, 0xac, 0x61, + 0xc5, 0xe9, 0x08, 0x89, 0xd6, 0xe9, 0x04, 0x01, 0xc5, 0xe9, 0x0a, 0x01, + 0xe8, 0x6c, 0x0a, 0xfa, 0x0b, 0xf1, 0x88, 0x43, 0xe8, 0x64, 0x1a, 0xe0, + 0x6f, 0xb1, 0x00, 0x23, 0x07, 0xeb, 0x8b, 0x07, 0xf3, 0xf7, 0xda, 0xfa, + 0xc7, 0xf8, 0x20, 0x01, 0x40, 0x46, 0x72, 0x68, 0x49, 0x46, 0x00, 0x23, + 0xf3, 0xf7, 0xd2, 0xfa, 0x38, 0x66, 0xec, 0x61, 0xc5, 0xe9, 0x0c, 0x89, + 0xd6, 0xe9, 0x04, 0x01, 0xc5, 0xe9, 0x0e, 0x01, 0xa8, 0x6c, 0x0a, 0xfa, + 0x0b, 0xf1, 0x88, 0x43, 0xa8, 0x64, 0x00, 0x20, 0x70, 0x60, 0xc6, 0xe9, + 0x04, 0x00, 0xc6, 0xe9, 0x02, 0x00, 0x0b, 0xe0, 0x01, 0x28, 0x08, 0xbf, + 0x68, 0x64, 0x07, 0xd0, 0xe8, 0x68, 0xc5, 0xf8, 0x44, 0xa0, 0x40, 0xf0, + 0x04, 0x00, 0xc5, 0xf8, 0x40, 0xa0, 0xe8, 0x60, 0xbd, 0xe8, 0xf7, 0x8f, + 0x2d, 0xe9, 0xfe, 0x4f, 0x04, 0x46, 0xdf, 0xf8, 0x90, 0x13, 0x20, 0x78, + 0xdf, 0xf8, 0x8c, 0x53, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x90, 0x00, 0x20, + 0x60, 0x61, 0x60, 0x78, 0x01, 0x28, 0x04, 0xd1, 0xd1, 0xe9, 0x08, 0x6b, + 0x2b, 0x6c, 0xaa, 0x69, 0x03, 0xe0, 0xd1, 0xe9, 0x06, 0x6b, 0xeb, 0x6a, + 0x6a, 0x6b, 0xa1, 0x68, 0x0f, 0x88, 0x39, 0x0a, 0x01, 0xf0, 0x03, 0x0a, + 0x01, 0x28, 0x08, 0xbf, 0x4f, 0xf0, 0x00, 0x0a, 0x09, 0xd0, 0x00, 0x21, + 0x8b, 0x45, 0xd5, 0x48, 0x05, 0xd8, 0x86, 0x42, 0x3c, 0xbf, 0xba, 0xf1, + 0x03, 0x0f, 0x4f, 0xf0, 0x03, 0x0a, 0x4f, 0xf6, 0xff, 0x40, 0x38, 0x40, + 0x40, 0xea, 0x0a, 0x20, 0xad, 0xf8, 0x0a, 0x00, 0x28, 0x68, 0xb0, 0xeb, + 0x83, 0x0f, 0x39, 0xd3, 0x60, 0x68, 0x01, 0x89, 0xad, 0xf8, 0x04, 0x10, + 0x4f, 0xf0, 0x01, 0x09, 0x40, 0x89, 0xad, 0xf8, 0x06, 0x00, 0x4f, 0xf0, + 0x00, 0x0c, 0x01, 0xa8, 0x4f, 0xf4, 0x7a, 0x78, 0x30, 0xf8, 0x1c, 0x50, + 0xa8, 0x05, 0x80, 0x0d, 0xb3, 0xfb, 0xf8, 0xf8, 0xc5, 0xf3, 0x81, 0x21, + 0x08, 0xfb, 0x00, 0xf7, 0x21, 0xb9, 0x4f, 0xf4, 0x7a, 0x70, 0xb7, 0xfb, + 0xf0, 0xf0, 0x07, 0xe0, 0x01, 0x29, 0x05, 0xd1, 0xbc, 0x48, 0xa0, 0xfb, + 0x07, 0x01, 0xc0, 0x0f, 0x40, 0xea, 0x41, 0x00, 0xb0, 0xf5, 0x80, 0x6f, + 0x02, 0xd3, 0xc4, 0xf8, 0x14, 0x90, 0x64, 0xe1, 0x05, 0xf4, 0x70, 0x41, + 0x08, 0x43, 0x01, 0xa9, 0x40, 0xf4, 0x00, 0x60, 0x21, 0xf8, 0x1c, 0x00, + 0x0c, 0xf1, 0x01, 0x0c, 0xbc, 0xf1, 0x02, 0x0f, 0xd1, 0xd3, 0x01, 0xe0, + 0x4f, 0xf0, 0x00, 0x09, 0x19, 0x46, 0x10, 0x46, 0xfe, 0xf7, 0x76, 0xf9, + 0x05, 0x28, 0x38, 0xbf, 0x04, 0x20, 0x01, 0x21, 0x40, 0x1c, 0x01, 0xfa, + 0x00, 0xf0, 0x61, 0x68, 0x0a, 0x68, 0x49, 0x68, 0x40, 0x1e, 0x02, 0x40, + 0x08, 0x40, 0xa1, 0x78, 0xa2, 0x61, 0x22, 0x65, 0xe0, 0x61, 0x60, 0x65, + 0x00, 0x29, 0x18, 0xbf, 0x01, 0x29, 0x04, 0xf1, 0x58, 0x00, 0x28, 0xd1, + 0x01, 0x21, 0x01, 0x70, 0xa1, 0x78, 0x01, 0x29, 0x08, 0xbf, 0x04, 0x21, + 0x04, 0xd0, 0x00, 0x99, 0x00, 0x29, 0x0c, 0xbf, 0x01, 0x21, 0x02, 0x21, + 0xc1, 0x70, 0x61, 0x78, 0x09, 0xb9, 0x81, 0x70, 0x1a, 0xe0, 0x01, 0x21, + 0x81, 0x70, 0x02, 0x21, 0x41, 0x70, 0x00, 0x21, 0xa1, 0x64, 0xc0, 0xe9, + 0x02, 0x11, 0xc0, 0xe9, 0x04, 0x11, 0x41, 0x60, 0x30, 0x46, 0x59, 0x46, + 0xf1, 0xf7, 0x52, 0xfc, 0x8d, 0xf8, 0x08, 0x00, 0x04, 0xf1, 0x7a, 0x06, + 0xdf, 0xf8, 0x3c, 0x82, 0x40, 0xf6, 0x41, 0x4b, 0x21, 0xe0, 0x61, 0x78, + 0x00, 0x29, 0xe6, 0xd1, 0x00, 0x99, 0xe5, 0xe7, 0xee, 0xf7, 0xe4, 0xff, + 0xf1, 0x78, 0x40, 0xf2, 0x35, 0x40, 0xee, 0xf7, 0xdf, 0xff, 0x31, 0x79, + 0x40, 0xf2, 0x36, 0x40, 0xee, 0xf7, 0xda, 0xff, 0xb1, 0x78, 0x40, 0xf2, + 0x33, 0x40, 0xee, 0xf7, 0xd5, 0xff, 0x71, 0x78, 0x40, 0xf2, 0x2e, 0x40, + 0xee, 0xf7, 0xd0, 0xff, 0x00, 0xf0, 0x08, 0xf9, 0xee, 0xf7, 0xea, 0xff, + 0x00, 0x20, 0xef, 0xf7, 0x7b, 0xfa, 0xa1, 0x6c, 0x20, 0x6d, 0x00, 0x29, + 0x40, 0xf0, 0xe2, 0x80, 0x00, 0x28, 0x04, 0xbf, 0x60, 0x6d, 0x00, 0x28, + 0x00, 0xf0, 0xe1, 0x80, 0x00, 0x20, 0xe0, 0x64, 0xef, 0xf7, 0x0f, 0xfa, + 0x00, 0xf0, 0xf2, 0xf8, 0xee, 0xf7, 0xe7, 0xff, 0x73, 0x48, 0x00, 0x78, + 0x30, 0x70, 0x04, 0xf1, 0x70, 0x00, 0xf1, 0xf7, 0x5c, 0xfc, 0x60, 0x78, + 0x01, 0x28, 0x0c, 0xbf, 0x02, 0x21, 0x03, 0x21, 0x00, 0x98, 0xc0, 0xb2, + 0xf1, 0xf7, 0x54, 0xfb, 0x00, 0x98, 0x9d, 0xf8, 0x08, 0x10, 0xc0, 0xb2, + 0xf1, 0xf7, 0x1c, 0xfc, 0x50, 0x46, 0xf1, 0xf7, 0x21, 0xfc, 0x00, 0x98, + 0x03, 0x21, 0xc0, 0xb2, 0xf1, 0xf7, 0x2f, 0xfc, 0x00, 0x98, 0x3f, 0x21, + 0xc0, 0xb2, 0xf1, 0xf7, 0x35, 0xfc, 0xf1, 0xf7, 0x98, 0xfb, 0xf1, 0xf7, + 0x7a, 0xfb, 0x60, 0x78, 0x01, 0x28, 0x0b, 0xd1, 0x60, 0x68, 0x00, 0x7d, + 0x20, 0xb1, 0xc0, 0x22, 0xc0, 0x21, 0x58, 0x46, 0xf1, 0xf7, 0x60, 0xf9, + 0xff, 0x20, 0x60, 0x74, 0x04, 0x20, 0x5f, 0xe0, 0x98, 0xf8, 0x00, 0x00, + 0x70, 0x70, 0x98, 0xf8, 0x05, 0x00, 0xb0, 0x70, 0x00, 0xf0, 0xfc, 0x01, + 0x40, 0xf2, 0x33, 0x40, 0xee, 0xf7, 0x74, 0xff, 0x70, 0x78, 0x00, 0xf0, + 0xf0, 0x01, 0x40, 0xf2, 0x2e, 0x40, 0xee, 0xf7, 0x6d, 0xff, 0x98, 0xf8, + 0x07, 0x00, 0xf0, 0x70, 0x98, 0xf8, 0x08, 0x00, 0x30, 0x71, 0x00, 0x20, + 0xf8, 0xf7, 0x10, 0xfc, 0x00, 0x23, 0x99, 0x42, 0x4a, 0x4a, 0x05, 0xd8, + 0x90, 0x42, 0x03, 0xd2, 0x49, 0x48, 0x90, 0xf9, 0x1d, 0x50, 0x02, 0xe0, + 0x47, 0x48, 0x90, 0xf9, 0x24, 0x50, 0x60, 0x68, 0x00, 0x99, 0x00, 0x7d, + 0xc9, 0xb9, 0x20, 0xb1, 0x0c, 0x22, 0x0c, 0x21, 0x58, 0x46, 0xee, 0xf7, + 0x57, 0xff, 0xf0, 0x78, 0x60, 0x74, 0xff, 0x27, 0xf9, 0xb2, 0x00, 0x20, + 0xee, 0xf7, 0xf9, 0xff, 0x85, 0x42, 0x06, 0xdb, 0x67, 0x74, 0xf9, 0xb2, + 0x40, 0xf2, 0x35, 0x40, 0xee, 0xf7, 0x3e, 0xff, 0x01, 0xe0, 0x7f, 0x1e, + 0xf0, 0xd5, 0x00, 0x20, 0x18, 0xe0, 0x20, 0xb1, 0x30, 0x22, 0x30, 0x21, + 0x58, 0x46, 0xee, 0xf7, 0x3d, 0xff, 0x30, 0x79, 0x60, 0x74, 0xff, 0x27, + 0xf9, 0xb2, 0x01, 0x20, 0xee, 0xf7, 0xdf, 0xff, 0x85, 0x42, 0x06, 0xdb, + 0x67, 0x74, 0xf9, 0xb2, 0x40, 0xf2, 0x36, 0x40, 0xee, 0xf7, 0x24, 0xff, + 0x01, 0xe0, 0x7f, 0x1e, 0xf0, 0xd5, 0x01, 0x20, 0xee, 0xf7, 0xca, 0xff, + 0x20, 0x74, 0x60, 0x68, 0xf0, 0xf7, 0x8c, 0xfd, 0xbd, 0xf8, 0x0a, 0x00, + 0xf0, 0xf7, 0x84, 0xfd, 0xb9, 0xf1, 0x00, 0x0f, 0x06, 0xd0, 0xbd, 0xf8, + 0x04, 0x00, 0x24, 0x49, 0x08, 0x80, 0xbd, 0xf8, 0x06, 0x00, 0x48, 0x80, + 0x01, 0x25, 0x07, 0xe0, 0x60, 0x6d, 0xe8, 0x40, 0xc0, 0x07, 0x08, 0xd5, + 0x29, 0x46, 0x20, 0x46, 0xff, 0xf7, 0xbe, 0xfd, 0xe0, 0x6c, 0x00, 0x28, + 0xf4, 0xd0, 0xe0, 0x6c, 0x40, 0xb9, 0x20, 0x6d, 0xe8, 0x40, 0xc0, 0x07, + 0x04, 0xd5, 0x69, 0x42, 0x20, 0x46, 0xff, 0xf7, 0xb1, 0xfd, 0xf4, 0xe7, + 0x6d, 0x1c, 0x18, 0x2d, 0xee, 0xd3, 0xf0, 0xf7, 0xc1, 0xfd, 0x04, 0xf1, + 0x70, 0x00, 0xf1, 0xf7, 0xa5, 0xfb, 0x60, 0x78, 0x31, 0x78, 0x01, 0x28, + 0x58, 0x46, 0x7f, 0xf4, 0xff, 0xae, 0xf1, 0xf7, 0x98, 0xf8, 0x11, 0xe7, + 0x00, 0x28, 0x04, 0xbf, 0x60, 0x6d, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20, + 0x00, 0xe0, 0x00, 0x20, 0xbd, 0xe8, 0xfe, 0x8f, 0x00, 0xf2, 0x00, 0x20, + 0x78, 0x29, 0x00, 0x20, 0x00, 0x9c, 0xe4, 0xa6, 0x98, 0x6e, 0x12, 0x83, + 0x2e, 0x04, 0x00, 0x46, 0x41, 0x0c, 0x00, 0x46, 0x00, 0x28, 0x6b, 0xee, + 0xdc, 0x29, 0x00, 0x20, 0x08, 0x00, 0x00, 0x41, 0x02, 0x22, 0x04, 0xf1, + 0x78, 0x01, 0x0f, 0xf2, 0x1c, 0x00, 0x70, 0x47, 0x00, 0x29, 0x18, 0xbf, + 0x01, 0x29, 0x05, 0xd1, 0x01, 0x00, 0x18, 0xbf, 0x01, 0x21, 0x08, 0x46, + 0xf0, 0xf7, 0x7e, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x82, 0x01, 0x0b, 0x02, + 0x38, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0xf1, 0xf7, 0x7e, 0xfc, 0x20, 0x68, + 0xf1, 0xf7, 0x77, 0xfc, 0x28, 0x46, 0xbd, 0xe8, 0x32, 0x40, 0xf1, 0xf7, + 0x7d, 0xbc, 0x2d, 0xe9, 0xf0, 0x41, 0x0d, 0x46, 0x04, 0x46, 0x00, 0x26, + 0x05, 0xf5, 0x98, 0x77, 0x05, 0xf5, 0x90, 0x78, 0x64, 0x42, 0x28, 0x68, + 0x21, 0xb2, 0x00, 0xf0, 0x7a, 0xfa, 0xf1, 0xf7, 0x0a, 0xfc, 0xf1, 0xf7, + 0x24, 0xfc, 0x08, 0xb1, 0x04, 0x26, 0x17, 0xe0, 0xf9, 0x68, 0xa8, 0x68, + 0xf1, 0xf7, 0xe0, 0xfd, 0xa8, 0x68, 0x41, 0x46, 0x00, 0xf0, 0xa1, 0xfa, + 0x69, 0x68, 0xdf, 0xf8, 0x44, 0x04, 0xf2, 0xf7, 0x41, 0xfd, 0x01, 0x46, + 0x38, 0x68, 0xf2, 0xf7, 0x45, 0xfe, 0xe1, 0xd8, 0x28, 0x68, 0x05, 0xf5, + 0x9a, 0x72, 0x41, 0x46, 0x00, 0xf0, 0x32, 0xfb, 0xa8, 0x68, 0x00, 0xf0, + 0x8b, 0xfa, 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0x2d, 0xe9, 0xf8, 0x4f, + 0x04, 0x46, 0x80, 0x25, 0xb4, 0xf9, 0x18, 0x61, 0x31, 0x00, 0x48, 0xbf, + 0x49, 0x42, 0x80, 0x29, 0x4f, 0xf0, 0x00, 0x0a, 0x4f, 0xf0, 0x04, 0x08, + 0x04, 0xda, 0x00, 0x2e, 0x46, 0xbf, 0x75, 0x42, 0x2d, 0xb2, 0x35, 0x46, + 0x77, 0x1b, 0x3f, 0xb2, 0xd1, 0x46, 0x5f, 0xea, 0xc9, 0x70, 0x52, 0xbf, + 0x07, 0xeb, 0x45, 0x07, 0x3f, 0xb2, 0xa7, 0xeb, 0x45, 0x07, 0x20, 0x68, + 0x3a, 0xb2, 0x00, 0x21, 0xf1, 0xf7, 0x74, 0xfb, 0x21, 0x46, 0x40, 0x46, + 0xff, 0xf7, 0xa5, 0xff, 0x5f, 0xea, 0x00, 0x0b, 0x16, 0xd1, 0x04, 0xf5, + 0x8c, 0x70, 0x00, 0x21, 0xc2, 0x69, 0x10, 0x46, 0xf2, 0xf7, 0xec, 0xfc, + 0x38, 0xbf, 0x82, 0xf0, 0x00, 0x42, 0x50, 0x46, 0x11, 0x46, 0xf2, 0xf7, + 0xe5, 0xfc, 0x38, 0xbf, 0x92, 0x46, 0x09, 0xf1, 0x01, 0x09, 0xb9, 0xf1, + 0x04, 0x0f, 0x4f, 0xf0, 0x00, 0x08, 0xd4, 0xd3, 0x20, 0x68, 0x32, 0x46, + 0x00, 0x21, 0xf1, 0xf7, 0x51, 0xfb, 0xbb, 0xf1, 0x00, 0x0f, 0x14, 0xd1, + 0x28, 0x46, 0xf2, 0xf7, 0x3b, 0xfb, 0x51, 0x46, 0xf2, 0xf7, 0x52, 0xfb, + 0xdf, 0x49, 0xf2, 0xf7, 0xcb, 0xfc, 0x38, 0xbf, 0x08, 0x46, 0x04, 0xd3, + 0xdd, 0x49, 0xf2, 0xf7, 0xdf, 0xfd, 0x98, 0xbf, 0xdc, 0x48, 0x01, 0x46, + 0x20, 0x68, 0x00, 0xf0, 0xc4, 0xfa, 0x58, 0x46, 0xbd, 0xe8, 0xf2, 0x8f, + 0x2d, 0xe9, 0xf0, 0x47, 0x05, 0x46, 0x8a, 0x46, 0x17, 0x46, 0x4f, 0xf0, + 0x00, 0x09, 0x4f, 0xf0, 0x06, 0x08, 0x05, 0xf5, 0x8e, 0x74, 0x38, 0x68, + 0x41, 0x42, 0x39, 0x60, 0x09, 0xb2, 0x28, 0x68, 0x00, 0xf0, 0xe1, 0xf9, + 0xf1, 0xf7, 0x71, 0xfb, 0xf1, 0xf7, 0x8b, 0xfb, 0x10, 0xb1, 0x4f, 0xf0, + 0x04, 0x09, 0x28, 0xe0, 0x21, 0x6a, 0xa8, 0x68, 0xf1, 0xf7, 0x46, 0xfd, + 0x39, 0x68, 0xa8, 0x68, 0x05, 0xf5, 0x90, 0x72, 0x00, 0xf0, 0x14, 0xfb, + 0x21, 0x68, 0x08, 0x1a, 0x20, 0x60, 0x81, 0x11, 0x00, 0xeb, 0x51, 0x60, + 0x46, 0x02, 0x36, 0x14, 0x30, 0x46, 0x48, 0xbf, 0x40, 0x42, 0x7f, 0x28, + 0x04, 0xdb, 0x01, 0x2e, 0xac, 0xbf, 0x7f, 0x26, 0x6f, 0xf0, 0x7e, 0x06, + 0x28, 0x68, 0x32, 0x46, 0x02, 0x21, 0xf1, 0xf7, 0xfb, 0xfa, 0xa8, 0x68, + 0x00, 0xf0, 0xe8, 0xf9, 0xb8, 0xf1, 0x01, 0x08, 0xc9, 0xd1, 0xaa, 0xf8, + 0x00, 0x61, 0x48, 0x46, 0xbd, 0xe8, 0xf0, 0x87, 0x2d, 0xe9, 0xf0, 0x4f, + 0x04, 0x46, 0x8f, 0xb0, 0x20, 0x68, 0x02, 0x90, 0x88, 0x46, 0xf9, 0xf7, + 0x91, 0xfb, 0xb2, 0x4a, 0x06, 0x90, 0xd2, 0xe9, 0x08, 0x01, 0x27, 0x69, + 0xb0, 0x4a, 0x00, 0x23, 0xf2, 0xf7, 0xe6, 0xff, 0x39, 0x8b, 0x00, 0x26, + 0x80, 0xb2, 0x88, 0x42, 0x34, 0xbf, 0xb8, 0x7c, 0xb8, 0x7e, 0x8d, 0xf8, + 0x04, 0x00, 0xaa, 0x49, 0xb7, 0xf9, 0x0e, 0x00, 0x81, 0xfb, 0x00, 0x01, + 0x00, 0xf0, 0xa5, 0xf9, 0x05, 0x90, 0x04, 0xf5, 0x8a, 0x77, 0x02, 0x98, + 0xc0, 0xf1, 0x01, 0x00, 0x38, 0x70, 0xc0, 0xb2, 0x00, 0xf0, 0x86, 0xfc, + 0x78, 0x80, 0x00, 0x21, 0x00, 0x20, 0xee, 0xf7, 0xee, 0xff, 0x3a, 0x78, + 0x79, 0x88, 0x04, 0xf1, 0x14, 0x00, 0x00, 0xf0, 0xfa, 0xfb, 0x38, 0x78, + 0x00, 0xf0, 0x50, 0xfc, 0x20, 0xb1, 0x00, 0x20, 0xef, 0xf7, 0x3e, 0xf8, + 0x05, 0x20, 0x22, 0xe1, 0x02, 0x98, 0x0b, 0xa9, 0xf1, 0xf7, 0x82, 0xfd, + 0x40, 0xf2, 0xee, 0x20, 0xb8, 0x80, 0xfe, 0x80, 0xbe, 0x60, 0x02, 0x98, + 0xf1, 0xf7, 0x70, 0xfa, 0xa0, 0x68, 0x00, 0xf0, 0x91, 0xf9, 0x02, 0x98, + 0x09, 0xa9, 0xf2, 0xf7, 0xc1, 0xfe, 0xdd, 0xe9, 0x09, 0x01, 0xcd, 0xe9, + 0x07, 0x01, 0x8d, 0xf8, 0x1e, 0x60, 0x07, 0xaa, 0x02, 0x98, 0x02, 0x21, + 0xf2, 0xf7, 0xed, 0xfe, 0xe2, 0x68, 0x12, 0x78, 0x02, 0x99, 0x20, 0x69, + 0x52, 0x1e, 0x12, 0x04, 0x02, 0xf4, 0xfe, 0x02, 0x42, 0xea, 0x81, 0x71, + 0x9d, 0xf8, 0x04, 0x20, 0xd2, 0x05, 0x02, 0xf0, 0x7e, 0x52, 0x11, 0x43, + 0x82, 0x7d, 0xd2, 0x03, 0x02, 0xf4, 0x00, 0x42, 0x11, 0x43, 0x02, 0x7d, + 0x02, 0xf0, 0x07, 0x02, 0x11, 0x43, 0x41, 0xf0, 0x00, 0x41, 0x41, 0xf4, + 0x80, 0x41, 0x04, 0x91, 0x85, 0x78, 0x00, 0xe0, 0x6d, 0x1c, 0x20, 0x69, + 0xc1, 0x78, 0xa9, 0x42, 0xc0, 0xf0, 0x83, 0x80, 0x28, 0x18, 0x01, 0x79, + 0x03, 0x91, 0x06, 0x99, 0x03, 0x29, 0x07, 0xd1, 0x03, 0x98, 0x1b, 0x28, + 0x34, 0xbf, 0xc0, 0xf1, 0x64, 0x09, 0x4f, 0xf0, 0x32, 0x09, 0x01, 0xe0, + 0x90, 0xf8, 0x1b, 0x90, 0x03, 0x9a, 0x02, 0x98, 0x5f, 0xfa, 0x89, 0xf1, + 0xf2, 0xf7, 0xe8, 0xfe, 0x9d, 0xf8, 0x04, 0x10, 0x04, 0xa8, 0xff, 0xf7, + 0x79, 0xfe, 0xb8, 0x62, 0xe0, 0x68, 0x40, 0x78, 0xf1, 0xf7, 0x16, 0xfb, + 0x01, 0x2d, 0x03, 0xd1, 0x20, 0x46, 0xff, 0xf7, 0xaf, 0xfe, 0x06, 0x46, + 0x4f, 0xf0, 0x04, 0x0a, 0x86, 0xbb, 0x21, 0x46, 0x04, 0x20, 0xff, 0xf7, + 0x74, 0xfe, 0x06, 0x00, 0x2a, 0xd1, 0x78, 0x6a, 0x5e, 0x49, 0xf2, 0xf7, + 0xd1, 0xfb, 0x78, 0x62, 0x5c, 0x49, 0x38, 0x6a, 0xf2, 0xf7, 0xcc, 0xfb, + 0x83, 0x46, 0xf8, 0x88, 0xc7, 0xf8, 0x20, 0xb0, 0x00, 0x90, 0x78, 0x6a, + 0xf2, 0xf7, 0x30, 0xfc, 0x00, 0x99, 0x40, 0x18, 0xf8, 0x80, 0xb8, 0x88, + 0x00, 0x90, 0x58, 0x46, 0xf2, 0xf7, 0x28, 0xfc, 0x00, 0x99, 0x42, 0x18, + 0xba, 0x80, 0x12, 0xb2, 0x02, 0x98, 0x00, 0x21, 0xf1, 0xf7, 0x1c, 0xfa, + 0xb7, 0xf9, 0x06, 0x20, 0x02, 0x98, 0x01, 0x21, 0xf1, 0xf7, 0x16, 0xfa, + 0xba, 0xf1, 0x01, 0x0a, 0xcf, 0xd1, 0x00, 0xe0, 0x3e, 0xbb, 0x20, 0x69, + 0xb9, 0x88, 0x28, 0x18, 0x04, 0x2d, 0x00, 0x79, 0x28, 0xf8, 0x10, 0x10, + 0x08, 0xeb, 0x40, 0x00, 0xf9, 0x88, 0xa0, 0xf8, 0x80, 0x10, 0x91, 0xd2, + 0x0f, 0xf2, 0x0c, 0x10, 0x28, 0x5c, 0x03, 0x9a, 0x00, 0xeb, 0x09, 0x01, + 0x02, 0x98, 0xd2, 0xb2, 0xc9, 0xb2, 0xf2, 0xf7, 0x8b, 0xfe, 0x9d, 0xf8, + 0x04, 0x00, 0x29, 0x18, 0xc9, 0xb2, 0x04, 0xa8, 0xff, 0xf7, 0x1a, 0xfe, + 0xb8, 0x62, 0x05, 0xaa, 0x41, 0x46, 0x20, 0x46, 0xff, 0xf7, 0xb6, 0xfe, + 0x06, 0x00, 0x3f, 0xf4, 0x77, 0xaf, 0x00, 0xf0, 0x6d, 0xf8, 0x20, 0x69, + 0x80, 0x78, 0x45, 0x1c, 0x10, 0xe0, 0x28, 0x18, 0x90, 0xf8, 0x04, 0x90, + 0x90, 0xf8, 0x05, 0xa0, 0x52, 0x46, 0x49, 0x46, 0x40, 0x46, 0x00, 0xf0, + 0xc2, 0xfa, 0x52, 0x46, 0x49, 0x46, 0x08, 0xf1, 0x80, 0x00, 0x00, 0xf0, + 0xbc, 0xfa, 0x6d, 0x1c, 0x20, 0x69, 0xc1, 0x78, 0x8d, 0x42, 0xea, 0xd3, + 0x81, 0x78, 0x09, 0x18, 0x00, 0x22, 0x49, 0x79, 0x0c, 0xe0, 0x38, 0xf8, + 0x11, 0x30, 0x28, 0xf8, 0x12, 0x30, 0x08, 0xeb, 0x42, 0x05, 0x08, 0xeb, + 0x41, 0x03, 0x52, 0x1c, 0xb3, 0xf8, 0x80, 0x30, 0xa5, 0xf8, 0x80, 0x30, + 0x8a, 0x42, 0xf0, 0xdb, 0xc1, 0x78, 0x08, 0x18, 0x00, 0x79, 0x41, 0x1c, + 0x0c, 0xe0, 0x38, 0xf8, 0x10, 0x20, 0x28, 0xf8, 0x11, 0x20, 0x08, 0xeb, + 0x41, 0x03, 0x08, 0xeb, 0x40, 0x02, 0x49, 0x1c, 0xb2, 0xf8, 0x80, 0x20, + 0xa3, 0xf8, 0x80, 0x20, 0x40, 0x29, 0xf0, 0xdb, 0x02, 0x98, 0x09, 0xa9, + 0xf2, 0xf7, 0xe6, 0xfd, 0x02, 0x98, 0x0b, 0xa9, 0xf1, 0xf7, 0x8a, 0xfc, + 0x3a, 0x78, 0x79, 0x88, 0x04, 0xf1, 0x14, 0x00, 0x00, 0xf0, 0xff, 0xfa, + 0x08, 0xb1, 0x06, 0xb9, 0x05, 0x26, 0x00, 0x20, 0xee, 0xf7, 0x1e, 0xff, + 0x02, 0x98, 0x41, 0x46, 0x00, 0xf0, 0x27, 0xfa, 0x30, 0x46, 0x0f, 0xb0, + 0xbd, 0xe8, 0xf0, 0x8f, 0xb7, 0x43, 0xba, 0x51, 0xcd, 0xcc, 0xcc, 0x3e, + 0x01, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 0x00, 0xf2, 0x00, 0x20, + 0x40, 0x42, 0x0f, 0x00, 0x66, 0x66, 0x26, 0x3f, 0x00, 0x00, 0x0a, 0x1c, + 0x00, 0x21, 0x4f, 0xf4, 0x44, 0x60, 0xee, 0xf7, 0x4f, 0xbc, 0x80, 0xb5, + 0x80, 0x21, 0x4f, 0xf4, 0x44, 0x60, 0xee, 0xf7, 0x49, 0xfc, 0xbd, 0xe8, + 0x02, 0x40, 0x28, 0x20, 0xf2, 0xf7, 0x88, 0xb8, 0x70, 0xb5, 0x0d, 0x46, + 0x04, 0x46, 0x2e, 0x12, 0x00, 0x2c, 0x0c, 0xbf, 0x31, 0x46, 0x00, 0x21, + 0xc9, 0xb2, 0x40, 0xf6, 0xcb, 0x10, 0xee, 0xf7, 0x37, 0xfc, 0x00, 0x2c, + 0x0c, 0xbf, 0x29, 0x46, 0x00, 0x21, 0xc9, 0xb2, 0x40, 0xf6, 0xcc, 0x10, + 0xee, 0xf7, 0x2e, 0xfc, 0x04, 0xb9, 0x00, 0x26, 0xf1, 0xb2, 0x40, 0xf6, + 0xcd, 0x10, 0xee, 0xf7, 0x27, 0xfc, 0x04, 0xb9, 0x00, 0x25, 0xe9, 0xb2, + 0x40, 0xf6, 0xce, 0x10, 0xee, 0xf7, 0x20, 0xfc, 0xbd, 0xe8, 0x70, 0x40, + 0xcd, 0xe7, 0x31, 0xb1, 0xc9, 0x03, 0xc0, 0x22, 0x91, 0xfb, 0xf2, 0xf1, + 0xc1, 0xf5, 0x80, 0x31, 0xd0, 0xe7, 0x70, 0x47, 0x10, 0xb5, 0x04, 0x46, + 0x1b, 0x04, 0x43, 0xea, 0x12, 0x41, 0x10, 0x04, 0x0d, 0x4a, 0x52, 0x69, + 0x00, 0x23, 0xf2, 0xf7, 0x15, 0xfe, 0xc0, 0xf5, 0x80, 0x31, 0x20, 0x46, + 0xbd, 0xe8, 0x10, 0x40, 0xbe, 0xe7, 0x10, 0xb5, 0x4f, 0xf4, 0xc0, 0x74, + 0xa4, 0xfb, 0x00, 0x23, 0x10, 0x46, 0x05, 0x4a, 0x52, 0x69, 0x04, 0xfb, + 0x01, 0x33, 0x19, 0x46, 0x00, 0x23, 0xf2, 0xf7, 0x01, 0xfe, 0x00, 0xb2, + 0x10, 0xbd, 0x00, 0x00, 0x78, 0x29, 0x00, 0x20, 0xef, 0xf3, 0x11, 0x80, + 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x50, 0x21, 0xee, 0xf7, + 0xa9, 0xbb, 0x2d, 0xe9, 0xf0, 0x41, 0x00, 0xf1, 0x34, 0x05, 0x0c, 0x46, + 0xd5, 0xf8, 0x04, 0x80, 0xaf, 0x68, 0x28, 0x68, 0x00, 0xf0, 0x98, 0xf9, + 0x06, 0x46, 0x00, 0xf0, 0x91, 0xf9, 0x01, 0x46, 0x30, 0x46, 0xf2, 0xf7, + 0x83, 0xf9, 0x06, 0x46, 0x31, 0x46, 0xf2, 0xf7, 0x8f, 0xfa, 0xba, 0x49, + 0xf2, 0xf7, 0x94, 0xfb, 0x4c, 0xd8, 0xe8, 0x68, 0x00, 0xf0, 0x86, 0xf9, + 0x80, 0x46, 0x68, 0x69, 0x00, 0xf0, 0x7f, 0xf9, 0x01, 0x46, 0x40, 0x46, + 0xf2, 0xf7, 0x70, 0xf9, 0x00, 0xf0, 0x48, 0xf8, 0x20, 0x60, 0x29, 0x69, + 0x68, 0x68, 0xf2, 0xf7, 0x79, 0xfa, 0x07, 0x46, 0xa9, 0x69, 0xa8, 0x68, + 0xf2, 0xf7, 0x74, 0xfa, 0x00, 0xf0, 0xd8, 0xf8, 0x00, 0xf0, 0x3a, 0xf8, + 0x60, 0x60, 0x69, 0x69, 0x28, 0x68, 0xf2, 0xf7, 0x6b, 0xfa, 0x07, 0x46, + 0xe9, 0x68, 0xa8, 0x68, 0xf2, 0xf7, 0x66, 0xfa, 0x00, 0xf0, 0xca, 0xf8, + 0x00, 0xf0, 0x2c, 0xf8, 0xa0, 0x60, 0xa9, 0x69, 0x28, 0x68, 0xf2, 0xf7, + 0x5d, 0xfa, 0x07, 0x46, 0x29, 0x69, 0xa8, 0x68, 0xf2, 0xf7, 0x58, 0xfa, + 0x00, 0xf0, 0xbc, 0xf8, 0x00, 0xf0, 0x1e, 0xf8, 0xe0, 0x60, 0x66, 0x68, + 0x27, 0x68, 0x29, 0x68, 0x68, 0x68, 0xf2, 0xf7, 0xb1, 0xf9, 0x05, 0x46, + 0x00, 0xf0, 0x44, 0xf9, 0x07, 0x46, 0x30, 0x46, 0x31, 0x46, 0xf2, 0xf7, + 0x45, 0xfa, 0x39, 0x46, 0xf2, 0xf7, 0xa6, 0xf9, 0x00, 0xf0, 0xa3, 0xf8, + 0x20, 0x61, 0x05, 0xe0, 0x20, 0x46, 0xbd, 0xe8, 0xf0, 0x41, 0x14, 0x21, + 0xee, 0xf7, 0x3c, 0xbb, 0xbd, 0xe8, 0xf0, 0x81, 0x31, 0x46, 0xf2, 0xf7, + 0xa5, 0xb8, 0x30, 0xb5, 0x0c, 0x46, 0x15, 0x46, 0x85, 0xb0, 0x29, 0x46, + 0xff, 0xf7, 0x87, 0xff, 0x69, 0x46, 0x20, 0x46, 0xff, 0xf7, 0x83, 0xff, + 0x28, 0x68, 0x00, 0x99, 0xf2, 0xf7, 0x14, 0xf9, 0x28, 0x60, 0x01, 0x99, + 0x68, 0x68, 0xf2, 0xf7, 0x0f, 0xf9, 0x68, 0x60, 0x02, 0x99, 0xa8, 0x68, + 0xf2, 0xf7, 0x0a, 0xf9, 0xa8, 0x60, 0x03, 0x99, 0xe8, 0x68, 0xf2, 0xf7, + 0x05, 0xf9, 0xe8, 0x60, 0x29, 0x69, 0x04, 0x98, 0xf2, 0xf7, 0x74, 0xf9, + 0x28, 0x61, 0x05, 0xb0, 0x30, 0xbd, 0x10, 0xb5, 0x04, 0x46, 0x79, 0x48, + 0xf2, 0xf7, 0x08, 0xfa, 0x78, 0x49, 0x41, 0xf8, 0x24, 0x00, 0x10, 0xbd, + 0x2d, 0xe9, 0xf0, 0x4f, 0x82, 0x46, 0x83, 0xb0, 0x0f, 0x46, 0x14, 0x46, + 0x01, 0x20, 0xf7, 0xf7, 0xe9, 0xff, 0x3d, 0x68, 0x7e, 0x68, 0xd7, 0xf8, + 0x08, 0xb0, 0xff, 0x68, 0x80, 0x46, 0x89, 0x46, 0x28, 0x46, 0x00, 0xf0, + 0x54, 0xf8, 0x00, 0x90, 0x31, 0x46, 0x30, 0x46, 0xf2, 0xf7, 0xec, 0xf9, + 0x00, 0x99, 0xf2, 0xf7, 0x4d, 0xf9, 0x01, 0x90, 0x59, 0x46, 0x58, 0x46, + 0xf2, 0xf7, 0xe4, 0xf9, 0x00, 0x90, 0x39, 0x46, 0x38, 0x46, 0xf2, 0xf7, + 0xdf, 0xf9, 0x00, 0x99, 0xf2, 0xf7, 0x40, 0xf9, 0x01, 0x46, 0x01, 0x98, + 0xf2, 0xf7, 0x4a, 0xf8, 0xf2, 0xf7, 0x7c, 0xf9, 0x60, 0x49, 0xf2, 0xf7, + 0x37, 0xf9, 0x60, 0x49, 0xf2, 0xf7, 0xd0, 0xf9, 0x60, 0x60, 0x59, 0x46, + 0x28, 0x46, 0xf2, 0xf7, 0xcb, 0xf9, 0x00, 0x90, 0x39, 0x46, 0x30, 0x46, + 0xf2, 0xf7, 0xc6, 0xf9, 0x00, 0x99, 0xf2, 0xf7, 0x27, 0xf9, 0x00, 0x90, + 0x39, 0x46, 0x28, 0x46, 0xf2, 0xf7, 0xbe, 0xf9, 0x07, 0x46, 0x30, 0x46, + 0x59, 0x46, 0xf2, 0xf7, 0xb9, 0xf9, 0x00, 0xf0, 0x1d, 0xf8, 0x01, 0x46, + 0x00, 0x98, 0xf2, 0xf7, 0x25, 0xf8, 0x4e, 0x49, 0x51, 0xf8, 0x2a, 0x10, + 0xf2, 0xf7, 0xae, 0xf9, 0x05, 0x46, 0x40, 0x46, 0x49, 0x46, 0xf1, 0xf7, + 0xdd, 0xff, 0x4c, 0x49, 0xf2, 0xf7, 0x18, 0xf8, 0x01, 0x46, 0x28, 0x46, + 0xf2, 0xf7, 0x14, 0xf8, 0x80, 0xf0, 0x00, 0x40, 0x20, 0x60, 0xbd, 0xe8, + 0xf7, 0x8f, 0x29, 0x46, 0xf2, 0xf7, 0x9a, 0xb9, 0x01, 0x46, 0x38, 0x46, + 0xf2, 0xf7, 0x86, 0xb8, 0x2d, 0xe9, 0xf2, 0x4f, 0x82, 0xb0, 0xd7, 0x68, + 0xd2, 0xf8, 0x00, 0x80, 0x95, 0x68, 0x56, 0x68, 0x00, 0xf1, 0x34, 0x04, + 0x40, 0x46, 0x00, 0xf0, 0x84, 0xf8, 0x81, 0x46, 0x30, 0x46, 0xff, 0xf7, + 0xe8, 0xff, 0x01, 0x46, 0x48, 0x46, 0xf2, 0xf7, 0x71, 0xf8, 0x81, 0x46, + 0x20, 0x69, 0x01, 0x90, 0x38, 0x46, 0xd4, 0xf8, 0x0c, 0xa0, 0x51, 0x46, + 0xf2, 0xf7, 0x78, 0xf9, 0x83, 0x46, 0x01, 0x98, 0xff, 0xf7, 0xd7, 0xff, + 0x01, 0x46, 0x58, 0x46, 0xf2, 0xf7, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8, + 0x83, 0x46, 0x01, 0x98, 0x00, 0xf0, 0x68, 0xf8, 0x00, 0x90, 0x51, 0x46, + 0x30, 0x46, 0xf2, 0xf7, 0x65, 0xf9, 0x01, 0x46, 0x00, 0x98, 0xf2, 0xf7, + 0x51, 0xf8, 0x00, 0xf0, 0x53, 0xf8, 0x82, 0x46, 0xa0, 0x69, 0x00, 0x90, + 0x38, 0x46, 0x64, 0x69, 0x00, 0xf0, 0x4f, 0xf8, 0x07, 0x46, 0x00, 0x98, + 0xff, 0xf7, 0xb7, 0xff, 0xff, 0xf7, 0xb8, 0xff, 0x00, 0xf0, 0x44, 0xf8, + 0x05, 0x46, 0x00, 0x98, 0x00, 0xf0, 0x4a, 0xf8, 0x07, 0x46, 0x30, 0x46, + 0x00, 0xf0, 0x3f, 0xf8, 0xff, 0xf7, 0xac, 0xff, 0x00, 0xf0, 0x38, 0xf8, + 0x04, 0x46, 0x28, 0x46, 0x00, 0xf0, 0x37, 0xf8, 0x06, 0x46, 0x58, 0x46, + 0x51, 0x46, 0xf2, 0xf7, 0x3b, 0xf9, 0x31, 0x46, 0xf2, 0xf7, 0x9c, 0xf8, + 0x06, 0x46, 0x28, 0x46, 0x51, 0x46, 0xf2, 0xf7, 0x33, 0xf9, 0x05, 0x46, + 0x58, 0x46, 0x00, 0xf0, 0x26, 0xf8, 0x01, 0x46, 0x28, 0x46, 0xf2, 0xf7, + 0x1b, 0xf8, 0x01, 0x46, 0x30, 0x46, 0xf1, 0xf7, 0x99, 0xff, 0x04, 0x46, + 0x02, 0x98, 0xf1, 0xf7, 0x7b, 0xff, 0x0a, 0x49, 0xf2, 0xf7, 0x20, 0xf9, + 0x00, 0xf0, 0x15, 0xf8, 0xbd, 0xe8, 0xfe, 0x4f, 0xf2, 0xf7, 0x86, 0xb9, + 0x00, 0x24, 0x74, 0x49, 0x00, 0xcc, 0x6e, 0x46, 0x84, 0xb8, 0x00, 0x20, + 0x00, 0x00, 0x80, 0xbf, 0x00, 0xff, 0x7f, 0x47, 0x28, 0x6b, 0x6e, 0x4e, + 0x00, 0x30, 0x81, 0x45, 0x49, 0x46, 0xf1, 0xf7, 0x7b, 0xbf, 0x21, 0x46, + 0xf2, 0xf7, 0x06, 0xb9, 0x38, 0x46, 0x39, 0x46, 0xf2, 0xf7, 0x02, 0xb9, + 0x41, 0x46, 0xf2, 0xf7, 0xff, 0xb8, 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0xff, 0xf7, 0x4c, 0xfe, 0x06, 0x46, 0x20, 0x46, 0xee, 0xf7, 0xa0, 0xfb, + 0x07, 0x46, 0x35, 0xf9, 0x17, 0x20, 0x00, 0x21, 0x20, 0x46, 0xf0, 0xf7, + 0x57, 0xff, 0x05, 0xeb, 0x47, 0x00, 0x01, 0x21, 0xb0, 0xf9, 0x80, 0x20, + 0x20, 0x46, 0xf0, 0xf7, 0x4f, 0xff, 0x00, 0x20, 0x85, 0xf8, 0x02, 0x01, + 0x86, 0xf3, 0x11, 0x88, 0xf1, 0xbd, 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, + 0x17, 0x46, 0x1e, 0x46, 0xff, 0xf7, 0x2c, 0xfe, 0x06, 0x99, 0xfa, 0x07, + 0x44, 0xbf, 0x0a, 0x88, 0x25, 0xf8, 0x16, 0x20, 0xba, 0x07, 0x04, 0xd5, + 0x49, 0x88, 0x05, 0xeb, 0x46, 0x02, 0xa2, 0xf8, 0x80, 0x10, 0x80, 0xf3, + 0x11, 0x88, 0x29, 0x46, 0x20, 0x46, 0xbd, 0xe8, 0xf4, 0x40, 0xc6, 0xe7, + 0xf8, 0xb5, 0x04, 0x46, 0x0d, 0x46, 0x16, 0x46, 0xff, 0xf7, 0x12, 0xfe, + 0x07, 0x46, 0x20, 0x46, 0xee, 0xf7, 0x66, 0xfb, 0xa9, 0x19, 0x91, 0xf8, + 0x02, 0x21, 0x01, 0x2a, 0x18, 0xbf, 0x40, 0xf0, 0x00, 0x40, 0x01, 0x22, + 0x81, 0xf8, 0x02, 0x21, 0x87, 0xf3, 0x11, 0x88, 0xf2, 0xbd, 0xf0, 0xb5, + 0x30, 0xf9, 0x11, 0x30, 0x30, 0xf9, 0x12, 0x40, 0x4d, 0x1c, 0x09, 0xe0, + 0xe6, 0x1a, 0x6f, 0x1a, 0x7e, 0x43, 0x57, 0x1a, 0x96, 0xfb, 0xf7, 0xf6, + 0x9e, 0x19, 0x20, 0xf8, 0x15, 0x60, 0x6d, 0x1c, 0x95, 0x42, 0xf3, 0xdb, + 0xf0, 0xbd, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, 0x05, 0x46, 0x0f, 0x46, + 0x16, 0x46, 0x98, 0x46, 0x00, 0x24, 0xef, 0xf7, 0xa8, 0xfc, 0x08, 0xb1, + 0x02, 0x24, 0x0d, 0xe0, 0x05, 0xf1, 0x8c, 0x40, 0x07, 0xea, 0x06, 0x01, + 0x00, 0x78, 0x38, 0x40, 0x88, 0x42, 0x05, 0xd0, 0x40, 0x46, 0xf1, 0xf7, + 0x75, 0xfe, 0x00, 0x28, 0xed, 0xd0, 0x01, 0x24, 0x20, 0x46, 0xbd, 0xe8, + 0xf0, 0x81, 0x10, 0xb5, 0x4f, 0xf4, 0x7a, 0x71, 0x00, 0x20, 0xf1, 0xf7, + 0x51, 0xfe, 0x00, 0x23, 0x00, 0x22, 0x40, 0x21, 0x40, 0xf6, 0xff, 0x50, + 0xff, 0xf7, 0xd6, 0xff, 0x04, 0x46, 0x00, 0x20, 0xf1, 0xf7, 0xd6, 0xfd, + 0x01, 0x2c, 0x16, 0xbf, 0x03, 0x2c, 0x01, 0x20, 0x00, 0x20, 0x10, 0xbd, + 0x10, 0xb5, 0x01, 0x21, 0x01, 0xfa, 0x00, 0xf0, 0x40, 0xf0, 0x80, 0x04, + 0xe1, 0xb2, 0x40, 0xf6, 0xff, 0x50, 0xee, 0xf7, 0x9d, 0xf9, 0x44, 0xf0, + 0x40, 0x00, 0xc0, 0xb2, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, 0x04, 0x46, + 0x88, 0x46, 0x10, 0x46, 0xff, 0xf7, 0xea, 0xff, 0x00, 0x27, 0x00, 0x26, + 0x12, 0xe0, 0x00, 0x20, 0x24, 0xf8, 0x16, 0x00, 0x00, 0x25, 0x00, 0xf0, + 0x44, 0xf8, 0x47, 0x48, 0x00, 0x78, 0x34, 0xf8, 0x16, 0x10, 0xa8, 0x40, + 0x7f, 0x1c, 0x08, 0x43, 0x08, 0x35, 0x24, 0xf8, 0x16, 0x00, 0x09, 0x2d, + 0xf1, 0xd3, 0x76, 0x1c, 0x46, 0x45, 0xea, 0xd3, 0xbd, 0xe8, 0xf0, 0x41, + 0x00, 0x21, 0x40, 0xf6, 0xff, 0x50, 0xee, 0xf7, 0x73, 0xb9, 0x2d, 0xe9, + 0xf8, 0x4f, 0x80, 0x46, 0x8a, 0x46, 0x10, 0x46, 0xff, 0xf7, 0xc4, 0xff, + 0x00, 0x26, 0x00, 0x27, 0x83, 0x46, 0x00, 0x24, 0x40, 0xf6, 0xff, 0x59, + 0x16, 0xe0, 0x00, 0x25, 0x00, 0xf0, 0x1d, 0xf8, 0x38, 0xf9, 0x14, 0x00, + 0x28, 0x41, 0xc1, 0xb2, 0x4f, 0xf4, 0x60, 0x60, 0xee, 0xf7, 0x5a, 0xf9, + 0x59, 0x46, 0x48, 0x46, 0xee, 0xf7, 0x56, 0xf9, 0xff, 0xf7, 0x95, 0xff, + 0x7f, 0x1c, 0x06, 0x43, 0x08, 0x35, 0x09, 0x2d, 0xea, 0xd3, 0x64, 0x1c, + 0x54, 0x45, 0xe6, 0xd3, 0x00, 0x21, 0x48, 0x46, 0xee, 0xf7, 0x48, 0xf9, + 0x30, 0x46, 0xbd, 0xe8, 0xf2, 0x8f, 0xf9, 0xb2, 0x40, 0xf6, 0x01, 0x60, + 0xee, 0xf7, 0x40, 0xb9, 0x2d, 0xe9, 0xf0, 0x41, 0x04, 0x46, 0xff, 0xf7, + 0x93, 0xff, 0x06, 0x46, 0x20, 0x46, 0x00, 0xf0, 0x1f, 0xf8, 0x44, 0x00, + 0x00, 0x25, 0xa4, 0xb2, 0x00, 0x27, 0x40, 0xf6, 0xff, 0x58, 0x0e, 0xe0, + 0xff, 0xf7, 0xe9, 0xff, 0x00, 0x21, 0x4f, 0xf4, 0x60, 0x60, 0xee, 0xf7, + 0x29, 0xf9, 0x31, 0x46, 0x40, 0x46, 0xee, 0xf7, 0x25, 0xf9, 0xff, 0xf7, + 0x64, 0xff, 0x05, 0x43, 0x7f, 0x1c, 0xa7, 0x42, 0xee, 0xd3, 0x00, 0x21, + 0x40, 0x46, 0xee, 0xf7, 0x1b, 0xf9, 0x28, 0x46, 0xbd, 0xe8, 0xf0, 0x81, + 0x18, 0x21, 0x04, 0x28, 0x0e, 0x4a, 0x12, 0xd8, 0xdf, 0xe8, 0x00, 0xf0, + 0x03, 0x03, 0x09, 0x09, 0x0d, 0x00, 0x0c, 0x48, 0x00, 0x78, 0x40, 0x09, + 0x40, 0x1c, 0x00, 0x01, 0x70, 0x47, 0x10, 0x78, 0xc0, 0xf3, 0x41, 0x10, + 0x06, 0xe0, 0x10, 0x78, 0xc0, 0xf3, 0x41, 0x00, 0x02, 0xe0, 0x10, 0x78, + 0xc0, 0xf3, 0xc1, 0x00, 0x40, 0x1c, 0x48, 0x43, 0x70, 0x47, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x46, 0x10, 0x04, 0x00, 0x46, 0x10, 0x09, 0x00, 0x46, + 0xef, 0xf3, 0x11, 0x80, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, + 0x2d, 0xe9, 0xf0, 0x47, 0xad, 0xf5, 0x08, 0x7d, 0x04, 0x46, 0x4f, 0xf0, + 0x00, 0x08, 0xdf, 0xf8, 0xbc, 0x93, 0x00, 0x21, 0x00, 0x20, 0xee, 0xf7, + 0x36, 0xfb, 0x20, 0x88, 0x01, 0xa9, 0xf1, 0xf7, 0x94, 0xf8, 0xa2, 0x69, + 0x12, 0x78, 0x21, 0x88, 0xa0, 0x68, 0x52, 0x1e, 0x12, 0x04, 0x02, 0xf4, + 0xfe, 0x02, 0x42, 0xea, 0x81, 0x71, 0xa2, 0x78, 0xd2, 0x05, 0x02, 0xf0, + 0x7e, 0x52, 0x11, 0x43, 0x42, 0x78, 0x00, 0x79, 0xd2, 0x03, 0x02, 0xf4, + 0x00, 0x42, 0x11, 0x43, 0x00, 0xf0, 0x07, 0x00, 0x08, 0x43, 0x40, 0xf0, + 0x00, 0x40, 0x40, 0xf4, 0x80, 0x40, 0xf0, 0xf7, 0x8c, 0xfe, 0xa0, 0x69, + 0x40, 0x78, 0xf0, 0xf7, 0xab, 0xfe, 0x00, 0x27, 0x00, 0x25, 0x04, 0xeb, + 0x85, 0x00, 0x06, 0x69, 0x6d, 0xb1, 0x00, 0x2f, 0x02, 0xbf, 0xe0, 0x69, + 0x00, 0x68, 0x00, 0x28, 0x4b, 0xd1, 0x20, 0x88, 0x01, 0x21, 0xc0, 0xb2, + 0xf0, 0xf7, 0x77, 0xfd, 0x02, 0x20, 0xf1, 0xf7, 0xeb, 0xfc, 0x00, 0xf0, + 0x18, 0xf9, 0x0f, 0xfa, 0x80, 0xfa, 0x30, 0x6b, 0x82, 0x45, 0x18, 0xd0, + 0x04, 0xa8, 0x31, 0x46, 0x50, 0x22, 0xf4, 0xf7, 0xd3, 0xfe, 0x30, 0x46, + 0x06, 0xf1, 0x50, 0x01, 0x50, 0x22, 0xf4, 0xf7, 0xcd, 0xfe, 0x06, 0xf1, + 0x50, 0x00, 0x04, 0xa9, 0x50, 0x22, 0xf4, 0xf7, 0xc7, 0xfe, 0x30, 0x6b, + 0x82, 0x45, 0x04, 0xd0, 0x30, 0x46, 0xff, 0xf7, 0x9f, 0xfc, 0xc6, 0xf8, + 0x30, 0xa0, 0xf0, 0xf7, 0xfa, 0xfd, 0xf0, 0xf7, 0x14, 0xfe, 0x02, 0x28, + 0x06, 0xd1, 0xe0, 0x69, 0x81, 0x8a, 0x09, 0x04, 0x41, 0xf0, 0x01, 0x01, + 0x01, 0x60, 0x02, 0xe0, 0x01, 0x28, 0x08, 0xbf, 0x01, 0x27, 0x00, 0xf0, + 0xe8, 0xf8, 0x06, 0x46, 0x17, 0xb9, 0xef, 0xf7, 0x46, 0xfb, 0x00, 0xe0, + 0x01, 0x20, 0x36, 0xb2, 0x40, 0xea, 0xd6, 0x77, 0x18, 0xa8, 0xe0, 0x21, + 0x01, 0xfb, 0x05, 0x00, 0xf0, 0xf7, 0x9a, 0xfe, 0x6d, 0x1c, 0x02, 0x2d, + 0xa9, 0xd3, 0x01, 0xa8, 0xf1, 0xf7, 0x67, 0xf8, 0x00, 0x20, 0xee, 0xf7, + 0x0f, 0xfb, 0xe0, 0x69, 0x00, 0x68, 0x00, 0x28, 0x4a, 0xd1, 0x00, 0x2f, + 0x42, 0xd1, 0xa0, 0x78, 0xf0, 0xf7, 0x2c, 0xfe, 0x02, 0x46, 0xa0, 0x68, + 0x62, 0x64, 0xc1, 0x68, 0x18, 0xa8, 0xf0, 0xf7, 0xaf, 0xff, 0x98, 0xb3, + 0x62, 0x6c, 0x20, 0x69, 0x18, 0xa9, 0xf0, 0xf7, 0x85, 0xfe, 0x62, 0x6c, + 0x60, 0x69, 0x50, 0xa9, 0xf0, 0xf7, 0x80, 0xfe, 0x61, 0x69, 0x20, 0x69, + 0x04, 0xf1, 0x28, 0x02, 0xff, 0xf7, 0xc7, 0xfc, 0xa0, 0x6b, 0x49, 0x46, + 0xf1, 0xf7, 0xf6, 0xfe, 0x05, 0x46, 0x61, 0x68, 0x97, 0x48, 0xf1, 0xf7, + 0xf1, 0xfe, 0x01, 0x46, 0x28, 0x46, 0xf1, 0xf7, 0x5f, 0xfd, 0x80, 0x46, + 0xff, 0xf7, 0x38, 0xff, 0x07, 0x46, 0xe0, 0x69, 0xc1, 0x8a, 0x49, 0x1c, + 0xc1, 0x82, 0x40, 0x46, 0x49, 0x46, 0xf1, 0xf7, 0xe9, 0xff, 0x98, 0xbf, + 0x64, 0x20, 0x02, 0xd9, 0xf1, 0xf7, 0x48, 0xff, 0x80, 0xb2, 0xe1, 0x69, + 0x48, 0x60, 0x87, 0xf3, 0x11, 0x88, 0x03, 0xe0, 0xa0, 0x68, 0x80, 0x68, + 0xed, 0xf7, 0x7a, 0xfd, 0x40, 0x46, 0x49, 0x46, 0xf1, 0xf7, 0xbc, 0xfe, + 0xff, 0xf4, 0x29, 0xaf, 0xe0, 0x69, 0x00, 0x68, 0x00, 0x28, 0x72, 0xd1, + 0x20, 0x88, 0x03, 0x22, 0x04, 0xf1, 0x24, 0x01, 0xf0, 0xf7, 0x07, 0xfe, + 0xb4, 0xf9, 0x24, 0x60, 0xb4, 0xf9, 0x26, 0x90, 0x20, 0x88, 0x04, 0xf1, + 0x3c, 0x02, 0x04, 0xf1, 0x28, 0x01, 0xff, 0xf7, 0xb3, 0xfc, 0x27, 0x6c, + 0x38, 0x46, 0x00, 0x21, 0xf1, 0xf7, 0xa0, 0xfe, 0x38, 0xbf, 0x87, 0xf0, + 0x00, 0x47, 0xe0, 0x6b, 0xf1, 0xf7, 0x9a, 0xfe, 0x38, 0xbf, 0x80, 0xf0, + 0x00, 0x40, 0x39, 0x46, 0xf1, 0xf7, 0x0a, 0xfe, 0xf8, 0xf7, 0xa4, 0xfd, + 0x05, 0x46, 0x21, 0x46, 0x00, 0x20, 0x00, 0xf0, 0x59, 0xf8, 0x21, 0x46, + 0x01, 0x20, 0x00, 0xf0, 0x55, 0xf8, 0xb4, 0xf9, 0x26, 0x00, 0xb0, 0xf5, + 0x00, 0x5f, 0xa8, 0xbf, 0x41, 0xf6, 0xff, 0x70, 0x03, 0xda, 0x10, 0xf5, + 0x00, 0x5f, 0x01, 0xda, 0x66, 0x48, 0xe0, 0x84, 0xb4, 0xf9, 0x24, 0x00, + 0xb0, 0xf5, 0x80, 0x6f, 0xa8, 0xbf, 0x40, 0xf2, 0xff, 0x30, 0x02, 0xda, + 0x00, 0x28, 0x01, 0xd5, 0x00, 0x20, 0xa0, 0x84, 0xff, 0xf7, 0xce, 0xfe, + 0x07, 0x46, 0xb4, 0xf9, 0x26, 0x00, 0x48, 0x45, 0x04, 0xbf, 0xb4, 0xf9, + 0x24, 0x00, 0xb0, 0x42, 0x13, 0xd0, 0x04, 0xf1, 0x24, 0x00, 0x00, 0x90, + 0x03, 0x22, 0x60, 0x69, 0x03, 0x6b, 0xe1, 0x68, 0x20, 0x88, 0xff, 0xf7, + 0x8c, 0xfd, 0x22, 0x88, 0x20, 0x6a, 0x01, 0x21, 0x91, 0x40, 0x08, 0x43, + 0x20, 0x62, 0xe0, 0x69, 0x01, 0x69, 0x49, 0x1c, 0x01, 0x61, 0x64, 0x20, + 0xe1, 0x69, 0x48, 0x60, 0xe0, 0x69, 0x85, 0x60, 0xe0, 0x69, 0xc1, 0x68, + 0x49, 0x1c, 0xc1, 0x60, 0xe0, 0x69, 0xc1, 0x8a, 0x01, 0x83, 0x87, 0xf3, + 0x11, 0x88, 0x20, 0x69, 0xff, 0xf7, 0xaa, 0xfb, 0x60, 0x69, 0xff, 0xf7, + 0xa7, 0xfb, 0x0d, 0xf5, 0x08, 0x7d, 0xbd, 0xe8, 0xf0, 0x87, 0xe2, 0x68, + 0x20, 0x88, 0x00, 0x21, 0xff, 0xf7, 0x80, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, + 0x8e, 0x68, 0x00, 0x28, 0xb0, 0x7c, 0x07, 0xbf, 0xcd, 0x6b, 0x01, 0xf1, + 0x24, 0x04, 0x0d, 0x6c, 0x01, 0xf1, 0x26, 0x04, 0x80, 0xb1, 0x28, 0x46, + 0x00, 0x21, 0xf1, 0xf7, 0x3d, 0xff, 0x38, 0xbf, 0x4f, 0xf0, 0x7c, 0x50, + 0x04, 0xd3, 0xf1, 0xf7, 0x1d, 0xfe, 0x05, 0xd2, 0x4f, 0xf0, 0x3f, 0x40, + 0x29, 0x46, 0xf1, 0xf7, 0x8d, 0xfd, 0x05, 0x46, 0x36, 0x7c, 0x27, 0x88, + 0x30, 0x09, 0xf1, 0xf7, 0x85, 0xfc, 0x80, 0x46, 0x06, 0xf0, 0x0f, 0x00, + 0xf1, 0xf7, 0x76, 0xfc, 0x01, 0x46, 0x40, 0x46, 0xf1, 0xf7, 0x8c, 0xfc, + 0x29, 0x46, 0xf1, 0xf7, 0x17, 0xfe, 0xf1, 0xf7, 0x81, 0xfe, 0xc0, 0x19, + 0x20, 0x80, 0xbd, 0xe8, 0xf0, 0x81, 0xfe, 0xb5, 0x0d, 0x46, 0x06, 0x46, + 0x28, 0x68, 0x00, 0x28, 0x41, 0xd0, 0x00, 0x21, 0x00, 0x20, 0xee, 0xf7, + 0x9e, 0xf9, 0x30, 0x88, 0x69, 0x46, 0xf0, 0xf7, 0xfc, 0xfe, 0x28, 0x68, + 0xc0, 0xf3, 0x07, 0x20, 0xc0, 0xb1, 0x95, 0xf9, 0x01, 0x00, 0x1e, 0x49, + 0x01, 0xfb, 0x00, 0xf4, 0x30, 0x88, 0x02, 0x21, 0xc0, 0xb2, 0xf0, 0xf7, + 0xe5, 0xfa, 0x30, 0x88, 0x1a, 0x49, 0x00, 0x28, 0x14, 0xbf, 0x02, 0x20, + 0x01, 0x20, 0xd1, 0xe9, 0x08, 0x67, 0x32, 0x19, 0x47, 0xeb, 0xe4, 0x73, + 0xf8, 0xf7, 0x79, 0xfc, 0xf8, 0xf7, 0x54, 0xfc, 0x14, 0x48, 0x04, 0x78, + 0x40, 0xf6, 0x41, 0x46, 0x00, 0x22, 0xc0, 0x21, 0x30, 0x46, 0xf0, 0xf7, + 0xfb, 0xf8, 0x01, 0x20, 0x68, 0x60, 0x28, 0x68, 0x18, 0xb1, 0xef, 0xf7, + 0xee, 0xf9, 0x00, 0x28, 0xf9, 0xd0, 0x00, 0x20, 0x68, 0x60, 0x21, 0x46, + 0x30, 0x46, 0xf0, 0xf7, 0xc6, 0xf8, 0x68, 0x46, 0xf0, 0xf7, 0x15, 0xff, + 0x00, 0x20, 0xee, 0xf7, 0xbd, 0xf9, 0x00, 0x20, 0xfe, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0xc8, 0x42, 0xb7, 0x43, 0xba, 0x51, 0x00, 0xe0, 0xff, 0xff, + 0x40, 0x42, 0x0f, 0x00, 0x00, 0xf2, 0x00, 0x20, 0x41, 0x0c, 0x00, 0x46, + 0x2d, 0xe9, 0xf0, 0x47, 0xc0, 0x48, 0x04, 0x78, 0x45, 0x78, 0x86, 0x78, + 0xc7, 0x78, 0x90, 0xf8, 0x08, 0x80, 0x90, 0xf8, 0x09, 0x90, 0xbd, 0x48, + 0x00, 0x6a, 0xf1, 0xf7, 0x0d, 0xfc, 0x01, 0x46, 0xbb, 0x48, 0xf1, 0xf7, + 0x19, 0xfc, 0x82, 0x46, 0x07, 0xf0, 0x0f, 0x00, 0x06, 0xeb, 0x00, 0x20, + 0xf1, 0xf7, 0x02, 0xfc, 0x06, 0x46, 0x09, 0xf0, 0x0f, 0x00, 0x08, 0xeb, + 0x00, 0x20, 0xf1, 0xf7, 0xfb, 0xfb, 0x01, 0x46, 0x30, 0x46, 0xf1, 0xf7, + 0x07, 0xfc, 0x06, 0x46, 0x04, 0xeb, 0x05, 0x20, 0xf1, 0xf7, 0xe8, 0xfb, + 0x4f, 0xf0, 0x76, 0x51, 0xf1, 0xf7, 0x8c, 0xfd, 0x31, 0x46, 0xf1, 0xf7, + 0x89, 0xfd, 0x51, 0x46, 0xf1, 0xf7, 0x86, 0xfd, 0xf1, 0xf7, 0xf0, 0xfd, + 0x80, 0xf3, 0x09, 0x04, 0xa0, 0x05, 0x01, 0x0e, 0x40, 0xf6, 0xad, 0x10, + 0xed, 0xf7, 0xbe, 0xfe, 0x04, 0xf0, 0x03, 0x01, 0xbd, 0xe8, 0xf0, 0x47, + 0x40, 0xf6, 0xae, 0x10, 0xed, 0xf7, 0xb6, 0xbe, 0x10, 0xb5, 0xf1, 0xf7, + 0xe3, 0xfb, 0x4f, 0xf0, 0x81, 0x44, 0x21, 0x46, 0xf1, 0xf7, 0xe3, 0xff, + 0x4f, 0xf0, 0x7e, 0x51, 0xf1, 0xf7, 0xcc, 0xfc, 0x01, 0x21, 0xf8, 0xf7, + 0x6f, 0xfe, 0x9a, 0x49, 0xf1, 0xf7, 0x62, 0xfd, 0x99, 0x49, 0xf1, 0xf7, + 0xc3, 0xfc, 0x99, 0x49, 0xf1, 0xf7, 0xce, 0xfb, 0xf1, 0xf7, 0xc6, 0xfd, + 0xc0, 0xb2, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, 0x0d, 0x46, 0x85, 0xb0, + 0x00, 0x21, 0x00, 0x20, 0xee, 0xf7, 0xe7, 0xf8, 0x92, 0x48, 0x00, 0x78, + 0x00, 0x24, 0xc0, 0x07, 0x00, 0xf1, 0x0c, 0x81, 0x8a, 0x4f, 0x97, 0xf8, + 0x10, 0x80, 0xb8, 0xf1, 0x03, 0x0f, 0xa8, 0xbf, 0x03, 0x24, 0x80, 0xf2, + 0x03, 0x81, 0x0f, 0xf2, 0x68, 0x21, 0x4c, 0xc9, 0x02, 0xa8, 0x40, 0xf2, + 0x01, 0x1a, 0x4c, 0xc0, 0x78, 0x6a, 0xf1, 0xf7, 0x99, 0xfb, 0x87, 0x49, + 0xf1, 0xf7, 0xa6, 0xfb, 0x06, 0x46, 0x86, 0x48, 0x00, 0x6b, 0xf1, 0xf7, + 0x91, 0xfb, 0x81, 0x46, 0x02, 0xa8, 0x84, 0x49, 0x50, 0xf8, 0x28, 0x00, + 0xf1, 0xf7, 0x28, 0xfd, 0x01, 0x46, 0x48, 0x46, 0xf1, 0xf7, 0x96, 0xfb, + 0x80, 0x46, 0xb8, 0x7a, 0x7f, 0x49, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x90, + 0x40, 0xf2, 0xca, 0x2b, 0x40, 0x46, 0xf1, 0xf7, 0x19, 0xfd, 0x31, 0x46, + 0xf1, 0xf7, 0x04, 0xfd, 0x81, 0x46, 0x28, 0xbf, 0xb1, 0x46, 0x48, 0x46, + 0xff, 0xf7, 0x9c, 0xff, 0x8d, 0xf8, 0x04, 0x00, 0x4f, 0xf0, 0x7d, 0x51, + 0x48, 0x46, 0xf1, 0xf7, 0x09, 0xfd, 0x31, 0x46, 0xff, 0xf7, 0x92, 0xff, + 0x07, 0x46, 0x4f, 0xf0, 0x88, 0x41, 0x48, 0x46, 0xf1, 0xf7, 0x00, 0xfd, + 0x41, 0x46, 0xf1, 0xf7, 0x6f, 0xfb, 0xf1, 0xf7, 0x67, 0xfd, 0x80, 0x46, + 0x6c, 0x48, 0x00, 0x78, 0x05, 0xf5, 0x80, 0x79, 0x89, 0xf8, 0x00, 0x00, + 0x6a, 0x48, 0x00, 0x78, 0x89, 0xf8, 0x01, 0x00, 0x69, 0x48, 0x00, 0x78, + 0x89, 0xf8, 0x02, 0x00, 0x00, 0x98, 0x80, 0x01, 0x40, 0xf0, 0x11, 0x01, + 0xc9, 0xb2, 0x50, 0x46, 0xed, 0xf7, 0x26, 0xfe, 0x64, 0x48, 0x00, 0x57, + 0x06, 0x28, 0x0c, 0xbf, 0x01, 0x21, 0x00, 0x21, 0x4f, 0xf4, 0x11, 0x60, + 0xed, 0xf7, 0x1c, 0xfe, 0x6e, 0x21, 0x40, 0xf6, 0xc1, 0x10, 0xed, 0xf7, + 0x17, 0xfe, 0x03, 0x21, 0x40, 0xf6, 0xc2, 0x10, 0xed, 0xf7, 0x12, 0xfe, + 0x03, 0x21, 0x40, 0xf6, 0xac, 0x10, 0xed, 0xf7, 0x0d, 0xfe, 0x12, 0x21, + 0x58, 0x46, 0xed, 0xf7, 0x09, 0xfe, 0x30, 0x46, 0x56, 0x49, 0xf1, 0xf7, + 0xb1, 0xfc, 0x34, 0xbf, 0x02, 0x26, 0x01, 0x26, 0x31, 0x46, 0x4f, 0xf4, + 0x1a, 0x60, 0xed, 0xf7, 0xfd, 0xfd, 0x31, 0x46, 0x40, 0xf6, 0xa1, 0x10, + 0xed, 0xf7, 0xf8, 0xfd, 0x9d, 0xf8, 0x04, 0x10, 0x40, 0xf6, 0xc3, 0x10, + 0xed, 0xf7, 0xf2, 0xfd, 0x39, 0x46, 0x40, 0xf6, 0xc4, 0x10, 0xed, 0xf7, + 0xed, 0xfd, 0x3c, 0x21, 0x40, 0xf6, 0xc5, 0x10, 0xed, 0xf7, 0xe8, 0xfd, + 0x5f, 0xfa, 0x88, 0xf1, 0x40, 0xf6, 0xc6, 0x10, 0xed, 0xf7, 0xe2, 0xfd, + 0x00, 0x21, 0x40, 0xf6, 0xa4, 0x10, 0xed, 0xf7, 0xdd, 0xfd, 0x00, 0x21, + 0x40, 0xf6, 0xa5, 0x10, 0xed, 0xf7, 0xd8, 0xfd, 0x00, 0x21, 0x40, 0xf6, + 0xa8, 0x10, 0xed, 0xf7, 0xd3, 0xfd, 0x00, 0x21, 0x40, 0xf6, 0xa9, 0x10, + 0xed, 0xf7, 0xce, 0xfd, 0x00, 0x26, 0x01, 0x20, 0x00, 0x99, 0xb0, 0x40, + 0x01, 0x42, 0x34, 0xd0, 0x47, 0x1e, 0xf8, 0xb2, 0xff, 0xf7, 0xac, 0xfc, + 0x80, 0x46, 0xfa, 0xb2, 0x1f, 0xfa, 0x88, 0xf1, 0x28, 0x46, 0xff, 0xf7, + 0x24, 0xfc, 0xf8, 0xb2, 0xff, 0xf7, 0x7a, 0xfc, 0x18, 0xbb, 0xfa, 0xb2, + 0x10, 0x21, 0x2f, 0x48, 0xff, 0xf7, 0x41, 0xfc, 0xe8, 0xb9, 0x00, 0x2e, + 0x0c, 0xbf, 0x2d, 0x21, 0x2c, 0x21, 0x4f, 0xf4, 0x1c, 0x60, 0xed, 0xf7, + 0xab, 0xfd, 0x01, 0x22, 0x00, 0xf0, 0x54, 0xf8, 0x28, 0x4b, 0x00, 0x22, + 0x01, 0x21, 0x4f, 0xf4, 0xd9, 0x70, 0xf4, 0xf7, 0x65, 0xfa, 0x18, 0xb1, + 0x00, 0x22, 0x00, 0xf0, 0x49, 0xf8, 0x02, 0x24, 0xfa, 0xb2, 0x1f, 0xfa, + 0x88, 0xf1, 0x28, 0x46, 0xff, 0xf7, 0x23, 0xfc, 0x08, 0xb1, 0x04, 0x24, + 0x02, 0xe0, 0x76, 0x1c, 0x02, 0x2e, 0xc2, 0xd3, 0x99, 0xf8, 0x00, 0x10, + 0x50, 0x46, 0xed, 0xf7, 0x8b, 0xfd, 0x99, 0xf8, 0x01, 0x10, 0x4f, 0xf4, + 0x11, 0x60, 0xed, 0xf7, 0x85, 0xfd, 0x99, 0xf8, 0x02, 0x10, 0x58, 0x46, + 0xed, 0xf7, 0x80, 0xfd, 0x00, 0x20, 0xee, 0xf7, 0x2f, 0xf8, 0x20, 0x46, + 0x05, 0xb0, 0xbd, 0xe8, 0xf0, 0x8f, 0x00, 0x00, 0xd3, 0x05, 0x00, 0x46, + 0x78, 0x29, 0x00, 0x20, 0xc6, 0xe3, 0x33, 0x4c, 0x00, 0x00, 0x20, 0x41, + 0x00, 0x00, 0x40, 0x40, 0xcd, 0xcc, 0x4c, 0x3d, 0xe8, 0xf2, 0x00, 0x20, + 0x00, 0x00, 0x7a, 0x44, 0x00, 0xf2, 0x00, 0x20, 0x00, 0x00, 0xfa, 0x44, + 0x4e, 0x62, 0xd0, 0x3e, 0x01, 0x01, 0x00, 0x46, 0x10, 0x09, 0x00, 0x46, + 0xca, 0x02, 0x00, 0x46, 0xb8, 0x2a, 0x00, 0x20, 0x00, 0x40, 0x9c, 0x47, + 0xba, 0x2a, 0x00, 0x20, 0x20, 0xa1, 0x07, 0x00, 0x01, 0x21, 0x4f, 0xf4, + 0xd9, 0x70, 0xed, 0xf7, 0x59, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x80, 0x40, 0x70, 0x47, 0xf0, 0xb5, + 0x0d, 0x46, 0x83, 0xb0, 0x00, 0x21, 0x00, 0x20, 0xed, 0xf7, 0x95, 0xff, + 0x69, 0x46, 0x28, 0x46, 0x00, 0xf0, 0x54, 0xf8, 0x04, 0x00, 0x4c, 0xd1, + 0x00, 0x26, 0x69, 0x4f, 0x07, 0xeb, 0x46, 0x12, 0xf1, 0xb2, 0x28, 0x46, + 0x00, 0xf0, 0xe8, 0xf8, 0x76, 0x1c, 0x04, 0x2e, 0xf6, 0xdb, 0x07, 0xf1, + 0x80, 0x05, 0x40, 0xf2, 0xdd, 0x50, 0x29, 0x78, 0xed, 0xf7, 0x28, 0xfd, + 0x69, 0x78, 0x40, 0xf2, 0xde, 0x50, 0xed, 0xf7, 0x23, 0xfd, 0xa9, 0x78, + 0x40, 0xf2, 0xdf, 0x50, 0xed, 0xf7, 0x1e, 0xfd, 0xe9, 0x78, 0x4f, 0xf4, + 0xbc, 0x60, 0xed, 0xf7, 0x19, 0xfd, 0x29, 0x79, 0x40, 0xf2, 0xe1, 0x50, + 0xed, 0xf7, 0x14, 0xfd, 0x57, 0x48, 0x58, 0x4a, 0x01, 0x78, 0x40, 0x78, + 0x93, 0x78, 0xd5, 0x78, 0x43, 0xea, 0x05, 0x23, 0x15, 0x78, 0x52, 0x78, + 0x41, 0xea, 0x00, 0x20, 0x45, 0xea, 0x02, 0x21, 0xc0, 0x1a, 0xc9, 0x1a, + 0x00, 0x01, 0x49, 0x1c, 0x90, 0xfb, 0xf1, 0xf1, 0x89, 0xb2, 0x10, 0x29, + 0xa8, 0xbf, 0x0f, 0x21, 0xc9, 0xb2, 0x4f, 0xf4, 0x09, 0x70, 0xed, 0xf7, + 0xf7, 0xfc, 0x4b, 0x48, 0x80, 0x7a, 0x03, 0x21, 0x08, 0x42, 0x04, 0xd0, + 0xff, 0xf7, 0xf4, 0xfd, 0x68, 0x46, 0xf0, 0xf7, 0xe2, 0xf8, 0x00, 0x20, + 0xed, 0xf7, 0x9c, 0xff, 0x20, 0x46, 0xfe, 0xbd, 0x2d, 0xe9, 0xf0, 0x41, + 0x04, 0x46, 0x0d, 0x46, 0x00, 0x22, 0x03, 0x21, 0x40, 0xf2, 0xd1, 0x50, + 0xed, 0xf7, 0xe8, 0xfc, 0x4f, 0xf4, 0x7a, 0x70, 0xf1, 0xf7, 0x1e, 0xf9, + 0xc0, 0x22, 0xc0, 0x21, 0x4f, 0xf4, 0xd9, 0x70, 0xed, 0xf7, 0xde, 0xfc, + 0x41, 0xf2, 0x88, 0x33, 0x00, 0x22, 0xc0, 0x21, 0x4f, 0xf4, 0xd9, 0x70, + 0xf4, 0xf7, 0x90, 0xf9, 0x08, 0xb1, 0x01, 0x20, 0x60, 0xe0, 0x35, 0x4e, + 0x70, 0x79, 0xb1, 0x79, 0xf2, 0x79, 0x33, 0x7a, 0x37, 0x78, 0x01, 0xf0, + 0x07, 0x01, 0x40, 0xea, 0x01, 0x20, 0x03, 0xf0, 0x07, 0x01, 0x42, 0xea, + 0x01, 0x21, 0x08, 0x18, 0x80, 0xb2, 0x07, 0xf0, 0x3f, 0x01, 0xc1, 0xeb, + 0x50, 0x07, 0x2c, 0x48, 0x2c, 0x49, 0x00, 0x78, 0x09, 0x6b, 0x40, 0x07, + 0x4c, 0xbf, 0x2b, 0x48, 0x2b, 0x48, 0xb1, 0xfb, 0xf0, 0xf0, 0x00, 0x04, + 0xc0, 0x0a, 0xf1, 0xf7, 0xbd, 0xf9, 0x80, 0x46, 0xb8, 0xb2, 0xf1, 0xf7, + 0xc3, 0xf9, 0x01, 0x46, 0x40, 0x46, 0xf1, 0xf7, 0xcf, 0xf9, 0x07, 0x46, + 0x2f, 0x60, 0xf1, 0xf7, 0xc5, 0xfb, 0x80, 0x46, 0xa4, 0xf8, 0x00, 0x80, + 0x4f, 0xf0, 0x76, 0x50, 0x39, 0x46, 0xf1, 0xf7, 0x51, 0xfb, 0x28, 0x60, + 0x5f, 0xfa, 0x88, 0xf1, 0x40, 0xf2, 0xd3, 0x50, 0xed, 0xf7, 0x8c, 0xfc, + 0x20, 0x88, 0x01, 0x0a, 0x40, 0xf2, 0xd4, 0x50, 0xed, 0xf7, 0x86, 0xfc, + 0x70, 0x7a, 0xb1, 0x7a, 0xf7, 0x78, 0x36, 0x79, 0x40, 0xea, 0x01, 0x20, + 0x00, 0x03, 0xf1, 0xf7, 0x93, 0xf9, 0x80, 0x46, 0x47, 0xea, 0x06, 0x20, + 0xf1, 0xf7, 0x98, 0xf9, 0x01, 0x46, 0x40, 0x46, 0xf1, 0xf7, 0xa4, 0xf9, + 0x06, 0x46, 0x6e, 0x60, 0xf1, 0xf7, 0x9a, 0xfb, 0x60, 0x80, 0x31, 0x46, + 0x4f, 0xf0, 0x66, 0x50, 0xf1, 0xf7, 0x28, 0xfb, 0x68, 0x60, 0x00, 0x20, + 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x02, 0x00, 0x20, 0xdb, 0x05, 0x00, 0x46, + 0x20, 0x02, 0x00, 0x46, 0x78, 0x29, 0x00, 0x20, 0xd2, 0x05, 0x00, 0x46, + 0x02, 0x01, 0x00, 0x46, 0x00, 0xf2, 0x00, 0x20, 0x40, 0x4b, 0x4c, 0x00, + 0x00, 0x09, 0x3d, 0x00, 0x01, 0x22, 0x40, 0x1c, 0x02, 0xfa, 0x00, 0xf0, + 0x40, 0x1e, 0x80, 0xb2, 0x88, 0x42, 0x88, 0xbf, 0x08, 0x46, 0x70, 0x47, + 0x2d, 0xe9, 0xf0, 0x4f, 0x91, 0x46, 0x0f, 0xf2, 0xe0, 0x02, 0x83, 0xb0, + 0x04, 0x46, 0xb2, 0xe8, 0x08, 0x04, 0x68, 0x46, 0x00, 0x25, 0xa0, 0xe8, + 0x08, 0x04, 0x01, 0xf0, 0x07, 0x00, 0x40, 0xf0, 0x20, 0x01, 0x40, 0xf2, + 0xdd, 0x50, 0xed, 0xf7, 0x35, 0xfc, 0x00, 0x21, 0x40, 0xf2, 0xe2, 0x50, + 0xed, 0xf7, 0x30, 0xfc, 0x00, 0x27, 0x40, 0xf2, 0xe4, 0x5a, 0x40, 0xf2, + 0xe3, 0x5b, 0x0f, 0xf2, 0xc8, 0x08, 0x20, 0x88, 0x39, 0xf8, 0x17, 0x10, + 0x48, 0x43, 0x3d, 0xf8, 0x17, 0x10, 0xc1, 0xeb, 0x10, 0x11, 0x15, 0xf8, + 0x08, 0x00, 0x89, 0xb2, 0xff, 0xf7, 0xc8, 0xff, 0x00, 0xf0, 0x3e, 0xf8, + 0x00, 0xf0, 0x38, 0xf8, 0x6d, 0x1c, 0x7f, 0x1c, 0x04, 0x2f, 0xea, 0xdb, + 0x00, 0x27, 0x09, 0xeb, 0x47, 0x01, 0x60, 0x88, 0x09, 0x89, 0x48, 0x43, + 0x01, 0x01, 0x15, 0xf8, 0x08, 0x00, 0x09, 0x0c, 0xff, 0xf7, 0xb4, 0xff, + 0x00, 0xf0, 0x2a, 0xf8, 0x00, 0xf0, 0x24, 0xf8, 0x6d, 0x1c, 0x7f, 0x1c, + 0x07, 0x2f, 0xec, 0xdb, 0x00, 0x24, 0x09, 0xeb, 0x44, 0x00, 0x64, 0x1c, + 0xc1, 0x8a, 0x15, 0xf8, 0x08, 0x00, 0xff, 0xf7, 0xa3, 0xff, 0x00, 0xf0, + 0x19, 0xf8, 0x00, 0xf0, 0x13, 0xf8, 0x6d, 0x1c, 0x05, 0x2c, 0xf0, 0xdb, + 0x0f, 0xf2, 0x38, 0x05, 0x00, 0x24, 0x00, 0x21, 0x58, 0x46, 0xed, 0xf7, + 0xe9, 0xfb, 0x61, 0x5d, 0x50, 0x46, 0xed, 0xf7, 0xe5, 0xfb, 0x64, 0x1c, + 0x15, 0x2c, 0xf4, 0xdb, 0xbd, 0xe8, 0xf7, 0x8f, 0xf1, 0xb2, 0x50, 0x46, + 0xed, 0xf7, 0xdc, 0xbb, 0x06, 0x46, 0x30, 0x04, 0x01, 0x0e, 0x58, 0x46, + 0xed, 0xf7, 0xd6, 0xbb, 0x30, 0x01, 0xa0, 0x00, 0x70, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x08, 0x06, 0x05, 0x0a, 0x0a, 0x0b, 0x09, 0x0a, 0x09, 0x0a, 0x05, + 0x05, 0x05, 0x05, 0x07, 0xb3, 0x49, 0x4f, 0xf4, 0x82, 0x72, 0x02, 0xfb, + 0x00, 0x11, 0x01, 0xf5, 0x21, 0x71, 0xff, 0xf7, 0x74, 0xb9, 0x38, 0xb5, + 0xae, 0x4c, 0x00, 0x20, 0x20, 0x70, 0x00, 0x21, 0x01, 0x20, 0xed, 0xf7, + 0xec, 0xfc, 0x00, 0x20, 0xf0, 0xf7, 0x9c, 0xf8, 0x00, 0x20, 0x01, 0x25, + 0x60, 0x70, 0x01, 0x21, 0x04, 0xe0, 0x00, 0x20, 0x28, 0x55, 0x29, 0x00, + 0x18, 0xbf, 0x01, 0x21, 0xc9, 0xb2, 0x01, 0x20, 0xed, 0xf7, 0xdb, 0xfc, + 0x28, 0x46, 0xf0, 0xf7, 0x8b, 0xf8, 0x6d, 0x1c, 0x02, 0x2d, 0xf0, 0xd3, + 0x31, 0xbd, 0x2d, 0xe9, 0xf0, 0x47, 0x9f, 0x4e, 0xdf, 0xf8, 0x7c, 0x82, + 0x70, 0x69, 0xdf, 0xf8, 0x70, 0x92, 0x0c, 0x46, 0xb1, 0x69, 0x00, 0x25, + 0x81, 0x42, 0x38, 0xbf, 0x08, 0x46, 0xf1, 0xf7, 0xa5, 0xf8, 0x4f, 0xf0, + 0x7c, 0x51, 0xf1, 0xf7, 0x3f, 0xfa, 0x98, 0x49, 0xf1, 0xf7, 0xae, 0xf8, + 0xf1, 0xf7, 0xa6, 0xfa, 0x96, 0x49, 0xb1, 0xf9, 0x0e, 0x20, 0x00, 0xb2, + 0x90, 0x42, 0xc8, 0xbf, 0x10, 0x46, 0xc8, 0x81, 0x00, 0x27, 0xb0, 0x7a, + 0x21, 0x61, 0x00, 0xf0, 0x03, 0x06, 0x08, 0x8a, 0x00, 0xf0, 0x03, 0xf9, + 0x60, 0x60, 0x26, 0xfa, 0x07, 0xf0, 0xc0, 0x07, 0x3e, 0xd5, 0x01, 0x20, + 0xb8, 0x40, 0xed, 0xf7, 0xcd, 0xfb, 0x08, 0xb9, 0x02, 0x25, 0x3a, 0xe0, + 0x39, 0x46, 0x01, 0x20, 0xf1, 0xf7, 0x73, 0xfe, 0x08, 0xb9, 0x03, 0x25, + 0x33, 0xe0, 0x27, 0x60, 0x39, 0x46, 0x00, 0xf0, 0xe7, 0xf8, 0xe0, 0x60, + 0x4f, 0xf4, 0xa0, 0x70, 0x00, 0xfb, 0x07, 0x9a, 0x0a, 0xf1, 0x04, 0x00, + 0xa0, 0x60, 0xed, 0xf7, 0x8d, 0xfc, 0x4f, 0xf0, 0x7e, 0x51, 0x38, 0x46, + 0xfe, 0xf7, 0xf7, 0xff, 0x4f, 0xf4, 0x82, 0x70, 0x00, 0xfb, 0x07, 0x90, + 0x00, 0xf5, 0x21, 0x71, 0x20, 0x46, 0xfe, 0xf7, 0x73, 0xfd, 0x05, 0x46, + 0x0a, 0xf1, 0x04, 0x00, 0xfe, 0xf7, 0x4e, 0xff, 0x0a, 0xf1, 0x54, 0x00, + 0xfe, 0xf7, 0x4a, 0xff, 0x43, 0x46, 0x01, 0x22, 0xf9, 0xb2, 0x01, 0x20, + 0xed, 0xf7, 0x5a, 0xfc, 0xed, 0xf7, 0x71, 0xfc, 0x15, 0xb9, 0x01, 0x20, + 0x07, 0xf8, 0x09, 0x00, 0x7f, 0x1c, 0x02, 0x2f, 0xb9, 0xd3, 0x28, 0x46, + 0xbd, 0xe8, 0xf0, 0x87, 0x38, 0x21, 0x6a, 0x48, 0xf2, 0xf7, 0x8c, 0xb8, + 0x2d, 0xe9, 0xfc, 0x4e, 0x81, 0x46, 0x68, 0x4e, 0x1c, 0x20, 0x00, 0xfb, + 0x09, 0x60, 0x0d, 0x46, 0x00, 0xf1, 0x28, 0x07, 0xef, 0xf3, 0x11, 0x80, + 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x00, 0x21, 0xb9, 0x82, 0x39, 0x60, + 0x64, 0x21, 0x79, 0x60, 0x00, 0x21, 0xf9, 0x82, 0x80, 0xf3, 0x11, 0x88, + 0x06, 0xeb, 0xc9, 0x00, 0x01, 0x90, 0x34, 0x78, 0xdf, 0xf8, 0x54, 0xb1, + 0x20, 0x07, 0x44, 0xbf, 0x01, 0x98, 0x84, 0x69, 0x4f, 0xf4, 0x82, 0x70, + 0x00, 0xfb, 0x09, 0xb0, 0x00, 0xf5, 0x21, 0x7a, 0xe0, 0x07, 0x0a, 0xd5, + 0x01, 0x20, 0xb8, 0x82, 0x29, 0x46, 0x48, 0x46, 0x00, 0xf0, 0x3a, 0xf9, + 0x30, 0xb3, 0xb9, 0x8a, 0x40, 0xea, 0x01, 0x40, 0x38, 0x60, 0x38, 0x68, + 0x60, 0xb9, 0xa0, 0x07, 0x0d, 0xd5, 0x02, 0x20, 0xb8, 0x82, 0x29, 0x46, + 0x48, 0x46, 0x00, 0xf0, 0xd1, 0xf9, 0xc8, 0xb1, 0xb9, 0x8a, 0x40, 0xea, + 0x01, 0x40, 0x38, 0x60, 0x38, 0x68, 0x00, 0x28, 0x4d, 0xd1, 0x60, 0x07, + 0x4d, 0xd5, 0x03, 0x20, 0xb8, 0x82, 0x19, 0xf8, 0x0b, 0x00, 0x20, 0xb1, + 0x49, 0x46, 0x01, 0x20, 0xf1, 0xf7, 0xe3, 0xfd, 0x40, 0xb9, 0xb8, 0x8a, + 0x00, 0x04, 0x40, 0xf0, 0x03, 0x00, 0x3b, 0xe0, 0x38, 0x60, 0xdc, 0xe7, + 0x38, 0x60, 0xea, 0xe7, 0xa5, 0xf8, 0x00, 0x90, 0x30, 0x1d, 0xa8, 0x60, + 0xf0, 0x88, 0x00, 0xf0, 0x52, 0xf8, 0x68, 0x60, 0xc5, 0xf8, 0x0c, 0xa0, + 0x4f, 0xf4, 0xa0, 0x70, 0x00, 0xfb, 0x09, 0xb0, 0x01, 0x1d, 0xa4, 0x30, + 0x29, 0x61, 0x68, 0x61, 0x00, 0xf0, 0x3e, 0xf8, 0xa8, 0x61, 0x00, 0x20, + 0x28, 0x62, 0xee, 0xf7, 0x99, 0xfb, 0x83, 0x46, 0xbb, 0xf1, 0x2e, 0x0f, + 0x16, 0xd3, 0x00, 0xf0, 0x48, 0xf8, 0x29, 0x49, 0xf0, 0xf7, 0xd0, 0xff, + 0x00, 0x90, 0xab, 0xf1, 0x2d, 0x00, 0xf0, 0xf7, 0xbb, 0xff, 0x00, 0x99, + 0xf1, 0xf7, 0x56, 0xf9, 0xf8, 0xf7, 0x54, 0xf8, 0x40, 0x08, 0xf0, 0xf7, + 0x75, 0xf8, 0xa8, 0x70, 0x28, 0x46, 0xff, 0xf7, 0xa1, 0xf9, 0x04, 0xe0, + 0xb8, 0x8a, 0x00, 0x04, 0x40, 0xf0, 0x04, 0x00, 0x38, 0x60, 0x38, 0x68, + 0x98, 0xb9, 0x20, 0x07, 0x11, 0xd5, 0xa5, 0xf8, 0x00, 0x90, 0x30, 0x1d, + 0xa8, 0x60, 0xc5, 0xf8, 0x0c, 0xa0, 0x00, 0xf0, 0x0d, 0xf8, 0xa8, 0x61, + 0x00, 0x20, 0x28, 0x62, 0x01, 0x98, 0x00, 0xf1, 0x18, 0x01, 0x28, 0x46, + 0xff, 0xf7, 0x21, 0xfb, 0x38, 0x60, 0x38, 0x68, 0xbd, 0xe8, 0xf6, 0x8e, + 0xef, 0x61, 0x49, 0x46, 0x01, 0x20, 0xf1, 0xf7, 0x87, 0xbd, 0x00, 0xf0, + 0xc0, 0xb8, 0x10, 0xb5, 0xf0, 0xf7, 0x86, 0xff, 0x04, 0x46, 0x00, 0xf0, + 0x08, 0xf8, 0x21, 0x46, 0xf1, 0xf7, 0x1e, 0xf9, 0xbd, 0xe8, 0x10, 0x40, + 0x0a, 0x49, 0xf0, 0xf7, 0x8b, 0xbf, 0x03, 0x48, 0x00, 0x6c, 0xf0, 0xf7, + 0x77, 0xbf, 0x00, 0x00, 0x48, 0xa8, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, + 0xa5, 0x58, 0x01, 0x01, 0x00, 0x24, 0x74, 0x49, 0x68, 0x2b, 0x00, 0x20, + 0xb4, 0x2b, 0x00, 0x20, 0x8c, 0x2b, 0x00, 0x20, 0x00, 0x7c, 0x92, 0x4d, + 0x53, 0x48, 0x41, 0x89, 0x03, 0x22, 0x11, 0x42, 0x00, 0xd1, 0x70, 0x47, + 0x80, 0xb5, 0xc1, 0xf3, 0x01, 0x11, 0x61, 0xb1, 0x01, 0x6c, 0x80, 0x69, + 0xfc, 0xf7, 0x82, 0xfb, 0x05, 0x28, 0x28, 0xbf, 0x05, 0x20, 0x01, 0x21, + 0x01, 0xfa, 0x00, 0xf0, 0x4a, 0x49, 0x88, 0x60, 0xc8, 0x60, 0x01, 0xbd, + 0xc1, 0x68, 0xca, 0x07, 0x01, 0xd5, 0x04, 0x20, 0x70, 0x47, 0x8a, 0x07, + 0x01, 0xd5, 0x03, 0x20, 0x70, 0x47, 0x49, 0x07, 0x01, 0xd5, 0x05, 0x20, + 0x70, 0x47, 0x00, 0x69, 0x00, 0xb1, 0x06, 0x20, 0x70, 0x47, 0x2d, 0xe9, + 0xf0, 0x41, 0x04, 0x46, 0x0d, 0x46, 0xdf, 0xf8, 0xf8, 0x80, 0x08, 0xf1, + 0x08, 0x00, 0x68, 0x60, 0x00, 0x26, 0x00, 0x20, 0xee, 0xf7, 0x00, 0xfb, + 0x32, 0x28, 0x28, 0xd3, 0x6b, 0x68, 0x37, 0x49, 0x9f, 0x89, 0x93, 0xf8, + 0x0e, 0xc0, 0x5b, 0x8a, 0x09, 0x6c, 0x1b, 0x0a, 0x0c, 0xf0, 0x07, 0x0c, + 0x03, 0xf0, 0x07, 0x03, 0x01, 0x22, 0x63, 0x44, 0x9a, 0x40, 0x32, 0x38, + 0x92, 0xb2, 0xb0, 0xfb, 0xf2, 0xf0, 0xef, 0xf7, 0x8b, 0xf8, 0x4f, 0xf6, + 0xc0, 0x71, 0x39, 0x40, 0x01, 0x43, 0x29, 0x81, 0xef, 0xf7, 0xab, 0xf8, + 0xf0, 0xf7, 0x10, 0xff, 0x01, 0x46, 0x4f, 0xf0, 0x8f, 0x40, 0xf0, 0xf7, + 0x1b, 0xff, 0x00, 0xf0, 0xb5, 0xf9, 0xf7, 0xf7, 0xa5, 0xff, 0x68, 0x81, + 0x00, 0xe0, 0x07, 0x26, 0x00, 0x27, 0x86, 0xb9, 0x24, 0xfa, 0x07, 0xf0, + 0xc0, 0x07, 0x0c, 0xd5, 0x2f, 0x60, 0x28, 0x46, 0x00, 0xf0, 0xc7, 0xf9, + 0x28, 0x46, 0xff, 0xf7, 0xa9, 0xff, 0x06, 0x00, 0x03, 0xd1, 0x68, 0x69, + 0x08, 0xeb, 0x87, 0x01, 0x08, 0x62, 0x7f, 0x1c, 0x02, 0x2f, 0xea, 0xd3, + 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0x38, 0xb5, 0x0c, 0x46, 0x16, 0x48, + 0x14, 0x49, 0x00, 0x68, 0x89, 0x7a, 0x80, 0x08, 0x01, 0xf0, 0x03, 0x01, + 0x41, 0xea, 0x80, 0x05, 0x05, 0xf0, 0x03, 0x00, 0xed, 0xf7, 0x26, 0xfa, + 0x08, 0xb9, 0x02, 0x20, 0x32, 0xbd, 0x21, 0x46, 0x28, 0x46, 0xbd, 0xe8, + 0x34, 0x40, 0x96, 0xe7, 0x0b, 0x4a, 0x52, 0x68, 0x01, 0x23, 0x00, 0xf0, + 0x01, 0x00, 0x92, 0x08, 0x03, 0xfa, 0x00, 0xf0, 0x40, 0xea, 0x82, 0x00, + 0x8b, 0xe7, 0x02, 0x28, 0x06, 0xd2, 0x01, 0x46, 0x04, 0x4a, 0x02, 0xeb, + 0x80, 0x00, 0x00, 0x6a, 0x00, 0xf0, 0x2b, 0xba, 0x70, 0x47, 0x00, 0x00, + 0x78, 0x29, 0x00, 0x20, 0xf8, 0x28, 0x00, 0x20, 0xef, 0xf3, 0x11, 0x80, + 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, 0x70, 0x47, 0x80, 0xb5, 0x8a, 0x48, + 0xc1, 0x6a, 0x40, 0x6b, 0xfc, 0xf7, 0xd8, 0xfa, 0x88, 0x49, 0x4a, 0xe0, + 0x2d, 0xe9, 0xf8, 0x43, 0x0c, 0x46, 0x00, 0x27, 0x61, 0x68, 0x8d, 0x89, + 0x8e, 0x7d, 0x61, 0x78, 0x01, 0x29, 0x08, 0xbf, 0x01, 0x28, 0x32, 0xd1, + 0x00, 0x20, 0xee, 0xf7, 0x6d, 0xfa, 0x0f, 0x28, 0x38, 0xbf, 0x01, 0x27, + 0x2b, 0xd3, 0x62, 0x68, 0x7c, 0x49, 0x92, 0xf8, 0x0e, 0xc0, 0x52, 0x8a, + 0x09, 0x6c, 0x12, 0x0a, 0x0c, 0xf0, 0x07, 0x0c, 0x02, 0xf0, 0x07, 0x02, + 0x01, 0x23, 0x62, 0x44, 0x03, 0xfa, 0x02, 0xf2, 0x0f, 0x38, 0x92, 0xb2, + 0xb0, 0xfb, 0xf2, 0xf0, 0xee, 0xf7, 0xf6, 0xff, 0x80, 0x46, 0x05, 0xf0, + 0x3f, 0x00, 0xef, 0xf7, 0x18, 0xf8, 0x81, 0x46, 0x40, 0x46, 0xef, 0xf7, + 0x14, 0xf8, 0x48, 0x45, 0x0b, 0xd2, 0xb9, 0xfb, 0xf0, 0xf6, 0xb6, 0xb2, + 0x4f, 0xf6, 0xc0, 0x71, 0x70, 0x43, 0x29, 0x40, 0x48, 0x45, 0x48, 0xea, + 0x01, 0x05, 0x38, 0xbf, 0x76, 0x1c, 0x25, 0x81, 0x66, 0x81, 0x38, 0x46, + 0xbd, 0xe8, 0xf2, 0x83, 0x80, 0xb5, 0x64, 0x48, 0x01, 0x6c, 0x80, 0x69, + 0xfc, 0xf7, 0x8c, 0xfa, 0x63, 0x49, 0x81, 0xf8, 0x21, 0x00, 0x01, 0xbd, + 0x38, 0xb5, 0x0c, 0x46, 0x5f, 0x48, 0x5e, 0x49, 0x00, 0x68, 0x49, 0x89, + 0x80, 0x08, 0xc1, 0xf3, 0x81, 0x01, 0x41, 0xea, 0x80, 0x05, 0x05, 0xf0, + 0x03, 0x00, 0xed, 0xf7, 0x8b, 0xf9, 0x08, 0xb9, 0x01, 0x20, 0x32, 0xbd, + 0x22, 0x46, 0x29, 0x46, 0xbd, 0xe8, 0x38, 0x40, 0x00, 0x20, 0x22, 0xe0, + 0x38, 0xb5, 0x0c, 0x46, 0x54, 0x48, 0x52, 0x49, 0x00, 0x68, 0x89, 0x7a, + 0x80, 0x08, 0x01, 0xf0, 0x03, 0x01, 0x41, 0xea, 0x80, 0x05, 0x05, 0xf0, + 0x03, 0x00, 0xed, 0xf7, 0x81, 0xf9, 0x08, 0xb9, 0x02, 0x20, 0x32, 0xbd, + 0x22, 0x46, 0x29, 0x46, 0xbd, 0xe8, 0x38, 0x40, 0x00, 0x20, 0x54, 0xe0, + 0x0a, 0x46, 0x49, 0x49, 0x01, 0x23, 0x49, 0x68, 0x00, 0xf0, 0x01, 0x00, + 0x03, 0xfa, 0x00, 0xf0, 0x01, 0x43, 0x01, 0x20, 0x49, 0xe0, 0x2d, 0xe9, + 0xf8, 0x43, 0x0c, 0x46, 0x04, 0xf0, 0x04, 0x01, 0xdf, 0xf8, 0x00, 0x81, + 0x15, 0x46, 0x00, 0x26, 0xa9, 0x70, 0x6e, 0x70, 0x04, 0xf0, 0x08, 0x01, + 0xe9, 0x70, 0x2e, 0x61, 0x08, 0xf1, 0x08, 0x01, 0x69, 0x60, 0x29, 0x46, + 0xff, 0xf7, 0x62, 0xff, 0x00, 0xb1, 0x08, 0x26, 0x00, 0x27, 0x00, 0x20, + 0x02, 0xe0, 0x38, 0x00, 0x18, 0xbf, 0x01, 0x20, 0x2e, 0xbb, 0x24, 0xfa, + 0x07, 0xf1, 0xc9, 0x07, 0x21, 0xd5, 0x34, 0x49, 0x2f, 0x70, 0x4f, 0xf4, + 0x7c, 0x72, 0x02, 0xfb, 0x00, 0x16, 0x06, 0xf1, 0xe0, 0x00, 0xe8, 0x60, + 0x30, 0x1d, 0x68, 0x61, 0x14, 0x20, 0x00, 0xfb, 0x07, 0x89, 0x09, 0xf1, + 0x28, 0x01, 0x28, 0x46, 0x00, 0xf0, 0x58, 0xf8, 0x28, 0x46, 0x00, 0xf0, + 0x09, 0xfa, 0x6b, 0x6a, 0xaa, 0x6a, 0x29, 0x7e, 0x30, 0x46, 0xfa, 0xf7, + 0x37, 0xf9, 0x09, 0xf1, 0x28, 0x01, 0x28, 0x46, 0x00, 0xf0, 0x58, 0xf8, + 0x06, 0x46, 0x7f, 0x1c, 0x02, 0x2f, 0xd2, 0xd3, 0x30, 0x46, 0xbd, 0xe8, + 0xf2, 0x83, 0x2d, 0xe9, 0xf0, 0x41, 0x0c, 0x46, 0x15, 0x46, 0x01, 0x21, + 0x69, 0x70, 0x04, 0xf0, 0x04, 0x01, 0xa9, 0x70, 0x04, 0xf0, 0x08, 0x01, + 0xe9, 0x70, 0x00, 0x26, 0xdf, 0xf8, 0x60, 0x80, 0x6e, 0x61, 0x08, 0xf1, + 0x08, 0x01, 0x69, 0x60, 0x2e, 0x61, 0x05, 0xf5, 0xde, 0x71, 0xe9, 0x60, + 0x29, 0x46, 0xff, 0xf7, 0x13, 0xff, 0x00, 0xb1, 0x08, 0x26, 0x00, 0x27, + 0xae, 0xb9, 0x24, 0xfa, 0x07, 0xf0, 0xc0, 0x07, 0x11, 0xd5, 0x14, 0x20, + 0x00, 0xfb, 0x07, 0x86, 0x2f, 0x70, 0x06, 0xf1, 0x24, 0x01, 0x28, 0x46, + 0x00, 0xf0, 0x18, 0xf8, 0x28, 0x46, 0x00, 0xf0, 0xc9, 0xf9, 0x06, 0xf1, + 0x24, 0x01, 0x28, 0x46, 0x00, 0xf0, 0x1e, 0xf8, 0x06, 0x46, 0x7f, 0x1c, + 0x02, 0x2f, 0xe5, 0xd3, 0x30, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x00, + 0x78, 0x29, 0x00, 0x20, 0xdc, 0x29, 0x00, 0x20, 0x2c, 0x2a, 0x00, 0x20, + 0xc0, 0x92, 0x00, 0x20, 0x10, 0xb5, 0x0c, 0x46, 0xff, 0xf7, 0xd8, 0xfe, + 0x01, 0x21, 0x61, 0x60, 0x00, 0x21, 0x21, 0x60, 0xa1, 0x60, 0xe1, 0x60, + 0x21, 0x61, 0x80, 0xf3, 0x11, 0x88, 0x10, 0xbd, 0x70, 0xb5, 0x04, 0x46, + 0x0d, 0x46, 0x20, 0x6a, 0xc1, 0x07, 0x48, 0xbf, 0x04, 0x26, 0x1b, 0xd4, + 0x81, 0x07, 0x48, 0xbf, 0x03, 0x26, 0x17, 0xd4, 0x40, 0x07, 0x48, 0xbf, + 0x07, 0x26, 0x13, 0xd4, 0x60, 0x7e, 0x08, 0xb1, 0x0a, 0x26, 0x0f, 0xe0, + 0xa0, 0x7e, 0x81, 0x07, 0x48, 0xbf, 0x09, 0x26, 0x0a, 0xd4, 0xc0, 0x07, + 0x05, 0xd4, 0xe0, 0x7e, 0x08, 0xb1, 0x05, 0x26, 0x04, 0xe0, 0x20, 0x7f, + 0x08, 0xb1, 0x06, 0x26, 0x00, 0xe0, 0x00, 0x26, 0xff, 0xf7, 0xa8, 0xfe, + 0x2e, 0x60, 0xa1, 0x6a, 0xa9, 0x60, 0x61, 0x6a, 0xe9, 0x60, 0x21, 0x7e, + 0x29, 0x61, 0x00, 0x21, 0x69, 0x60, 0x80, 0xf3, 0x11, 0x88, 0x30, 0x46, + 0x70, 0xbd, 0x00, 0x00, 0xc0, 0xf3, 0xc7, 0x52, 0x7e, 0x3a, 0xcc, 0xbf, + 0xd2, 0xf1, 0x18, 0x0c, 0x07, 0xe0, 0x6f, 0xf0, 0x7f, 0x41, 0xd1, 0x40, + 0x00, 0x42, 0x58, 0xbf, 0x40, 0x18, 0x88, 0x43, 0x70, 0x47, 0x18, 0x2a, + 0x06, 0xda, 0x41, 0x00, 0x18, 0xbf, 0x4f, 0xf0, 0x7e, 0x50, 0x28, 0xbf, + 0x4f, 0xf0, 0x00, 0x40, 0x70, 0x47, 0x00, 0x00, 0x00, 0x21, 0xc0, 0xf8, + 0x98, 0x10, 0x40, 0xf8, 0x0c, 0x1f, 0x41, 0x60, 0x70, 0x47, 0x10, 0xb5, + 0x04, 0x46, 0xff, 0xf7, 0xf5, 0xff, 0x00, 0x21, 0x01, 0x20, 0xfe, 0xf7, + 0x4b, 0xf9, 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x2d, 0xe9, 0xf0, 0x41, + 0x05, 0x46, 0x4f, 0xf4, 0x80, 0x70, 0x29, 0x68, 0x00, 0xf0, 0x8b, 0xf8, + 0x00, 0xf0, 0x87, 0xf8, 0x04, 0x46, 0xd5, 0xf8, 0x98, 0x00, 0x00, 0x28, + 0x7a, 0xd1, 0x29, 0x68, 0x4f, 0xf4, 0x40, 0x70, 0x00, 0xf0, 0x7f, 0xf8, + 0x00, 0xf0, 0x7b, 0xf8, 0x01, 0x46, 0xd5, 0xf8, 0x98, 0x00, 0x00, 0x28, + 0x6e, 0xd1, 0x20, 0x46, 0xf0, 0xf7, 0x98, 0xfd, 0x01, 0x46, 0x4f, 0xf0, + 0x44, 0x40, 0xf0, 0xf7, 0x15, 0xfd, 0x80, 0x46, 0x20, 0x46, 0x41, 0x46, + 0xf0, 0xf7, 0x9e, 0xfe, 0x00, 0x21, 0xf0, 0xf7, 0xa3, 0xff, 0x94, 0xbf, + 0x4f, 0xf0, 0x7c, 0x51, 0x4f, 0xf0, 0x3f, 0x41, 0xf0, 0xf7, 0xf8, 0xfd, + 0xf0, 0xf7, 0xfe, 0xfe, 0xc0, 0xf5, 0x80, 0x70, 0x00, 0xf0, 0x54, 0xf8, + 0x00, 0xf0, 0x57, 0xf8, 0x07, 0x46, 0xd5, 0xf8, 0x98, 0x00, 0x00, 0x28, + 0x4a, 0xd1, 0x4f, 0xf0, 0x40, 0x40, 0x39, 0x46, 0xf0, 0xf7, 0x82, 0xfe, + 0x41, 0x46, 0xf0, 0xf7, 0x7f, 0xfe, 0x00, 0x21, 0xf0, 0xf7, 0x84, 0xff, + 0x04, 0x46, 0x94, 0xbf, 0x4f, 0xf0, 0x7c, 0x50, 0x4f, 0xf0, 0x3f, 0x40, + 0x21, 0x46, 0xf0, 0xf7, 0xd7, 0xfd, 0xf0, 0xf7, 0xdd, 0xfe, 0x00, 0x28, + 0x54, 0xbf, 0x08, 0x20, 0x6f, 0xf0, 0x07, 0x00, 0x84, 0x19, 0xb4, 0xf5, + 0x80, 0x6f, 0x28, 0xbf, 0x34, 0x1a, 0x29, 0x68, 0x20, 0x46, 0x00, 0xf0, + 0x30, 0xf8, 0x00, 0xf0, 0x2c, 0xf8, 0x80, 0x46, 0xd5, 0xf8, 0x98, 0x00, + 0x00, 0xbb, 0xa0, 0x1b, 0xf0, 0xf7, 0xb2, 0xfc, 0x39, 0x46, 0xf0, 0xf7, + 0x57, 0xfe, 0x04, 0x46, 0x40, 0x46, 0x39, 0x46, 0xf0, 0xf7, 0x42, 0xfd, + 0x01, 0x46, 0x20, 0x46, 0xf0, 0xf7, 0xc0, 0xfc, 0x00, 0x21, 0xf0, 0xf7, + 0x53, 0xff, 0x04, 0x46, 0x94, 0xbf, 0x4f, 0xf0, 0x7c, 0x50, 0x4f, 0xf0, + 0x3f, 0x40, 0x21, 0x46, 0xf0, 0xf7, 0xa6, 0xfd, 0xf0, 0xf7, 0xac, 0xfe, + 0x30, 0x1a, 0x00, 0xf0, 0x03, 0xf8, 0x6e, 0x61, 0xbd, 0xe8, 0xf0, 0x81, + 0x80, 0xf3, 0x0a, 0x06, 0x29, 0x68, 0x30, 0x46, 0x01, 0xe0, 0x28, 0x46, + 0x38, 0xe0, 0x70, 0xb5, 0x04, 0x46, 0x00, 0x29, 0x07, 0xbf, 0x40, 0xf2, + 0xe1, 0x65, 0x4f, 0xf4, 0xdc, 0x60, 0x40, 0xf2, 0xe3, 0x65, 0x40, 0xf2, + 0xe2, 0x60, 0xef, 0xf3, 0x11, 0x86, 0x60, 0x21, 0x81, 0xf3, 0x11, 0x88, + 0xa1, 0x05, 0x09, 0x0e, 0xec, 0xf7, 0x60, 0xff, 0x04, 0xf0, 0x03, 0x04, + 0x00, 0xf0, 0x0f, 0xf8, 0x44, 0xf0, 0x80, 0x01, 0x00, 0xf0, 0x0c, 0xf8, + 0x00, 0xf0, 0x09, 0xf8, 0x00, 0xf0, 0x07, 0xf8, 0x05, 0xf1, 0x8c, 0x40, + 0x01, 0x78, 0x00, 0x78, 0x86, 0xf3, 0x11, 0x88, 0x70, 0xbd, 0x21, 0x46, + 0x28, 0x46, 0xec, 0xf7, 0x49, 0xbf, 0x00, 0x21, 0x01, 0x22, 0x20, 0xfa, + 0x02, 0xf3, 0xdb, 0x07, 0x01, 0xd5, 0x11, 0x46, 0x02, 0xe0, 0x52, 0x1c, + 0x18, 0x2a, 0xf6, 0xd3, 0x08, 0x46, 0x70, 0x47, 0x70, 0xb5, 0x04, 0x46, + 0x60, 0x68, 0x40, 0x68, 0xff, 0xf7, 0xed, 0xff, 0x05, 0xb2, 0x20, 0x68, + 0x20, 0x76, 0x01, 0x20, 0x60, 0x76, 0x00, 0x20, 0xa0, 0x76, 0x60, 0x68, + 0xe0, 0x61, 0x04, 0xf1, 0x08, 0x00, 0x20, 0x62, 0x00, 0x20, 0x60, 0x62, + 0x04, 0xf1, 0x18, 0x00, 0xfd, 0xf7, 0x80, 0xfe, 0xe0, 0x6a, 0xe0, 0x60, + 0x08, 0xb1, 0x01, 0x20, 0x07, 0xe0, 0xa0, 0x6b, 0xa8, 0x42, 0x04, 0xbf, + 0xe0, 0x6b, 0xe8, 0x42, 0x03, 0xd0, 0x01, 0x20, 0x20, 0x61, 0xc4, 0xf8, + 0x98, 0x00, 0x00, 0x20, 0xd4, 0xf8, 0x98, 0x10, 0x00, 0x29, 0x41, 0xd1, + 0xd4, 0xe9, 0x12, 0x01, 0xf0, 0xf7, 0xf0, 0xfb, 0x05, 0x46, 0xd4, 0xe9, + 0x10, 0x01, 0xf0, 0xf7, 0xeb, 0xfb, 0x01, 0x46, 0x28, 0x46, 0xf0, 0xf7, + 0x33, 0xfc, 0x05, 0x46, 0xd4, 0xe9, 0x16, 0x01, 0xf0, 0xf7, 0xe2, 0xfb, + 0x06, 0x46, 0xd4, 0xe9, 0x14, 0x01, 0xf0, 0xf7, 0xdd, 0xfb, 0x01, 0x46, + 0x30, 0x46, 0xf0, 0xf7, 0x25, 0xfc, 0x04, 0x46, 0x28, 0x46, 0x29, 0x46, + 0xf0, 0xf7, 0xae, 0xfd, 0x29, 0x46, 0xf0, 0xf7, 0xab, 0xfd, 0x10, 0x49, + 0xf0, 0xf7, 0x1a, 0xfc, 0x01, 0x46, 0x28, 0x46, 0xf0, 0xf7, 0x94, 0xfc, + 0x05, 0x46, 0x20, 0x46, 0x21, 0x46, 0xf0, 0xf7, 0x9f, 0xfd, 0x21, 0x46, + 0xf0, 0xf7, 0x9c, 0xfd, 0x08, 0x49, 0xf0, 0xf7, 0x0b, 0xfc, 0x01, 0x46, + 0x20, 0x46, 0xf0, 0xf7, 0x85, 0xfc, 0x29, 0x46, 0xf0, 0xf7, 0xf6, 0xfc, + 0xbd, 0xe8, 0x70, 0x40, 0x4f, 0xf0, 0x7c, 0x51, 0xf0, 0xf7, 0x8c, 0xbd, + 0x70, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x21, 0x41, 0x63, + 0x01, 0x62, 0x41, 0x76, 0x81, 0x76, 0xc1, 0x76, 0x01, 0x77, 0x70, 0x47, + 0x10, 0xb5, 0x04, 0x46, 0xff, 0xf7, 0xf4, 0xff, 0x20, 0x46, 0x00, 0xf0, + 0x8f, 0xf8, 0x20, 0x6a, 0x60, 0xb9, 0xa0, 0x78, 0x02, 0x28, 0x09, 0xd0, + 0xe0, 0x78, 0x00, 0x28, 0x04, 0xbf, 0x60, 0x6b, 0x00, 0x28, 0x03, 0xd1, + 0x20, 0x46, 0xbd, 0xe8, 0x10, 0x40, 0x13, 0xe0, 0x10, 0xbd, 0x10, 0xb5, + 0xb4, 0xb0, 0x04, 0x46, 0x00, 0x20, 0x00, 0x90, 0x69, 0x46, 0x20, 0x46, + 0xfc, 0xf7, 0x74, 0xfa, 0x6b, 0x46, 0x01, 0xaa, 0x04, 0xf5, 0x79, 0x71, + 0x04, 0xf5, 0x96, 0x60, 0xfb, 0xf7, 0xfb, 0xff, 0x34, 0xb0, 0x10, 0xbd, + 0xf8, 0xb5, 0x04, 0x46, 0x6a, 0x46, 0x60, 0x78, 0x25, 0x78, 0x00, 0x28, + 0x0c, 0xbf, 0x2e, 0x46, 0x02, 0x26, 0x00, 0x21, 0x00, 0x20, 0xed, 0xf7, + 0x92, 0xfa, 0x00, 0x98, 0x10, 0xb9, 0x01, 0x20, 0x60, 0x76, 0xf1, 0xbd, + 0x00, 0x99, 0x2b, 0x4a, 0x00, 0x20, 0x08, 0x60, 0x00, 0x99, 0x48, 0x71, + 0x00, 0x99, 0x94, 0xf8, 0xb8, 0x01, 0x08, 0x71, 0x00, 0x99, 0x60, 0x6a, + 0xc8, 0x60, 0x00, 0x99, 0xa0, 0x6a, 0x08, 0x61, 0x00, 0x99, 0x00, 0x98, + 0x00, 0xf5, 0x96, 0x60, 0x48, 0x61, 0x04, 0xf1, 0x38, 0x00, 0x00, 0x99, + 0x88, 0x60, 0x60, 0x68, 0x00, 0x99, 0x18, 0x30, 0x88, 0x61, 0x00, 0x21, + 0x00, 0x20, 0xed, 0xf7, 0xf8, 0xfa, 0x00, 0x98, 0x00, 0x7f, 0xa0, 0x76, + 0x60, 0x69, 0x28, 0xb1, 0x00, 0x99, 0xcc, 0x22, 0x01, 0xf5, 0x79, 0x71, + 0xf3, 0xf7, 0x92, 0xfc, 0xe0, 0x68, 0x28, 0xb1, 0x00, 0x99, 0xcc, 0x22, + 0x01, 0xf5, 0x96, 0x61, 0xf3, 0xf7, 0x8a, 0xfc, 0xef, 0xf3, 0x11, 0x87, + 0x60, 0x20, 0x80, 0xf3, 0x11, 0x88, 0x30, 0x46, 0xee, 0xf7, 0x23, 0xff, + 0x00, 0x99, 0x01, 0xf5, 0x79, 0x71, 0xee, 0xf7, 0xbd, 0xfe, 0x10, 0xb9, + 0x01, 0x20, 0xe0, 0x76, 0x0b, 0xe0, 0x00, 0x2d, 0x0c, 0xbf, 0x0a, 0x21, + 0x0e, 0x21, 0x30, 0x46, 0xee, 0xf7, 0x1f, 0xff, 0x60, 0x78, 0x10, 0xb9, + 0x28, 0x46, 0xf8, 0xf7, 0xf4, 0xf9, 0x87, 0xf3, 0x11, 0x88, 0x00, 0x20, + 0xed, 0xf7, 0x7f, 0xfa, 0xf1, 0xbd, 0x00, 0x00, 0xcb, 0x62, 0x01, 0x01, + 0x10, 0xb5, 0x04, 0x46, 0xa0, 0xb0, 0x20, 0x78, 0x8d, 0xf8, 0x00, 0x00, + 0x60, 0x78, 0x8d, 0xf8, 0x01, 0x00, 0xa0, 0x78, 0x8d, 0xf8, 0x02, 0x00, + 0x60, 0x68, 0x01, 0x90, 0x04, 0xf1, 0x08, 0x00, 0x02, 0x90, 0x04, 0xf1, + 0x38, 0x00, 0x03, 0x90, 0xa1, 0x78, 0x60, 0x78, 0xfd, 0xf7, 0x54, 0xff, + 0x68, 0x46, 0xfd, 0xf7, 0x6d, 0xfd, 0x20, 0x69, 0x20, 0xb1, 0x03, 0x99, + 0x4f, 0xf4, 0xc0, 0x72, 0xf3, 0xf7, 0x42, 0xfc, 0x9d, 0xf9, 0x10, 0x00, + 0x40, 0x42, 0x84, 0xf8, 0xb8, 0x01, 0x9d, 0xf8, 0x11, 0x00, 0x20, 0x76, + 0x05, 0x98, 0x20, 0x62, 0x06, 0x98, 0x60, 0x62, 0x07, 0x98, 0xa0, 0x62, + 0x20, 0xb0, 0x10, 0xbd, 0x00, 0x21, 0x00, 0x20, 0x10, 0xb5, 0xed, 0xf7, + 0x4a, 0xf8, 0x60, 0x48, 0x01, 0x78, 0x00, 0x24, 0x39, 0xb1, 0x41, 0x78, + 0x90, 0xf9, 0x02, 0x00, 0x40, 0x18, 0xc0, 0xb2, 0x00, 0xf0, 0x00, 0xf9, + 0x0d, 0xe0, 0x5b, 0x48, 0x80, 0x7a, 0x10, 0xf0, 0x03, 0x00, 0x08, 0xbf, + 0x01, 0x24, 0x06, 0xd0, 0x00, 0xf0, 0x01, 0x00, 0x80, 0xf0, 0x01, 0x00, + 0x00, 0xf0, 0x06, 0xf8, 0x04, 0x46, 0x00, 0x20, 0xed, 0xf7, 0x8a, 0xf8, + 0x20, 0x46, 0x10, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, 0x89, 0xb0, 0x05, 0x46, + 0x04, 0xa8, 0xef, 0xf7, 0x7c, 0xfa, 0x69, 0x46, 0x28, 0x46, 0xf0, 0xf7, + 0x15, 0xff, 0xdd, 0xe9, 0x00, 0x01, 0xcd, 0xe9, 0x02, 0x01, 0x02, 0xaa, + 0x02, 0x21, 0x28, 0x46, 0xf0, 0xf7, 0x43, 0xff, 0x00, 0x21, 0x00, 0x20, + 0x00, 0xf0, 0xd4, 0xf8, 0x01, 0x21, 0xe8, 0xb2, 0xef, 0xf7, 0x68, 0xf9, + 0x44, 0x4a, 0x0f, 0xf2, 0xc0, 0x19, 0xd2, 0xe9, 0x08, 0x01, 0xef, 0xf7, + 0x11, 0xfa, 0x01, 0x46, 0xe8, 0xb2, 0xef, 0xf7, 0x2b, 0xfa, 0x3e, 0x48, + 0xc0, 0x69, 0x40, 0x00, 0x05, 0x21, 0xb0, 0xfb, 0xf1, 0xf2, 0x00, 0x23, + 0x28, 0x46, 0xfe, 0xf7, 0x91, 0xf9, 0x3b, 0x48, 0x3b, 0x49, 0x00, 0x78, + 0x08, 0x70, 0x06, 0x23, 0x0f, 0xf2, 0x84, 0x12, 0x80, 0x08, 0x06, 0x21, + 0x90, 0xfb, 0xf1, 0xf1, 0x03, 0xfb, 0x11, 0x00, 0x88, 0x46, 0x10, 0xf8, + 0x02, 0xa0, 0x00, 0x26, 0x01, 0xe0, 0x00, 0x2c, 0x46, 0xd1, 0x00, 0x27, + 0x5f, 0xfa, 0x87, 0xfb, 0x19, 0xf8, 0x1b, 0x10, 0x40, 0xf2, 0x32, 0x70, + 0xec, 0xf7, 0x88, 0xfd, 0x09, 0xeb, 0x4b, 0x00, 0x00, 0x24, 0x41, 0x78, + 0x40, 0xf2, 0x34, 0x70, 0xec, 0xf7, 0x80, 0xfd, 0x01, 0x21, 0x40, 0xf2, + 0x33, 0x70, 0xec, 0xf7, 0x7b, 0xfd, 0x00, 0x21, 0x40, 0xf2, 0x35, 0x70, + 0xec, 0xf7, 0x76, 0xfd, 0x51, 0x46, 0x40, 0xf2, 0x36, 0x70, 0xec, 0xf7, + 0x71, 0xfd, 0xff, 0x21, 0x40, 0xf2, 0x31, 0x70, 0xec, 0xf7, 0x6c, 0xfd, + 0x00, 0x2d, 0x0c, 0xbf, 0x4f, 0xf0, 0x01, 0x0b, 0x4f, 0xf0, 0x02, 0x0b, + 0x4b, 0xea, 0x48, 0x11, 0xc9, 0xb2, 0x4f, 0xf4, 0xe6, 0x60, 0xec, 0xf7, + 0x5f, 0xfd, 0x42, 0xf2, 0x10, 0x73, 0x00, 0x22, 0x59, 0x46, 0x4f, 0xf4, + 0xe6, 0x60, 0xf3, 0xf7, 0x1b, 0xfa, 0x00, 0xb1, 0x03, 0x24, 0x4c, 0xb9, + 0x14, 0x48, 0x00, 0x78, 0x06, 0xa9, 0x71, 0x18, 0x07, 0xeb, 0x47, 0x02, + 0x7f, 0x1c, 0x50, 0x54, 0x02, 0x2f, 0xb9, 0xd3, 0x76, 0x1c, 0x03, 0x2e, + 0xb3, 0xd3, 0x1c, 0xb9, 0x06, 0xa8, 0x00, 0xf0, 0x1b, 0xf8, 0x04, 0x46, + 0x69, 0x46, 0x28, 0x46, 0xf0, 0xf7, 0xa8, 0xfe, 0xfe, 0xf7, 0xe8, 0xf8, + 0x04, 0xa8, 0xef, 0xf7, 0xf3, 0xf9, 0x20, 0x46, 0x09, 0xb0, 0xbd, 0xe8, + 0xf0, 0x8f, 0x00, 0x00, 0xb4, 0x2a, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, + 0x00, 0xf2, 0x00, 0x20, 0xe6, 0x04, 0x00, 0x46, 0x9f, 0xf3, 0x00, 0x20, + 0x37, 0x07, 0x00, 0x46, 0x70, 0xb5, 0x00, 0x24, 0x00, 0x22, 0x00, 0xeb, + 0x42, 0x03, 0x00, 0x21, 0xd9, 0x80, 0x02, 0xeb, 0x42, 0x06, 0x36, 0x18, + 0xdd, 0x88, 0x8e, 0x5d, 0x49, 0x1c, 0x75, 0x19, 0x03, 0x29, 0xdd, 0x80, + 0xf5, 0xd3, 0xad, 0xb2, 0x03, 0x21, 0x52, 0x1c, 0xb5, 0xfb, 0xf1, 0xf1, + 0x02, 0x2a, 0xd9, 0x80, 0xe9, 0xd3, 0x00, 0x22, 0x00, 0x21, 0x02, 0xeb, + 0x42, 0x03, 0x1b, 0x18, 0xcb, 0x5c, 0x5b, 0xb1, 0x80, 0x2b, 0x09, 0xda, + 0x00, 0xeb, 0x42, 0x06, 0xf6, 0x88, 0x9d, 0x1b, 0x4c, 0xbf, 0xf3, 0x1a, + 0x9b, 0x1b, 0x9b, 0xb2, 0x04, 0x2b, 0x00, 0xd3, 0x02, 0x24, 0x49, 0x1c, + 0x03, 0x29, 0xea, 0xd3, 0x52, 0x1c, 0x02, 0x2a, 0xe6, 0xd3, 0x3c, 0xb9, + 0xc1, 0x88, 0x00, 0x89, 0x09, 0x1a, 0xc9, 0xb2, 0x48, 0x1e, 0xc0, 0xb2, + 0x00, 0xf0, 0x02, 0xf8, 0x20, 0x46, 0x70, 0xbd, 0x10, 0xb5, 0x0c, 0x46, + 0x01, 0x46, 0x40, 0xf6, 0x65, 0x10, 0xec, 0xf7, 0xe3, 0xfc, 0x21, 0x46, + 0xbd, 0xe8, 0x10, 0x40, 0x40, 0xf6, 0x66, 0x10, 0xec, 0xf7, 0xdc, 0xbc, + 0xcb, 0xb5, 0xa1, 0x8f, 0x80, 0x72, 0x00, 0x00, 0x78, 0x00, 0x01, 0x28, + 0x3e, 0x48, 0x0f, 0xf2, 0x10, 0x12, 0x2d, 0xe9, 0xf0, 0x4f, 0x44, 0x68, + 0xef, 0xf3, 0x08, 0x80, 0x20, 0x60, 0x00, 0x21, 0xef, 0xf3, 0x09, 0x80, + 0x60, 0x60, 0xef, 0xf3, 0x03, 0x80, 0xe0, 0x60, 0x04, 0xf1, 0x10, 0x00, + 0x52, 0xf8, 0x21, 0x30, 0x1b, 0x68, 0x40, 0xf8, 0x21, 0x30, 0x49, 0x1c, + 0x13, 0x29, 0xf7, 0xd3, 0x15, 0x22, 0x04, 0xf1, 0x5c, 0x01, 0x0f, 0xf2, + 0x24, 0x10, 0xec, 0xf7, 0xe6, 0xfc, 0x20, 0x68, 0x41, 0x6c, 0xa1, 0x60, + 0x11, 0xf1, 0x0f, 0x0f, 0x18, 0xbf, 0x11, 0xf1, 0x07, 0x0f, 0x06, 0xd1, + 0xc1, 0x6d, 0x61, 0x67, 0x00, 0x6e, 0xa0, 0x67, 0x20, 0x68, 0x40, 0x6e, + 0x02, 0xe0, 0x00, 0x20, 0x60, 0x67, 0xa0, 0x67, 0xe0, 0x67, 0x25, 0x48, + 0x00, 0x68, 0x90, 0xf8, 0x32, 0x00, 0xc4, 0xf8, 0x80, 0x00, 0xbd, 0xe8, + 0xf0, 0x4f, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, 0x20, 0x4c, 0x4f, 0xf0, + 0xee, 0x31, 0x20, 0x46, 0xec, 0xf7, 0xd9, 0xfc, 0x1b, 0x4d, 0x1e, 0x49, + 0xef, 0xf3, 0x08, 0x80, 0xa8, 0x60, 0x88, 0x42, 0x24, 0xbf, 0x1c, 0x4a, + 0x82, 0x42, 0x04, 0xd2, 0x1b, 0x48, 0x08, 0x18, 0x40, 0x08, 0x80, 0xf3, + 0x08, 0x88, 0x05, 0xf1, 0x0c, 0x00, 0x68, 0x60, 0xff, 0xf7, 0xa6, 0xff, + 0x0d, 0x20, 0xf1, 0xf7, 0x56, 0xfc, 0x4f, 0xf0, 0xff, 0x31, 0x20, 0x46, + 0xec, 0xf7, 0xbd, 0xfc, 0x80, 0x22, 0x00, 0x23, 0x80, 0x20, 0x00, 0x21, + 0xf1, 0xf7, 0xd6, 0xfc, 0x0a, 0x20, 0xf7, 0xf7, 0xc1, 0xf8, 0xf8, 0xf7, + 0x77, 0xfe, 0x00, 0xb1, 0x01, 0x20, 0x28, 0x70, 0xf8, 0xf7, 0x5a, 0xfe, + 0x20, 0x68, 0x00, 0x28, 0xfc, 0xd1, 0x28, 0x78, 0x08, 0xb1, 0xf8, 0xf7, + 0x4d, 0xfe, 0xf7, 0xf7, 0xbb, 0xf8, 0xbd, 0xe8, 0xf0, 0x4f, 0x70, 0x47, + 0xe8, 0xb7, 0x00, 0x20, 0x40, 0xbd, 0x00, 0x20, 0xf0, 0x7f, 0x01, 0x01, + 0x90, 0xb8, 0x00, 0x20, 0x6c, 0xbc, 0x00, 0x20, 0x90, 0xbc, 0x00, 0x20, + 0x00, 0xe3, 0x00, 0xe0, 0x04, 0xe3, 0x00, 0xe0, 0x04, 0xed, 0x00, 0xe0, + 0x24, 0xed, 0x00, 0xe0, 0x28, 0xed, 0x00, 0xe0, 0x2c, 0xed, 0x00, 0xe0, + 0x38, 0xed, 0x00, 0xe0, 0x40, 0x00, 0x00, 0x50, 0x44, 0x00, 0x00, 0x50, + 0x48, 0x00, 0x00, 0x50, 0x40, 0x00, 0x00, 0x58, 0x44, 0x00, 0x00, 0x58, + 0x00, 0x00, 0x00, 0x49, 0x04, 0x00, 0x00, 0x49, 0x08, 0x00, 0x00, 0x49, + 0x0c, 0x00, 0x00, 0x49, 0x10, 0x00, 0x00, 0x49, 0x14, 0x00, 0x00, 0x49, + 0x18, 0x00, 0x00, 0x49, 0x00, 0x0d, 0x01, 0x0d, 0x08, 0x0d, 0x09, 0x0d, + 0x50, 0x0c, 0x51, 0x0c, 0x52, 0x0c, 0x53, 0x0c, 0x54, 0x0c, 0x55, 0x0c, + 0x56, 0x0c, 0x57, 0x0c, 0x58, 0x0c, 0x59, 0x0c, 0x5a, 0x0c, 0x5b, 0x0c, + 0x5c, 0x0c, 0x5d, 0x0c, 0x5e, 0x0c, 0x5f, 0x0c, 0x60, 0x0c, 0x00, 0x00, + 0xb8, 0x2a, 0x00, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, + 0x86, 0x00, 0x00, 0x00, 0x88, 0xf3, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x2a, 0x00, 0x20, + 0x03, 0x00, 0x00, 0x00, 0x70, 0x29, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, + 0x68, 0xf3, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x20, 0x29, 0x00, 0x20, + 0x2c, 0x00, 0x00, 0x00, 0xdc, 0x2a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x00, + 0xdc, 0x2a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x00, 0x68, 0x2b, 0x00, 0x20, + 0x24, 0x00, 0x00, 0x00, 0xf8, 0x28, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, + 0x2c, 0x2a, 0x00, 0x20, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xdc, 0x29, 0x00, 0x20, 0x28, 0x00, 0x00, 0x00, + 0x9c, 0x28, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x26, 0x00, 0x20, + 0x18, 0x00, 0x00, 0x00, 0x2c, 0x2c, 0x00, 0x20, 0x2c, 0x00, 0x00, 0x00, + 0x70, 0xf3, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2a, 0x00, 0x20, + 0x64, 0x2a, 0x00, 0x20, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2a, 0x00, 0x20, + 0x18, 0x2a, 0x00, 0x20, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x47, 0x2d, 0xe9, + 0xf8, 0x46, 0x89, 0x46, 0x00, 0x21, 0x00, 0x20, 0xec, 0xf7, 0x9f, 0xfd, + 0x48, 0x46, 0x00, 0xf0, 0x8d, 0xf8, 0x42, 0x4d, 0x42, 0x4c, 0x68, 0x89, + 0x00, 0x26, 0xc0, 0xf3, 0x01, 0x10, 0x00, 0x28, 0x40, 0xf2, 0x99, 0x6a, + 0x2c, 0xd0, 0xe8, 0x6c, 0x00, 0xf0, 0x6f, 0xf8, 0x10, 0xb1, 0xf7, 0xf7, + 0x63, 0xf8, 0x08, 0xb9, 0x01, 0x26, 0x42, 0xe0, 0xe8, 0x6c, 0x00, 0xf0, + 0x4e, 0xf8, 0xa8, 0xbf, 0x64, 0x20, 0x00, 0xf0, 0x45, 0xf8, 0x00, 0xf0, + 0x5b, 0xf8, 0x9c, 0x21, 0x00, 0xf0, 0x59, 0xf8, 0x00, 0xf0, 0x49, 0xf8, + 0x00, 0xf0, 0x4c, 0xf8, 0x08, 0xb1, 0x02, 0x26, 0x2f, 0xe0, 0x31, 0x4f, + 0x39, 0x78, 0x40, 0xf6, 0x93, 0x00, 0xec, 0xf7, 0x1b, 0xfb, 0x7a, 0x78, + 0x1f, 0x21, 0x40, 0xf6, 0x94, 0x00, 0xec, 0xf7, 0x1f, 0xfb, 0x39, 0x79, + 0x40, 0xf6, 0x95, 0x00, 0xec, 0xf7, 0x10, 0xfb, 0x68, 0x89, 0xc0, 0xf3, + 0x81, 0x00, 0xd0, 0xb1, 0xa8, 0x6b, 0x00, 0xf0, 0x3e, 0xf8, 0x10, 0xb1, + 0xf7, 0xf7, 0x32, 0xf8, 0x08, 0xb9, 0x03, 0x26, 0x11, 0xe0, 0xa8, 0x6b, + 0x00, 0xf0, 0x1d, 0xf8, 0xa8, 0xbf, 0x64, 0x20, 0x00, 0xf0, 0x14, 0xf8, + 0x00, 0xf0, 0x2a, 0xf8, 0x9c, 0x21, 0x00, 0xf0, 0x28, 0xf8, 0x00, 0xf0, + 0x18, 0xf8, 0x00, 0xf0, 0x1b, 0xf8, 0x00, 0xb1, 0x04, 0x26, 0x48, 0x46, + 0x00, 0xf0, 0x43, 0xf8, 0x00, 0x20, 0xec, 0xf7, 0x9d, 0xfd, 0x30, 0x46, + 0xbd, 0xe8, 0xf2, 0x86, 0x00, 0xf0, 0x7f, 0x01, 0x50, 0x46, 0xec, 0xf7, + 0xe3, 0xba, 0x13, 0x49, 0xb0, 0xfb, 0xf1, 0xf0, 0xc0, 0xb2, 0x65, 0x28, + 0x70, 0x47, 0x20, 0x21, 0x4f, 0xf4, 0xd9, 0x70, 0xec, 0xf7, 0xd8, 0xba, + 0x4f, 0xf4, 0x7a, 0x73, 0x00, 0x22, 0x20, 0x21, 0x4f, 0xf4, 0xd9, 0x70, + 0xf2, 0xf7, 0x94, 0xbf, 0x1c, 0x21, 0x4f, 0xf4, 0xd2, 0x60, 0xec, 0xf7, + 0xcb, 0xba, 0xa4, 0xfb, 0x00, 0x23, 0x12, 0x0f, 0x42, 0xea, 0x03, 0x12, + 0x1b, 0x0f, 0x00, 0x20, 0xf7, 0xf7, 0x11, 0xb8, 0x78, 0x29, 0x00, 0x20, + 0x22, 0x18, 0x09, 0x91, 0x93, 0x06, 0x00, 0x46, 0x40, 0x42, 0x0f, 0x00, + 0x80, 0xb5, 0x00, 0x21, 0xff, 0xf7, 0xda, 0xff, 0x00, 0xf0, 0x18, 0xf8, + 0x1b, 0x21, 0x40, 0xf2, 0x91, 0x60, 0xec, 0xf7, 0xaf, 0xfa, 0xbd, 0xe8, + 0x04, 0x40, 0x7c, 0x21, 0x0a, 0xe0, 0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, + 0xdb, 0x21, 0x40, 0xf2, 0x91, 0x60, 0xec, 0xf7, 0xa3, 0xfa, 0xbd, 0xe8, + 0x04, 0x40, 0x7e, 0x21, 0x40, 0xf2, 0x0b, 0x20, 0xec, 0xf7, 0x9c, 0xba, + 0x07, 0x21, 0x40, 0xf2, 0x83, 0x10, 0xec, 0xf7, 0x97, 0xba, 0x00, 0x00, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0x2e, 0x4c, 0x2f, 0x48, 0x2f, 0x4d, 0x30, 0x49, + 0x20, 0x60, 0x20, 0x60, 0x01, 0x22, 0x00, 0x20, 0x28, 0x60, 0x08, 0x60, + 0x2d, 0x49, 0x08, 0x60, 0x0f, 0xf2, 0xd0, 0x01, 0x0f, 0xf2, 0xc8, 0x00, + 0x00, 0xf0, 0x66, 0xf8, 0x2a, 0x49, 0x28, 0x60, 0x09, 0x68, 0x88, 0x42, + 0x00, 0xd0, 0xfe, 0xe7, 0x00, 0x20, 0x20, 0x60, 0x20, 0x60, 0x27, 0x49, + 0x27, 0x48, 0x01, 0x60, 0x4f, 0xf4, 0xe0, 0x21, 0xc1, 0x61, 0x00, 0xf0, + 0x02, 0xf8, 0x00, 0xf0, 0xab, 0xb8, 0x1c, 0x48, 0x23, 0x4c, 0x4f, 0xf6, + 0xfe, 0x61, 0x01, 0x60, 0x01, 0x60, 0x22, 0x49, 0x0a, 0x78, 0x0b, 0x78, + 0x43, 0xf0, 0x08, 0x03, 0x0b, 0x70, 0x23, 0x46, 0x1d, 0x68, 0x1d, 0x60, + 0x1e, 0x68, 0xae, 0x42, 0x03, 0xd0, 0x17, 0x48, 0x00, 0x68, 0x03, 0x60, + 0xfe, 0xe7, 0x1b, 0x1d, 0x04, 0xf5, 0x80, 0x75, 0xab, 0x42, 0xf1, 0xd3, + 0x18, 0x4d, 0xab, 0x42, 0x14, 0xd2, 0x4f, 0xf0, 0xff, 0x35, 0x1d, 0x60, + 0x1d, 0x68, 0x15, 0xf1, 0x01, 0x0f, 0x03, 0xd0, 0x0d, 0x48, 0x00, 0x68, + 0x03, 0x60, 0xfe, 0xe7, 0x00, 0x25, 0x1d, 0x60, 0x1d, 0x68, 0x1d, 0xb1, + 0x09, 0x48, 0x00, 0x68, 0x03, 0x60, 0xfe, 0xe7, 0x1b, 0x1d, 0xe7, 0xe7, + 0x0a, 0x70, 0x00, 0x21, 0x01, 0x60, 0x01, 0x60, 0x70, 0x47, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x50, 0x00, 0x00, 0xab, 0xab, 0xe4, 0x7f, 0x01, 0x01, + 0xf0, 0x7f, 0x01, 0x01, 0xf4, 0x7f, 0x01, 0x01, 0xe0, 0x7f, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x0d, 0x00, 0x46, 0xff, 0xff, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, + 0xdf, 0x7f, 0x01, 0x01, 0x2d, 0xe9, 0xf0, 0x41, 0x00, 0x23, 0x00, 0x25, + 0x0f, 0xf2, 0x64, 0x08, 0x15, 0xe0, 0x17, 0xf8, 0x06, 0xe0, 0x4f, 0xea, + 0x1e, 0x14, 0x44, 0xea, 0x03, 0x14, 0x1b, 0x0f, 0x58, 0xf8, 0x23, 0x30, + 0x63, 0x40, 0x0e, 0xf0, 0x0f, 0x04, 0x44, 0xea, 0x03, 0x14, 0x1b, 0x0f, + 0x58, 0xf8, 0x23, 0x30, 0x63, 0x40, 0x7f, 0x1c, 0x67, 0x45, 0xea, 0xd3, + 0x6d, 0x1c, 0x95, 0x42, 0x08, 0xd2, 0x50, 0xf8, 0x25, 0x60, 0x51, 0xf8, + 0x25, 0x70, 0xbf, 0x1b, 0x07, 0xf1, 0x01, 0x0c, 0x00, 0x27, 0xf1, 0xe7, + 0x04, 0x20, 0x19, 0x0f, 0x58, 0xf8, 0x21, 0x10, 0x81, 0xea, 0x03, 0x11, + 0x0a, 0x0f, 0x58, 0xf8, 0x22, 0x20, 0x40, 0x1e, 0x82, 0xea, 0x01, 0x13, + 0xf3, 0xd1, 0x18, 0x46, 0xbd, 0xe8, 0xf0, 0x81, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x1d, 0xc1, 0x04, 0x6e, 0x3b, 0x82, 0x09, 0xd9, 0x26, 0x43, 0x0d, + 0xdc, 0x76, 0x04, 0x13, 0x6b, 0x6b, 0xc5, 0x17, 0xb2, 0x4d, 0x86, 0x1a, + 0x05, 0x50, 0x47, 0x1e, 0xb8, 0xed, 0x08, 0x26, 0x0f, 0xf0, 0xc9, 0x22, + 0xd6, 0xd6, 0x8a, 0x2f, 0x61, 0xcb, 0x4b, 0x2b, 0x64, 0x9b, 0x0c, 0x35, + 0xd3, 0x86, 0xcd, 0x31, 0x0a, 0xa0, 0x8e, 0x3c, 0xbd, 0xbd, 0x4f, 0x38, + 0x01, 0x20, 0xc0, 0x46, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x08, 0xf8, + 0x00, 0x20, 0xc0, 0x46, 0xc0, 0x46, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, + 0x6f, 0xf8, 0x00, 0x00, 0x10, 0xb5, 0x07, 0x49, 0x79, 0x44, 0x18, 0x31, + 0x06, 0x4c, 0x7c, 0x44, 0x16, 0x34, 0x04, 0xe0, 0x0a, 0x68, 0x08, 0x1d, + 0x51, 0x18, 0x88, 0x47, 0x01, 0x46, 0xa1, 0x42, 0xf8, 0xd1, 0x10, 0xbd, + 0x20, 0x0a, 0x00, 0x00, 0xfc, 0x0a, 0x00, 0x00, 0x00, 0xb5, 0x87, 0xb0, + 0xf1, 0xf7, 0x12, 0xf9, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, + 0xea, 0xf7, 0x74, 0xff, 0x03, 0x21, 0x04, 0x91, 0x00, 0x21, 0x03, 0x91, + 0x64, 0x21, 0x02, 0x91, 0x05, 0x21, 0x1e, 0x48, 0x01, 0x90, 0x00, 0x91, + 0x00, 0xf5, 0xc6, 0x72, 0x05, 0x23, 0x00, 0x21, 0x0f, 0xf2, 0x1d, 0x00, + 0xeb, 0xf7, 0xdd, 0xfd, 0x05, 0xaa, 0x0f, 0xf2, 0x70, 0x01, 0x05, 0x20, + 0xeb, 0xf7, 0x8e, 0xfe, 0xeb, 0xf7, 0x2b, 0xf8, 0x00, 0x20, 0x07, 0xb0, + 0x00, 0xbd, 0x00, 0x00, 0x80, 0xb5, 0xf0, 0xf7, 0x71, 0xff, 0x40, 0x1e, + 0x80, 0x41, 0xc0, 0x0f, 0xf1, 0xf7, 0x6d, 0xf8, 0xf7, 0xf7, 0x54, 0xf8, + 0x0e, 0x48, 0x00, 0x6c, 0x40, 0x1e, 0xb0, 0xf1, 0x80, 0x7f, 0x08, 0xd2, + 0x0c, 0x49, 0x0d, 0x4a, 0x48, 0x60, 0xf0, 0x20, 0x10, 0x70, 0x00, 0x20, + 0x88, 0x60, 0x07, 0x20, 0x08, 0x60, 0xea, 0xf7, 0xe1, 0xff, 0x68, 0x46, + 0xf2, 0xf7, 0xba, 0xfb, 0xea, 0xf7, 0xf1, 0xff, 0xf2, 0xf7, 0xec, 0xff, + 0xf2, 0xf7, 0xb2, 0xff, 0xfc, 0xe7, 0x00, 0x00, 0x48, 0x80, 0x00, 0x20, + 0x00, 0xf2, 0x00, 0x20, 0x10, 0xe0, 0x00, 0xe0, 0x23, 0xed, 0x00, 0xe0, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb8, + 0x07, 0x46, 0x38, 0x46, 0x00, 0xf0, 0x02, 0xf8, 0xfb, 0xe7, 0x00, 0x00, + 0x80, 0xb5, 0xc0, 0x46, 0xc0, 0x46, 0x02, 0x4a, 0x11, 0x00, 0x18, 0x20, + 0xab, 0xbe, 0xfb, 0xe7, 0x26, 0x00, 0x02, 0x00, 0x49, 0x6e, 0x69, 0x74, + 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x78, 0x31, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0x52, 0x78, 0x32, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0x54, 0x78, 0x31, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0x54, 0x78, 0x32, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0x54, 0x78, 0x31, 0x20, 0x4c, 0x4f, 0x4c, 0x20, 0x43, 0x61, 0x6c, 0x54, + 0x61, 0x73, 0x6b, 0x00, 0x54, 0x78, 0x32, 0x20, 0x4c, 0x4f, 0x4c, 0x20, + 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, 0x4f, 0x52, 0x58, 0x31, + 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x52, 0x58, 0x32, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x78, 0x31, 0x20, 0x44, 0x50, 0x44, 0x20, + 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, 0x54, 0x78, 0x32, 0x20, + 0x44, 0x50, 0x44, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0x54, 0x78, 0x31, 0x20, 0x43, 0x4c, 0x47, 0x43, 0x20, 0x43, 0x61, 0x6c, + 0x54, 0x61, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x54, 0x78, 0x32, 0x20, + 0x43, 0x4c, 0x47, 0x43, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x78, 0x31, 0x20, 0x56, 0x53, 0x57, 0x52, + 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x78, 0x32, 0x20, 0x56, 0x53, 0x57, 0x52, 0x20, 0x43, 0x61, 0x6c, + 0x54, 0x61, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x54, 0x78, 0x31, 0x20, + 0x50, 0x41, 0x20, 0x42, 0x49, 0x41, 0x53, 0x20, 0x43, 0x61, 0x6c, 0x54, + 0x61, 0x73, 0x6b, 0x00, 0x54, 0x78, 0x32, 0x20, 0x50, 0x41, 0x20, 0x42, + 0x49, 0x41, 0x53, 0x20, 0x43, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x00, + 0xc5, 0xfe, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x16, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, + 0xdd, 0x59, 0x01, 0x01, 0xe5, 0x59, 0x01, 0x01, 0x38, 0x00, 0x00, 0x00, + 0xc7, 0xdc, 0x00, 0x01, 0xe5, 0xdc, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0x61, 0x00, 0x01, 0xf7, 0x61, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, + 0x4b, 0x34, 0x00, 0x01, 0x4d, 0x34, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, + 0x98, 0x02, 0x00, 0x20, 0x10, 0x01, 0x00, 0x00, 0xa8, 0x03, 0x00, 0x20, + 0x10, 0x01, 0x00, 0x00, 0xdc, 0x2a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x00, + 0x8c, 0x2b, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x30, 0x27, 0x00, 0x20, + 0x44, 0x00, 0x01, 0x00, 0xd8, 0x26, 0x00, 0x20, 0x3a, 0x00, 0x01, 0x00, + 0xf8, 0x2b, 0x00, 0x20, 0x1a, 0x00, 0x00, 0x00, 0x74, 0xf3, 0x00, 0x20, + 0x02, 0x00, 0x00, 0x00, 0x04, 0xea, 0x00, 0x20, 0xa0, 0xea, 0x00, 0x20, + 0x9c, 0x00, 0x00, 0x00, 0x3c, 0xeb, 0x00, 0x20, 0xd8, 0xeb, 0x00, 0x20, + 0x9c, 0x00, 0x00, 0x00, 0x98, 0xf1, 0x00, 0x20, 0xcc, 0xf1, 0x00, 0x20, + 0x34, 0x00, 0x00, 0x00, 0xb4, 0x2b, 0x00, 0x20, 0xd0, 0x2b, 0x00, 0x20, + 0x1c, 0x00, 0x00, 0x00, 0x74, 0x27, 0x00, 0x20, 0x08, 0x28, 0x00, 0x20, + 0x94, 0x00, 0x00, 0x00, 0xa8, 0xef, 0x00, 0x20, 0xec, 0xef, 0x00, 0x20, + 0x44, 0x00, 0x00, 0x00, 0x94, 0xed, 0x00, 0x20, 0xe8, 0xed, 0x00, 0x20, + 0x54, 0x00, 0x00, 0x00, 0x40, 0xf3, 0x00, 0x20, 0x44, 0xf3, 0x00, 0x20, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, + 0x83, 0xb0, 0x07, 0x46, 0xed, 0xf7, 0x12, 0xf9, 0xed, 0xf7, 0xe6, 0xf8, + 0x00, 0x2f, 0x04, 0x46, 0x0c, 0xbf, 0x02, 0x25, 0x03, 0x25, 0x35, 0x4e, + 0xdf, 0xf8, 0xd4, 0x80, 0xed, 0xf7, 0x13, 0xf9, 0xb8, 0x55, 0x4f, 0xf0, + 0x6c, 0x0a, 0x28, 0x46, 0xf8, 0xf7, 0x65, 0xff, 0x07, 0xf1, 0x1f, 0x00, + 0x8d, 0xf8, 0x04, 0x00, 0x4c, 0xb9, 0x06, 0xe0, 0x01, 0x21, 0xed, 0xf7, + 0x27, 0xf9, 0x14, 0xb1, 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, 0xed, 0xf7, + 0x81, 0xf9, 0xb8, 0x5d, 0x03, 0x21, 0xed, 0xf7, 0x1d, 0xf9, 0xb8, 0x5d, + 0x00, 0x21, 0xed, 0xf7, 0x19, 0xf9, 0x9d, 0xf8, 0x04, 0x00, 0x01, 0x21, + 0xf0, 0xf7, 0xc3, 0xff, 0xed, 0xf7, 0x48, 0xf9, 0xed, 0xf7, 0xed, 0xf8, + 0x0a, 0xfb, 0x00, 0x89, 0xeb, 0xf7, 0x56, 0xfd, 0xc9, 0xf8, 0x38, 0x00, + 0x4f, 0xf4, 0x60, 0x71, 0x06, 0xf1, 0x08, 0x00, 0x01, 0xfb, 0x07, 0x02, + 0x01, 0x21, 0x28, 0x46, 0xf8, 0xf7, 0x3c, 0xff, 0x81, 0x46, 0x00, 0x20, + 0xec, 0xf7, 0xb5, 0xfa, 0xed, 0xf7, 0xd7, 0xf8, 0x83, 0x46, 0xeb, 0xf7, + 0x41, 0xfd, 0x0a, 0xfb, 0x0b, 0x81, 0x8a, 0x6b, 0x82, 0x42, 0x23, 0xbf, + 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, 0x80, 0x1a, 0xc8, 0x63, + 0x00, 0x21, 0x9d, 0xf8, 0x04, 0x00, 0xf0, 0xf7, 0x96, 0xff, 0xb8, 0x5d, + 0xb9, 0xf1, 0x00, 0x0f, 0xb8, 0xd0, 0x02, 0x21, 0xed, 0xf7, 0xe0, 0xf8, + 0xb8, 0x5d, 0x01, 0x21, 0xed, 0xf7, 0xdc, 0xf8, 0xed, 0xf7, 0xbe, 0xf8, + 0x0d, 0xf1, 0x05, 0x01, 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, 0x20, 0x21, + 0xeb, 0xf7, 0xbe, 0xf8, 0xa9, 0xe7, 0x00, 0x00, 0x48, 0xc8, 0x00, 0x20, + 0x8c, 0x09, 0x00, 0x20, 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, + 0x83, 0xb0, 0x07, 0x46, 0xed, 0xf7, 0x94, 0xf8, 0xed, 0xf7, 0x68, 0xf8, + 0x04, 0x46, 0x38, 0x00, 0x18, 0xbf, 0x01, 0x20, 0x8d, 0xf8, 0x04, 0x00, + 0xed, 0xf7, 0x97, 0xf8, 0x32, 0x4d, 0xdf, 0xf8, 0xcc, 0x80, 0x78, 0x55, + 0x07, 0xf1, 0x1d, 0x06, 0x9d, 0xf8, 0x04, 0x00, 0xf8, 0xf7, 0xe5, 0xfe, + 0x4f, 0xf0, 0x6c, 0x0a, 0x4c, 0xb9, 0x06, 0xe0, 0x01, 0x21, 0xed, 0xf7, + 0xa9, 0xf8, 0x14, 0xb1, 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, 0xed, 0xf7, + 0x03, 0xf9, 0x78, 0x5d, 0x03, 0x21, 0xed, 0xf7, 0x9f, 0xf8, 0x78, 0x5d, + 0x00, 0x21, 0xed, 0xf7, 0x9b, 0xf8, 0x01, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, + 0x46, 0xff, 0xed, 0xf7, 0xcb, 0xf8, 0xed, 0xf7, 0x70, 0xf8, 0x0a, 0xfb, + 0x00, 0x89, 0xeb, 0xf7, 0xd9, 0xfc, 0xc9, 0xf8, 0x38, 0x00, 0x4f, 0xf4, + 0x60, 0x71, 0x05, 0xf1, 0x08, 0x00, 0x01, 0xfb, 0x07, 0x02, 0x9d, 0xf8, + 0x04, 0x00, 0x01, 0x21, 0xf8, 0xf7, 0xbd, 0xfe, 0x81, 0x46, 0x00, 0x20, + 0xec, 0xf7, 0x37, 0xfa, 0xed, 0xf7, 0x59, 0xf8, 0x83, 0x46, 0xeb, 0xf7, + 0xc3, 0xfc, 0x0a, 0xfb, 0x0b, 0x81, 0x8a, 0x6b, 0x82, 0x42, 0x23, 0xbf, + 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, 0x80, 0x1a, 0xc8, 0x63, + 0x00, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0x19, 0xff, 0x78, 0x5d, 0xb9, 0xf1, + 0x00, 0x0f, 0xb9, 0xd0, 0x02, 0x21, 0xed, 0xf7, 0x63, 0xf8, 0x78, 0x5d, + 0x01, 0x21, 0xed, 0xf7, 0x5f, 0xf8, 0xed, 0xf7, 0x41, 0xf8, 0x0d, 0xf1, + 0x05, 0x01, 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, 0x20, 0x21, 0xeb, 0xf7, + 0x41, 0xf8, 0xaa, 0xe7, 0x50, 0xcf, 0x00, 0x20, 0x8c, 0x09, 0x00, 0x20, + 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xfe, 0x4f, 0x05, 0x46, 0xed, 0xf7, + 0x19, 0xf8, 0xec, 0xf7, 0xed, 0xff, 0x04, 0x46, 0x02, 0x95, 0xed, 0xf7, + 0x20, 0xf8, 0x81, 0x46, 0x02, 0x98, 0xdf, 0xf8, 0xb8, 0x80, 0x01, 0x27, + 0x00, 0xf1, 0x25, 0x06, 0x4f, 0xf0, 0x6c, 0x0a, 0x44, 0xb9, 0x05, 0xe0, + 0x00, 0xf0, 0x56, 0xf8, 0x14, 0xb1, 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, + 0xed, 0xf7, 0x90, 0xf8, 0x00, 0x21, 0x00, 0xf0, 0x4e, 0xf8, 0x01, 0x21, + 0xf0, 0xb2, 0xf0, 0xf7, 0xd8, 0xfe, 0xed, 0xf7, 0x5d, 0xf8, 0xed, 0xf7, + 0x02, 0xf8, 0x0a, 0xfb, 0x00, 0x85, 0xeb, 0xf7, 0x6b, 0xfc, 0xa8, 0x63, + 0xc8, 0x23, 0x02, 0x99, 0x1d, 0x48, 0x03, 0xfb, 0x01, 0x01, 0x02, 0x98, + 0x3a, 0x46, 0xf6, 0xf7, 0x3b, 0xfd, 0x05, 0x46, 0x00, 0x21, 0xf0, 0xb2, + 0xf0, 0xf7, 0xc1, 0xfe, 0x00, 0x20, 0xec, 0xf7, 0xc8, 0xf9, 0xec, 0xf7, + 0xea, 0xff, 0x83, 0x46, 0xeb, 0xf7, 0x54, 0xfc, 0x0a, 0xfb, 0x0b, 0x81, + 0x00, 0x27, 0x8a, 0x6b, 0x82, 0x42, 0x23, 0xbf, 0x4f, 0xf0, 0xff, 0x33, + 0x9a, 0x1a, 0x80, 0x18, 0x80, 0x1a, 0xc8, 0x63, 0x01, 0x2d, 0x18, 0xbf, + 0x02, 0x2d, 0x04, 0xd0, 0x03, 0x2d, 0x1c, 0xbf, 0x04, 0x2d, 0x0c, 0x2d, + 0xbc, 0xd1, 0x02, 0x21, 0x00, 0xf0, 0x13, 0xf8, 0x00, 0xf0, 0x10, 0xf8, + 0xec, 0xf7, 0xd2, 0xff, 0x01, 0xa9, 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, + 0x20, 0x21, 0xea, 0xf7, 0xd3, 0xff, 0xaf, 0xe7, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0x09, 0x00, 0x20, 0x74, 0xe8, 0x00, 0x20, 0x01, 0x21, 0x48, 0x46, + 0xec, 0xf7, 0xdc, 0xbf, 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, + 0x83, 0xb0, 0x83, 0x46, 0xec, 0xf7, 0xa4, 0xff, 0xec, 0xf7, 0x78, 0xff, + 0x04, 0x46, 0xec, 0xf7, 0xac, 0xff, 0x81, 0x46, 0x0b, 0xf1, 0x29, 0x06, + 0x6c, 0x27, 0xdf, 0xf8, 0xac, 0x80, 0x4c, 0xb9, 0x06, 0xe0, 0x01, 0x21, + 0x00, 0xf0, 0x54, 0xf8, 0x14, 0xb1, 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, + 0xed, 0xf7, 0x1e, 0xf8, 0x00, 0x21, 0x00, 0xf0, 0x4b, 0xf8, 0x01, 0x21, + 0xf0, 0xb2, 0xf0, 0xf7, 0x66, 0xfe, 0xec, 0xf7, 0xeb, 0xff, 0xec, 0xf7, + 0x90, 0xff, 0x07, 0xfb, 0x00, 0x85, 0xeb, 0xf7, 0xf9, 0xfb, 0xa8, 0x63, + 0x1d, 0x48, 0x00, 0xeb, 0x4b, 0x11, 0x58, 0x46, 0xee, 0xf7, 0x55, 0xff, + 0x05, 0x46, 0x00, 0x20, 0xec, 0xf7, 0x5d, 0xf9, 0xec, 0xf7, 0x7f, 0xff, + 0x82, 0x46, 0xeb, 0xf7, 0xe9, 0xfb, 0x07, 0xfb, 0x0a, 0x81, 0x8a, 0x6b, + 0x82, 0x42, 0x23, 0xbf, 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, + 0x80, 0x1a, 0xc8, 0x63, 0x00, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0x3f, 0xfe, + 0x01, 0x2d, 0x18, 0xbf, 0x02, 0x2d, 0x04, 0xd0, 0x04, 0x2d, 0x1c, 0xbf, + 0x05, 0x2d, 0x0b, 0x2d, 0xbf, 0xd1, 0x02, 0x21, 0x00, 0xf0, 0x14, 0xf8, + 0x01, 0x21, 0x00, 0xf0, 0x11, 0xf8, 0xec, 0xf7, 0x63, 0xff, 0x01, 0xa9, + 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, 0x20, 0x21, 0xea, 0xf7, 0x64, 0xff, + 0x03, 0x21, 0xaf, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x09, 0x00, 0x20, + 0x48, 0xf2, 0x00, 0x20, 0x48, 0x46, 0xec, 0xf7, 0x6d, 0xbf, 0x00, 0x00, + 0x80, 0xb5, 0x01, 0x29, 0x08, 0xbf, 0xfe, 0xf7, 0xbe, 0xfb, 0x00, 0x20, + 0x02, 0xbd, 0x2d, 0xe9, 0xf0, 0x4f, 0x83, 0xb0, 0x83, 0x46, 0xec, 0xf7, + 0x2f, 0xff, 0xec, 0xf7, 0x03, 0xff, 0x04, 0x46, 0xec, 0xf7, 0x37, 0xff, + 0x81, 0x46, 0x0b, 0xf1, 0x23, 0x06, 0x6c, 0x27, 0xdf, 0xf8, 0x98, 0x80, + 0x44, 0xb9, 0x05, 0xe0, 0x00, 0xf0, 0x4c, 0xf8, 0x14, 0xb1, 0x14, 0xf1, + 0x01, 0x0f, 0x01, 0xd0, 0xec, 0xf7, 0xaa, 0xff, 0x00, 0x21, 0x00, 0xf0, + 0x44, 0xf8, 0x01, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0xf2, 0xfd, 0xec, 0xf7, + 0x77, 0xff, 0xec, 0xf7, 0x1c, 0xff, 0x07, 0xfb, 0x00, 0x85, 0xeb, 0xf7, + 0x85, 0xfb, 0xa8, 0x63, 0x4f, 0xf4, 0x22, 0x71, 0x18, 0x48, 0x01, 0xfb, + 0x0b, 0x01, 0x58, 0x46, 0xfe, 0xf7, 0xd6, 0xfa, 0x05, 0x46, 0x00, 0x20, + 0xec, 0xf7, 0xe7, 0xf8, 0xec, 0xf7, 0x09, 0xff, 0x82, 0x46, 0xeb, 0xf7, + 0x73, 0xfb, 0x07, 0xfb, 0x0a, 0x81, 0x8a, 0x6b, 0x82, 0x42, 0x23, 0xbf, + 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, 0x80, 0x1a, 0xc8, 0x63, + 0x00, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0xc9, 0xfd, 0x00, 0x2d, 0xc5, 0xd0, + 0x02, 0x21, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0xf0, 0x0f, 0xf8, 0xec, 0xf7, + 0xf5, 0xfe, 0x01, 0xa9, 0x00, 0x91, 0x00, 0x23, 0x82, 0x22, 0x20, 0x21, + 0xea, 0xf7, 0xf6, 0xfe, 0xb8, 0xe7, 0x00, 0x00, 0x8c, 0x09, 0x00, 0x20, + 0x58, 0xd6, 0x00, 0x20, 0x01, 0x21, 0x48, 0x46, 0xec, 0xf7, 0x00, 0xbf, + 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, 0x83, 0xb0, 0x83, 0x46, + 0xec, 0xf7, 0xc8, 0xfe, 0xec, 0xf7, 0x9c, 0xfe, 0x04, 0x46, 0xec, 0xf7, + 0xd0, 0xfe, 0x81, 0x46, 0x0b, 0xf1, 0x27, 0x06, 0x6c, 0x27, 0xdf, 0xf8, + 0xa0, 0x80, 0x44, 0xb9, 0x05, 0xe0, 0x00, 0xf0, 0x4d, 0xf8, 0x14, 0xb1, + 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, 0xec, 0xf7, 0x43, 0xff, 0x00, 0x21, + 0x00, 0xf0, 0x45, 0xf8, 0x01, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0x8b, 0xfd, + 0xec, 0xf7, 0x10, 0xff, 0xec, 0xf7, 0xb5, 0xfe, 0x07, 0xfb, 0x00, 0x85, + 0xeb, 0xf7, 0x1e, 0xfb, 0xa8, 0x63, 0x58, 0x46, 0xf3, 0xf7, 0xea, 0xf8, + 0x05, 0x46, 0x00, 0x20, 0xec, 0xf7, 0x85, 0xf8, 0xec, 0xf7, 0xa7, 0xfe, + 0x82, 0x46, 0xeb, 0xf7, 0x11, 0xfb, 0x07, 0xfb, 0x0a, 0x81, 0x8a, 0x6b, + 0x82, 0x42, 0x23, 0xbf, 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, + 0x80, 0x1a, 0xc8, 0x63, 0x00, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0x67, 0xfd, + 0x05, 0x2d, 0x18, 0xbf, 0x01, 0x2d, 0x04, 0xd0, 0x06, 0x2d, 0x1c, 0xbf, + 0x02, 0x2d, 0x0e, 0x2d, 0xc3, 0xd1, 0x02, 0x21, 0x00, 0xf0, 0x11, 0xf8, + 0x00, 0xf0, 0x0e, 0xf8, 0xec, 0xf7, 0x8c, 0xfe, 0x01, 0xa9, 0x00, 0x91, + 0x00, 0x23, 0x82, 0x22, 0x20, 0x21, 0xea, 0xf7, 0x8d, 0xfe, 0xb6, 0xe7, + 0x00, 0x00, 0x00, 0x00, 0x8c, 0x09, 0x00, 0x20, 0x01, 0x21, 0x48, 0x46, + 0xec, 0xf7, 0x98, 0xbe, 0x00, 0x20, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x4f, + 0x83, 0xb0, 0x83, 0x46, 0xec, 0xf7, 0x60, 0xfe, 0xec, 0xf7, 0x34, 0xfe, + 0x04, 0x46, 0xec, 0xf7, 0x68, 0xfe, 0x81, 0x46, 0x0b, 0xf1, 0x21, 0x06, + 0x6c, 0x27, 0xdf, 0xf8, 0x98, 0x80, 0x44, 0xb9, 0x05, 0xe0, 0x00, 0xf0, + 0x4b, 0xf8, 0x14, 0xb1, 0x14, 0xf1, 0x01, 0x0f, 0x01, 0xd0, 0xec, 0xf7, + 0xdb, 0xfe, 0x00, 0x21, 0x00, 0xf0, 0x43, 0xf8, 0x01, 0x21, 0xf0, 0xb2, + 0xf0, 0xf7, 0x23, 0xfd, 0xec, 0xf7, 0xa8, 0xfe, 0xec, 0xf7, 0x4d, 0xfe, + 0x07, 0xfb, 0x00, 0x85, 0xeb, 0xf7, 0xb6, 0xfa, 0xa8, 0x63, 0x38, 0x21, + 0x18, 0x48, 0x01, 0xfb, 0x0b, 0x01, 0x58, 0x46, 0xea, 0xf7, 0x2e, 0xf8, + 0x05, 0x46, 0x00, 0x20, 0xec, 0xf7, 0x19, 0xf8, 0xec, 0xf7, 0x3b, 0xfe, + 0x82, 0x46, 0xeb, 0xf7, 0xa5, 0xfa, 0x07, 0xfb, 0x0a, 0x81, 0x8a, 0x6b, + 0x82, 0x42, 0x23, 0xbf, 0x4f, 0xf0, 0xff, 0x33, 0x9a, 0x1a, 0x80, 0x18, + 0x80, 0x1a, 0xc8, 0x63, 0x00, 0x21, 0xf0, 0xb2, 0xf0, 0xf7, 0xfb, 0xfc, + 0x00, 0x2d, 0xc6, 0xd0, 0x02, 0x21, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0xf0, + 0x0f, 0xf8, 0xec, 0xf7, 0x27, 0xfe, 0x01, 0xa9, 0x00, 0x91, 0x00, 0x23, + 0x82, 0x22, 0x20, 0x21, 0xea, 0xf7, 0x28, 0xfe, 0xb9, 0xe7, 0x00, 0x00, + 0x8c, 0x09, 0x00, 0x20, 0x28, 0xf1, 0x00, 0x20, 0x01, 0x21, 0x48, 0x46, + 0xec, 0xf7, 0x32, 0xbe, 0x78, 0x29, 0x00, 0x20, 0x64, 0x00, 0x00, 0x00, + 0x4c, 0x1f, 0x00, 0x20, 0x84, 0x00, 0x00, 0x00, 0xd4, 0x28, 0x00, 0x20, + 0x21, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x20, 0x5c, 0x00, 0x00, 0x00, + 0x84, 0xf3, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x1f, 0x00, 0x20, + 0x14, 0x00, 0x00, 0x00, 0x30, 0x1f, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, + 0x88, 0x02, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x19, 0xe0, 0x50, 0xf8, + 0x04, 0x1b, 0xcb, 0x07, 0x44, 0xbf, 0xa9, 0xf1, 0x01, 0x03, 0x59, 0x18, + 0x12, 0x1f, 0x00, 0x23, 0x04, 0x2a, 0x41, 0xf8, 0x04, 0x3b, 0xf9, 0xd2, + 0x5f, 0xea, 0x82, 0x7c, 0x0b, 0x46, 0x04, 0xd5, 0x4f, 0xf0, 0x00, 0x0c, + 0xa1, 0xf8, 0x00, 0xc0, 0x9b, 0x1c, 0xd1, 0x07, 0x44, 0xbf, 0x00, 0x21, + 0x19, 0x70, 0x50, 0xf8, 0x04, 0x2b, 0x00, 0x2a, 0xe1, 0xd1, 0x70, 0x47, + 0x80, 0xb5, 0x01, 0x29, 0x04, 0xd0, 0x02, 0x29, 0x08, 0xbf, 0xf2, 0xf7, + 0x8d, 0xf8, 0x01, 0xe0, 0xf2, 0xf7, 0xce, 0xf8, 0x00, 0x20, 0x02, 0xbd, + 0x10, 0xb5, 0x07, 0x4c, 0x02, 0x21, 0x21, 0x60, 0x00, 0x21, 0x61, 0x60, + 0xf2, 0xf7, 0xd9, 0xf8, 0x08, 0x21, 0x60, 0x60, 0x21, 0x60, 0x20, 0x46, + 0xeb, 0xf7, 0xbe, 0xff, 0xfe, 0xe7, 0x00, 0x00, 0x28, 0xf3, 0x00, 0x20, + 0x38, 0xb5, 0x0c, 0x4c, 0x0c, 0x49, 0x20, 0x68, 0xc9, 0x6a, 0x88, 0x42, + 0x34, 0xbf, 0x65, 0x79, 0x25, 0x79, 0x2a, 0x46, 0x7f, 0x21, 0x4f, 0xf4, + 0x9e, 0x60, 0xeb, 0xf7, 0x91, 0xfc, 0x94, 0xf9, 0x06, 0x00, 0x41, 0x19, + 0xc9, 0xb2, 0x4f, 0xf4, 0xe2, 0x60, 0xeb, 0xf7, 0x7f, 0xfc, 0x00, 0x20, + 0x32, 0xbd, 0x00, 0x00, 0x70, 0x29, 0x00, 0x20, 0x78, 0x29, 0x00, 0x20, + 0x49, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x00, 0x68, 0x2c, 0x00, 0x20, + 0x00, 0x08, 0x00, 0x00, 0x68, 0x36, 0x00, 0x20, 0x00, 0x02, 0x00, 0x00, + 0x68, 0x76, 0x00, 0x20, 0x00, 0x06, 0x00, 0x00, 0x68, 0x4e, 0x00, 0x20, + 0x00, 0x06, 0x00, 0x00, 0x68, 0x54, 0x00, 0x20, 0x00, 0x06, 0x00, 0x00, + 0x68, 0x5a, 0x00, 0x20, 0x00, 0x06, 0x00, 0x00, 0x68, 0x60, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x68, 0x66, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x68, 0x6a, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x68, 0x6e, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x68, 0x72, 0x00, 0x20, 0x00, 0x08, 0x00, 0x00, + 0x68, 0x3e, 0x00, 0x20, 0x00, 0x08, 0x00, 0x00, 0x68, 0x46, 0x00, 0x20, + 0xf0, 0x01, 0x00, 0x00, 0x68, 0x7c, 0x00, 0x20, 0xf0, 0x01, 0x00, 0x00, + 0x58, 0x7e, 0x00, 0x20, 0x70, 0x00, 0x00, 0x00, 0xd8, 0x81, 0x00, 0x20, + 0x70, 0x00, 0x00, 0x00, 0x48, 0x82, 0x00, 0x20, 0x00, 0x02, 0x00, 0x00, + 0x68, 0x78, 0x00, 0x20, 0x90, 0x01, 0x00, 0x00, 0x48, 0x80, 0x00, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x68, 0x7a, 0x00, 0x20, 0x80, 0x36, 0x00, 0x00, + 0x20, 0xbd, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xcb, 0xb7, 0xfe, 0xff, + 0xc8, 0x00, 0x00, 0x00, 0x72, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, + 0x59, 0x51, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x70, 0x89, 0xfe, 0xff, + 0x90, 0xbc, 0x00, 0x20, 0x84, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x9c, 0xbc, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x47, + 0x80, 0xb5, 0xec, 0xf7, 0x11, 0xfd, 0xec, 0xf7, 0xe5, 0xfc, 0xbd, 0xe8, + 0x01, 0x40, 0xec, 0xf7, 0x18, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x25, 0xe0, 0x02, + 0xd4, 0x01, 0xbf, 0x00, 0x63, 0x00, 0x00, 0x05, 0x4b, 0x01, 0xc4, 0x07, + 0x32, 0x01, 0xf8, 0x04, 0x99, 0x00, 0xbc, 0x03, 0x24, 0x00, 0x30, 0x00, + 0x1e, 0x00, 0x17, 0x00, 0xcd, 0x00, 0xc4, 0x01, 0x80, 0x01, 0xc7, 0x00, + 0x69, 0x20, 0x10, 0x0b, 0xb6, 0x02, 0x22, 0x07, 0x56, 0x03, 0xd5, 0x05, + 0x72, 0x02, 0xe5, 0x03, 0x17, 0x20, 0x10, 0x0b, 0x26, 0x00, 0x1d, 0x00, + 0xe3, 0x00, 0xf0, 0x02, 0xc7, 0x01, 0xc1, 0x00, 0x65, 0x20, 0x10, 0x0b, + 0xbf, 0x00, 0x89, 0x07, 0xa8, 0x00, 0x04, 0x05, 0x56, 0x00, 0xe9, 0x03, + 0x27, 0x20, 0xf0, 0x04, 0x0f, 0x1f, 0x00, 0x18, 0x00, 0xcf, 0x00, 0x60, + 0x80, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x52, 0xff, 0x01, + 0x30, 0x01, 0x00, 0x00, 0x64, 0x16, 0x50, 0x01, 0xdf, 0xa2, 0x05, 0x1e, + 0x10, 0x01, 0x03, 0x00, 0x0a, 0x0a, 0xf0, 0x31, 0x00, 0xb8, 0x0c, 0xf6, + 0x0d, 0x42, 0x15, 0x4f, 0x1b, 0xf9, 0x24, 0xb1, 0x2d, 0xb7, 0x39, 0xd5, + 0x44, 0xeb, 0x52, 0xfe, 0x5f, 0x8b, 0x6f, 0xe2, 0x7d, 0x14, 0x8e, 0xc9, + 0x9c, 0x9f, 0xac, 0xa8, 0xba, 0x0e, 0xc9, 0x5d, 0xd5, 0x45, 0xe1, 0xde, + 0xea, 0x5f, 0xf3, 0x79, 0xf9, 0xe7, 0xfd, 0xff, 0xff, 0x1f, 0xe0, 0x00, + 0x01, 0x12, 0x03, 0x71, 0x10, 0x0a, 0x0a, 0xd7, 0xa3, 0x3b, 0x00, 0x00, + 0x80, 0x40, 0xac, 0xc5, 0xa7, 0x38, 0x22, 0x20, 0x0f, 0x3f, 0x6f, 0x12, + 0x83, 0x3a, 0x17, 0xb7, 0xd1, 0x38, 0x95, 0xbf, 0xd6, 0x33, 0x0a, 0xd7, + 0x23, 0x3c, 0x04, 0x11, 0x20, 0x20, 0x5f, 0x3f, 0xed, 0xdf, 0x4b, 0x3e, + 0x33, 0x63, 0x94, 0x35, 0xdc, 0x6e, 0xc8, 0x37, 0x5e, 0x72, 0x0b, 0x37, + 0x1a, 0xd6, 0x38, 0x36, 0x46, 0xf6, 0x71, 0x35, 0x0f, 0xde, 0x8e, 0x34, + 0xc7, 0xb4, 0x6f, 0x33, 0x63, 0x2e, 0x2e, 0x31, 0x06, 0xb1, 0xe7, 0x31, + 0x88, 0x5d, 0x01, 0x33, 0xe2, 0x10, 0x70, 0x33, 0x5b, 0xb5, 0xaf, 0x33, + 0x34, 0x9f, 0xe3, 0x33, 0xb3, 0x7c, 0x07, 0x34, 0xdb, 0x33, 0x1d, 0x34, + 0x6c, 0x83, 0x31, 0x34, 0xa5, 0x95, 0x47, 0x34, 0xae, 0xb5, 0x64, 0x34, + 0xb7, 0xff, 0x8a, 0x34, 0x99, 0x7f, 0xc1, 0x34, 0x10, 0x6f, 0x2e, 0x35, + 0xa0, 0xd0, 0x56, 0x36, 0xbd, 0x37, 0x86, 0x35, 0x9e, 0x21, 0x8c, 0x21, + 0xee, 0x12, 0x06, 0x04, 0x12, 0x08, 0x04, 0x20, 0x02, 0xf9, 0x83, 0x01, + 0x3d, 0x04, 0xc1, 0xba, 0x45, 0x10, 0xf4, 0x01, 0x5c, 0xb6, 0x5c, 0x38, + 0x10, 0x21, 0x04, 0xf5, 0x85, 0x10, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0x21, 0x01, 0xb0, 0x05, 0xff, 0x00, 0x07, 0x00, + 0x01, 0x00, 0x00, 0x04, 0x43, 0x90, 0x01, 0x04, 0x43, 0x70, 0x17, 0x04, + 0xc3, 0x32, 0x00, 0x04, 0x52, 0xc8, 0x04, 0x43, 0xe8, 0x03, 0x04, 0xd2, + 0x20, 0x04, 0x2d, 0xf0, 0x05, 0xf2, 0xff, 0x00, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, + 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0xff, 0x01, 0xf1, 0x20, 0x01, + 0xfc, 0x0d, 0x02, 0x01, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x91, 0x16, 0x2d, 0x76, 0x1c, 0x8f, + 0xa0, 0x0f, 0xc8, 0x16, 0x21, 0x04, 0x2d, 0x00, 0x17, 0x12, 0x5e, 0x05, + 0x33, 0x30, 0x75, 0x31, 0x1e, 0x20, 0xa6, 0x1c, 0x2e, 0x20, 0x17, 0x17, + 0xe0, 0x02, 0xff, 0x7f, 0x01, 0x01, 0x43, 0x12, 0x0c, 0x11, 0x80, 0x06, + 0x3f, 0x0c, 0xc8, 0x16, 0xf0, 0x00, 0x00, 0x00, 0x1d, 0x10, 0x0a, 0x3c, + 0x3c, 0xb3, 0x28, 0x00, 0x00, 0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x80, 0x0e, + 0x13, 0x00, 0xb1, 0x0e, 0x3c, 0x01, 0x2d, 0xe0, 0x2d, 0x94, 0x1b, 0x1c, + 0x01, 0x30, 0x00, 0xb1, 0xed, 0x1a, 0x30, 0x01, 0x31, 0xe0, 0x31, 0x0e, + 0x43, 0x23, 0x00, 0x84, 0x1e, 0x23, 0x56, 0x17, 0x50, 0x0e, 0x03, 0x00, + 0xb4, 0x2c, 0x10, 0x20, 0x0f, 0xaa, 0x0f, 0xaa, 0x00, 0x89, 0xb7, 0x2d, + 0x00, 0x30, 0x0a, 0x40, 0x01, 0x2e, 0x00, 0x24, 0x0a, 0xfd, 0x07, 0x50, + 0x17, 0x40, 0x03, 0x44, 0x00, 0x00, 0x50, 0x40, 0x04, 0x21, 0x0c, 0x12, + 0x58, 0x08, 0x70, 0x02, 0x58, 0x00, 0x00, 0x10, 0x18, 0xb2, 0x80, 0x18, + 0x92, 0x08, 0x0c, 0xf1, 0x46, 0x01, 0xf2, 0x02, 0x80, 0x5a, 0xf1, 0x36, + 0x14, 0x54, 0x06, 0x01, 0x02, 0x07, 0x08, 0x05, 0x06, 0x03, 0x04, 0xd2, + 0x62, 0x10, 0x1a, 0x6d, 0x5c, 0x1e, 0x2c, 0x02, 0xb9, 0x76, 0x01, 0x01, + 0x5c, 0x1e, 0xf1, 0x13, 0xdc, 0x12, 0x04, 0x25, 0x10, 0x03, 0xf0, 0x6d, + 0x01, 0x01, 0xd1, 0x34, 0x17, 0x68, 0x36, 0xe4, 0x42, 0x02, 0x14, 0x2d, + 0xf0, 0x18, 0x56, 0x01, 0xce, 0x21, 0x58, 0x25, 0xa0, 0xf3, 0x19, 0x05, + 0x71, 0x58, 0x22, 0x12, 0x25, 0x10, 0x02, 0x6e, 0x01, 0x01, 0x09, 0x34, + 0x40, 0x04, 0x68, 0x5a, 0x00, 0x20, 0x80, 0x01, 0x58, 0x21, 0x52, 0x22, + 0x02, 0x65, 0x11, 0x01, 0xf1, 0x0b, 0x58, 0xf2, 0x06, 0x01, 0x65, 0x12, + 0x13, 0x18, 0x62, 0x0c, 0x58, 0xc2, 0x60, 0x58, 0x56, 0x03, 0x02, 0x21, + 0x06, 0x21, 0x14, 0xf3, 0x19, 0xc5, 0x73, 0xb0, 0x12, 0x0e, 0x25, 0x12, + 0x18, 0x58, 0x12, 0xd3, 0x34, 0x17, 0x68, 0x66, 0x08, 0x86, 0x01, 0x08, + 0x32, 0x04, 0x0a, 0xf1, 0x0d, 0x58, 0xf1, 0x07, 0xb0, 0x2d, 0x70, 0x03, + 0x62, 0x24, 0x58, 0xc2, 0x6e, 0x58, 0x32, 0x03, 0xfe, 0x41, 0x58, 0x21, + 0x40, 0xf3, 0x19, 0x6d, 0x75, 0xb0, 0x2d, 0x30, 0x1e, 0x12, 0x30, 0x58, + 0x12, 0x71, 0x34, 0x83, 0x68, 0x6a, 0x58, 0x32, 0x90, 0x08, 0xf2, 0x10, + 0x06, 0x58, 0xf1, 0x07, 0xb0, 0x12, 0x07, 0x18, 0x62, 0x40, 0x58, 0xc2, + 0x72, 0x58, 0x32, 0x05, 0x1e, 0x85, 0xb8, 0xf3, 0x19, 0x09, 0x70, 0xb0, + 0x29, 0xa5, 0x12, 0x50, 0x58, 0x12, 0x0d, 0x34, 0xc7, 0x68, 0x4e, 0xb8, + 0xf0, 0x01, 0x10, 0x06, 0x00, 0x08, 0x58, 0xf1, 0x07, 0xb0, 0x12, 0x11, + 0x18, 0x62, 0x60, 0x58, 0xea, 0x54, 0x10, 0x72, 0x09, 0x58, 0x29, 0x72, + 0xfa, 0x1a, 0xfd, 0xc0, 0x21, 0x92, 0x12, 0x70, 0x58, 0x13, 0x01, 0x72, + 0x58, 0x8e, 0x3e, 0x18, 0x03, 0x2d, 0xf8, 0x1b, 0xf0, 0x01, 0x10, 0x04, + 0x00, 0x0a, 0x58, 0xf1, 0x07, 0xb0, 0x21, 0x92, 0x62, 0x80, 0x58, 0xc2, + 0x46, 0x58, 0xb0, 0x01, 0x03, 0x00, 0x0b, 0x58, 0xf3, 0x19, 0x9d, 0x74, + 0xb0, 0x21, 0x92, 0x12, 0x90, 0x58, 0x12, 0xa1, 0x34, 0x17, 0xcc, 0xe2, + 0x08, 0xa2, 0x00, 0xb0, 0xf2, 0x10, 0x0c, 0x58, 0xf1, 0x07, 0xb0, 0x21, + 0x92, 0x62, 0xa4, 0x58, 0xc2, 0xe4, 0x58, 0x70, 0x01, 0x03, 0x00, 0x0d, + 0x58, 0x21, 0x04, 0xf3, 0x19, 0xe5, 0x72, 0xb0, 0x21, 0x92, 0x12, 0xb8, + 0x58, 0x26, 0xe9, 0x08, 0x50, 0x02, 0x7c, 0x00, 0x20, 0x7c, 0x58, 0x32, + 0xc8, 0x08, 0xf2, 0x10, 0x0e, 0x58, 0xf1, 0x07, 0xb0, 0x21, 0x92, 0x52, + 0xcc, 0x58, 0xc3, 0x58, 0x7e, 0x58, 0x70, 0x01, 0x03, 0x00, 0x0f, 0x58, + 0x25, 0x08, 0xf3, 0x19, 0x11, 0x78, 0x58, 0x12, 0x14, 0x18, 0x12, 0xe0, + 0x58, 0x12, 0x15, 0x34, 0x50, 0x03, 0xd8, 0x81, 0x00, 0x20, 0x1c, 0x58, + 0x2d, 0x2c, 0x07, 0x3a, 0x04, 0xde, 0xf1, 0x25, 0x58, 0x12, 0x15, 0x18, + 0x52, 0xf4, 0x58, 0xc3, 0x48, 0x82, 0x58, 0x81, 0x01, 0x23, 0x80, 0xbf, + 0x04, 0x12, 0x29, 0x13, 0x27, 0x40, 0x7f, 0x1c, 0x1e, 0xff, 0x89, 0x07, + 0x1d, 0x54, 0x03, 0x42, 0x01, 0x04, 0x60, 0x02, 0x30, 0xf8, 0x30, 0xf8, + 0x2e, 0x12, 0x4b, 0x02, 0x12, 0x64, 0x02, 0x3d, 0xbc, 0x05, 0x1d, 0x69, + 0x05, 0x12, 0xde, 0x02, 0x6d, 0xc8, 0x05, 0x50, 0x05, 0x58, 0x02, 0x58, + 0x02, 0x01, 0x01, 0xa4, 0x02, 0x21, 0x1a, 0xf1, 0x01, 0x95, 0xa1, 0xa8, + 0x1c, 0x03, 0x15, 0x07, 0x00, 0x02, 0x64, 0x79, 0x06, 0x70, 0x05, 0x10, + 0x27, 0x00, 0x10, 0x0a, 0x00, 0x40, 0x1a, 0x28, 0x02, 0x05, 0x00, 0x5a, + 0x0f, 0x08, 0xbc, 0x05, 0x3f, 0x3e, 0x3f, 0x1e, 0x04, 0x00, 0xfa, 0xaf, + 0x06, 0x1a, 0x01, 0x1a, 0x11, 0x44, 0x23, 0x01, 0x2c, 0x49, 0xf0, 0x01, + 0xff, 0x02, 0x64, 0x00, 0x01, 0xf1, 0x07, 0x01, 0xf5, 0x07, 0xdc, 0x1e, + 0x09, 0xda, 0x03, 0x1e, 0x0b, 0x2e, 0x03, 0xf2, 0x04, 0x13, 0x02, 0x2d, + 0x00, 0x05, 0x1f, 0x01, 0x02, 0x0b, 0x08, 0xf4, 0x09, 0x11, 0x05, 0x0b, + 0x0e, 0x0c, 0x07, 0x08, 0x0a, 0x11, 0x09, 0x0f, 0x10, 0x73, 0x4c, 0x02, + 0x0a, 0x20, 0x0a, 0x20, 0x8a, 0x04, 0x55, 0xf0, 0x29, 0x08, 0x4a, 0x02, + 0xc0, 0x20, 0x01, 0x20, 0x7f, 0x0b, 0x13, 0x80, 0x01, 0x10, 0x00, 0xf0, + 0x84, 0x11, 0x14, 0xd3, 0x00, 0x00, 0x14, 0x40, 0x04, 0x2e, 0x33, 0x33, + 0x2b, 0x28, 0x1c, 0x06, 0xa0, 0x04, 0x2c, 0x2c, 0x37, 0x20, 0x20, 0x11, + 0x12, 0x51, 0x84, 0xf8, 0x06, 0x5a, 0xe1, 0xf5, 0x05, 0x43, 0x44, 0x02, + 0x00, 0x01, 0x06, 0x1e, 0xfc, 0x77, 0x03, 0x21, 0x04, 0x21, 0xe4, 0x2d, + 0x00, 0x06, 0x11, 0xb3, 0xf0, 0x04, 0x26, 0x07, 0x01, 0xf6, 0x01, 0x00, + 0xff, 0x84, 0xa1, 0x50, 0x5e, 0x0e, 0xf8, 0x05, 0xf0, 0x01, 0x1d, 0x01, + 0x00, 0x01, 0xd4, 0x4d, 0xe7, 0x07, 0x5e, 0x47, 0x97, 0x07, 0x5e, 0x48, + 0x47, 0x07, 0x5e, 0x53, 0xf7, 0x06, 0x30, 0x01, 0x54, 0x00, 0x2f, 0x08, + 0x1e, 0x59, 0x17, 0x0b, 0x11, 0x01, 0x63, 0x10, 0x59, 0x5b, 0x21, 0x64, + 0x10, 0x01, 0x01, 0x1e, 0xff, 0x37, 0x11, 0x82, 0x10, 0x16, 0xff, 0xf7, + 0xff, 0x13, 0x00, 0xdc, 0xff, 0x58, 0x00, 0x9d, 0xfe, 0x45, 0x42, 0x9c, + 0xfe, 0x5a, 0x00, 0xd9, 0xff, 0x17, 0x00, 0xf3, 0xff, 0x05, 0x1c, 0x21, + 0x96, 0x20, 0x02, 0xc8, 0x00, 0xb8, 0x0b, 0x50, 0x32, 0x80, 0x99, 0x30, + 0x03, 0x10, 0x00, 0x30, 0x1b, 0x0f, 0x04, 0x1c, 0x04, 0x58, 0x3e, 0x0f, + 0x00, 0xa0, 0xbb, 0x16, 0x05, 0x3c, 0x04, 0x09, 0x11, 0x02, 0x00, 0x20, + 0x02, 0x1a, 0x04, 0x3e, 0x80, 0xcc, 0x03, 0x37, 0x01, 0x00, 0x9a, 0x34, + 0x02, 0x01, 0x00, 0x2f, 0x02, 0xfa, 0x42, 0x01, 0xde, 0x1c, 0x0c, 0xff, + 0x01, 0xff, 0x02, 0x03, 0xff, 0x04, 0xff, 0x05, 0x06, 0xff, 0x07, 0x08, + 0xff, 0x63, 0x0a, 0x2e, 0xff, 0x64, 0x0a, 0x40, 0x28, 0xff, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0xff, 0x1b, 0x1c, + 0x1d, 0xff, 0x1e, 0xff, 0x1f, 0x20, 0xff, 0x21, 0x22, 0x23, 0x24, 0xff, + 0x25, 0x26, 0x27, 0x28, 0xff, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x9d, 0xbd, 0x11, 0xe2, 0x5c, 0x09, 0x0d, 0x1b, 0x2b, 0x34, + 0x37, 0x39, 0x00, 0x00, 0x28, 0x00, 0x3c, 0x20, 0x05, 0x20, 0x05, 0xa0, + 0x0f, 0x11, 0x3c, 0x3c, 0x14, 0x02, 0x01, 0x55, 0x03, 0x3d, 0x26, 0x04, + 0x13, 0x00, 0xf4, 0x06, 0xf8, 0x03, 0x46, 0xff, 0xe6, 0xdb, 0x2e, 0x12, + 0x2a, 0x96, 0x01, 0xb2, 0x12, 0x32, 0x02, 0x2e, 0x20, 0xcb, 0x0c, 0xff, + 0x0c, 0x02, 0x00, 0x9c, 0x23, 0xfd, 0x07, 0x90, 0x03, 0xf1, 0x03, 0x14, + 0xa1, 0x01, 0x03, 0x01, 0x01, 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, 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, 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, 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, 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, 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, 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, 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, 0xe7, 0x0c, 0x37, 0xfb, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +unsigned int firmware_Mykonos_M3_bin_len = 98304; diff --git a/src/hardware/mykonos/Mykonos_M3.h b/src/hardware/mykonos/Mykonos_M3.h new file mode 100644 index 0000000..30215b8 --- /dev/null +++ b/src/hardware/mykonos/Mykonos_M3.h @@ -0,0 +1,13 @@ +/** +SOFTWARE LICENSE AGREEMENT +20180301-AD937X-CTSLA +**/ + +// Version 5.2.2 +#ifndef SRC_MYKONOS_BIN_H_ +#define SRC_MYKONOS_BIN_H_ + +unsigned char firmware_Mykonos_M3_bin[]; +unsigned int firmware_Mykonos_M3_bin_len; + +#endif diff --git a/src/hardware/mykonos/ad9528.c b/src/hardware/mykonos/ad9528.c new file mode 100644 index 0000000..645acf6 --- /dev/null +++ b/src/hardware/mykonos/ad9528.c @@ -0,0 +1,740 @@ +/** + * \file ad9528.c + * \brief Contains source code for configuring and initializing AD9528 clock device + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include "ad9528.h" + +/** + * \brief Performs a hard reset on the AD9528 DUT + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the AD9528 data structure containing settings + * \return Returns enum ADI_ERR, ADIERR_OK=pass, !ADIERR_OK=fail + */ +ADI_ERR AD9528_resetDevice(ad9528Device_t *device) +{ + /* toggle RESETB on device with matching spi chip select index */ + CMB_hardReset(device->spiSettings->chipSelectIndex); + return ADIERR_OK; +} + +/** + * \brief Sets the AD9528 device SPI settings (3wire/4wire, MSBFirst, etc). + * + * This function will use the settings in the device->spiSettings structure + * to set SPI stream mode, address auto increment direction, MSBFirst/LSBfirst, + * and 3wire/4wire mode. The AD9528 device always uses SPI MODE 0 (CPHA=0, CPOL=0). + * This function will update your device->spiSettings to set CHPA=0 and CPOL=0 and + * longInstructionWord =1 to use a 16bit instruction word. + * + * Dependencies + * - writes device->spiSettings->CPHA = 0 + * - writes device->spiSettings->CPOL = 0 + * - writes device->spiSettings->longInstructionWord = 1 + * + * - device->spiSettings->MSBFirst + * - device->spiSettings->enSpiStreaming + * - device->spiSettings->autoIncAddrUp + * - device->spiSettings->fourWireMode + * + * \param device is structure pointer to the AD9528 data structure containing settings + * + * \return Returns enum ADI_ERR, ADIERR_OK=pass, !ADIERR_OK=fail + */ +ADI_ERR AD9528_setSpiSettings(ad9528Device_t *device) +{ + //device->spiSettings->enSpiStreaming + uint8_t spiReg = 0; + + device->spiSettings->CPHA = 0; + device->spiSettings->CPOL = 0; + device->spiSettings->longInstructionWord = 1; + + if (device->spiSettings->MSBFirst == 0) + { + spiReg |= 0x42; /* SPI bit is 1=LSB first */ + } + + if (device->spiSettings->autoIncAddrUp > 0) + { + spiReg |= 0x24; + } + + if (device->spiSettings->fourWireMode > 0) + { + spiReg |= 0x18; + } + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_ADI_SPI_CONFIG_A, spiReg); + + if (device->spiSettings->enSpiStreaming > 0) + { + /* Allow SPI streaming mode: SPI message ends when chip select deasserts */ + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_ADI_SPI_CONFIG_B, 0x00); + } + else + { + /* Force single instruction mode */ + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_ADI_SPI_CONFIG_B, 0x80); + } + + return ADIERR_OK; +} + + +/** + * \brief Helper function for ADI transceiver eval boards to init the AD9528 data structure + * + * This function inits the AD9528 device data structure with defaults that + * are known to work with the ADI AD9369 and AD9371 evaluation boards. NOTE: This function will + * modify the contents of the AD9528 device data structure. + * + * Dependencies + * - spi->chipSelectIndex + * - spi + * + * \param device Pointer to the AD9528 device data structure to initialize + * \param vcxoFrequency_Hz The VCXO frequency that is connected to the AD9528 + * \param refAFrequency_Hz The reference clock frequency being input into the AD9528 REFCLK A input + * \param outputDeviceClock_Hz Desired output clock frequency to the FPGA and transceiver device + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail +*/ +ADI_ERR AD9528_initDeviceDataStruct(ad9528Device_t *device, uint32_t vcxoFrequency_Hz, uint32_t refAFrequency_Hz, uint32_t outputDeviceClock_Hz) +{ +// uint16_t chDiv; +// uint8_t i = 0; +// +// uint32_t pll1PfdFreq_Hz = 0; +// uint8_t pll1Ndiv = 0; +// uint8_t validPll1DivSetting = 0; +// uint8_t refAdiv = 1; +// +// +// uint8_t pll2RfDiv = 3; /* Valid values 3,4,5 */ +// uint16_t pll2Ndiv = 1; /* Valid values 1-256 */ +// uint32_t pll2InputFreq_Hz = 0; +// uint64_t pll2VcoFreq_Hz = 0; +// uint16_t pll2NdivStart = 0; +// uint8_t validPll2DivSetting = 0; +// uint64_t chDivU64 = 0; +// +// static const uint64_t PLL2_MIN_VCO_FREQ_HZ = 3450000000ULL; +// static const uint64_t PLL2_MAX_VCO_FREQ_HZ = 4025000000ULL; +// /******************************************************************* +// * PLL1 Settings +// ******************************************************************* +// */ +// +// /* find valid PLL1 Ndiv and REFA div */ +// for (pll1Ndiv = 1; pll1Ndiv < 20; pll1Ndiv++) +// { +// pll1PfdFreq_Hz = vcxoFrequency_Hz / pll1Ndiv; +// +// if ((pll1PfdFreq_Hz <= 110000000) && (pll1PfdFreq_Hz >= 1000000) && +// (pll1PfdFreq_Hz <= refAFrequency_Hz) && +// (refAFrequency_Hz % pll1PfdFreq_Hz == 0) +// ) +// { +// validPll1DivSetting = 1; +// refAdiv = refAFrequency_Hz / pll1PfdFreq_Hz ; +// break; +// } +// } +// +// if (validPll1DivSetting == 0) +// { +// return ADIERR_INV_PARM; +// } +// +// device->pll1Settings->nDivider = pll1Ndiv; //This init function always runs PLL1 at 30.72MHz Pfd rate +// device->pll1Settings->refA_bufferCtrl = DIFFERENTIAL; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL +// device->pll1Settings->refA_Divider = refAdiv; +// device->pll1Settings->refA_Frequency_Hz = refAFrequency_Hz; +// device->pll1Settings->refB_bufferCtrl = DISABLED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL +// device->pll1Settings->refB_Divider = 1; +// device->pll1Settings->refB_Frequency_Hz = 0; +// device->pll1Settings->vcxoBufferCtrl = NEG_SINGLE_ENDED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL +// device->pll1Settings->vcxo_Frequency_Hz = vcxoFrequency_Hz; +// +// /******************************************************************* +// * PLL2 Settings +// ******************************************************************* +// */ +// +// /******************************************************************* +// * Output Distribution Settings +// * 9369CE02A uses the following clock outputs +// * OUT 1: FPGA REFCLK +// * OUT 3: FPGA SYSREF +// * OUT 12: DUT SYSREF +// * OUT 13: DUT REFCLK +// ******************************************************************* +// */ +// +// /* PLL 2 input clock can be several different things. Currently hard coded by this init funciton to use +// * PLL 1 output (VCXO Frequency) with no scaling +// */ +// pll2InputFreq_Hz = device->pll1Settings->vcxo_Frequency_Hz; +// validPll2DivSetting = 0; +// +// /* Sweep PLL2 Divider settings to find something that has a valid integer divide (3,4,5)*/ +// for (pll2RfDiv = 3; pll2RfDiv <= 5; pll2RfDiv++) +// { +// +// pll2NdivStart = (PLL2_MIN_VCO_FREQ_HZ / pll2RfDiv / pll2InputFreq_Hz); +// /* find valid PLL2 Ndiv (1-256) */ +// for (pll2Ndiv = pll2NdivStart; pll2Ndiv <= 256; pll2Ndiv++) +// { +// pll2VcoFreq_Hz = (pll2InputFreq_Hz * pll2RfDiv * pll2Ndiv); +// +// if (pll2VcoFreq_Hz < PLL2_MIN_VCO_FREQ_HZ) +// { +// /* Continue to next PLL2 N div */ +// continue; +// } +// else if (pll2VcoFreq_Hz > PLL2_MAX_VCO_FREQ_HZ) +// { +// /* Break to next PLL2 RF div */ +// break; +// } +// +// if (((pll2VcoFreq_Hz / pll2RfDiv) % outputDeviceClock_Hz) == 0) +// { +// +// device->pll2Settings->rfDivider = pll2RfDiv; +// device->pll2Settings->n2Divider = pll2Ndiv; +// device->pll2Settings->totalNdiv = pll2RfDiv * pll2Ndiv; +// chDivU64 = ((pll2VcoFreq_Hz / pll2RfDiv) / outputDeviceClock_Hz); +// +// if ((chDivU64 < 1) || (chDivU64 > 256)) +// { +// return ADIERR_INV_PARM; +// } +// else +// { +// chDiv = (uint16_t)(chDivU64); +// } +// +// validPll2DivSetting = 1; +// break; +// } +// } +// +// if (validPll2DivSetting == 1) +// { +// break; +// } +// } +// +// if (validPll2DivSetting == 0) +// { +// return ADIERR_INV_PARM; +// } +// +// device->outputSettings->outPowerDown = (uint16_t)(~0x300A); //enable outputs 13,12,3 and 1 +// +// for (i=0; i<14; i++){ +// device->outputSettings->outSource[i] = CHANNEL_DIV; //CHANNEL_DIV , PLL1_OUTPUT, SYSREF, INV_PLL1_OUTPUT +// device->outputSettings->outBufferCtrl[i] = LVDS; //LVDS, LVDS_BOOST, HSTL +// device->outputSettings->outChannelDiv[i] = chDiv; +// device->outputSettings->outFrequency_Hz[i] = outputDeviceClock_Hz; +// device->outputSettings->outAnalogDelay[i] = 0; +// device->outputSettings->outDigitalDelay[i] = 0; +// } +// +// +// device->outputSettings->outSource[3] = SYSREF; +// device->outputSettings->outSource[12] = SYSREF; +// +// +// device->sysrefSettings->sysrefDivide = 512; //SYSREF frequency = VCXO / 2 / sysrefDivde +// device->sysrefSettings->sysrefNshotMode = ONE_PULSE; //ONE_PULSE=0, TWO_PULSES=2, FOUR_PULSES=3, SIX_PULSES=4, EIGHT_PULSES=5 +// device->sysrefSettings->sysrefPatternMode = NSHOT; //NSHOT=0, CONTINUOUS=1, PRBS=2, STOP=3 +// device->sysrefSettings->sysrefPinBufferMode = DISABLED; //DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL +// device->sysrefSettings->sysrefPinEdgeMode = LEVEL_ACTIVE_HIGH; //LEVEL_ACTIVE_HIGH=0, LEVEL_ACTIVE_LOW=1, RISING_EDGE=2, FALLING_EDGE=3 +// device->sysrefSettings->sysrefRequestMethod = SPI; //SPI=0,PIN=1 +// device->sysrefSettings->sysrefSource = INTERNAL; //EXTERNAL=0, EXT_RESAMPLED=1, INTERNAL=2 + return ADIERR_OK; +} + +/** + * \brief Debug function to print out summary of AD9528 setup + * + * \param device AD9528 Device data structure describing setup of device. + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail +***********************************************************************************/ +ADI_ERR AD9528_reportClockRates(ad9528Device_t *device) +{ + + return ADIERR_OK; +} //debug function to help verify data structure is setup correctly. + +/** + * \brief Initializes the AD9528 by writing all SPI registers + * + * Initializes the AD9528 for use with the AD9369 transceiver. Designed to work with + * a reference clock of 122.88MHz. Reference clock is expected to be 30.72MHz. + * The output clocks from the AD9528 can run at 122.88M, 153.6M, 184.32M, 245.76M, or 307.2M. + * Typical setup: REFA frequency = 30.72, VCXO = 122.88MHz + * SYNC(SYSREF) pulses output at rate of 120kHz + * + * Dependencies + * - All parameters in device structure + * + * \param device is structure pointer to AD9528 clock device structure + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + */ +ADI_ERR AD9528_initialize(ad9528Device_t *device) { //writes all registers to desired values, leaves clock outputs off, SYSREF output disabled. + uint8_t pll2_Adiv=0; + uint8_t pll2_Bdiv=0; + uint8_t reg108=0; + uint8_t reg109=0; + uint8_t i = 0; + uint8_t j = 0; + uint8_t reg508; + ADI_ERR retval = ADIERR_OK; + + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, ADIERR_OK, "\n// AD9528_initialize\n"); + + //CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_ADI_SPI_CONFIG_A, 0x18); //[4] and [3] =1 enable 4 wire SPI + //CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_ADI_SPI_CONFIG_B, 0x00); + retval = AD9528_setSpiSettings(device); + if (retval != ADIERR_OK) + { + return retval; + } + + /********************************************************************** + * Configure PLL1 + ********************************************************************** + */ + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_REF_A_DIVIDER_LSB, + device->pll1Settings->refA_Divider & 0xFF); //REF A div[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_REF_A_DIVIDER_MSB, + (device->pll1Settings->refA_Divider >> 8) & 0x03); //REF A div[9:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_REF_B_DIVIDER_LSB, + device->pll1Settings->refB_Divider & 0xFF); //REF B div[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_REF_B_DIVIDER_MSB, + (device->pll1Settings->refB_Divider >> 8) & 0x03); //REF B div[9:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL1_N_DIV_LSB, + device->pll1Settings->nDivider & 0xFF); //PLL1 N div[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL1_N_DIV_MSB, + (device->pll1Settings->nDivider >> 8) & 0x03); //PLL1 N div[9:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL1_CHARGEPUMP, + 0x0A); //PLL1 Charge Pump control 1 + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL1_CP_CTRL2, + 0x03); //PLL1 Charge Pump control 2 + + switch (device->pll1Settings->refA_bufferCtrl){ + case DISABLED: + reg108 &= ~0x28; + reg109 &= ~0x01; + break; //clear all REFA enable bits + case SINGLE_ENDED: + reg108 |= 0x08; + reg109 &= ~0x01; + break; //Set REFA receiver enable, clear REFA SE negative input enable + case NEG_SINGLE_ENDED: + reg108 |= 0x08; + reg108 &= ~0x10; + reg109 |= 0x01; + break; //Disable REFA diff receiver, enable REFA receiver and use negative REFA input + case DIFFERENTIAL: + reg108 |= 0x28; + reg109 &= ~0x01; + break; + default: + reg108 |= 0x08; + reg109 &= ~0x01; + break; //default to single ended case + } + switch (device->pll1Settings->refB_bufferCtrl){ + case DISABLED: + reg108 &= ~0x50; + reg109 &= ~0x02; + break; //clear all REFB enable bits + case SINGLE_ENDED: + reg108 |= 0x10; + reg109 &= ~0x02; + break; //Set REFB receiver enable, clear REFB SE negative input enable + case NEG_SINGLE_ENDED: + reg108 |= 0x10; + reg108 &= ~0x40; + reg109 |= 0x02; + break; //Disable REFB diff receiver, enable REFB receiver and use negative REFB input + case DIFFERENTIAL: + reg108 |= 0x50; + reg109 &= ~0x02; + break; + default: + reg108 |= 0x10; + reg109 &= ~0x02; + break; //default to single ended case + } + switch (device->pll1Settings->vcxoBufferCtrl){ + case DISABLED: + reg108 &= ~0x03; + reg108 |= 0x04; + break; //power down VCXO input + case SINGLE_ENDED: + reg108 &= ~0x07; + break; //Clear VCXO receiver power down, defaults to Single ended mode + case NEG_SINGLE_ENDED: + reg108 &= ~0x07; + reg108 |= 0x02; + break; //Clear VCXO power down, enable Negative single ended mode[1] + case DIFFERENTIAL: + reg108 &= ~0x07; + reg108 |= 0x01; + break; //Clear VCXO power down, enable differential input buffer[0] + default: + reg108 &= ~0x07; + break; //default to positive single ended case + } + + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_INPUT_RECEIVERS1, + reg108); //Input receiver settings (single ended or differential clock inputs) + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_INPUT_RECEIVERS2, + reg109); //Input receiver settings + + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_INPUT_RECEIVERS3, + 0x0A); //Reference selection mode + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL1_FASTLOCK, + 0x00); //Disable Fast lock + + /********************************************************************** + * Configure PLL2 + ********************************************************************** + */ + pll2_Bdiv = device->pll2Settings->totalNdiv / 4; + pll2_Adiv = device->pll2Settings->totalNdiv % 4; + + if (pll2_Adiv > 3) { //A div valid range (0 to 3) + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, ADIERR_INV_PARM, "\n// AD9528 PLL2 A Divider out of range (0 to 3)\n"); + return ADIERR_INV_PARM; + } + if (pll2_Bdiv < 3 || pll2_Bdiv > 63) { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, ADIERR_INV_PARM, "\n// AD9528 PLL2 B Divider out of range (3 to 63)\n"); + return ADIERR_INV_PARM; + } + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_CHARGEPUMP, + 0xE6); //PLL2 Charge Pump[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_N_DIV, + ((pll2_Adiv & 0x3) << 6) | (pll2_Bdiv & 0x3F)); //PLL2 A and B divider + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_CTRL, 0x03); //PLL2 control + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_VCO_CTRL, 0x01); //Manual VCO CAL + + if (device->pll2Settings->rfDivider < 3 || device->pll2Settings->rfDivider > 5) { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, ADIERR_INV_PARM, "\n// AD9528 PLL2 RF Divider out of range (3,4, or 5)\n"); + return ADIERR_INV_PARM; + } + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_VCO_DIV, + device->pll2Settings->rfDivider); //VCO divider + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_LF_CTRL1, + 0x3A); //PLL2 Loop filter [7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_LF_CTRL2, + 0x00); //PLL2 Loop filter [8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_RDIV, + 0x00); //R divider + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_REPLICA_CHDIV, + (device->pll2Settings->totalNdiv / device->pll2Settings->rfDivider) + -1 ); //Replica channel divider: Ndivider = rfDivider * R divider + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_PLL2_REPLICA_DIV_PHASE, + 0x00); //Replica Channel Divider phase + + /********************************************************************** + * Configure Output Distribution + ********************************************************************** + */ + for (i=0; i<14; i=i+1){ + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_OUT0_CTRL1 + j, + ((device->outputSettings->outSource[i] & 0x7) << 5) | + (device->outputSettings->outAnalogDelay[i] & 0x1F)); + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_OUT0_CTRL2 + j, + ((device->outputSettings->outBufferCtrl[i] & 0x3) << 6) | + (device->outputSettings->outDigitalDelay[i] & 0x3F)); + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_OUT0_CHDIV + j, + device->outputSettings->outChannelDiv[i]-1); + j = j+3; + } + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_OUTPUT_SYNC, 0x00); //Sync outputs + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_MASK_SYNC1, 0x00); //Mask SYNC[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_MASK_SYNC2, 0x00); //Mask SYNC[13:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_EN_OUTPUT_PATH_SEL1, + 0x00); //Bypass SYSREF resample [6:0], bit0:Enable VCXO to feed output distrubution + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_EN_OUTPUT_PATH_SEL2, + 0x00); //Bypass SYSREF resample [13:7] + + /********************************************************************** + * Configure SYSREF operation + ********************************************************************** + */ + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSERF_DIV_LSB, + device->sysrefSettings->sysrefDivide & 0xFF); //SYSREF divider [7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSERF_DIV_MSB, + (device->sysrefSettings->sysrefDivide >> 8) & 0xFF); //SYSREF divider [7:0] + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL3, + ((device->sysrefSettings->sysrefRequestMethod & 0x1) << 7) | + ((device->sysrefSettings->sysrefPinEdgeMode & 0x3) << 5) ); + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL4, + ((device->sysrefSettings->sysrefSource & 0x03) << 6) | + ((device->sysrefSettings->sysrefPatternMode & 0x3) << 4 ) | + ((device->sysrefSettings->sysrefNshotMode & 0x7) << 1) ); + + if(device->sysrefSettings->sysrefPinBufferMode == DISABLED) + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL5, + 0x04); //power down input buffer for external SYSREF + } + else if(device->sysrefSettings->sysrefPinBufferMode == SINGLE_ENDED) + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL5, + 0x00); //enable positive singled ended input + } + else if(device->sysrefSettings->sysrefPinBufferMode == NEG_SINGLE_ENDED) + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL5, + 0x02); //enable negative singled ended input + } + else if(device->sysrefSettings->sysrefPinBufferMode == DIFFERENTIAL) + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL5, + 0x01); //enable differential input buffer + } + else + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL5, + 0x04); //power down input buffer for external SYSREF + } + + /********************************************************************** + * Power down control + ********************************************************************** + */ + + if (device->pll1Settings->bypassPll1 > 0) + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_POWERDOWN_CTRL, + 0x14);// power up PLL2 and output distribution, power down PLL1 + } + else + { + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_POWERDOWN_CTRL, + 0x10);// power up PLL1, PLL2 and output distribution + } + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_POWERDOWN1, + device->outputSettings->outPowerDown & 0xFF); //power down out[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_POWERDOWN2, + ((device->outputSettings->outPowerDown >> 8) & 0x3F)); //power down out[13:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_LDO_ENABLES1, + 0xFF); //LDO enable per output channel [7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_LDO_ENABLES2, + 0xFF); //LDO enable per output channel [15:8] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_STATUS0_CTRL, + 0x07); //STATUS 0 outputs REFA present + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_STATUS1_CTRL, + 0x01); //STATUS 1 outputs PLL1 and PLL2 locked + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_STATUS_OE, + 0x0C);// Make Status0 and Status1 outputs after reset. + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_IO_UPDATE, + 0x01); //IO update to make all these settings valid in the 9528 + + CMB_setTimeout_ms(1000); + do{ + CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_STATUS_READBACK0, ®508); + if(CMB_hasTimeoutExpired() > 0) + { + return ADIERR_FAILED; + } + }while((reg508 & 0xA2) != 0xA2); + + return ADIERR_OK; +} + +/// Send a SPI message to request a SYSREF pulse or continuous SYSREF from the AD9528. +/*******************************************************************************//** + * Requests a SYSREF from the AD9528. It will use whatever settings for SYSREF + * that are current configured in the AD9528. This could be a single pulse, + * multiple pulses, or continuous pulses. + * Dependencies + * - device->spiSettings + * - device->sysrefSettings->sysrefPatternMode + * + * \param device is structure pointer to AD9528 clock device structure + * \param enableSYSREF If NSHOT SYSREF mode, this parameter is ignored. If PRBS/CONTINUOUS SYSREF mode, 1= enable SYSREF, 0= disable SYSREF. + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + ***********************************************************************************/ +ADI_ERR AD9528_requestSysref(ad9528Device_t *device, uint8_t enableSYSREF){ + uint8_t _enableSYSREF=0; + + if (device->sysrefSettings->sysrefPatternMode == NSHOT || enableSYSREF > 0) + { + _enableSYSREF = 1; + } + else + { + _enableSYSREF = 0; + } + + CMB_SPIWriteField(device->spiSettings, AD9528_ADDR_SYSREF_CTRL4, _enableSYSREF, 0x01, 0x00); //Set SPI SYSREF request bit + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_IO_UPDATE, 0x01); //IO update to make all these settings valid in the 9528 + + return ADIERR_OK; +} + +/// Allow changing the 9528 SYSREF frequency and pattern mode(CONTINUOUS, PRBS vs NSHOT mode) +/*******************************************************************************//** + * NOTE: this function will update the device structure with the parameter values passed + * into this function. The device->sysrefSettings->sysrefPatternMode, device->sysrefSettings->sysrefNshotMode, + * and device->sysrefSettings->sysrefDivide values will be updated in the device structure. + * + * Dependencies + * - device->spiSettings + * + * \param device is structure pointer to AD9528 clock device structure + * \param divideFromPll1Out Sets the SYSREF pulse frequency. SYSREF frequency = PLL1_VCXO frequency/divideFromPll1Out + * \param sysrefPatternMode Valid settings: NSHOT, CONTINUOUS, PRBS, STOP + * \param nShotPulses Valid settings: ONE_PULSE=0, TWO_PULSES=2, FOUR_PULSES=3, SIX_PULSES=4, EIGHT_PULSES=5 + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + ***********************************************************************************/ +ADI_ERR AD9528_setupSYSREF(ad9528Device_t *device, uint16_t divideFromPll1Out, sysrefPatternMode_t sysrefPatternMode, sysrefNshotMode_t nShotPulses) +{ + uint8_t reg403=0; + + device->sysrefSettings->sysrefPatternMode = sysrefPatternMode; + device->sysrefSettings->sysrefNshotMode = nShotPulses; + device->sysrefSettings->sysrefDivide = divideFromPll1Out >> 1; //SYSREF frequency is (PLL1)VCXO frequency / 2 / device->sysrefSettings->sysrefDivide + + CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL4, ®403); + + reg403 = reg403 & ~0x01; //clear bit 0 to stop a continuous sysref if it is on. + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL4, reg403); + + reg403 = reg403 & ~0x3E; //clear bits for pattern mode and Nshot mode bitfields + reg403 = reg403 | ((sysrefPatternMode & 0x3) << 4) | ((nShotPulses & 0x7) << 1); + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_SYSREF_CTRL4, reg403); //update internal sysref pattern mode and Nshot mode (number of pulses) + + //SYSREF request bit x403[0] is left 0. The next call to AD9528_requestSysref will start the SYSREF + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_IO_UPDATE, 0x01); //IO update to make all these settings valid in the 9528 + + + return ADIERR_OK; +} + +/// Update the AD9528 clock outputs that are enabled. +/*******************************************************************************//** + * NOTE: this function will update the device structure with the parameter values passed + * into this function. The device->sysrefSettings->sysrefPatternMode, device->sysrefSettings->sysrefNshotMode, + * and device->sysrefSettings->sysrefDivide values will be updated in the device structure. + * + * Dependencies + * - device->spiSettings + * + * \param device is structure pointer to AD9528 clock device structure + * \param clkEnable Sets which clock outputs are enabled. Bit per clock output. bit0 = out0, etc. + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + ***********************************************************************************/ +ADI_ERR AD9528_enableClockOutputs(ad9528Device_t *device, uint16_t clkEnable) +{ //clkEnable: bit per clock output + + device->outputSettings->outPowerDown = ~clkEnable; + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_POWERDOWN1, device->outputSettings->outPowerDown & 0xFF); //power down out[7:0] + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_CH_POWERDOWN2, ((device->outputSettings->outPowerDown >> 8) & 0x3F)); //power down out[13:8] + + CMB_SPIWriteByte(device->spiSettings, AD9528_ADDR_IO_UPDATE, 0x01); //IO update to make all these settings valid in the 9528 + return ADIERR_OK; +} + +/// Waits for PLL1 and PLL2 to lock and the REFA and VCXO clocks to be present +/*******************************************************************************//** + * Waits until Reference A clock and VCXO clock input to be detected (present), + * and PLL1 and PLL2 to lock. Will timeout after 1 second and return ADIERR_FAILED. + * If clock are detected and PLLs locked, returns ADIERR_OK. + * + * Dependencies + * - device->spiSettings + * + * \param device is structure pointer to AD9528 clock device structure + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + ***********************************************************************************/ +ADI_ERR AD9528_waitForPllLock(ad9528Device_t *device) +{ + uint8_t reg508; + + CMB_setTimeout_ms(1000); + do{ + CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_STATUS_READBACK0, ®508); + if(CMB_hasTimeoutExpired() > 0) + { + return ADIERR_FAILED; + } + }while((reg508 & 0x27) != 0x27); + + return ADIERR_OK; +} + +/// Reads the Lock Status of the PLLs and present detect of the reference clocks +/*******************************************************************************//** + * NOTE: This is a non blocking function that reads a register to see if PLL1 + * and PLL2 are locked and Reference clock A and the VCXO input clock are + * detected (present). If the *status parameter is not NULL, the status will + * be returned. If *status is NULL, the error return value will denote if + * the PllStatus is locked or not with ADIERR_OK or ADIERR_FAILED. + * + * Dependencies + * - device->spiSettings + * + * \param device is structure pointer to AD9528 clock device structure + * + * \return Returns enum ADI_ERR, 0=pass, >0 = fail + ***********************************************************************************/ +ADI_ERR AD9528_readPllStatus(ad9528Device_t *device, uint8_t *status) +{ + uint8_t reg508; + + //bit5 is VCXO clock detected + //bit2 is REFCLK A detected + //bit1 is PLL2 lock detect + //bit0 is PLL1 lock detect + + /* read twice to refresh status bits */ + CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_STATUS_READBACK0, ®508); + CMB_SPIReadByte(device->spiSettings, AD9528_ADDR_STATUS_READBACK0, ®508); + /* if status is a valid pointer, return the PLL status */ + if (status > 0) + { + *status = reg508; + } + + /* PLLs 1 and 2 are locked and VCXO and REFA detected if reg508 has bits 5,2,1 and 0 set */ + if((reg508 & 0x27) == 0x27) + return ADIERR_OK; + else + return ADIERR_FAILED; +} diff --git a/src/hardware/mykonos/ad9528.h b/src/hardware/mykonos/ad9528.h new file mode 100644 index 0000000..b7e6cfe --- /dev/null +++ b/src/hardware/mykonos/ad9528.h @@ -0,0 +1,44 @@ +/** + * \file ad9528.h + * \brief Contains function declarations and ad9528Device_t structure typedef for ad9528.c + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _AD9528_LIB_H_ +#define _AD9528_LIB_H_ + +#include +#include "../common.h" +#include "t_ad9528.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLEMENTE_TDD_AD9528_CLKOUT_INDEX 13 + +//Helper function to setup the 9528 device data structure specifically for the ADI transceiver evaluation cards +ADI_ERR AD9528_initDeviceDataStruct(ad9528Device_t *device, uint32_t vcxoFrequency_Hz, uint32_t refAFrequency_Hz, uint32_t outputDeviceClock_Hz); +ADI_ERR AD9528_reportClockRates(ad9528Device_t *device); //debug function to help verify data structure is setup correctly. + +//AD9528 API functions +ADI_ERR AD9528_resetDevice(ad9528Device_t *device); +ADI_ERR AD9528_setSpiSettings(ad9528Device_t *device); +ADI_ERR AD9528_initialize(ad9528Device_t *device); //writes all registers to desired values, leaves clock outputs off. +ADI_ERR AD9528_waitForPllLock(ad9528Device_t *device); +ADI_ERR AD9528_readPllStatus(ad9528Device_t *device, uint8_t *status); +ADI_ERR AD9528_enableClockOutputs(ad9528Device_t *device, uint16_t clkEnable); //clkEnable: bit per clock output +ADI_ERR AD9528_setupSYSREF(ad9528Device_t *device, uint16_t divideFromPll1Out, sysrefPatternMode_t sysrefPatternMode, sysrefNshotMode_t nShotPulses); +ADI_ERR AD9528_requestSysref(ad9528Device_t *device, uint8_t enableSYSREF); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/mykonos.c b/src/hardware/mykonos/mykonos.c new file mode 100644 index 0000000..c8db0e3 --- /dev/null +++ b/src/hardware/mykonos/mykonos.c @@ -0,0 +1,18444 @@ +/** + *\file mykonos.c + * + *\brief Contains Mykonos APIs for transceiver configuration and control + * + * Mykonos API version: 1.5.2.3566 + */ + +/** + * \mainpage Overview + * + * This document is intended for use by software engineering professionals and + * includes detailed information regarding the data types and function calls + * which comprise the Mykonos ANSI C API. + * References to "Mykonos" in the API refer to the Analog Devices development name for the AD9371 family of devices. + * + */ + +/** + * \page Use Suggested Use + * The purpose of this API library is to add abstraction for the low level + * SPI control and calculations necessary to control the Mykonos family of transceiver devices + * + * Add the included source code as required to your baseband processor software build. Please reference the integration document + * as well for further instructions. + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +#include +#include "../common.h" +#include "mykonos.h" +#include "mykonos_gpio.h" +#include "mykonos_macros.h" +#include "mykonos_user.h" + +/* Private helper functions local to this file */ +static mykonosErr_t MYKONOS_calculateScaledDeviceClk_kHz(mykonosDevice_t *device, uint32_t *scaledRefClk_kHz, uint8_t *deviceClkDiv); +static mykonosErr_t MYKONOS_calculateDigitalClocks(mykonosDevice_t *device, uint32_t *hsDigClk_kHz, uint32_t *hsDigClkDiv4or5_kHz); +static mykonosErr_t enableDpdTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable); +static mykonosErr_t enableClgcTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable); + +/** + * \brief Verifies the Tx profile members are valid (in range) in the init structure + * + * If the Tx profile IQ data rate = 0, it is assumed that the Tx profile is + * not used. If Tx IQ data rate > 0, and Tx profile members are out of range, + * + * \pre This function is private and is not called directly by the user. + * + * Dependencies + * - device->tx->txProfile + * + * \param device Structure pointer to Mykonos device data structure + * \param txProfile txProfile settings to be verified + * \param txHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Tx profile + * + * \retval MYKONOS_ERR_TXPROFILE_IQRATE Profile IQ rate out of range + * \retval MYKONOS_ERR_TXPROFILE_RFBW Tx Profile RF bandwidth out of range + * \retval MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION Filter interpolation not valid + * \retval MYKONOS_ERR_TXPROFILE_FIR_INT FIR filter not valid + * \retval MYKONOS_ERR_OK All profile members are valid + */ +static mykonosErr_t mykVerifyTxProfile(mykonosDevice_t *device, mykonosTxProfile_t *txProfile, uint32_t *txHsDigClk_kHz) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + + *txHsDigClk_kHz = 0; + + /********************************/ + /* Check for a valid Tx profile */ + /********************************/ + + if ((txProfile->iqRate_kHz < MIN_TX_IQRATE_KHZ) || (txProfile->iqRate_kHz > MAX_TX_IQRATE_KHZ)) + { + return MYKONOS_ERR_TXPROFILE_IQRATE; + } + + if ((txProfile->rfBandwidth_Hz < MIN_TX_RFBW_HZ) || (txProfile->rfBandwidth_Hz > MAX_TX_RFBW_HZ)) + { + return MYKONOS_ERR_TXPROFILE_RFBW; + } + + if ((txProfile->thb1Interpolation != 1) && (txProfile->thb1Interpolation != 2)) + { + return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION; + } + + if ((txProfile->thb2Interpolation != 1) && (txProfile->thb2Interpolation != 2)) + { + return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION; + } + + if ((txProfile->txFirInterpolation != 1) && (txProfile->txFirInterpolation != 2) && (txProfile->txFirInterpolation != 4)) + { + return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION; + } + + if ((txProfile->txFir->coefs == NULL) && (txProfile->txFirInterpolation != 1)) + { + return MYKONOS_ERR_TXPROFILE_FIR_COEFS; + } + + if ((txProfile->dacDiv != DACDIV_2) && (txProfile->dacDiv != DACDIV_2p5) && (txProfile->dacDiv != DACDIV_4)) + { + return MYKONOS_ERR_TXPROFILE_DACDIV; + } + + *txHsDigClk_kHz = (txProfile->iqRate_kHz * txProfile->txFirInterpolation * txProfile->thb1Interpolation * txProfile->thb2Interpolation * (uint32_t)txProfile->dacDiv); + + device->profilesValid |= TX_PROFILE_VALID; + + return retVal; +} + +/** + * \brief Verifies the Rx profile members are valid (in range) and calculates HS Dig Clock require for the Rx Profile + * + * Private helper function to verify the Rx profile members are valid (in range) + * and calculates HS Dig Clock require for the Rx Profile + * If the Rx profile IQ data rate = 0, it is assumed that the Rx profile is + * not used. If Rx IQ data rate > 0, and Rx profile members are out of range. + * + * \pre This function is private and is not called directly by the user. + * + * Dependencies + * - device->rx->rxProfile + * + * \param device Structure pointer to Talise device data structure + * \param rxChannel receiver channel to be checked + * \param rxProfile rxProfile settings to be verified + * \param rxHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Rx profile + * + * \retval MYKONOS_ERR_RXPROFILE_RXCHANNEL Rx channel is not valid. + * \retval MYKONOS_ERR_RXPROFILE_IQRATE out of range IQ rate + * \retval MYKONOS_ERR_RXPROFILE_RFBW out of range RF bandwidth + * \retval MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION not valid filter decimation setting + * \retval MYKONOS_ERR_RXPROFILE_FIR_COEFS FIR filter not valid + * \retval MYKONOS_ERR_RXPROFILE_ADCDIV not valid ADC divider + * \retval MYKONOS_ERR_OK all profile members are valid + */ +static mykonosErr_t mykVerifyRxProfile(mykonosDevice_t *device, mykonosRxProfType_t rxChannel, mykonosRxProfile_t *rxProfile, uint32_t *rxHsDigClk_kHz) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t minBwHz = 0; + uint32_t maxBwHz = 0; + + *rxHsDigClk_kHz = 0; + + switch (rxChannel) + { + case MYK_RX_PROFILE: + minBwHz = MIN_RX_RFBW_HZ; + maxBwHz = MAX_RX_RFBW_HZ; + break; + case MYK_OBS_PROFILE: + minBwHz = MIN_ORX_RFBW_HZ; + maxBwHz = MAX_ORX_RFBW_HZ; + break; + case MYK_SNIFFER_PROFILE: + minBwHz = MIN_SNIFFER_RFBW_HZ; + maxBwHz = MAX_SNIFFER_RFBW_HZ; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXPROFILE_RXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_RXPROFILE_RXCHANNEL)); + return MYKONOS_ERR_RXPROFILE_RXCHANNEL; + } + + /********************************/ + /* Check for a valid Rx profile */ + /********************************/ + if ((rxProfile->iqRate_kHz < MIN_RX_IQRATE_KHZ) || (rxProfile->iqRate_kHz > MAX_RX_IQRATE_KHZ)) + { + return MYKONOS_ERR_RXPROFILE_IQRATE; + } + + /* check for Rx/Obs or Sniffer BW */ + if ((rxProfile->rfBandwidth_Hz < minBwHz) || (rxProfile->rfBandwidth_Hz > maxBwHz)) + { + return MYKONOS_ERR_RXPROFILE_RFBW; + } + + if ((rxProfile->rhb1Decimation != 1) && (rxProfile->rhb1Decimation != 2)) + { + return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION; + } + + if ((rxProfile->rxDec5Decimation != 4) && (rxProfile->rxDec5Decimation != 5)) + { + return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION; + } + + if ((rxProfile->rxFirDecimation != 1) && (rxProfile->rxFirDecimation != 2) && (rxProfile->rxFirDecimation != 4)) + { + return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION; + } + + if ((rxProfile->rxFir->coefs == NULL) && (rxProfile->rxFirDecimation != 1)) + { + return MYKONOS_ERR_RXPROFILE_FIR_COEFS; + } + + if ((rxProfile->adcDiv != 1) && (rxProfile->adcDiv != 2)) + { + return MYKONOS_ERR_RXPROFILE_ADCDIV; + } + + *rxHsDigClk_kHz = (rxProfile->iqRate_kHz * rxProfile->rxFirDecimation * rxProfile->rhb1Decimation * rxProfile->rxDec5Decimation * rxProfile->adcDiv); + + switch (rxChannel) + { + case MYK_RX_PROFILE: + device->profilesValid |= RX_PROFILE_VALID; + break; + case MYK_OBS_PROFILE: + device->profilesValid |= ORX_PROFILE_VALID; + break; + /*case MYK_SNIFFER_PROFILE:*/ + default: + device->profilesValid |= SNIFF_PROFILE_VALID; + break; + } + + return retVal; +} + +/** + * \brief Performs a hard reset on the MYKONOS DUT (Toggles RESETB pin on device) + * + * Toggles the Mykonos devices RESETB pin. Only resets the device with + * the SPI chip select indicated in the device->spiSettings structure. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to Mykonos device data structure containing settings + * + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_resetDevice(mykonosDevice_t *device) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDevice()\n"); +#endif + + /* toggle RESETB on device with matching spi chip select index */ + CMB_hardReset(device->spiSettings->chipSelectIndex); + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads back the silicon revision for the Mykonos Device + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to Mykonos device data structure containing settings + * \param revision Return value of the Mykonos silicon revision + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDeviceRev(mykonosDevice_t *device, uint8_t *revision) +{ +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDeviceRev()\n"); +#endif + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PRODUCT_ID, revision, 0x07, 0); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads back the Product ID for the Mykonos Device + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to Mykonos device data structure containing settings + * \param productId Return value of the Mykonos product Id + * + * \retval MYKONOS_ERR_GETPRODUCTID__NULL_PARAM recovery action for bad parameter check + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getProductId(mykonosDevice_t *device, uint8_t *productId) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getProductId()\n"); +#endif + + if (productId == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETPRODUCTID_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETPRODUCTID_NULL_PARAM)); + return MYKONOS_ERR_GETPRODUCTID_NULL_PARAM; + } + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PRODUCT_ID, productId, 0xF8, 3); + + return retVal; +} + +/** + * \brief Get API version number + * + * This function reads back the version number of the API + * + * \param device Pointer to the Mykonos data structure + * \param siVer A pointer to the current silicon version number. + * \param majorVer A pointer to the current major version number. + * \param minorVer A pointer to the current minor version number. + * \param buildVer A pointer to the current build version number. + * + * \retval MYKONOS_ERR_GET_API_VERSION_NULL_PARAM Null parameter passed to the function. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getApiVersion(mykonosDevice_t *device, uint32_t *siVer, uint32_t *majorVer, uint32_t *minorVer, uint32_t *buildVer) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getApiVersion()\n"); +#endif + + if ((siVer == NULL) || (majorVer == NULL) || (minorVer == NULL) || (buildVer == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_API_VERSION_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GET_API_VERSION_NULL_PARAM)); + return MYKONOS_ERR_GET_API_VERSION_NULL_PARAM; + } + + *siVer = (uint32_t)MYKONOS_CURRENT_SI_VERSION; + *majorVer = (uint32_t)MYKONOS_CURRENT_MAJOR_VERSION; + *minorVer = (uint32_t)MYKONOS_CURRENT_MINOR_VERSION; + *buildVer = (uint32_t)MYKONOS_CURRENT_BUILD_VERSION; + return retVal; +} + +/** + * \brief Sets the Mykonos device SPI settings (3wire/4wire, MSBFirst, etc). + * + * This function will use the settings in the device->spiSettings structure + * to set SPI stream mode, address auto increment direction, MSBFirst/LSBfirst, + * and 3wire/4wire mode. The Mykonos device always uses SPI MODE 0 (CPHA=0, CPOL=0). + * This function will update your device->spiSettings to set CHPA=0 and CPOL=0 and + * longInstructionWord =1 to use a 16bit instruction word. + * + * Dependencies + * - writes device->spiSettings->CPHA = 0 + * - writes device->spiSettings->CPOL = 0 + * - writes device->spiSettings->longInstructionWord = 1 + * + * - device->spiSettings->MSBFirst + * - device->spiSettings->enSpiStreaming + * - device->spiSettings->autoIncAddrUp + * - device->spiSettings->fourWireMode + * + * \param device Pointer to Mykonos device data structure containing settings + * + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_setSpiSettings(mykonosDevice_t *device) +{ + //device->spiSettings->enSpiStreaming + uint8_t spiReg = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setSpiSettings()\n"); +#endif + + device->spiSettings->CPHA = 0; + device->spiSettings->CPOL = 0; + device->spiSettings->longInstructionWord = 1; + + if (device->spiSettings->MSBFirst == 0) + { + spiReg |= 0x42; /* SPI bit is 1=LSB first */ + } + + if (device->spiSettings->autoIncAddrUp > 0) + { + spiReg |= 0x24; + } + + if (device->spiSettings->fourWireMode > 0) + { + spiReg |= 0x18; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_0, spiReg); + + if (device->spiSettings->enSpiStreaming > 0) + { + /* Allow SPI streaming mode: SPI message ends when chip select deasserts */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SPI_CONFIGURATION_CONTROL_1, 0x00); + } + else + { + /* Force single instruction mode */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SPI_CONFIGURATION_CONTROL_1, 0x80); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Verifies the integrity of the Mykonos device data structure. + * + * The Mykonos device data structure has many pointers to other structures. The + * main purpose of this function to verify that the necessary pointers within the + * device data structure have non zero pointers. The focus is on the Rx/Tx/ObsRx + * profiles and FIR filters where if a channel is disabled, it may be valid for + * some pointers to be NULL. This function updates device->profileValid to remember + * which profile pointers are valid. + * profileValid[3:0] = {SnifferProfileValid, ObsRxProfileValid, RxProfileValid, TxProfileValid}; + * + * Dependencies + * - device (all variables) + * + * \param device Pointer to Mykonos device data structure containing settings + * + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_verifyDeviceDataStructure(mykonosDevice_t *device) +{ + if (device == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER)); + return MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER; + } + + device->profilesValid = 0; /* Reset */ + + if (device->spiSettings == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CHECKDEVSTRUCT_SPI, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SPI)); + return MYKONOS_ERR_CHECKDEVSTRUCT_SPI; + } + + /* place this writeToLog after verifying the spiSettings structure is not NULL */ +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyDeviceDataStructure()\n"); +#endif + + /************************************************************************** + * Check Rx stucture pointers + ************************************************************************** + */ + if (device->rx == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RX, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RX)); + return MYKONOS_ERR_CHECKDEVSTRUCT_RX; + } + else + { + if (device->rx->rxChannels == RXOFF) + {/* If no Rx channel enabled, ok to have null pointers for rx gain control, framer, and Rx profile/Rx FIR Filter */ + } + else + { + if ((device->rx->framer == NULL) || (device->rx->rxGainCtrl == NULL) || (device->rx->rxProfile == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB)); + return MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB; + } + + if ((device->rx->rxProfile->rxFir == NULL) && (device->rx->rxProfile->rxFirDecimation != 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR)); + return MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR; + } + } + } + + /************************************************************************** + * Check Tx stucture pointers + ************************************************************************** + */ + if (device->tx == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TX, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TX)); + return MYKONOS_ERR_CHECKDEVSTRUCT_TX; + } + else + { + if (device->tx->txChannels == TXOFF) + {/* If no Tx channel enabled, ok to have null pointers for deframer, and Tx profile/Tx FIR filter */ + } + else + { + if ((device->tx->deframer == NULL) || (device->tx->txProfile == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB)); + return MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB; + } + + if ((device->tx->txProfile->txFir == NULL) && (device->tx->txProfile->txFirInterpolation != 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR)); + return MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR; + } + } + } + + /************************************************************************** + * Check ObsRx stucture pointers + ************************************************************************** + */ + if (device->obsRx == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX)); + return MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX; + } + else + { + if (device->obsRx->obsRxChannelsEnable == MYK_OBS_RXOFF) + {/* If no ObsRx channel enabled, ok to have null pointers for ObsRx gain control, framer, and ObsRx profile/FIR Filter */ + } + else + { + if ((device->obsRx->framer == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER)); + return MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER; + } + + if (device->obsRx->snifferProfile != NULL) + { + if (device->obsRx->snifferGainCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL)); + return MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL; + } + + if ((device->obsRx->snifferProfile->rxFir == NULL) && (device->obsRx->snifferProfile->rxFirDecimation != 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR)); + return MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR; + } + } + + if (device->obsRx->orxProfile != NULL) + { + if (device->obsRx->orxGainCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL)); + return MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL; + } + + if ((device->obsRx->orxProfile->rxFir == NULL) && (device->obsRx->orxProfile->rxFirDecimation != 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR, + getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR)); + return MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR; + } + } + } + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Initializes the Mykonos device based on the desired device settings. + * + * This function initializes the mykonos device, setting up the CLKPLL, digital clocks, + * JESD204b settings, FIR Filters, digital filtering. It does not load the ARM + * or perform any of the ARM init calibrations. It also sets the Rx Manual gain indexes and + * TxAttenuation settings to the initial values found in the device data structure. It leaves the + * Mykonos in a state ready for multichip sync (which can bring up the JESD204 links), the + * ARM to be loaded, and the init calibartions run. + * + * Dependencies + * - device (all variables) + * + * \param device Pointer to Mykonos device data structure containing settings + * + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_initialize(mykonosDevice_t *device) +{ + uint8_t txChannelSettings = 0; + uint8_t rxChannelSettings = 0; + uint8_t orxChannelSettings = 0; + uint8_t sniffChannelSettings = 0; + uint8_t adcDacClockRateSelect = 0; + uint8_t enableDpd = 0; + uint8_t obsRxRealIf = 0; + uint8_t enRxHighRejDec5 = 0; + uint8_t rxRealIfData = 0; + uint8_t txSyncb = 0x00; + uint8_t rxSyncb = 0x00; + uint8_t orxSyncb = 0x00; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initialize()\n"); +#endif + + retVal = MYKONOS_verifyDeviceDataStructure(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Verify Rx/Tx and ObsRx profiles are valid combinations */ + retVal = MYKONOS_verifyProfiles(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Set 3 or 4-wire SPI mode, MSBFirst/LSBfirst in device, pushes CPOL=0, CPHA=0, longInstWord=1 into device->spiSettings */ + retVal = MYKONOS_setSpiSettings(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Increase SPI_DO drive strength */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_IO_CONTROL, 0x10); + + /* Enable Reference clock - Set REFCLK pad common mode voltage */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_REF_PAD_CONFIG2, 0x07); + + /* Set Mykonos IO pin settings, GPIO direction, enable relevant LVDS pads */ + /* Enable SYSREF LVDS input pad + 100ohm internal termination */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SYSREF_PAD_CONFIG, 0x12); //Enable SYSREF input buffer + + if ((device->tx > 0) && (device->tx->txProfile > 0)) + { + /* Check for LVDS/CMOS mode */ + if (device->tx->deframer->txSyncbMode > 0) + { + txSyncb = 0xF0; + } + else + { + txSyncb = 0x02; + } + + /* Enable SYNCOUTB output buffer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_SYNC_PAD_CONFIG, txSyncb); + } + + /* Look at each framer and enable the RXSYNCB used for each framer. + * It is possible that they use the same RXSYNCB pin */ + if ((device->rx > 0) && (device->rx->framer > 0)) + { + /* Check for LVDS/CMOS mode */ + if (device->rx->framer->rxSyncbMode > 0) + { + rxSyncb = 0x00; + } + else + { + rxSyncb = 0x12; + } + + if (device->rx->framer->obsRxSyncbSelect == 0) + { + /* Enable SYNCINB0 LVDS/CMOS input buffer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_SYNC_CONFIG, rxSyncb); + } + else + { + /* Enable SYNCINB1 LVDS/CMOS input buffer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_SYNC_CONFIG, rxSyncb); + } + } + if ((device->obsRx > 0) && (device->obsRx->framer > 0)) + { + /* Check for LVDS/CMOS mode */ + if (device->obsRx->framer->rxSyncbMode > 0) + { + orxSyncb = 0x00; + } + else + { + orxSyncb = 0x12; + } + + if (device->obsRx->framer->obsRxSyncbSelect == 0) + { + /* Check for rxSyncb and orxSyncb when using the same RXSYNCB */ + if ((orxSyncb != rxSyncb) && (device->rx->framer->obsRxSyncbSelect == 0)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE)); + return MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE; + } + + /* Enable SYNCINB0 LVDS input buffer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_SYNC_CONFIG, orxSyncb); + } + else + { + /* Check for rxSyncb and orxSyncb when using the same ORXSYNCB */ + if ((orxSyncb != rxSyncb) && (device->rx->framer->obsRxSyncbSelect == 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE)); + return MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE; + } + + /* Enable SYNCINB1 LVDS input buffer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_SYNC_CONFIG, orxSyncb); + } + } + + /* Set number of device clock cycles per microsecond [round(freq/2) - 1] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_REFERENCE_CLOCK_CYCLES, (uint8_t)((((device->clocks->deviceClock_kHz / 1000) + 1) >> 1) - 1)); + + /* Set profile specific digital clock dividers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_1, 0x04); /* Negate Rx2 so phase matches Rx1 */ + + if (device->profilesValid & TX_PROFILE_VALID) + { + txChannelSettings = (((uint8_t)device->tx->txChannels & 0x3) << 6); + switch (device->tx->txProfile->thb2Interpolation) + { + case 1: + break; /* keep bit as 0 in bitfield */ + case 2: + txChannelSettings |= 0x20; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION)); + return MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION; + } + + switch (device->tx->txProfile->thb1Interpolation) + { + case 1: + break; /* keep bit as 0 in bitfield */ + case 2: + txChannelSettings |= 0x10; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION)); + return MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION; + } + + if (device->tx->txProfile->txFir == NULL) + { + /* If invalid pointer to FIR filter, Bypass programmable FIR, keep txChannelSettings[1:0] == 0 */ + } + else + { + switch (device->tx->txProfile->txFirInterpolation) + { + case 1: + txChannelSettings |= 0x01; + break; + case 2: + txChannelSettings |= 0x02; + break; + case 4: + txChannelSettings |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION)); + return MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION; + } + } + + switch (device->tx->txProfile->dacDiv) + { + case DACDIV_2: + break; /* Keep bit [1]=0 */ + case DACDIV_2p5: + break; /* Keep bit [1]=0, div 2.5 is set when Rx DEC5 filter enabled*/ + case DACDIV_4: + adcDacClockRateSelect |= 2; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_DACDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_DACDIV)); + return MYKONOS_ERR_INIT_INV_DACDIV; + } + } + + if (device->profilesValid & RX_PROFILE_VALID) + { + rxChannelSettings = (((uint8_t)device->rx->rxChannels & 0x3) << 6); + switch (device->rx->rxProfile->rxDec5Decimation) + { + case 4: + break; /* keep bit as 0 in bitfield */ + case 5: + rxChannelSettings |= 0x04; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION)); + return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION; + } + + switch (device->rx->rxProfile->rhb1Decimation) + { + case 1: + break; /* keep bit as 0 in bitfield */ + case 2: + rxChannelSettings |= 0x10; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION)); + return MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION; + } + + if (device->rx->rxProfile->rxFir == NULL) + { + /* If invalid pointer to FIR filter, Bypass programmable FIR, keep rxChannelSettings[1:0] == 0 */ + } + else + { + switch (device->rx->rxProfile->rxFirDecimation) + { + case 1: + rxChannelSettings |= 0x01; + break; + case 2: + rxChannelSettings |= 0x02; + break; + case 4: + rxChannelSettings |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION)); + return MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION; + } + } + + switch (device->rx->rxProfile->adcDiv) + { + case 1: + adcDacClockRateSelect |= 0; + break; + case 2: + adcDacClockRateSelect |= 1; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV)); + return MYKONOS_ERR_INIT_INV_ADCDIV; + } + + rxRealIfData = (device->rx->realIfData > 0) ? 1 : 0; + enRxHighRejDec5 = (device->rx->rxProfile->enHighRejDec5 > 0) ? 1 : 0; + } + else if (device->profilesValid & ORX_PROFILE_VALID) + { + /* if Rx profile not valid, but ORX profile valid, set RX ADC divider and dec5 to match orx profile setting */ + /* ARM clock is derived from Rx clocking, so Rx ADC div needs to be set */ + switch (device->obsRx->orxProfile->rxDec5Decimation) + { + case 4: + break; /* keep bit as 0 in bitfield */ + case 5: + rxChannelSettings |= 0x04; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION)); + return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION; + } + + switch (device->obsRx->orxProfile->adcDiv) + { + case 1: + adcDacClockRateSelect |= 0; + break; + case 2: + adcDacClockRateSelect |= 1; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV)); + return MYKONOS_ERR_INIT_INV_ADCDIV; + } + } + else if (device->profilesValid & SNIFF_PROFILE_VALID) + { + /* if Rx profile not valid, and ORX profile not valid, set RX ADC divider and dec5 to match sniffer profile setting */ + /* ARM clock is derived from Rx clocking, so Rx ADC div needs to be set */ + switch (device->obsRx->snifferProfile->rxDec5Decimation) + { + case 4: + break; /* keep bit as 0 in bitfield */ + case 5: + rxChannelSettings |= 0x04; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION)); + return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION; + } + + switch (device->obsRx->snifferProfile->adcDiv) + { + case 1: + adcDacClockRateSelect |= 0; + break; + case 2: + adcDacClockRateSelect |= 1; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV)); + return MYKONOS_ERR_INIT_INV_ADCDIV; + } + } + + /* determine ObsRx ADC Div setting */ + if (device->profilesValid & ORX_PROFILE_VALID) + { + switch (device->obsRx->orxProfile->adcDiv) + { + case 1: + break; /* Keep bit[4]=0 */ + case 2: + adcDacClockRateSelect |= 0x10; + break; /* Set bit[4]=1 */ + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV)); + return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV; + } + } + else if (device->profilesValid & SNIFF_PROFILE_VALID) + { + switch (device->obsRx->snifferProfile->adcDiv) + { + case 1: + break; /* Keep bit[4]=0 */ + case 2: + adcDacClockRateSelect |= 0x10; + break; /* Set bit[4]=1 */ + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV)); + return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV; + } + } + else if (device->profilesValid & RX_PROFILE_VALID) + { /* if OBSRX profiles are not valid, set obsRx ADC div to match Rx ADC divider */ + switch (device->rx->rxProfile->adcDiv) + { + case 1: + break; /* Keep bit[4]=0 */ + case 2: + adcDacClockRateSelect |= 0x10; + break; /* Set bit[4]=1 */ + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV)); + return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV; + } + } + + /* Determine ORx and Sniffer channel settings */ + if (device->obsRx != NULL) + { + /* verify pointers in data structure are valid (non-zero) */ + if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)) + { + if (device->obsRx->realIfData > 0) + { + obsRxRealIf = 1; + } + } + + /* TODO: verify that the decimation matches the given IQ rate in the data structure */ + + /* Set Sniffer profile (digital filter enables) if sniffer profile enabled (valid pointer) */ + if (device->profilesValid & SNIFF_PROFILE_VALID) + { + sniffChannelSettings = 0; + switch (device->obsRx->snifferProfile->rhb1Decimation) + { + case 1: + break; + case 2: + sniffChannelSettings |= 0x10; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_SNIFFER_RHB1, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_SNIFFER_RHB1)); + return MYKONOS_ERR_INIT_INV_SNIFFER_RHB1; + } + + if (device->obsRx->snifferProfile->rxFir != NULL) + { + + switch (device->obsRx->snifferProfile->rxFirDecimation) + { + case 1: + sniffChannelSettings |= 0x01; + break; + case 2: + sniffChannelSettings |= 0x02; + break; + case 4: + sniffChannelSettings |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC)); + return MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC; + } + } + } + + /* Set ORx profile (digital filter enables) if ORx profile enabled (valid pointer) */ + if (device->profilesValid & ORX_PROFILE_VALID) + { + orxChannelSettings = 0; + switch (device->obsRx->orxProfile->rhb1Decimation) + { + case 1: + break; + case 2: + orxChannelSettings |= 0x10; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ORX_RHB1, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ORX_RHB1)); + return MYKONOS_ERR_INIT_INV_ORX_RHB1; + } + + if (device->obsRx->orxProfile->rxFir != NULL) + {/* if pointer to orx rxFIR is valid */ + + switch (device->obsRx->orxProfile->rxFirDecimation) + { + case 1: + orxChannelSettings |= 0x01; + break; + case 2: + orxChannelSettings |= 0x02; + break; + case 4: + orxChannelSettings |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC)); + return MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC; + } + } + } + } + + /************************************************************************ + * Set channel config settings for Rx/Tx/oRx and Sniffer channels + *********************************************************************** + */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_2, txChannelSettings); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_4, rxChannelSettings); + + /* Set option to use new high rejection DEC5 filters in main Rx1/Rx2 path. */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_5, ((uint8_t)(rxRealIfData << 2) | (enRxHighRejDec5 ? 3 : 0))); + + if (rxRealIfData > 0) + { + /* Set Rx1 NCO frequency */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_3, 0x40); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_2, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_1, 0x01); + + /* Set Rx2 NCO frequency */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_3, 0x40); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_2, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_1, 0x01); + + /* Enable NCO for Rx1 and Rx2 to shift data from zero IF to real IF */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_NCO_CONTROL, 3, 0x03, 0); + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_2, obsRxRealIf, 0x40, 6); + + /* if sniffer profile disabled, Sniffer config reg is set to default = 0x80 */ + sniffChannelSettings |= 0x80; /* use PFIR coef set B = bit[7]=1*/ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNIFFER_CONFIGURATION_CONTROL, sniffChannelSettings); + + /* if orx profile not valid, SPI reg for orx config is set to default = 0x00 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_CONFIGURATION_CONTROL, orxChannelSettings); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_LOOPBACK_CONFIGURATION_CONTROL, orxChannelSettings); + + /* Set ADC divider, DAC divider, and ObsRx/sniffer dividers */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_1, adcDacClockRateSelect, 0x13, 0); + + /* Disable ORx digital DC offset - bad default SPI setting for ObsRx DC offset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT, 0x60); + + /* Necessary write for ARM init cals to work */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNIFF_RXLOGEN_BYTE1, 0x0E); + + /* Increase Sniffer LNA gain */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNRX_LNA_BIAS_C, 0x0F); + + /* Set the CLKPLL with the frequency from the device data structure */ + retVal = MYKONOS_initDigitalClocks(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Wait for CLKPLL CP Cal done and CLKPLL Lock or throw error message */ + CMB_wait_ms(500); + retVal = MYKONOS_waitForEvent(device, CLKPLLCP, 1000000); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_waitForEvent(device, CLKPLL_LOCK, 1000000); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Enable digital clocks - this is gated by the CLKPLL being locked */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_0, 0x14); + + /* Set the Tx PFIR synchronization clock */ + retVal = MYKONOS_setTxPfirSyncClk(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Set the Rx PFIR synchronization clock */ + retVal = MYKONOS_setRxPfirSyncClk(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (device->profilesValid & TX_PROFILE_VALID) + { + /* Set pre TxPFIR Half band filter interpolation */ + if (device->tx->txProfile->txInputHbInterpolation == 1) + { + /* disable TX input half band ([3:2]=00) - but allow DPD to still be enabled for tx profiles with wide BW [1] */ + enableDpd = (device->tx->txProfile->enableDpdDataPath > 0) ? 1 : 0; + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, enableDpd, 0x0E, 1); + } + else if (device->tx->txProfile->txInputHbInterpolation == 2) + { + if (device->tx->txProfile->iqRate_kHz > 160000) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE)); + return MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE; + } + + /* enable TX input half band[2]=1, and Enable DPD[1]=1*/ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, 3, 0x0E, 1); + } + else if (device->tx->txProfile->txInputHbInterpolation == 4) + { + if (device->tx->txProfile->iqRate_kHz > 80000) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE)); + return MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE; + } + + /* enable TX input HB0[3]=1 and Tx input HB[2]=1, and Enable DPD[1]=1*/ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, 7, 0x0E, 1); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM)); + return MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM; + } + + /* Enable SPI Tx Atten mode */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x01, 0x03, 0); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x01, 0x0C, 2); + + /* Set Tx1 Atten step size */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, device->tx->txAttenStepSize, 0x60, 5); + + /* Set Tx2 Atten step size */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, device->tx->txAttenStepSize, 0x60, 5); + } + else + { + /* Power down DACs */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_PD_OVERIDE_7_0, 3, 0x0C, 2); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_PD_OVERRIDE_CONTROL_7_0, 3, 0x0C, 2); + } + + /* Set RxFE LO Common mode */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXFE1_LOCM, 0xF0); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXFE2_LOCM, 0xF0); + + /* Set Rxloopback LO Common mode */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXLOOPBACK1_CNTRL_1, 0xFF); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXLOOPBACK2_CNTRL_1, 0xFF); + + /* Setup MGC or AGC Rx gain control */ + if ((retVal = MYKONOS_setupRxAgc(device)) != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Default Rx to use manual gain control until AGC enabled by user */ + if ((retVal = MYKONOS_setRxGainControlMode(device, MGC)) != MYKONOS_ERR_OK) + { + return retVal; + } + + + if ((retVal = MYKONOS_setupObsRxAgc(device)) != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Default ObsRx to use manual gain control until AGC enabled by user */ + if ((retVal = MYKONOS_setObsRxGainControlMode(device, MGC)) != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Disable GPIO select bits by setting to b11 */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_1, 3, 0x30, 4); + + /* Extra settings for ARM calibrations */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT, 0x11); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_LOOPBACK1_CNTRL_4, 0x04); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_LOOPBACK2_CNTRL_4, 0x04); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_2, 0x20, 0x20, 0); + + /* Extra settings for ADC initialisation */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_ADC_FLASH_DELAY, 0x28); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_ADC_FLASH_CTRL, 0x0E); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_ADC_FLASH_DELAY, 0x28); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_ADC_FLASH_CTRL, 0x0E); + + /* Move to Alert ENSM state */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ENSM_CONFIG_7_0, 0x05); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Verifies the init structure profiles are valid combinations + * + * This function checks that the Rx/Tx/ORx/Sniffer profiles have valid clock rates in + * order to operate together. Rx/Tx and ORx/Sniffer share a common high speed digital + * clock. If an invalid combination of profiles is detected, an error will be + * returned. If a profile in the init structure is unused, the user should zero + * out all members of that particular profile structure. If a Rx/Tx/ORx/Sniffer profile + * has an IQ rate = 0, it is assumed that the profile is disabled. + * + * \pre This function is private and is not called directly by the user. + * + * This function uses mykVerifyTxProfile() and mykVerifyRxProfile() as helper functions. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Structure pointer to Mykonos device data structure + * + * \retval MYKONOS_ERR_PROFILES_HSDIGCLK profiles loaded are not valid + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_verifyProfiles(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + + uint32_t rxHsDigClk_kHz = 0; + uint32_t orxHsDigClk_kHz = 0; + uint32_t snifferHsDigClk_kHz = 0; + uint32_t txHsDigClk_kHz = 0; + + mykonosRxProfile_t *rxProfile = NULL; + mykonosTxProfile_t *txProfile = NULL; + mykonosRxProfile_t *orxProfile = NULL; + mykonosRxProfile_t *snifferProfile = NULL; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyProfiles()\n"); +#endif + + device->profilesValid = 0; + + /* Check all loaded profiles */ + if (device->tx->txChannels != TXOFF) + { + txProfile = device->tx->txProfile; + retVal = mykVerifyTxProfile(device, txProfile, &txHsDigClk_kHz); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if (device->rx->rxChannels != RXOFF) + { + rxProfile = device->rx->rxProfile; + retVal = mykVerifyRxProfile(device, MYK_RX_PROFILE, rxProfile, &rxHsDigClk_kHz); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if (device->obsRx->obsRxChannelsEnable != MYK_OBS_RXOFF) + { + if ((uint32_t)device->obsRx->obsRxChannelsEnable & (uint32_t)MYK_ORX1_ORX2) + { + orxProfile = device->obsRx->orxProfile; + retVal = mykVerifyRxProfile(device, MYK_OBS_PROFILE, orxProfile, &orxHsDigClk_kHz); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if ((uint32_t)device->obsRx->obsRxChannelsEnable & (uint32_t)MYK_SNRXA_B_C) + { + snifferProfile = device->obsRx->snifferProfile; + retVal = mykVerifyRxProfile(device, MYK_SNIFFER_PROFILE, snifferProfile, &snifferHsDigClk_kHz); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + } + + return retVal; +} + +/** + * \brief Write indirect registers (Programmable FIRs, Rx gain tables, JESD204B settings). Must be done after Multi Chip Sync + * + * The BBP should never need to call this function. It is called automatically by the initArm function. + * This function is a continuation of the MYKONOS_initialize() function. This part of initialization must be done after + * the BBP has completed Multi chip Sync. These registers include FIR filters, Rx gain tables, and JESD204B framer/deframer + * config registers. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * an error. + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_initSubRegisterTables(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + + /* ------------------------------------------------------------------------------------------- */ + /* Program submap register tables after digital clocks are up and running and Multi Chip Sync */ + /* has been completed by BBP */ + if (device->profilesValid & TX_PROFILE_VALID) + { + if (device->tx->txProfile->txFir != NULL) + { + retVal = MYKONOS_programFir(device, TX1TX2_FIR, device->tx->txProfile->txFir); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + } + + if (device->profilesValid & RX_PROFILE_VALID) + { + if (device->rx->rxProfile->rxFir != NULL) + { + retVal = MYKONOS_programFir(device, RX1RX2_FIR, device->rx->rxProfile->rxFir); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Load Rx gain table */ + retVal = MYKONOS_programRxGainTable(device, &RxGainTable[0][0], (sizeof(RxGainTable) >> 2), RX1_RX2_GT); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setRx1ManualGain(device, device->rx->rxGainCtrl->rx1GainIndex); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setRx2ManualGain(device, device->rx->rxGainCtrl->rx2GainIndex); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Enable Digital gain for Rx and ObsRx gain tables */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_GAIN_CONFIG, 0x80); + } + } + + if (device->profilesValid & SNIFF_PROFILE_VALID) + { + if (device->obsRx->snifferProfile->rxFir != NULL) + { + retVal = MYKONOS_programFir(device, OBSRX_B_FIR, device->obsRx->snifferProfile->rxFir); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Load Sniffer Rx gain table */ + retVal = MYKONOS_programRxGainTable(device, &SnRxGainTable[0][0], (sizeof(SnRxGainTable) >> 2), SNRX_GT); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setObsRxManualGain(device, OBS_SNIFFER_A, device->obsRx->snifferGainCtrl->gainIndex); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + } + + if (device->profilesValid & ORX_PROFILE_VALID) + { + if (device->obsRx->orxProfile->rxFir != NULL) + {/* if pointer to orx rxFIR is valid */ + retVal = MYKONOS_programFir(device, OBSRX_A_FIR, device->obsRx->orxProfile->rxFir); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Load ORx gain table */ + retVal = MYKONOS_programRxGainTable(device, &ORxGainTable[0][0], (sizeof(ORxGainTable) >> 2), ORX_GT); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setObsRxManualGain(device, OBS_RX1_TXLO, device->obsRx->orxGainCtrl->orx1GainIndex); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setObsRxManualGain(device, OBS_RX2_TXLO, device->obsRx->orxGainCtrl->orx2GainIndex); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + } + + /* Load Loopback Gain Table for ARM calibrations */ + { + uint8_t loopBackGainTable[6][4] = { + /* Order: {FE table, External Ctl, Digital Gain/Atten, Enable Atten} */ + {0, 0, 0, 0}, /* Gain index 255 */ + {7, 0, 0, 0}, /* Gain index 254 */ + {13, 0, 1, 1}, /* Gain index 253 */ + {18, 0, 3, 1}, /* Gain index 252 */ + {23, 0, 3, 1}, /* Gain index 251 */ + {28, 0, 0, 0} /* Gain index 250 */ + }; + retVal = MYKONOS_programRxGainTable(device, &loopBackGainTable[0][0], (sizeof(loopBackGainTable) >> 2), LOOPBACK_GT); + } + + /* Enable Digital gain for ORx/Sniffer/Loopback gain table */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_DIGITAL_GAIN_CONFIG, 0x80); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RCAL_CONTROL, 0x07);/* Set RCAL code to nominal */ + + /* If Valid Rx Profile or valid ObsRx profile, setup serializers */ + if ((device->profilesValid & RX_PROFILE_VALID) || (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))) + { + retVal = MYKONOS_setupSerializers(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if ((device->rx->rxChannels != RXOFF) && (device->profilesValid & RX_PROFILE_VALID)) + { + retVal = MYKONOS_setupJesd204bFramer(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if ((device->obsRx->obsRxChannelsEnable != MYK_OBS_RXOFF) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))) + { + retVal = MYKONOS_setupJesd204bObsRxFramer(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + if ((device->tx->txChannels != TXOFF) && (device->profilesValid & TX_PROFILE_VALID)) + { + retVal = MYKONOS_setupDeserializers(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setupJesd204bDeframer(device); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setTx1Attenuation(device, device->tx->tx1Atten_mdB); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_setTx2Attenuation(device, device->tx->tx2Atten_mdB); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs a blocking wait for a Mykonos calibration or Pll Lock + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param waitEvent the enum value of the event to wait for + * \param timeout_us If timeout_us time has passed, function will return with + * an error. + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_waitForEvent(mykonosDevice_t *device, waitEvent_t waitEvent, uint32_t timeout_us) +{ + uint16_t spiAddr = 0; + uint8_t spiBit = 0; + uint8_t doneBitLevel = 0; + uint8_t data = 0; + mykonosErr_t errCode = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitForEvent()\n"); +#endif + + switch (waitEvent) + { + case CALPLL_LOCK:/* wait for x17F[7]=1 */ + spiAddr = MYKONOS_ADDR_CALPLL_SDM_CONTROL; + spiBit = 7; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CALPLL_LOCK; + break; + case CLKPLLCP: /* wait for x154[5]=1 */ + spiAddr = MYKONOS_ADDR_CLK_SYNTH_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLLCP; + break; + case CLKPLL_LOCK: /* wait for x157[0]=1 */ + spiAddr = MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLL_LOCK; + break; + case RF_RXPLLCP:/* wait for x254[5]=1 */ + spiAddr = MYKONOS_ADDR_RXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLLCP; + break; + case RF_RXPLL_LOCK: /* wait for x257[0]=1 */ + spiAddr = MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLL_LOCK; + break; + case RF_TXPLLCP: /* wait for x2C4[5]=1 */ + spiAddr = MYKONOS_ADDR_TXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLLCP; + break; + case RF_TXPLL_LOCK: /* wait for x2C7[0]=1 */ + spiAddr = MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLL_LOCK; + break; + case RF_SNIFFERPLLCP: /* wait for x354[7]=1 */ + spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLLCP; + break; + case RF_SNIFFERPLL_LOCK: /* wait for x357[0]=1 */ + spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLL_LOCK; + break; + case RXBBF_CALDONE: /* wait for x1B2[5]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 5; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXBBFCALDONE; + break; + case TXBBF_CALDONE:/* wait for x1B2[0]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 0; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXBBFCALDONE; + break; + case RX_RFDC_CALDONE: /* wait for x1B2[1]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 1; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RFDCCALDONE; + break; + case RX_ADCTUNER_CALDONE:/* wait for x1B2[7]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 7; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ADCTUNECALDONE; + break; + case RX1_ADCPROFILE:/* wait for x5DD[5]=0 */ + spiAddr = MYKONOS_ADDR_RX_ADC1_PRFL; + spiBit = 5; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX1ADCPROFILE; + break; + case RX2_ADCPROFILE:/* wait for x5DE[5]=0 */ + spiAddr = MYKONOS_ADDR_RX_ADC2_PRFL; + spiBit = 5; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX2ADCPROFILE; + break; + case ORX_ADCPROFILE:/* wait for x5DF[5]=0 */ + spiAddr = MYKONOS_ADDR_ORX_ADC_PRFL; + spiBit = 5; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ORXADCPROFILE; + break; + case RCAL_CALDONE: /* wait for x1B2[6]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 6; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RCALDONE; + break; + case ARMBUSY:/* wait for xD30[7]=0 */ + spiAddr = MYKONOS_ADDR_ARM_CMD; + spiBit = 7; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ARMBUSY; + break; + case INITARM_DONE: + spiAddr = MYKONOS_ADDR_ARM_CMD; + spiBit = 7; + doneBitLevel = 0; + errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_INITARMDONE; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITFOREVENT_INV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_WAITFOREVENT_INV_PARM)); + return MYKONOS_ERR_WAITFOREVENT_INV_PARM; + } + + CMB_setTimeout_us(timeout_us); /* timeout after desired time */ + + do + { + CMB_SPIReadByte(device->spiSettings, spiAddr, &data); + + /* For SW verification tests, allow API to think all cals are complete*/ +#ifdef MYK_CALS_DONE_SWDEBUG + if (doneBitLevel == 0) + { + data = 0x00; + } + else + { + data = 0xFF; + } +#endif + + if ((uint32_t)CMB_hasTimeoutExpired() > 0) + { + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, errCode, getMykonosErrorMessage(errCode)); + return errCode; + } + } while (((data >> spiBit) & 0x01) != doneBitLevel); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs a readback with no wait for a Mykonos calibration or Pll Lock + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param waitEvent the enum value of the event to wait for + * \param eventDone Return value: 1= calibration event is complete. 0 = Event is still pending + * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_readEventStatus(mykonosDevice_t *device, waitEvent_t waitEvent, uint8_t *eventDone) +{ + uint16_t spiAddr = 0; + uint8_t data = 0; + uint8_t spiBit = 0; + uint8_t doneBitLevel = 0; + + switch (waitEvent) + { + case CALPLL_LOCK:/* wait for x17F[7]=1 */ + spiAddr = MYKONOS_ADDR_CALPLL_SDM_CONTROL; + spiBit = 7; + doneBitLevel = 1; + break; + case CLKPLLCP: /* wait for x154[5]=1 */ + spiAddr = MYKONOS_ADDR_CLK_SYNTH_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + break; + case CLKPLL_LOCK: /* wait for x157[0]=1 */ + spiAddr = MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + break; + case RF_RXPLLCP:/* wait for x254[5]=1 */ + spiAddr = MYKONOS_ADDR_RXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + break; + case RF_RXPLL_LOCK: /* wait for x257[0]=1 */ + spiAddr = MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + break; + case RF_TXPLLCP: /* wait for x2C4[5]=1 */ + spiAddr = MYKONOS_ADDR_TXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + break; + case RF_TXPLL_LOCK: /* wait for x2C7[0]=1 */ + spiAddr = MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + break; + case RF_SNIFFERPLLCP: /* wait for x354[7]=1 */ + spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_CP_CAL_STAT; + spiBit = 5; + doneBitLevel = 1; + break; + case RF_SNIFFERPLL_LOCK: /* wait for x357[0]=1 */ + spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1; + spiBit = 0; + doneBitLevel = 1; + break; + case RXBBF_CALDONE: /* wait for x1B2[5]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 5; + doneBitLevel = 0; + break; + case TXBBF_CALDONE:/* wait for x1B2[0]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 0; + doneBitLevel = 0; + break; + case RX_RFDC_CALDONE: /* wait for x1B2[1]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 1; + doneBitLevel = 0; + break; + case RX_ADCTUNER_CALDONE:/* wait for x1B2[7]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 7; + doneBitLevel = 0; + break; + case RX1_ADCPROFILE:/* wait for x5DD[5]=0 */ + spiAddr = MYKONOS_ADDR_RX_ADC1_PRFL; + spiBit = 5; + doneBitLevel = 0; + break; + case RX2_ADCPROFILE:/* wait for x5DE[5]=0 */ + spiAddr = MYKONOS_ADDR_RX_ADC2_PRFL; + spiBit = 5; + doneBitLevel = 0; + break; + case ORX_ADCPROFILE:/* wait for x5DF[5]=0 */ + spiAddr = MYKONOS_ADDR_ORX_ADC_PRFL; + spiBit = 5; + doneBitLevel = 0; + break; + case RCAL_CALDONE: /* wait for x1B2[6]=0 */ + spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL; + spiBit = 6; + doneBitLevel = 0; + break; + case ARMBUSY:/* wait for xD30[7]=0 */ + spiAddr = MYKONOS_ADDR_ARM_CMD; + spiBit = 7; + doneBitLevel = 0; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITFOREVENT_INV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_WAITFOREVENT_INV_PARM)); + return MYKONOS_ERR_WAITFOREVENT_INV_PARM; + } + + CMB_SPIReadByte(device->spiSettings, spiAddr, &data); + + if (doneBitLevel) + { + *eventDone = (data >> spiBit) & 0x01; + } + else + { + *eventDone = (~(data >> spiBit) & 0x01); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the CLKPLL output frequency. + * + * This code updates the Synth and Loop filter settings based on a VCO + * frequency LUT. The VCO frequency break points for the Synth LUT can be + * found in an array called vcoFreqArrayMhz. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * - device->deviceClock_kHz + * - device->rxSettings->rxProfile->vcoFreq_kHz + * - device->rxSettings->rxProfile->clkPllHsDiv + * - device->rxSettings->rxProfile->clkPllVcoDiv + * + * \param device is structure pointer to the MYKONOS data structure containing settings + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_initDigitalClocks(mykonosDevice_t *device) +{ + /* RF Synth variables */ + /* pull Synth and Loop filter values from a Look Up Table */ + uint8_t vcoOutLvl; + uint8_t vcoVaractor; /* [3:0] */ + uint8_t vcoBiasRef; /* [2:0] */ + uint8_t vcoBiasTcf; /* [1:0] */ + uint8_t vcoCalOffset; /* [3:0] */ + uint8_t vcoVaractorRef; /* [3:0] */ + uint8_t loopFilterIcp; /* Icp[5:0] */ + uint8_t loopFilterC2C1; /* C2[3:0],C1[3:0] */ + uint8_t loopFilterR1C3; /* R1[3:0],C3[3:0] */ + uint8_t loopFilterR3; /* R3[3:0] */ + uint8_t vcoIndex; + uint8_t i; + + /* RF PLL variables */ + uint16_t integerWord; + uint32_t fractionalWord; + uint32_t fractionalRemainder; + uint32_t scaledRefClk_Hz; + + /* common */ + uint64_t hsDigClk_Hz = 0; + uint32_t scaledRefClk_kHz = 0; + uint8_t deviceClkDiv = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + + uint8_t clockControl2 = 0; + uint8_t sdmSettings = 0; + uint8_t hsDiv = 4; + uint8_t vcoDiv = 0; + uint8_t vcoDivTimes10 = 10; + + /******************RF Synth Section************************/ + static const uint8_t icp_46p08[53] = {15, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 27, 27, 28, 29, 30, 31, 32, 33, 32, 33, 32, 33, 33, 34, 27, 28, 29, + 29, 30, 39, 29, 30, 31, 31, 30, 31, 31, 32, 30, 31, 31, 32, 32, 31, 31, 32, 32, 33}; + + static const uint8_t icp_61p44[53] = {13, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 28, 29, 28, 29, 28, 29, 29, 30, 24, 25, 25, + 26, 26, 35, 33, 34, 35, 35, 26, 27, 27, 28, 27, 27, 27, 28, 28, 27, 27, 28, 28, 29}; + + static const uint8_t icp_76p8[53] = {7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 15, 16, 15, 16, 16, 17, 13, 14, 14, 14, 15, + 19, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, 15, 16, 16}; + + static const uint32_t vcoFreqArray_kHz[53] = {12605000UL, 12245000UL, 11906000UL, 11588000UL, 11288000UL, 11007000UL, 10742000UL, 10492000UL, 10258000UL, 10036000UL, + 9827800UL, 9631100UL, 9445300UL, 9269800UL, 9103600UL, 8946300UL, 8797000UL, 8655300UL, 8520600UL, 8392300UL, 8269900UL, 8153100UL, 8041400UL, 7934400UL, + 7831800UL, 7733200UL, 7638400UL, 7547100UL, 7459000UL, 7374000UL, 7291900UL, 7212400UL, 7135500UL, 7061000UL, 6988700UL, 6918600UL, 6850600UL, 6784600UL, + 6720500UL, 6658200UL, 6597800UL, 6539200UL, 6482300UL, 6427000UL, 6373400UL, 6321400UL, 6270900UL, 6222000UL, 6174500UL, 6128400UL, 6083600UL, 6040100UL, + 5997700UL}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initDigitalClocks()\n"); +#endif + + retVal = MYKONOS_calculateScaledDeviceClk_kHz(device, &scaledRefClk_kHz, &deviceClkDiv); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + hsDiv = device->clocks->clkPllHsDiv; + vcoDiv = device->clocks->clkPllVcoDiv; + + switch (hsDiv) + { + case 4: + hsDiv = 4; /* clockControl2[3:2] = 00 */ + break; + case 5: + hsDiv = 5; + clockControl2 |= 0x04; /* Set bit[2]=1 */ + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_HSDIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_HSDIV)); + return MYKONOS_ERR_CLKPLL_INV_HSDIV; + } + + switch (vcoDiv) + { + case VCODIV_1: + vcoDivTimes10 = 10; /* clockControl2[1:0] = 00 */ + break; + case VCODIV_1p5: + vcoDivTimes10 = 15; + clockControl2 |= 0x01; + break; + case VCODIV_2: + vcoDivTimes10 = 20; + clockControl2 |= 0x02; + break; + case VCODIV_3: + vcoDivTimes10 = 30; + clockControl2 |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_VCODIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_VCODIV)); + return MYKONOS_ERR_CLKPLL_INV_VCODIV; + } + + clockControl2 |= ((deviceClkDiv & 3) << 4); + + /* find vco table index based on vco frequency */ + for (i = 0; device->clocks->clkPllVcoFreq_kHz < vcoFreqArray_kHz[i]; i++) + { + /* Intentionally blank, for loop exits when condition met, index i used below */ + } + vcoIndex = i + 1; + + if (vcoIndex < 1 || vcoIndex > 53) + { + /* vco index out of range */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX, + getMykonosErrorMessage(MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX)); + return MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX; + } + + /* valid for all refclk frequencies */ + vcoOutLvl = (vcoIndex <= 16) ? 13 : (vcoIndex <= 23) ? 12 : (vcoIndex <= 25) ? + 11 : (vcoIndex <= 35) ? 10 : (vcoIndex <= 39) ? 9 : (vcoIndex <= 43) ? + 8 : (vcoIndex <= 48) ? 7 : 6; + vcoVaractor = (vcoIndex <= 29 || vcoIndex == 35) ? 1 : 2; + vcoBiasRef = (vcoIndex <= 7 ) ? 4 : (vcoIndex <= 16) ? 6 : 7; + vcoBiasTcf = (vcoIndex <= 25 || (vcoIndex > 26 && vcoIndex <= 29) || + (vcoIndex > 37 && vcoIndex <= 39)) || (vcoIndex > 40 && vcoIndex <= 43) ? + 2 : 3; + + vcoVaractorRef = (vcoIndex <= 29) ? 12 : (vcoIndex == 35) ? 14 : 13; + + if ((scaledRefClk_kHz >= 40000) && (scaledRefClk_kHz < 53760)) + { /* Settings designed for 46.08 MHz PLL REFCLK */ + vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? + 14 :(vcoIndex <= 10 || vcoIndex > 44) ? + 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? + 12 : 13; + + loopFilterIcp = icp_46p08[vcoIndex - 1]; + loopFilterC2C1 = 0xF9; /* C2=0xF0 */ + loopFilterR1C3 = 0xD5; + loopFilterR3 = 0x0E; + } + else if ((scaledRefClk_kHz >= 53760) && (scaledRefClk_kHz < 69120)) + { /* Settings designed for 61.44 MHz PLL REFCLK */ + vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 29 && vcoIndex <= 34) || vcoIndex == 40 || vcoIndex == 44) ? + 14 :(vcoIndex <= 10 || vcoIndex > 44) ? + 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 25) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 34 && vcoIndex <= 37)) ? + 12 : (vcoIndex > 37 && vcoIndex <= 39) ? 11 : 13; + + vcoVaractor = (vcoIndex > 35 && vcoIndex <= 39) ? 1 : vcoVaractor; + vcoBiasRef = (vcoIndex > 4 && vcoIndex <= 7) ? 5 : vcoBiasRef; + vcoVaractorRef = (vcoIndex > 35 && vcoIndex <= 39) ? 14 : vcoVaractorRef; + loopFilterIcp = icp_61p44[vcoIndex-1]; + loopFilterC2C1 = ((vcoIndex > 2 && vcoIndex <= 6) || (vcoIndex > 8 && vcoIndex <= 13) || (vcoIndex > 14)) ? 0xFD : 0xFC; /* C2=0xF0 */ + loopFilterR1C3 = 0xC5; + loopFilterR3 = (vcoIndex <= 2 || (vcoIndex > 6 && vcoIndex <= 8) || vcoIndex == 14) ? 14 : 13 ; + } + else if ((scaledRefClk_kHz >= 69120) && (scaledRefClk_kHz <= 80000)) + { /* Settings designed for 76.8 MHz PLL REFCLK */ + vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? + 14 :(vcoIndex <= 10 || vcoIndex > 44) ? + 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? + 12 : 13; + + loopFilterIcp = icp_76p8[vcoIndex-1]; + loopFilterC2C1 = (vcoIndex == 20 ) ? 0xF7 : (vcoIndex == 4 || vcoIndex == 6 || vcoIndex == 8 ) ? 0xE6: 0xF6; /*C2=0xF0, C1=6 or 7 */ + loopFilterR1C3 = (vcoIndex == 4 ) ? 0xE4 : 0xD5; + loopFilterR3 = 0x0E; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_INV_REFCLK, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_INV_REFCLK)); + return MYKONOS_ERR_SETRFPLL_INV_REFCLK; /* invalid ref clk */ + } + + /* Hold CLKPLL digital logic in reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x00); + + /* Set reference clock scaler + HSdiv + VCOdiv */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, clockControl2); + + /*Set VCO cal time */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_CAL_CONTROL, 0x02); + + /* Write Synth Setting regs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_F_VCOTN_BYTE1, ((vcoCalOffset & 0x0F) << 3)); /* Set VCO Cal offset[3:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE1, (0xC0 | (vcoVaractor & 0x0F))); /* Init ALC[3:0], VCO varactor[3:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE2, (0x40 | (vcoOutLvl & 0x0F))); /* VCO output level */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE9, (((vcoBiasTcf & 0x03) << 3) | (vcoBiasRef & 0x07))); /* Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_CAL_REF, 0x30); /* Set VCO cal time (compare length) + Set VCO Cal Ref Tcf[2:0]=0 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL1, 0x70); /* Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL2, (vcoVaractorRef & 0x0F)); /* Set VCO Varactor Reference[3:0] */ + + /* Write Loop filter */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE3, (0x80 | (loopFilterIcp & 0x03F))); /* Set Loop Filter Icp[5:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE6, loopFilterC2C1); /* Set Loop Filter C2[3:0] and C1[3:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE7, loopFilterR1C3); /* Set Loop Filter R1[3:0] and C3[3:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_LF_R3, (loopFilterR3 & 0x0F)); /*Set Loop Filter R3[3:0] */ + + /* Calculate PLL integer and fractional words with integer math */ + scaledRefClk_Hz = scaledRefClk_kHz * 1000; + hsDigClk_Hz = (((uint64_t)(device->clocks->clkPllVcoFreq_kHz) * 10000) / vcoDivTimes10) / hsDiv; + integerWord = (uint16_t)(hsDigClk_Hz / scaledRefClk_Hz); + fractionalRemainder = hsDigClk_Hz % scaledRefClk_Hz; + + /* +1 >> 1 is rounding (add .5) */ + fractionalWord = ((uint32_t)((((uint64_t)fractionalRemainder * 4177920) / (uint64_t)scaledRefClk_Hz) + 1) >> 1); + + /* if fractionalWord rounded up and == PLL modulus, fix it */ + if (fractionalWord == 2088960) + { + fractionalWord = 0; + integerWord = integerWord + 1; + } + + if (fractionalWord > 0) + { /* in normal case, the fractional word should be zero and SDM bypassed */ + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLKPLL_INV_FRACWORD, + getMykonosErrorMessage(MYKONOS_ERR_SETCLKPLL_INV_FRACWORD)); + /* down graded to warning, do not return error code */ + //return MYKONOS_ERR_SETCLKPLL_INV_FRACWORD; + sdmSettings = 0x20; + } + else + { + /* Bypass SDM */ + sdmSettings = 0xE0; + } + + /* Set PLL fractional word[22:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0, (fractionalWord & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1, ((fractionalWord >> 8) & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2, ((fractionalWord >> 16) & 0x7F)); + + /* Write PLL integer word [7:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, (sdmSettings | ((integerWord >> 8) & 0x7))); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0, (integerWord & 0xFF)); + + /* Release PLL from reset, and set start VCO cal bit to 0 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x80); + + /* Power up CLKPLL */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_0, 0x00); + CMB_wait_ms(200); /* Allow PLL time to power up */ + + /* Enable Charge pump cal after Charge Pump current set (Icp[5:0]) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE5, 0x84); + + /* Start VCO Cal */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x81); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the RF PLL local oscillator frequency (RF carrier frequency). + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the MYKONOS data structure containing settings + * \param pllName Name of the PLL to configure + * \param rfPllLoFrequency_Hz Desired RF LO frequency + * + * \return MYKONOS_ERR_OK Function completed successfully + * \return MYKONOS_ERR_SETRFPLL_ARMERROR ARM Command to set RF PLL frequency failed + */ +mykonosErr_t MYKONOS_setRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t rfPllLoFrequency_Hz) +{ + const uint8_t SETCMD_OPCODE = 0x0A; + const uint8_t SET_PLL_FREQUENCY = 0x63; + + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[8] = {0}; + uint8_t extData[2] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + + armData[0] = (uint8_t)(rfPllLoFrequency_Hz & 0xFF); + armData[1] = (uint8_t)((rfPllLoFrequency_Hz >> 8) & 0xFF); + armData[2] = (uint8_t)((rfPllLoFrequency_Hz >> 16) & 0xFF); + armData[3] = (uint8_t)((rfPllLoFrequency_Hz >> 24) & 0xFF); + armData[4] = (uint8_t)((rfPllLoFrequency_Hz >> 32) & 0xFF); + armData[5] = (uint8_t)((rfPllLoFrequency_Hz >> 40) & 0xFF); + armData[6] = (uint8_t)((rfPllLoFrequency_Hz >> 48) & 0xFF); + armData[7] = (uint8_t)((rfPllLoFrequency_Hz >> 56) & 0xFF); + + /* write 64-bit frequency to ARM memory */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + extData[0] = SET_PLL_FREQUENCY; + + switch (pllName) + { + case RX_PLL: + extData[1] = 0x00; + break; + case TX_PLL: + extData[1] = 0x01; + break; + case SNIFFER_PLL: + extData[1] = 0x02; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_INV_PLLNAME, + getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_INV_PLLNAME)); + return MYKONOS_ERR_SETRFPLL_INV_PLLNAME; + } + } + + retVal = MYKONOS_sendArmCommand(device, SETCMD_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, SETCMD_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_ARMERROR)); + return MYKONOS_ERR_SETRFPLL_ARMERROR; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_ARMERROR)); + return MYKONOS_ERR_SETRFPLL_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Gets the RF PLL local oscillator frequency (RF carrier frequency). + * + * This function is used to get the RF PLL's frequency. It can get the RX PLL, TX PLL + * Sniffer PLL, and CLKPLL. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * - device->clocks->deviceClock_kHz + * + * \param device is structure pointer to the MYKONOS data structure containing settings + * \param pllName Name of the PLL for which to read the frequency + * \param rfPllLoFrequency_Hz RF LO frequency currently set for the PLL specified + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV Invalid CLKPLL reference clock divider read from Mykonos device + * \retval MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV Invalid CLKPLL high speed clock divider read from Mykonos device + * \retval MYKONOS_ERR_GETRFPLL_INV_PLLNAME Invalid PLL name, can not get PLL frequency. Use PLL name ENUM. + * \retval MYKONOS_ERR_GETRFPLL_ARMERROR ARM Command to get RF PLL frequency failed + * \retval MYKONOS_ERR_GETRFPLL_NULLPARAM rfPllLoFrequency_Hz function parameter pointer is NULL + */ +mykonosErr_t MYKONOS_getRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t *rfPllLoFrequency_Hz) +{ + const uint8_t RFPLL_LO_FREQUENCY = 0x63; + + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t extData[2] = {0, 0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint8_t getClkPllFrequency = 0; + + uint32_t clkPllIntWord = 0; + uint32_t clkPllFracWord = 0; + uint8_t clkPllRefClkDiv = 0; + uint8_t hsDiv = 0; + uint8_t vcoDivTimes10 = 0; + uint8_t hsDivReg = 0; + uint8_t vcoDivReg = 0; + uint8_t clkPllIntWord7_0 = 0; + uint8_t clkPllIntWord10_8 = 0; + uint8_t clkPllFracWord7_0 = 0; + uint8_t clkPllFracWord15_8 = 0; + uint8_t clkPllFracWord22_16 = 0; + uint64_t refclk_Hz = 0; + + extData[0] = RFPLL_LO_FREQUENCY; + + switch (pllName) + { + case CLK_PLL: + getClkPllFrequency = 1; + break; + case RX_PLL: + extData[1] = 0x00; + break; + case TX_PLL: + extData[1] = 0x01; + break; + case SNIFFER_PLL: + extData[1] = 0x02; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_INV_PLLNAME, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_INV_PLLNAME)); + return MYKONOS_ERR_GETRFPLL_INV_PLLNAME; + } + } + + if (getClkPllFrequency > 0) + { + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &hsDivReg, 0x0C, 2); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &vcoDivReg, 0x03, 0); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &clkPllRefClkDiv, 0x70, 4); + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0, &clkPllIntWord7_0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, &clkPllIntWord10_8); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0, &clkPllFracWord7_0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1, &clkPllFracWord15_8); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2, &clkPllFracWord22_16); + + clkPllIntWord = (((uint32_t)(clkPllIntWord10_8 & 0x7) << 8) | clkPllIntWord7_0); + clkPllFracWord = (((uint32_t)(clkPllFracWord22_16 & 0x7F) << 16) | ((uint32_t)(clkPllFracWord15_8) << 8) | clkPllFracWord7_0); + + switch (clkPllRefClkDiv) + { + case 0: + refclk_Hz = ((uint64_t)device->clocks->deviceClock_kHz * 1000); + break; + case 1: + refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) >> 1); + break; /* div 2 */ + case 2: + refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) >> 2); + break; /* div 4 */ + case 3: + refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) << 1); + break; /* times 2 */ + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV, + getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV)); + return MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV; + } + } + + switch (vcoDivReg) + { + case 0: + vcoDivTimes10 = 10; + break; + case 1: + vcoDivTimes10 = 15; + break; + case 2: + vcoDivTimes10 = 20; + break; + case 3: + vcoDivTimes10 = 30; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV, + getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV)); + return MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV; + } + } + + switch (hsDivReg) + { + case 0: + hsDiv = 4; + break; + case 1: + hsDiv = 5; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV, + getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV)); + return MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV; + } + } + + /* round to nearest Hz for fractional word (fractional modulus = 2088960) */ + *rfPllLoFrequency_Hz = (uint64_t)(((refclk_Hz * clkPllIntWord) + (((refclk_Hz * clkPllFracWord / 1044480) + 1) >> 1)) * hsDiv * vcoDivTimes10 / 10); + } + else + { + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_ARMERROR)); + return MYKONOS_ERR_GETRFPLL_ARMERROR; + } + + return retVal; + } + + /* read 64-bit frequency from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_ARMERROR)); + return MYKONOS_ERR_GETRFPLL_ARMERROR; + } + + if (rfPllLoFrequency_Hz == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_NULLPARAM)); + return MYKONOS_ERR_GETRFPLL_NULLPARAM; + } + + *rfPllLoFrequency_Hz = (uint64_t)((uint64_t)(armData[0])) | ((uint64_t)(armData[1]) << 8) | ((uint64_t)(armData[2]) << 16) | ((uint64_t)(armData[3]) << 24) + | ((uint64_t)(armData[4]) << 32) | ((uint64_t)(armData[5]) << 40) | ((uint64_t)(armData[6]) << 48) | ((uint64_t)(armData[7]) << 56); + } + return MYKONOS_ERR_OK; +} + +/** + * \brief Checks if the PLLs are locked + * + * This function updates the pllLockStatus pointer with a lock status it per + * PLL. + * pllLockStatus[0] = CLKPLL Locked + * pllLockStatus[1] = RX_PLL Locked + * pllLockStatus[2] = TX_PLL Locked + * pllLockStatus[3] = SNIFFER_PLL Locked + * pllLockStatus[4] = CAL_PLL Locked + * + * \param device the Mykonos device data structure + * \param pllLockStatus Lock status bit per PLL + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_checkPllsLockStatus(mykonosDevice_t *device, uint8_t *pllLockStatus) +{ + uint8_t readData = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_checkPllsLockStatus()\n"); +#endif + + if (pllLockStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM)); + return MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM; + } + + *pllLockStatus = 0; + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0); + *pllLockStatus = readData; + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0); + *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 1); + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0); + *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 2); + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0); + *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 3); + + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CALPLL_SDM_CONTROL, &readData, 0x80, 7); + *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 4); + + return MYKONOS_ERR_OK; +} + +/* + ***************************************************************************** + * Shared Data path functions + ***************************************************************************** + */ + +/** + * \brief Sets the digital Tx PFIR SYNC clock divider. + * + * This function is a helper function. It is called automatically in + * MYKONOS_initialize() and should not need to be called by the BBIC. + * + * This function sets the digital clock divider that is used to synchronize the + * Tx PFIR each time the Tx channel power up. The Sync clock must + * be set equal to or slower than the FIR processing clock. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->txProfile->txFir + * - device->tx->txProfile->txFir->numFirCoefs + * - device->tx->txProfile->txFirInterpolation + * - device->tx->txProfile->iqRate_kHz + * + * \param device Pointer to the Mykonos data structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM: Invalid number of Tx FIR coefficients + * \retval MYKONOS_ERR_TXFIR_INV_NUMROWS Invalid number of PFIR coefficient rows + * \retval MYKONOS_ERR_TXFIR_TAPSEXCEEDED Too many Tx PFIR taps for the IQ sample rate. FIR processing clock can not run fast enough to handle the number of taps + */ +mykonosErr_t MYKONOS_setTxPfirSyncClk(mykonosDevice_t *device) +{ + const uint8_t numTapMultiple = 16; + const uint8_t maxNumTaps = 96; + uint8_t effectiveRows = 0; + uint8_t numRows = 0; + uint32_t dpClk_kHz = 0; + uint32_t syncClk_kHz = 0; + uint32_t hsDigClkDiv4or5_kHz = 0; + uint8_t syncDiv = 0; + mykonosErr_t retval = MYKONOS_ERR_OK; + + if (((device->profilesValid & TX_PROFILE_VALID) > 0) && (device->tx->txProfile->txFir != NULL)) + { + /* Calculate number of FIR rows for number of Taps */ + if ((device->tx->txProfile->txFir->numFirCoefs % numTapMultiple == 0) && (device->tx->txProfile->txFir->numFirCoefs > 0) + && (device->tx->txProfile->txFir->numFirCoefs <= maxNumTaps)) + { + numRows = (device->tx->txProfile->txFir->numFirCoefs / numTapMultiple); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM, + getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM)); + return MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM; + } + + effectiveRows = ((numRows + (device->tx->txProfile->txFirInterpolation - 1)) / device->tx->txProfile->txFirInterpolation); + + /* round up to next power of 2 */ + switch (effectiveRows) + { + case 1: + effectiveRows = 1; + break; + case 2: + effectiveRows = 2; + break; + case 3: /* fall through */ + case 4: + effectiveRows = 4; + break; + case 5: /* fall through */ + case 6: /* fall through */ + case 7: /* fall through */ + case 8: + effectiveRows = 8; + break; + default: + { + /* invalid number of FIR taps */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_NUMROWS, + getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_NUMROWS)); + return MYKONOS_ERR_TXFIR_INV_NUMROWS; + } + } + + dpClk_kHz = (device->tx->txProfile->iqRate_kHz * device->tx->txProfile->txInputHbInterpolation * device->tx->txProfile->txFirInterpolation * effectiveRows); + + /* FIR DPCLK can only run at max of 500MHz */ + if (dpClk_kHz > 500000) + { + /* Max number of Tx PFIR taps exceeded for Tx Profile */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_TAPSEXCEEDED, + getMykonosErrorMessage(MYKONOS_ERR_TXFIR_TAPSEXCEEDED)); + return MYKONOS_ERR_TXFIR_TAPSEXCEEDED; + } + + /* SYNC CLOCK is the PFIR output rate / 2 */ + syncClk_kHz = device->tx->txProfile->iqRate_kHz * device->tx->txProfile->txFirInterpolation / 2; + if ((retval = MYKONOS_calculateDigitalClocks(device, NULL, &hsDigClkDiv4or5_kHz)) != MYKONOS_ERR_OK) + { + return retval; + } + + /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */ + for (syncDiv = 0; syncDiv < 5; syncDiv++) + { + if ((hsDigClkDiv4or5_kHz / (uint32_t)(4 << syncDiv)) <= syncClk_kHz) + { + break; + } + } + + /* Write Tx PFIR SYNC Clock divider */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_5, syncDiv, 0x70, 4); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the digital Rx PFIR SYNC clock divider. + * + * This function is a helper function. It is called automatically in + * MYKONOS_initialize() and should not need to be called by the BBIC. + * + * This function sets the digital clock divider that is used to synchronize the + * Rx/ORx/Sniffer PFIRs each time the channels power up. The Sync clock must + * be set equal to or slower than the slowest Rx/ORx/Sniffer PFIR processing + * clock. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->rx->rxProfile->rxFir + * - device->rx->rxProfile->rxFir->numFirCoefs + * - device->rx->rxProfile->iqRate_kHz + * - device->obsRx->orxProfile->rxFir + * - device->obsRx->orxProfile->rxFir->numFirCoefs + * - device->obsRx->orxProfile->iqRate_kHz + * - device->obsRx->snifferProfile->rxFir + * - device->obsRx->snifferProfile->rxFir->numFirCoefs + * - device->obsRx->snifferProfile->iqRate_kHz + * + * \param device Pointer to the Mykonos data structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_RXFIR_TAPSEXCEEDED ERROR: the number of Rx FIR taps exceeds the number of taps accommodated by the FIR processing clock + * \retval MYKONOS_ERR_ORXFIR_TAPSEXCEEDED ERROR: the number of ORx FIR Taps exceeds the number of taps accommodated by the FIR processing clock + * \retval MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED ERROR: the number of sniffer FIR taps exceeds the number of taps accommodated by the FIR processing clock + */ +mykonosErr_t MYKONOS_setRxPfirSyncClk(mykonosDevice_t *device) +{ + uint32_t rxDpClk_kHz = 0; + uint32_t orxDpClk_kHz = 0; + uint32_t snRxDpClk_kHz = 0; + uint32_t slowestIqRate_kHz = 0; + uint32_t syncClk_kHz = 0; + uint8_t effectiveRxNumRows = 0; + uint8_t effectiveOrxNumRows = 0; + uint8_t effectiveSnrxNumRows = 0; + + uint32_t hsDigClkDiv4or5_kHz = 0; + uint8_t syncDiv = 0; + mykonosErr_t retval = MYKONOS_ERR_OK; + + /** + * Calculate Rx SYNC Clock divider for Rx PFIR. Same Rx SYNC Clock is used + * for Rx, ORx, and Sniffer PFIRs, and must be slow enough to handle the slowest + * PFIR rate. + **/ + + if (((device->profilesValid & RX_PROFILE_VALID) > 0) && (device->rx->rxProfile->rxFir != NULL)) + { + switch (device->rx->rxProfile->rxFir->numFirCoefs) + { + case 24: + effectiveRxNumRows = 1; + break; + case 48: + effectiveRxNumRows = 2; + break; + case 72: + effectiveRxNumRows = 4; + break; + default: + break; + } + + rxDpClk_kHz = device->rx->rxProfile->iqRate_kHz * effectiveRxNumRows; + + if (rxDpClk_kHz > 500000) + { + /* Max number of Rx PFIR taps exceeded for Profile */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_TAPSEXCEEDED, + getMykonosErrorMessage(MYKONOS_ERR_RXFIR_TAPSEXCEEDED)); + return MYKONOS_ERR_RXFIR_TAPSEXCEEDED; + } + + slowestIqRate_kHz = device->rx->rxProfile->iqRate_kHz; + } + + if (((device->profilesValid & ORX_PROFILE_VALID) > 0) && (device->obsRx->orxProfile->rxFir != NULL)) + { + switch (device->obsRx->orxProfile->rxFir->numFirCoefs) + { + case 24: + effectiveOrxNumRows = 1; + break; + case 48: + effectiveOrxNumRows = 2; + break; + case 72: + effectiveOrxNumRows = 4; + break; + default: + break; + } + + orxDpClk_kHz = device->obsRx->orxProfile->iqRate_kHz * effectiveOrxNumRows; + + if (orxDpClk_kHz > 500000) + { + /* Max number of ORx PFIR taps exceeded for Profile */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ORXFIR_TAPSEXCEEDED, + getMykonosErrorMessage(MYKONOS_ERR_ORXFIR_TAPSEXCEEDED)); + return MYKONOS_ERR_ORXFIR_TAPSEXCEEDED; + } + + if ((slowestIqRate_kHz == 0) || (slowestIqRate_kHz > device->obsRx->orxProfile->iqRate_kHz)) + { + slowestIqRate_kHz = device->obsRx->orxProfile->iqRate_kHz; + + } + } + + if (((device->profilesValid & SNIFF_PROFILE_VALID) > 0) && (device->obsRx->snifferProfile->rxFir != NULL)) + { + switch (device->obsRx->snifferProfile->rxFir->numFirCoefs) + { + case 24: + effectiveSnrxNumRows = 1; + break; + case 48: + effectiveSnrxNumRows = 2; + break; + case 72: + effectiveSnrxNumRows = 4; + break; + default: + break; + } + + snRxDpClk_kHz = device->obsRx->snifferProfile->iqRate_kHz * effectiveSnrxNumRows; + + if (snRxDpClk_kHz > 500000) + { + /* Max number of ORx PFIR taps exceeded for Profile */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED, + getMykonosErrorMessage(MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED)); + return MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED; + } + + if ((slowestIqRate_kHz == 0) || (slowestIqRate_kHz > device->obsRx->snifferProfile->iqRate_kHz)) + { + slowestIqRate_kHz = device->obsRx->snifferProfile->iqRate_kHz; + } + } + + /* SYNC CLOCK should be FIR output rate / 2 */ + syncClk_kHz = (slowestIqRate_kHz / 2); + if ((retval = MYKONOS_calculateDigitalClocks(device, NULL, &hsDigClkDiv4or5_kHz)) != MYKONOS_ERR_OK) + { + return retval; + } + + /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */ + for (syncDiv = 0; syncDiv < 5; syncDiv++) + { + if ((hsDigClkDiv4or5_kHz / (uint32_t)(4 << syncDiv)) <= syncClk_kHz) + { + break; + } + } + + /* Write Rx PFIR SYNC Clock divider */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_5, syncDiv, 0x07, 0); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Configures one or more FIR filters in the device + * + * The device stores up to 6 FIR filters (2Rx, 2Obs Rx/Sniffer, and 2Tx). + * Rx filters can have 24, 48, or 72 taps. Tx filters can have 16, 32, + * 48, 64, 80, or 96 taps. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos data structure + * \param filterToProgram Name of the desired filter to program + * \param firFilter Pointer to the filter to write into the device + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_PROGRAMFIR_NULL_PARM ERROR: firFilter parameter is a NULL pointer + * \retval MYKONOS_ERR_PROGRAMFIR_COEFS_NULL ERROR: firFilter->coefs is a NULL pointer + * \retval MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM ERROR: Invalid FIR filter name in filterToProgram parameter + * \retval MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM ERROR: Invalid number of taps for the filter + * \retval MYKONOS_ERR_RXFIR_INV_GAIN_PARM ERROR: Rx FIR filter has invalid gain setting + * \retval MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM ERROR: OBSRX_A (ORX) FIR filter has invalid gain setting + * \retval MYKONOS_ERR_SRXFIR_INV_GAIN_PARM ERROR: OBSRX_B (Sniffer) FIR filter has invalid gain setting + * \retval MYKONOS_ERR_TXFIR_INV_GAIN_PARM ERROR: Tx FIR filter has invalid gain setting + */ +mykonosErr_t MYKONOS_programFir(mykonosDevice_t *device, mykonosfirName_t filterToProgram, mykonosFir_t *firFilter) +{ + uint8_t filterSelect = 0; + uint8_t i = 0; + uint8_t numTapsReg = 0; + uint8_t numTapMultiple = 24; /* Rx=24, Tx=16 */ + uint8_t maxNumTaps = 72; /* Rx=72, Tx=96 */ + uint8_t filterGain = 0; + +#if MYK_ENABLE_SPIWRITEARRAY == 1 + uint32_t addrIndex = 0; + uint32_t dataIndex = 0; + uint32_t spiBufferSize = ((MYK_SPIWRITEARRAY_BUFFERSIZE / 6) * 6); /* Make buffer size a multiple of 6 */ + uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; + uint8_t dataArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; +#endif + + const uint8_t COEF_WRITE_EN = 0x40; + const uint8_t PROGRAM_CLK_EN = 0x80; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_programFir()\n"); +#endif + + if (firFilter == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_NULL_PARM)); + return MYKONOS_ERR_PROGRAMFIR_NULL_PARM; + } + + if (firFilter->coefs == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_COEFS_NULL, + getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_COEFS_NULL)); + return MYKONOS_ERR_PROGRAMFIR_COEFS_NULL; + } + + switch (filterToProgram) + { + case TX1_FIR: + filterSelect = 0x01; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case TX2_FIR: + filterSelect = 0x02; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case TX1TX2_FIR: + filterSelect = 0x03; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case RX1_FIR: + filterSelect = 0x04; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case RX2_FIR: + filterSelect = 0x08; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case RX1RX2_FIR: + filterSelect = 0x0C; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case OBSRX_A_FIR: + filterSelect = 0x10; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case OBSRX_B_FIR: + filterSelect = 0x20; + numTapMultiple = 24; + maxNumTaps = 72; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM)); + return MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM; + } + + /* Calculate register value for number of Taps */ + if ((firFilter->numFirCoefs % numTapMultiple == 0) && (firFilter->numFirCoefs > 0) && (firFilter->numFirCoefs <= maxNumTaps)) + { + numTapsReg = (firFilter->numFirCoefs / numTapMultiple) - 1; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM, + getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM)); + return MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM; + } + + /* Select which FIR filter to program coeffs for */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); //select filter and enable the programming clock + +#if (MYK_ENABLE_SPIWRITEARRAY == 0) + + /* write filter coefficients */ + for (i = 0; i < firFilter->numFirCoefs; i++) + { + /* Write Low byte of 16bit coefficient */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (i * 2)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, (firFilter->coefs[i] & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect)); /* write enable (self clearing) */ + + /* Write High Byte of 16bit coefficient */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, ((i * 2) + 1)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, ((firFilter->coefs[i] >> 8) & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect));/* write enable (self clearing) */ + } + +#elif (MYK_ENABLE_SPIWRITEARRAY == 1) + + addrIndex = 0; + dataIndex = 0; + for (i = 0; i < firFilter->numFirCoefs; i++) + { + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_ADDR; + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_DATA; + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_CTL; + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_ADDR; + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_DATA; + addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_CTL; + + dataArray[dataIndex++] = (uint8_t)(i * 2); + dataArray[dataIndex++] = (firFilter->coefs[i] & 0xFF); + dataArray[dataIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect); + dataArray[dataIndex++] = (uint8_t)((i * 2) + 1); + dataArray[dataIndex++] = (((uint16_t)firFilter->coefs[i] >> 8) & 0xFF); + dataArray[dataIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect); + + /* Send full buffer size when possible */ + /* spiBufferSize set to multiple of 6 at top of function */ + if (addrIndex >= spiBufferSize) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex); + dataIndex = 0; + addrIndex = 0; + } + } + + if (addrIndex > 0) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex); + } + +#endif + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, filterSelect); /* clear Program clock enable */ + /* write filter gain and #taps */ + if (filterToProgram == RX1_FIR || filterToProgram == RX2_FIR || filterToProgram == RX1RX2_FIR) + { + /* Write Rx FIR #taps */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x60, 5); + + /* Set Rx filter gain */ + switch (firFilter->gain_dB) + { + case -12: + filterGain = 0x00; + break; + case -6: + filterGain = 0x01; + break; + case 0: + filterGain = 0x02; + break; + case 6: + filterGain = 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_RXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_RXFIR_INV_GAIN_PARM; + } + + /* Write Rx filter gain */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_GAIN, filterGain, 0x03, 0); + } + else if (filterToProgram == OBSRX_A_FIR) + { + /* Write Obs Rx FIR A #taps */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x06, 1); + + /* Set Rx filter gain */ + switch (firFilter->gain_dB) + { + case -12: + filterGain = 0x00; + break; + case -6: + filterGain = 0x01; + break; + case 0: + filterGain = 0x02; + break; + case 6: + filterGain = 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM; + } + + /* Write Obs Rx filter gain */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, filterGain, 0x03, 0); + } + else if (filterToProgram == OBSRX_B_FIR) + { + /* Write Obs Rx FIR B #taps */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x18, 3); + + /* Set Rx filter gain */ + switch (firFilter->gain_dB) + { + case -12: + filterGain = 0x00; + break; + case -6: + filterGain = 0x01; + break; + case 0: + filterGain = 0x02; + break; + case 6: + filterGain = 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SRXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SRXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_SRXFIR_INV_GAIN_PARM; + } + + /* Write Obs Rx filter gain */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, filterGain, 0x60, 5); + } + else if (filterToProgram == TX1_FIR || filterToProgram == TX2_FIR || filterToProgram == TX1TX2_FIR) + { + /* Write number of Taps */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, numTapsReg, 0xE0, 5); + + switch (firFilter->gain_dB) + { + case 0: + filterGain = 0; + break; + case 6: + filterGain = 1; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_TXFIR_INV_GAIN_PARM; + } + + /* Write Tx Filter gain */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, filterGain, 0x01, 0); + + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the FIR filter programmed into the device + * + * The device stores up to 6 FIR filters (2Rx, 2Obs Rx/Sniffer, and 2Tx). + * Rx filters can have 24, 48, or 72 taps. Tx filters can have 16, 32, + * 48, 64, 80, or 96 taps. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos data structure + * \param filterToRead Name of the desired filter to be read + * \param firFilter Pointer to the filter to be read from the device + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READFIR_NULL_PARM ERROR: firFilter parameter is a NULL pointer + * \retval MYKONOS_ERR_READFIR_COEFS_NULL ERROR: firFilter->coefs is a NULL pointer + * \retval MYKONOS_ERR_READFIR_INV_FIRNAME_PARM ERROR: Invalid FIR filter name in filterToRead parameter + * \retval MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM ERROR: Invalid number of taps for the filter + * \retval MYKONOS_ERR_RXFIR_INV_GAIN_PARM ERROR: Rx FIR filter has invalid gain setting + * \retval MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM ERROR: OBSRX_A (ORX) FIR filter has invalid gain setting + * \retval MYKONOS_ERR_SRXFIR_INV_GAIN_PARM ERROR: OBSRX_B (Sniffer) FIR filter has invalid gain setting + * \retval MYKONOS_ERR_TXFIR_INV_GAIN_PARM ERROR: Tx FIR filter has invalid gain setting + */ +mykonosErr_t MYKONOS_readFir(mykonosDevice_t *device, mykonosfirName_t filterToRead, mykonosFir_t *firFilter) +{ + uint8_t filterSelect = 0; + uint8_t i = 0; + uint8_t numTapsReg = 0; + uint8_t numTapMultiple = 24; + uint8_t maxNumTaps = 72; + uint8_t filterGain = 0; + uint8_t msbRead = 0; + uint8_t lsbRead = 0; + + const uint8_t PROGRAM_CLK_EN = 0x80; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readFir()\n"); +#endif + + if (firFilter == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_READFIR_NULL_PARM)); + return MYKONOS_ERR_READFIR_NULL_PARM; + } + + if (firFilter->coefs == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_COEFS_NULL, getMykonosErrorMessage(MYKONOS_ERR_READFIR_COEFS_NULL)); + return MYKONOS_ERR_READFIR_COEFS_NULL; + } + + switch (filterToRead) + { + case TX1_FIR: + filterSelect = 0x01; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case TX2_FIR: + filterSelect = 0x02; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case TX1TX2_FIR: + filterSelect = 0x03; + numTapMultiple = 16; + maxNumTaps = 96; + break; + case RX1_FIR: + filterSelect = 0x04; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case RX2_FIR: + filterSelect = 0x08; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case RX1RX2_FIR: + filterSelect = 0x0C; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case OBSRX_A_FIR: + filterSelect = 0x10; + numTapMultiple = 24; + maxNumTaps = 72; + break; + case OBSRX_B_FIR: + filterSelect = 0x20; + numTapMultiple = 24; + maxNumTaps = 72; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_INV_FIRNAME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READFIR_INV_FIRNAME_PARM)); + return MYKONOS_ERR_READFIR_INV_FIRNAME_PARM; + } + + /* clear Program clock enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, filterSelect); + + /* Read filter gain and #taps */ + if (filterToRead == RX1_FIR || filterToRead == RX2_FIR || filterToRead == RX1RX2_FIR) + { + /* Read Rx FIR #taps */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x60, 5); + + firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple); + + /* Read Rx filter gain */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_GAIN, &filterGain, 0x03, 0); + + switch (filterGain) + { + case 0x00: + firFilter->gain_dB = -12; + break; + case 0x01: + firFilter->gain_dB = -6; + break; + case 0x02: + firFilter->gain_dB = 0; + break; + case 0x03: + firFilter->gain_dB = 6; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_RXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_RXFIR_INV_GAIN_PARM; + } + } + else if (filterToRead == OBSRX_A_FIR) + { + /* Read Obs Rx FIR A #taps */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x60, 1); + + firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple); + + /* Read Obs Rx FIR A gain */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, &filterGain, 0x03, 0); + + switch (filterGain) + { + case 0x00: + firFilter->gain_dB = -12; + break; + case 0x01: + firFilter->gain_dB = -6; + break; + case 0x02: + firFilter->gain_dB = 0; + break; + case 0x03: + firFilter->gain_dB = 6; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM; + } + } + else if (filterToRead == OBSRX_B_FIR) + { + /* Read Obs Rx FIR B #taps */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x18, 3); + + firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple); + + /* Read Obs Rx FIR B gain */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, &filterGain, 0x60, 5); + + switch (filterGain) + { + case 0x00: + firFilter->gain_dB = -12; + break; + case 0x01: + firFilter->gain_dB = -6; + break; + case 0x02: + firFilter->gain_dB = 0; + break; + case 0x03: + firFilter->gain_dB = 6; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SRXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SRXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_SRXFIR_INV_GAIN_PARM; + } + } + else if (filterToRead == TX1_FIR || filterToRead == TX2_FIR || filterToRead == TX1TX2_FIR) + { + /* Read number of Taps */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, &numTapsReg, 0xE0, 5); + + firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple); + + /* Read Tx Filter gain */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, &filterGain, 0x01, 0); + + switch (filterGain) + { + case 0: + firFilter->gain_dB = 0; + break; + case 1: + firFilter->gain_dB = 6; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_GAIN_PARM)); + return MYKONOS_ERR_TXFIR_INV_GAIN_PARM; + } + } + + /* Select which FIR filter to read the coeffs for */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); //select filter and enable the programming clock + + if (firFilter->numFirCoefs > maxNumTaps) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM)); + return MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM; + } + + /* write filter coefficients */ + for (i = 0; i < firFilter->numFirCoefs; i++) + { + /* Write Low byte of 16bit coefficient */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (uint8_t)(i * 2)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); /* write enable (self clearing) */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, &lsbRead); + + /* Write High Byte of 16bit coefficient */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (uint8_t)((i * 2) + 1)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect));/* write enable (self clearing) */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, &msbRead); + + firFilter->coefs[i] = (int16_t)((lsbRead & 0xFF) | ((msbRead << 8) & 0xFF00)); + } + + return MYKONOS_ERR_OK; +} + +/* + ***************************************************************************** + * Rx Data path functions + ***************************************************************************** + */ +/*! + * \brief Programs the gain table settings for either Rx1, Rx2, Rx1 + Rx2, ORx, or SnRx receiver types + * + * The gain table for a receiver type is set with the parameters passed by uint8_t gainTablePtr array. + * gainTablePtr is a 4 x n array, where there are four (4) elements per index, and the array + * length (n) is dependent upon receiver type. The (n) value is conveyed by numGainIndexesInTable. + * All gain tables have a maximum index of 255 when used with this function. The minimum gain index is + * application dependent. + * + * Where for Rx1, Rx2, and ObsRx: + * [A, B, C, D]: A = Front End Gain, B = External Control, C = Digital Attenuation/Gain, D = Attenuation/Gain select + * + * Where for SnRx: + * [A, B, C, D]: A = Front End Gain, B = LNA Bypass, C = Digital Attenuation/Gain, D = Attenuation/Gain select + * + * The gain table starting address changes with each receiver type. This function accounts for this change as well as the + * difference between byte [B] for {Rx1, Rx2, ObsRx} and SnRx receiver array values and programs the correct registers. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos data structure + * \param gainTablePtr Pointer to 4 x n array containing gain table program values + * \param numGainIndexesInTable The number of 'n' indices in 4 x n array. A range check is performed to ensure the maximum is not exceeded. + * \param rxChannel mykonosGainTable_t enum type to select either Rx1, Rx2, Rx1 + Rx2, ORx, or SnRx gain table for programming. A + * channel check is performed to ensure a valid selection. + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK if successful, MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL if invalid channel is selected, MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE + * if numGainIndexesInTable exceeds range for selected receiver gain table + */ +mykonosErr_t MYKONOS_programRxGainTable(mykonosDevice_t *device, uint8_t *gainTablePtr, uint8_t numGainIndexesInTable, mykonosGainTable_t rxChannel) +{ + uint8_t ctlReg = 0; + uint8_t ch3CtlReg = 0; + uint16_t rxFEGainAddr = 0; + uint16_t rxExtCtlLnaAddr = 0; + uint16_t rxDigGainAttenAddr = 0; + uint16_t rx2FEGainAddr = 0; + uint16_t rx2ExtCtlAddr = 0; + uint16_t rx2DigGainAttenAddr = 0; + uint8_t minGainIndex = 0; + uint8_t startIndex = 0; + int16_t i = 0; + uint16_t tableRowIndex = 0; + uint8_t retFlag = 0; + +#if MYK_ENABLE_SPIWRITEARRAY + uint32_t addrIndex = 0; + uint32_t dataIndex = 0; + uint32_t spiBufferSize = (((MYK_SPIWRITEARRAY_BUFFERSIZE / 9) - 1) * 9); + uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; + uint8_t dataArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; +#endif + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_programRxGainTable()\n"); +#endif + + if (gainTablePtr == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM)); + return MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM; + } + + /* checking range of numGainIndexesInTable against maximums and for valid rxChannel selection */ + switch (rxChannel) + { + case RX1_GT: + /* Rx1 max gain index = 255, check is out of range of uint8_t */ + break; + case RX2_GT: + /* Rx1 max gain index = 255, check is out of range of uint8_t */ + break; + case RX1_RX2_GT: + /* Rx1 max gain index = 255, check is out of range of uint8_t */ + break; + case ORX_GT: + if (numGainIndexesInTable > MAX_ORX_GAIN_TABLE_NUMINDEXES) + { + retFlag = 1; + } + break; + case SNRX_GT: + if (numGainIndexesInTable > MAX_SNRX_GAIN_TABLE_NUMINDEXES) + { + retFlag = 1; + } + break; + case LOOPBACK_GT: + if (numGainIndexesInTable > MAX_LOOPBACK_GAIN_TABLE_NUMINDEXES) + { + retFlag = 1; + } + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL)); + return MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL; + } + + if (retFlag) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE)); + return MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE; + } + else + { + /* calculating minimum gain index value */ + minGainIndex = MAX_GAIN_TABLE_INDEX - numGainIndexesInTable + 1; + } + + /* forming control register words based on channel select, assigning starting index, and register addressing, also updating max and min gain table indices in structure */ + switch (rxChannel) + { + case RX1_GT: + ctlReg = ((uint8_t)rxChannel << 3) | 0x05; + startIndex = START_RX_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_EXT_CTL; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_DIG_GAIN; + device->rx->rxGainCtrl->rx1MaxGainIndex = MAX_GAIN_TABLE_INDEX; + device->rx->rxGainCtrl->rx1MinGainIndex = minGainIndex; + break; + case RX2_GT: + ctlReg = ((uint8_t)rxChannel << 3) | 0x05; + startIndex = START_RX_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_EXT_CTL; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_DIG_GAIN; + device->rx->rxGainCtrl->rx2MaxGainIndex = MAX_GAIN_TABLE_INDEX; + device->rx->rxGainCtrl->rx2MinGainIndex = minGainIndex; + break; + case RX1_RX2_GT: + ctlReg = ((uint8_t)rxChannel << 3) | 0x05; + startIndex = START_RX_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_FE_GAIN; + rx2FEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_EXT_CTL; + rx2ExtCtlAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_EXT_CTL; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_DIG_GAIN; + rx2DigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_DIG_GAIN; + device->rx->rxGainCtrl->rx1MaxGainIndex = MAX_GAIN_TABLE_INDEX; + device->rx->rxGainCtrl->rx1MinGainIndex = minGainIndex; + device->rx->rxGainCtrl->rx2MaxGainIndex = MAX_GAIN_TABLE_INDEX; + device->rx->rxGainCtrl->rx2MinGainIndex = minGainIndex; + break; + case ORX_GT: + ctlReg = 0x05; + ch3CtlReg = 0x08; + startIndex = START_ORX_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN; + device->obsRx->orxGainCtrl->maxGainIndex = MAX_GAIN_TABLE_INDEX; + device->obsRx->orxGainCtrl->minGainIndex = minGainIndex; + break; + case SNRX_GT: + ctlReg = 0x05; + ch3CtlReg = 0x00; + startIndex = START_SNRX_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN; + device->obsRx->snifferGainCtrl->maxGainIndex = MAX_GAIN_TABLE_INDEX; + device->obsRx->snifferGainCtrl->minGainIndex = minGainIndex; + break; + /*case LOOPBACK_GT: Loopback is only for ARM calibrations */ + default: + ctlReg = 0x05; + ch3CtlReg = 0x10; + startIndex = START_LOOPBACK_GAIN_INDEX; + rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN; + rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB; + rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN; + break; + } + + /* starting the gain table clock and read from gain table address bits */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg); + + /* if ORx or Sniffer are selected also writing channel 3 readback bits for ObsRx or Sniffer selection */ + if (rxChannel > RX1_RX2_GT) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg); + } + + /* programming a table selected by rxChannel enum type */ + +#if MYK_ENABLE_SPIWRITEARRAY == 0 + + for(i = startIndex; i >= ((startIndex + 1) - numGainIndexesInTable); i--) + { + tableRowIndex = (uint16_t)(startIndex - i) << 2; + + /* set current gain table index (address) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_ADDR, i); + + /* Set Rx Front End gain[5:0] */ + CMB_SPIWriteByte(device->spiSettings, rxFEGainAddr, gainTablePtr[tableRowIndex]); + + /* Set external control [5:0] OR LNA bypass if rxChannel == SNRX_GT */ + if (rxChannel == SNRX_GT) + { + CMB_SPIWriteByte(device->spiSettings, rxExtCtlLnaAddr, gainTablePtr[tableRowIndex + 1] << 4); + } + else + { + CMB_SPIWriteByte(device->spiSettings, rxExtCtlLnaAddr, gainTablePtr[tableRowIndex + 1]); + } + + /* Set digital attenuation/gain[6:0] and set/clear attenuation bit */ + CMB_SPIWriteByte(device->spiSettings, rxDigGainAttenAddr, (gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]); + + /* repeating gain table settings if Rx1 and Rx2 are selected for Rx2 configuration */ + if (rxChannel == RX1_RX2_GT) + { + /* Set Rx Front End gain[5:0] */ + CMB_SPIWriteByte(device->spiSettings, rx2FEGainAddr, gainTablePtr[tableRowIndex]); + + /* Set external control [5:0] */ + CMB_SPIWriteByte(device->spiSettings, rx2ExtCtlAddr, gainTablePtr[tableRowIndex + 1]); + + /* Set digital attenuation/gain[6:0] */ + CMB_SPIWriteByte(device->spiSettings, rx2DigGainAttenAddr, (gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]); + } + + /* setting the write enable depending on rxChannel choice */ + if (rxChannel == ORX_GT) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x02); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02); + } + else if (rxChannel == SNRX_GT) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02); + } + else if (rxChannel == LOOPBACK_GT) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x04); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02); + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02); + } + } + +#elif MYK_ENABLE_SPIWRITEARRAY == 1 +//#elif 0 + + addrIndex = 0; + dataIndex = 0; + for(i = startIndex; i >= ((startIndex + 1) - numGainIndexesInTable); i--) + { + tableRowIndex = (uint16_t)(startIndex - (uint8_t)i) << 2; + + /* set current gain table index (address) */ + addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_ADDR; + dataArray[dataIndex++] = (uint8_t)i; + + /* Set Rx Front End gain[5:0] */ + addrArray[addrIndex++] = rxFEGainAddr; + dataArray[dataIndex++] = gainTablePtr[tableRowIndex]; + + /* Set external control [5:0] OR LNA bypass if rxChannel == SNRX_GT */ + addrArray[addrIndex++] = rxExtCtlLnaAddr; + dataArray[dataIndex++] = (rxChannel == SNRX_GT) ? (uint8_t)(gainTablePtr[tableRowIndex + 1] << 4) : (gainTablePtr[tableRowIndex + 1]); + + /* Set digital attenuation/gain[6:0] and set/clear attenuation bit */ + addrArray[addrIndex++] = rxDigGainAttenAddr; + dataArray[dataIndex++] = ((uint8_t)(gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]); + + /* repeating gain table settings if Rx1 and Rx2 are selected for Rx2 configuration */ + if (rxChannel == RX1_RX2_GT) + { + /* Set Rx Front End gain[5:0] */ + addrArray[addrIndex++] = rx2FEGainAddr; + dataArray[dataIndex++] = gainTablePtr[tableRowIndex]; + + /* Set external control [5:0] */ + addrArray[addrIndex++] = rx2ExtCtlAddr; + dataArray[dataIndex++] = gainTablePtr[tableRowIndex + 1]; + + /* Set digital attenuation/gain[6:0] */ + addrArray[addrIndex++] = rx2DigGainAttenAddr; + dataArray[dataIndex++] = ((uint8_t)(gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]); + } + + /* setting the write enable depending on rxChannel choice */ + if (rxChannel == ORX_GT) + { + addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ch3CtlReg | 0x02); + addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ctlReg | 0x02); + } + else if (rxChannel == SNRX_GT) + { + addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ch3CtlReg | 0x01); + addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ctlReg | 0x02); + } + else if (rxChannel == LOOPBACK_GT) + { + addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ch3CtlReg | 0x04); + addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ctlReg | 0x02); + } + else + { + addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION; + dataArray[dataIndex++] = (ctlReg | 0x02); + } + + if (addrIndex >= spiBufferSize) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex); + dataIndex = 0; + addrIndex = 0; + } + } + + if (addrIndex > 0) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex); + } + +#endif + + /* clearing the channel 3 gain table configuration register if selected and stopping the gain table clock */ + if (rxChannel > RX1_RX2_GT) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, 0x00); + } + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, 0x08); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the Rx1 Manual Gain Index + * + * If the value passed in the gainIndex parameter is within range of the gain table minimum and + * maximum indexes, the Rx1 gain index will be updated in the device data structure + * and written to the transceiver. Else, an error will be returned. The maximum index is 255 + * and the minimum index is application specific. + * + * Dependencies + * - device->spiSettings + * - device->rxSettings->rxGainControl->rx1GainIndex + * - device->rxSettings->rxGainControl->rx1MaxGainIndex + * - device->rxSettings->rxGainControl->rx1MinGainIndex + * + * \param device Pointer to the Mykonos data structure + * \param gainIndex Desired Rx1 gain index + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_setRx1ManualGain(mykonosDevice_t *device, uint8_t gainIndex) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx1ManualGain()\n"); +#endif + + if ((gainIndex < device->rx->rxGainCtrl->rx1MinGainIndex) || (gainIndex > device->rx->rxGainCtrl->rx1MaxGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM)); + return MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM; + + } + else + { + /* If the desired gain index is in range of the gain table, update the + * value in the device data structure, and write to device. + */ + device->rx->rxGainCtrl->rx1GainIndex = gainIndex; + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_1, gainIndex); + + return MYKONOS_ERR_OK; + } +} + +/** + * \brief Sets the Rx2 Manual Gain index + * + * If the value passed in the gainIndex parameter is within range of the gain table minimum and + * maximum indexes, the Rx2 gain index will be updated in the device data structure + * and written to the transceiver. Else, an error will be returned. The maximum index is 255 + * and the minimum index is application specific. + * + * Dependencies + * - device->spiSettings + * - device->rxTxSettings->rxGainControl->rx2GainIndex + * - device->rxTxSettings->rxGainControl->rx2MaxGainIndex + * - device->rxTxSettings->rxGainControl->rx2MinGainIndex + * + * \param device Pointer to the Mykonos data structure + * \param gainIndex Desired Rx2 gain index + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_setRx2ManualGain(mykonosDevice_t *device, uint8_t gainIndex) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx2ManualGain()\n"); +#endif + + if ((gainIndex < device->rx->rxGainCtrl->rx2MinGainIndex) || (gainIndex > device->rx->rxGainCtrl->rx2MaxGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM)); + return MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM; + + } + else + { + /* If the desired gain index is in range of the gain table, update the + * value in the device data structure, and write to device. + */ + device->rx->rxGainCtrl->rx2GainIndex = gainIndex; + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_2, gainIndex); + + return MYKONOS_ERR_OK; + } +} + +/** + * \brief Reads the Rx1 Gain Index for Manual or AGC gain control mode + * + * This function reads the Rx1 gain index for manual or AGC modes. If the + * *rx1GainIndex pointer is nonzero, the read back gain index will + * be returned in the parameter. If the *rx1GainIndex pointer + * is NULL, the device data structure will be updated with the new read back value + * + * Dependencies + * - device->spiSettings + * - device->rxTxSettings->rxGainControl->rx1GainIndex + * + * \param device Pointer to the Mykonos data structure + * \param rx1GainIndex uint8_t Pointer to the Rx1 gain index value + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_getRx1Gain(mykonosDevice_t *device, uint8_t *rx1GainIndex) +{ + uint8_t readData = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1Gain()\n"); +#endif + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_CHANNEL_1, &readData); + + /* + * If rx1GainIndex address is not NULL, return the Rx1 gain index in the + * rx1GainIndex function parameter + */ + if (rx1GainIndex != NULL) + { + *rx1GainIndex = readData; + } + + /* + * set the current Rx1 gain in the device data structure + */ + if (device->profilesValid & RX_PROFILE_VALID) + { + device->rx->rxGainCtrl->rx1GainIndex = readData; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the Rx2 Gain Index for Manual or AGC gain control mode + * + * This function reads the Rx2 gain index for manual or AGC modes. If the + * *rx1GainIndex pointer is nonzero, the read back gain index will + * be returned in the parameter. If the *rx1GainIndex pointer + * is NULL, the device data structure will be updated with the new read back value + * + * Dependencies + * - device->spiSettings + * - device->rxTxSettings->rxGainControl->rx2GainIndex + * + * \param device Pointer to the Mykonos data structure + * \param rx2GainIndex Desired Rx2 gain index + * + * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail + */ +mykonosErr_t MYKONOS_getRx2Gain(mykonosDevice_t *device, uint8_t *rx2GainIndex) +{ + uint8_t readData = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2Gain()\n"); +#endif + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_CHANNEL_2, &readData); + + /* + * If rx1GainIndex address is not NULL, return the Rx1 gain index in the + * rx1GainIndex function parameter + */ + if (rx2GainIndex != NULL) + { + *rx2GainIndex = readData; + } + + /* + * set the current Rx2 gain in the device data structure + */ + if (device->profilesValid & RX_PROFILE_VALID) + { + device->rx->rxGainCtrl->rx2GainIndex = readData; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the device Rx Automatic Gain Control (AGC) registers. + * + * Three data structures (mykonosAgcCfg_t, mykonosPeakDetAgcCfg_t, mykonosPowerMeasAgcCfg_t) + * must be instantiated prior to calling this function. Valid ranges for data structure members + * must also be provided. + * + * + * Dependencies: + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->rx->rxAgcCtrl->agcRx1MaxGainIndex + * - device->rx->rxAgcCtrl->agcRx1MinGainIndex + * - device->rx->rxAgcCtrl->agcRx2MaxGainIndex + * - device->rx->rxAgcCtrl->agcRx2MinGainIndex + * - device->rx->rxAgcCtrl->agcObsRxMaxGainIndex + * - device->rx->rxAgcCtrl->agcObsRxMinGainIndex + * - device->rx->rxAgcCtrl->agcObsRxSelect + * - device->rx->rxAgcCtrl->agcPeakThresholdMode + * - device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease + * - device->rx->rxAgcCtrl->agcGainUpdateCounter + * - device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay + * - device->rx->rxAgcCtrl->agcPeakWaitTime + * - device->rx->rxAgcCtrl->agcResetOnRxEnable + * - device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter + * - device->rx->rxAgcCtrl->peakAgc->apdHighThresh + * - device->rx->rxAgcCtrl->peakAgc->apdLowThresh + * - device->rx->rxAgcCtrl->peakAgc->hb2HighThresh + * - device->rx->rxAgcCtrl->peakAgc->hb2LowThresh + * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh + * - device->rx->rxAgcCtrl->peakAgc->apdHighThreshExceededCnt + * - device->rx->rxAgcCtrl->peakAgc->apdLowThreshExceededCnt + * - device->rx->rxAgcCtrl->peakAgc->hb2HighThreshExceededCnt + * - device->rx->rxAgcCtrl->peakAgc->hb2LowThreshExceededCnt + * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt + * - device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack + * - device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery + * - device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack + * - device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery + * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery + * - device->rx->rxAgcCtrl->peakAgc->apdFastAttack + * - device->rx->rxAgcCtrl->peakAgc->hb2FastAttack + * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable + * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt + * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt + * - device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh + * - device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh + * - device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh + * - device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh + * - device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack + * - device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack + * - device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery + * - device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery + * - device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration + * - device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig + * + * \param device is structure pointer to the Mykonos data structure containing settings + * The pointer to the Mykonos AGC data structure containing settings is checked for a null pointer + * to ensure it has been initialized. If not an error is thrown. + * + * \retval Returns MYKONOS_ERR=pass, !MYKONOS_ERR=fail + * \retval MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY + * \retval MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION + * \retval MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG + * \retval MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC + * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE + * \retval MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE + * \retval MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE + * \retval MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT + * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT + */ +mykonosErr_t MYKONOS_setupRxAgc(mykonosDevice_t *device) +{ + uint8_t decPowerConfig = 0; + uint8_t lower1ThreshGainStepRegValue = 0; + uint8_t powerThresholdsRegValue = 0; + uint8_t hb2OvldCfgRegValue = 0; + uint8_t agcGainUpdateCtr[3] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxAgc()\n"); +#endif + + /* Check mykonosAgcCfg_t device->rx->rxAgcCtrl pointer for initialization */ + if (device->rx->rxAgcCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT; + } + + /* Check mykonosPeakDetAgcCfg_t device->rx->rxAgcCtrl->peakAgc pointer for initialization */ + if (device->rx->rxAgcCtrl->peakAgc == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT; + } + + /* Check mykonosPowerMeasAgcCfg_t device->rx->rxAgcCtrl->powerAgc pointer for initialization */ + if (device->rx->rxAgcCtrl->powerAgc == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT; + } + + /* Range check agcRx1MaxGainIndex versus gain table limits */ + if ((device->rx->rxAgcCtrl->agcRx1MaxGainIndex > device->rx->rxGainCtrl->rx1MaxGainIndex) + || (device->rx->rxAgcCtrl->agcRx1MaxGainIndex < device->rx->rxAgcCtrl->agcRx1MinGainIndex)) + + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MAX_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx1MaxGainIndex); + } + + /* Range check agcRx1MinGainIndex versus gain table limits */ + if ((device->rx->rxAgcCtrl->agcRx1MinGainIndex < device->rx->rxGainCtrl->rx1MinGainIndex) + || (device->rx->rxAgcCtrl->agcRx1MaxGainIndex < device->rx->rxAgcCtrl->agcRx1MinGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MIN_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx1MinGainIndex); + } + + /* Range check agcRx2MaxGainIndex versus gain table limits */ + if ((device->rx->rxAgcCtrl->agcRx2MaxGainIndex > device->rx->rxGainCtrl->rx2MaxGainIndex) + || (device->rx->rxAgcCtrl->agcRx2MaxGainIndex < device->rx->rxAgcCtrl->agcRx2MinGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MAX_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx2MaxGainIndex); + } + + /* Range check agcRx2MinGainIndex versus gain table limits */ + if ((device->rx->rxAgcCtrl->agcRx2MinGainIndex < device->rx->rxGainCtrl->rx2MinGainIndex) + || (device->rx->rxAgcCtrl->agcRx2MaxGainIndex < device->rx->rxAgcCtrl->agcRx2MinGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MIN_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx2MinGainIndex); + } + + /* Range check for agcGainUpdateCounter (22-bit) */ + if ((device->rx->rxAgcCtrl->agcGainUpdateCounter > 0x3FFFFF) || (device->rx->rxAgcCtrl->agcGainUpdateCounter < 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM)); + return MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM; + } + else + { + /* Split agcGainUpdateCounter into three values */ + agcGainUpdateCtr[0] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter); + agcGainUpdateCtr[1] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter >> 8); + agcGainUpdateCtr[2] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter >> 16); + + /* Write two bytes directly due. Third word has its upper two bits masked off. */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_1, agcGainUpdateCtr[0]); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_2, agcGainUpdateCtr[1]); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_3, agcGainUpdateCtr[2], 0x3F, 0); + } + + /* Range check on agcPeakWaitTime (5-bit) */ + if (device->rx->rxAgcCtrl->agcPeakWaitTime > 0x1F || device->rx->rxAgcCtrl->agcPeakWaitTime < 0x02) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM)); + return MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM; + } + else + { + /* Write agcPeakWaitTime */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, device->rx->rxAgcCtrl->agcPeakWaitTime, 0x1F, 0); + } + + /* Set MYKONOS_ADDR_AGC_CFG_2 bits [6:5] = b11 to enable AGC counters for MGC mode - needed for ARM cals to work correctly */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 3, 0x60, 5); + + /* Range check for agcSlowLoopSettlingDelay (7-bit) */ + if (device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY)); + return MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY; + } + else + { + /* Write agcSlowLoopSettlingDelay */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay, 0x7F, 0); + } + + /* Range check for pmdMeasDuration */ + if ((uint32_t)(1 << (3 + device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration)) >= (device->rx->rxAgcCtrl->agcGainUpdateCounter)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION)); + return MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION; + } + else + { + /* Write pmdMeasDuration */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_DEC_POWER_CONFIG_2, device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration, 0x0F, 0); + } + + /* Range check for pmdMeasConfig */ + if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig > 0x3) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG)); + return MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG; + } + else + { + if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 0) + { + decPowerConfig = 0x0; /* Dec Pwr measurement disable */ + } + else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 1) + { + decPowerConfig = 0x3; /* Dec Pwr measurement enable, HB2 for decPwr measurement */ + } + else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 2) + { + decPowerConfig = 0x5; /* Dec Pwr measurement enable, RFIR for decPwr measurement */ + } + else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 3) + { + decPowerConfig = 0x11; /* Dec Pwr measurement enable, BBDC2 for decPwr measurement */ + } + /* Write pmdMeasConfig */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_DEC_POWER_CONFIG_1, decPowerConfig); + } + + /* Range check agcLowThsPreventGainIncrease (1-bit) */ + if (device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC)); + return MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC; + } + else + { + /* Write agcLowThsPreventGainIncrease */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOCK_LEV_THRSH, device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease, 0x80, 7); + } + + /* Range check agcPeakThresholdMode (1-bit), */ + if (device->rx->rxAgcCtrl->agcPeakThresholdMode > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE)); + return MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE; + } + else + { + /* Save to lower1ThreshGainStepRegValue register variable */ + lower1ThreshGainStepRegValue |= (uint8_t)(device->rx->rxAgcCtrl->agcPeakThresholdMode << 5); + } + + /* Range check agcResetOnRxEnable (1-bit) */ + if (device->rx->rxAgcCtrl->agcResetOnRxEnable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC)); + return MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE; + } + else + { + /* Write agcResetOnRxEnable */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_3, (uint8_t)(device->rx->rxAgcCtrl->agcResetOnRxEnable << 7), 0x80, 0); + } + + /* Range check agcEnableSyncPulseForGainCounter (1-bit) */ + if (device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER)); + return MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER; + } + else + { + /* Write agcEnableSyncPulseForGainCounter */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, (uint8_t)(device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter << 7), 0x80, 0); + } + + /* WRITE REGISTERS FOR THE AGC POWER MEASUREMENT DETECTOR (PMD) STRUCTURE */ + + /* Range check pmdLowerHighThresh (7-bit) vs 0x7F and pmdUpperLowThresh */ + if ((device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh <= device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh) + || device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH)); + return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH; + } + else + { + /* Write pmdLowerHighThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOCK_LEV_THRSH, device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh, 0x7F, 0); + } + + /* Range check pmdUpperLowThresh (7-bit): Comparison to pmdLowerHigh done earlier */ + if (device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH)); + return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH; + } + else + { + /* Write pmdUpperLowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_LOCK_LEVEL, device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh); + } + + /* Range check pmdLowerLowThresh (4-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH)); + return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH; + } + else + { + /* Write pmdUpperLowThresh to temp variable */ + powerThresholdsRegValue |= device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh; + } + + /* Range check pmdUpperHighThresh (4-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH)); + return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH; + } + else + { + /* Write pmdUpperHighThresh to temp var, then to register */ + powerThresholdsRegValue |= (uint8_t)(device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh << 4); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_POWER_THRSH, powerThresholdsRegValue); + } + + /* Range check pmdUpperHighGainStepAttack (5-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP; + } + else + { + /* Write pmdUpperHighGainStepAttack */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_UPPER1_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack, 0x1F, 0); + } + + /* Range check pmdLowerLowGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + lower1ThreshGainStepRegValue |= (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery); + } + + /* Range check pmdUpperLowGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_UPPER0_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack); + } + + /* Range check pmdLowerHighGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOWER0_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery); + } + + /* WRITE REGISTERS FOR THE AGC PEAK DETECTOR (APD/HB2) STRUCTURE */ + + /* Range check apdFastAttack and hb2FastAttack (1-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->apdFastAttack > 0x1 || device->rx->rxAgcCtrl->peakAgc->hb2FastAttack > 0x1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE)); + return MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + lower1ThreshGainStepRegValue |= (uint8_t)(device->rx->rxAgcCtrl->peakAgc->apdFastAttack << 7); + lower1ThreshGainStepRegValue |= (uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2FastAttack << 6); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOWER1_THRSH_GAIN_STEP, lower1ThreshGainStepRegValue); + } + + /* Range check apdHighThresh */ + if ((device->rx->rxAgcCtrl->peakAgc->apdHighThresh > 0x3F) || (device->rx->rxAgcCtrl->peakAgc->apdHighThresh <= device->rx->rxAgcCtrl->peakAgc->apdLowThresh)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM; + } + else + { + /* Write apdHighThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ULB_THRSH, device->rx->rxAgcCtrl->peakAgc->apdHighThresh, 0X3F, 0); + } + + /* Range check apdLowThresh */ + if ((device->rx->rxAgcCtrl->peakAgc->apdLowThresh > 0x3F) || (device->rx->rxAgcCtrl->peakAgc->apdHighThresh < device->rx->rxAgcCtrl->peakAgc->apdLowThresh)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM; + } + else + { + /* write apdLowThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_LLB_THRSH, device->rx->rxAgcCtrl->peakAgc->apdLowThresh, 0x3F, 0); + } + + /* Range check hb2HighThresh */ + if (device->rx->rxAgcCtrl->peakAgc->hb2HighThresh < device->rx->rxAgcCtrl->peakAgc->hb2LowThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM; + } + else + { + /* write hb2HighThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_UPPER_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2HighThresh); + } + + /* Range check hb2LowThresh */ + if (device->rx->rxAgcCtrl->peakAgc->hb2LowThresh > device->rx->rxAgcCtrl->peakAgc->hb2HighThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM; + } + else + { + /* write hb2LowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_LOWER_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2LowThresh); + } + + /* Range check hb2VeryLowThresh */ + if (device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh > device->rx->rxAgcCtrl->peakAgc->hb2LowThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM; + } + else + { + /* write hb2VeryLowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_VERYLOW_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh); + } + + /* Write threshold counter values for apdHigh/apdLow/hb2High/hb2Low/hb2VeryLow */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ULB_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->apdHighThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LLB_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->apdLowThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_HIGH_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2HighThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOW_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2LowThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_VERYLOW_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt); + + /* Range check on apdHighGainStepAttack (5-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM; + } + else + { + /* Write apdHighGainStepAttack */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_1, device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack); + } + + /* Range check on apdLowGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM; + } + else + { + /* Write apdLowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_4, device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery); + } + + /* Range check on hb2HighGainStepAttack (5-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM; + } + else + { + /* Write hb2HighGainStepAttack */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_2, device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack); + } + + /* Range check on hb2LowGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM; + } + else + { + /* Write hb2LowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_5, device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery); + } + + /* Range check on hb2VeryLowGainStepRecovery (5-bit) */ + if (device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM; + } + else + { + /* Write hb2VeryLowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_6, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery); + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable > 0x1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE)); + return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE; + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt > 0x7) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT)); + return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT; + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT)); + return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT; + } + else + { + /* Write the hb2OvldCfgRegValue, the combination of hb2OverloadThreshCnt, hb2OverloadDurationCnt, and hb2OverloadDetectEnable */ + hb2OvldCfgRegValue = (device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt) |(uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt << 4) + | (uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable << 7); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_CFG, hb2OvldCfgRegValue); + } + + /* Hard-coded value for the ADC overload configuration. Sets the HB2 offset to -6dB.*/ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_ADC_OVRLD_CFG, 0x18); + /* Hard-coded value for APD decay setting. Setting allows for the quickest settling time of peak detector */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX_BLOCK_DET_DECAY, 0x0); + + /* performing a soft reset */ + return MYKONOS_resetRxAgc(device); +} + +/** + * \brief This function resets the AGC state machine + * + * Calling this function resets all state machines within the gain control and maximum gain. + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_resetRxAgc(mykonosDevice_t *device) +{ + const uint8_t AGC_RESET = 0x80; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetRxAgc()\n"); +#endif + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 1, AGC_RESET, 7); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 0, AGC_RESET, 7); + + return MYKONOS_ERR_OK; + +} + +/** + * \brief This function sets the min/max gain indexes for AGC in the main RX channel + * + * Allows to change min/max gain index on runtime. + * If RX1_RX2 selected, then the maxGainIndex/minGainIndex value will be applied to both channels. + * If only Rx1 selected, then only Rx1 min/max gain indices will be updated, along with their device data structure values. + * If only Rx2 selected, then only Rx2 min/max gain indices will be updated, along with their device data structure values. + * + * Dependencies: + * - device->spiSettings + * - device->rx->rxAgcCtrl + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param rxChannelSelect RX channel for setting the max and min gain index settings + * \param maxGainIndex Max gain index setting + * \param minGainIndex Min gain index setting + * + * \retval MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX Max gain index bigger than max gain index loaded table. + * \retval MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX Min gain index lower than min gain index loaded table. + * \retval MYKONOS_ERR_AGC_MIN_MAX_CHANNEL Wrong RX channel selected + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosRxChannels_t rxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex) +{ + const uint8_t MIN_GAIN_INDEX = 1 + MAX_GAIN_TABLE_INDEX - (sizeof(RxGainTable) / sizeof(RxGainTable[0])); + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxAgcMinMaxGainIndex()\n"); +#endif + + /* Check for maxGainIndex */ + if (maxGainIndex > MAX_GAIN_TABLE_INDEX) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX)); + return MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX; + } + + /* Check for minGainIndex */ + if (minGainIndex < MIN_GAIN_INDEX) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX)); + return MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX; + } + + if ((uint32_t)rxChannelSelect & (uint32_t)RX1) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MAX_GAIN_INDEX, maxGainIndex); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MIN_GAIN_INDEX, minGainIndex); + device->rx->rxAgcCtrl->agcRx1MaxGainIndex = maxGainIndex; + device->rx->rxAgcCtrl->agcRx1MinGainIndex = minGainIndex; + } + + if ((uint32_t)rxChannelSelect & (uint32_t)RX2) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MAX_GAIN_INDEX, maxGainIndex); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MIN_GAIN_INDEX, minGainIndex); + device->rx->rxAgcCtrl->agcRx2MaxGainIndex = maxGainIndex; + device->rx->rxAgcCtrl->agcRx2MinGainIndex = minGainIndex; + } + + /* Check for invalid Rx channel */ + if (!((uint32_t)rxChannelSelect & (uint32_t)RX1_RX2)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL)); + return MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function sets the min/max gain indexes for AGC in the observation channel + * + * Allows to change min/max gain index on runtime. + * + * Dependencies: + * - device->spiSettings + * - device->rx->rxAgcCtrl + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param obsRxChannelSelect Observation channel for setting the max and min gain index settings + * \param maxGainIndex Max gain index setting + * \param minGainIndex Min gain index setting + * + * \retval MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL Wrong read back channel. + * \retval MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX Max gain index bigger than max gain index loaded table. + * \retval MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX Min gain index lower than min gain index loaded table. + * \retval MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL Wrong observation channel selected + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setObsRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex) +{ + uint8_t rdObsActive = 0x00; + uint8_t obsActive = 0x00; + uint8_t obsCheck = 0x00; + uint8_t minGainIndexCheck = 0x00; + uint8_t maxGainIndexCheck = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxAgcMinMaxGainIndex()\n"); +#endif + + /* Read active channel */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ACTIVE, &rdObsActive, 0x03, 0); + + /* Check active channel and set min/max checks */ + switch (rdObsActive) + { + case 0x00: + case 0x01: + /*sniffer*/ + maxGainIndexCheck = MAX_GAIN_TABLE_INDEX; + minGainIndexCheck = MAX_GAIN_TABLE_INDEX - (sizeof(SnRxGainTable) / sizeof(SnRxGainTable[0])); + obsActive = (uint32_t)OBS_SNIFFER | (uint32_t)OBS_SNIFFER_A | (uint32_t)OBS_SNIFFER_B | (uint32_t)OBS_SNIFFER_C; + break; + case 0x02: + case 0x03: + /*observation 1*/ + maxGainIndexCheck = MAX_GAIN_TABLE_INDEX; + minGainIndexCheck = MAX_GAIN_TABLE_INDEX - (sizeof(ORxGainTable) / sizeof(ORxGainTable[0])); + obsActive = (uint32_t)OBS_RX1_TXLO | (uint32_t)OBS_RX1_SNIFFERLO | (uint32_t)OBS_RX2_TXLO | (uint32_t)OBS_RX2_SNIFFERLO; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL)); + return MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL; + } + + /* Check for maxGainIndex */ + if ((maxGainIndex > maxGainIndexCheck) || (maxGainIndex < minGainIndexCheck)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX)); + return MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX; + } + + /* Check for minGainIndex */ + if ((minGainIndex < minGainIndexCheck) || (minGainIndex > maxGainIndexCheck)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX)); + return MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX; + } + + device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex = maxGainIndex; + device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex = minGainIndex; + + switch (obsRxChannelSelect) + { + case OBS_SNIFFER: + case OBS_SNIFFER_A: + case OBS_SNIFFER_B: + case OBS_SNIFFER_C: + obsCheck = (uint32_t)OBS_SNIFFER | (uint32_t)OBS_SNIFFER_A | (uint32_t)OBS_SNIFFER_B | (uint32_t)OBS_SNIFFER_C; + maxGainIndex = maxGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES; + minGainIndex = minGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES; + break; + + case OBS_RX1_TXLO: + case OBS_RX2_TXLO: + case OBS_RX1_SNIFFERLO: + case OBS_RX2_SNIFFERLO: + obsCheck = (uint32_t)OBS_RX1_TXLO | (uint32_t)OBS_RX1_SNIFFERLO | (uint32_t)OBS_RX2_TXLO | (uint32_t)OBS_RX2_SNIFFERLO; + maxGainIndex = maxGainIndex - MAX_ORX_GAIN_TABLE_NUMINDEXES; + minGainIndex = minGainIndex - MAX_ORX_GAIN_TABLE_NUMINDEXES; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL)); + return MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL; + } + + if (obsCheck == obsActive) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MAX_GAIN_INDEX, maxGainIndex); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MIN_GAIN_INDEX, minGainIndex); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL)); + return MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function sets the Temperature gain compensation for Rx1 channel + * + * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain + * in the data path. + * The resolution of the temperature compensation gain is 250mdB. + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param rx1TempCompGain_mdB gain compensation for Rx1, the range is from -3000mdB to +3000mdB in steps of 250mdB + * + * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB) + * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setRx1TempGainComp(mykonosDevice_t *device, int16_t rx1TempCompGain_mdB) +{ + int8_t tempGainComp = 0x00; + + const int16_t LOW_LIMIT_GAIN_COMP = -3000; + const int16_t HIGH_LIMIT_GAIN_COMP = 3000; + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx1TempGainComp()\n"); +#endif + + /* Check for Gain compensation range */ + if ((rx1TempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (rx1TempCompGain_mdB < LOW_LIMIT_GAIN_COMP)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE)); + return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE; + } + + /* Check for Gain compensation steps */ + if (rx1TempCompGain_mdB % GAIN_COMP_STEP) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP, + getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP)); + return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP; + } + + /* Prepare register write */ + tempGainComp = (rx1TempCompGain_mdB / GAIN_COMP_STEP) & 0x1F; + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_TEMP_GAIN_COMP, (uint8_t)tempGainComp); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function gets the Temperature gain compensation for Rx1 + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param rx1TempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for Rx1 channel. + * + * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL rx1TempCompGain_mdB pointer is null. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRx1TempGainComp(mykonosDevice_t *device, int16_t *rx1TempCompGain_mdB) +{ + uint8_t tempGainComp = 0x00; + int8_t tempGainCompDB = 0x00; + + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1TempGainComp()\n"); +#endif + + /* Check for null passed parameter */ + if (rx1TempCompGain_mdB == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL, + getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL)); + return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL; + } + + /* Read Temperature Gain Compensation */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX1_TEMP_GAIN_COMP, &tempGainComp); + + /* Convert to dB and prepare the signed return */ + tempGainCompDB = tempGainComp & 0x1F; + if (tempGainCompDB & 0x10) + { + tempGainCompDB = ((((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1)); + } + + /* Assign value to the passed pointer */ + *rx1TempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP; + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function sets the Temperature gain compensation for Rx2 channel + * + * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain + * in the data path. + * The resolution of the temperature compensation gain is 250mdB. + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param rx2TempCompGain_mdB gain compensation for Rx1, + * the range is from -3000mdB to +3000mdB in steps of 250mdB + * + * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB) + * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setRx2TempGainComp(mykonosDevice_t *device, int16_t rx2TempCompGain_mdB) +{ + int8_t tempGainComp = 0x00; + + const int16_t LOW_LIMIT_GAIN_COMP = -3000; + const int16_t HIGH_LIMIT_GAIN_COMP = 3000; + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx2TempGainComp()\n"); +#endif + + /* Check for Gain compensation range */ + if ((rx2TempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (rx2TempCompGain_mdB < LOW_LIMIT_GAIN_COMP)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE)); + return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE; + } + + /* Check for Gain compensation range */ + if (rx2TempCompGain_mdB % GAIN_COMP_STEP) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP, + getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP)); + return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP; + } + + /* Prepare register write */ + tempGainComp = (rx2TempCompGain_mdB / GAIN_COMP_STEP) & 0x1F; + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_TEMP_GAIN_COMP, (uint8_t)tempGainComp); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function gets the Temperature gain compensation for Rx2 + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param rx2TempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for Rx2 channel. + * + * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL rx2TempCompGain_mdB pointer is null. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRx2TempGainComp(mykonosDevice_t *device, int16_t *rx2TempCompGain_mdB) +{ + uint8_t tempGainComp = 0x00; + int8_t tempGainCompDB = 0x00; + + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2TempGainComp()\n"); +#endif + + /* Check for null passed parameter */ + if (rx2TempCompGain_mdB == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL, + getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL)); + return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL; + } + + /* Read programmed Temperature Gain Compensation */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX2_TEMP_GAIN_COMP, &tempGainComp); + + /* Convert to dB and prepare the signed return */ + tempGainCompDB = tempGainComp & 0x1F; + if (tempGainCompDB & 0x10) + { + tempGainCompDB = (((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1); + } + + /* Assign value to the passed pointer */ + *rx2TempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP; + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function sets the Temperature gain compensation for the observation channel + * + * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain + * in the data path. + * The resolution of the temperature compensation gain is 250mdB. + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param obsRxTempCompGain_mdB gain compensation for observation channel, + * the range is from -3000mdB to +3000mdB in steps of 250mdB + * + * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB) + * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setObsRxTempGainComp(mykonosDevice_t *device, int16_t obsRxTempCompGain_mdB) +{ + int8_t tempGainComp = 0x00; + + const int16_t LOW_LIMIT_GAIN_COMP = -3000; + const int16_t HIGH_LIMIT_GAIN_COMP = 3000; + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxTempGainComp()\n"); +#endif + + /* Check for Gain compensation range */ + if ((obsRxTempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (obsRxTempCompGain_mdB < LOW_LIMIT_GAIN_COMP)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE)); + return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE; + } + + /* Check for Gain compensation range */ + if (obsRxTempCompGain_mdB % GAIN_COMP_STEP) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP, + getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP)); + return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP; + } + + /* Prepare register write */ + tempGainComp = (obsRxTempCompGain_mdB / GAIN_COMP_STEP) & 0x1F; + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_TEMP_GAIN_COMP, (uint8_t)tempGainComp); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function gets the Temperature gain compensation for the observation channel + * + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param obsRxTempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for the observation channel. + * + * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL obsRxTempCompGain_mdB pointer is null. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getObsRxTempGainComp(mykonosDevice_t *device, int16_t *obsRxTempCompGain_mdB) +{ + uint8_t tempGainComp = 0x00; + int8_t tempGainCompDB = 0x00; + + const int16_t GAIN_COMP_STEP = 250; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxTempGainComp()\n"); +#endif + + /* Check for null passed parameter */ + if (obsRxTempCompGain_mdB == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL, + getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL)); + return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_TEMP_GAIN_COMP, &tempGainComp); + + /* Convert to dB and prepare the signed return */ + tempGainCompDB = tempGainComp & 0x1F; + if (tempGainCompDB & 0x10) + { + tempGainCompDB = (((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1); + } + + /* Assign value to the passed pointer */ + *obsRxTempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP; + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables or disables the Rx slow loop gain counter to use the sync pulse + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param enable is a uint8_t data type where '0' = disable Rx gain counter from using sync pulse, '1' = enable Rx gain. All other values will throw an error. + * counter to use the sync pulse. This value is written back to the device data structure for storage. + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable) +{ + const uint8_t syncPulseBitMask = 0x80; + uint8_t enableBit = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxGainCtrSyncPulse()\n"); +#endif + + /* read, modify, write Rx gain counter sync pulse enable bit */ + enableBit = (enable > 0) ? 1 : 0; + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, enableBit, syncPulseBitMask, 7); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Configures the Rx gain control mode + * + * Dependencies: + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->rx->rxGainCtrl->gainMode + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param mode is a mykonosGainMode_t enumerated gain control mode type where: + * Manual Gain = MGC, Automatic Gain Control = AGC, and hybrid mode = HYBRID + * + * When the mode enumerated type is passed, the Rx1 and Rx2 gain mode is set to this value and the + * Rx gainMode structure member is updated with the new value + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_INV_RX_GAIN_MODE_PARM Invalid AGC mode pass in function mode paramter + */ +mykonosErr_t MYKONOS_setRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode) +{ + uint8_t rxGainCfgReg = 0; + + const uint8_t RX_GAIN_TYPE_MASK = 0x1F; + const uint8_t RX_GAIN_HYBRID_MASK = 0x10; + const uint8_t RX_GAIN_TYPE_SHIFT = 0x02; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxGainControlMode()\n"); +#endif + + /* read AGC type for Rx1 and Rx2 for modify, write */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_CFG_1, &rxGainCfgReg); + rxGainCfgReg &= ~RX_GAIN_TYPE_MASK; + + /* performing AGC type check */ + switch (mode) + { + case MGC: + rxGainCfgReg &= ~RX_GAIN_HYBRID_MASK; + break; + case AGC: + rxGainCfgReg &= ~RX_GAIN_HYBRID_MASK; + break; + case HYBRID: + rxGainCfgReg |= RX_GAIN_HYBRID_MASK; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RX_GAIN_MODE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_RX_GAIN_MODE_PARM)); + return MYKONOS_ERR_INV_RX_GAIN_MODE_PARM; + } + + /* modify, write AGC type for Rx1 and Rx2 */ + rxGainCfgReg |= (uint8_t)mode; + rxGainCfgReg |= (uint8_t)((uint8_t)mode << RX_GAIN_TYPE_SHIFT); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_CFG_1, rxGainCfgReg); + + /* writing mode setting to data structure */ + if ((device->profilesValid & RX_PROFILE_VALID) > 0) + { + device->rx->rxGainCtrl->gainMode = mode; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs a power measurement in the Rx1 digital data path. + * + * Due to interdependencies between the AGC and power measurement the power measurement duration and + * where the measurement is taken is variable. + * The location of the power measurement is given by device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig + * The number of samples the power measurement uses is given by 8*2^(device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration) at the IQ rate, + * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter. + * If the receiver is disabled during the power measurement, this function returns a 0 value for rx1DecPower_mdBFS + * + * The resolution of this function is 0.25dB. + * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately. + * + * Dependencies + * - device->spiSettings + * - device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig + * - device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration + * + * \param device Pointer to the Mykonos data structure + * \param rx1DecPower_mdBFS Pointer to store the Rx1 decimated power return. Value returned in mdBFS + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRx1DecPower(mykonosDevice_t *device, uint16_t *rx1DecPower_mdBFS) +{ + uint8_t rx1DecPower_dBFS = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1DecPower()\n"); +#endif + + /* read Rx1 Dec Power Measurement */ + if (rx1DecPower_mdBFS != NULL) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_CH1_DECIMATED_PWR, &rx1DecPower_dBFS); + *rx1DecPower_mdBFS = (uint16_t)(rx1DecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */ + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM)); + return MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs a power measurement in the Rx2 digital data path. + * + * Due to interdependencies between the AGC and power measurement the power measurement duration and + * where the measurement is taken is variable. + * The location of the power measurement is given by device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig + * The number of samples the power measurement uses is given by 8*2^(device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration) at the IQ rate, + * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter. + * If the receiver is disabled during the power measurement, this function returns a 0 value for rx2DecPower_mdBFS + * + * The resolution of this function is 0.25dB. + * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately. + * + * Dependencies + * - device->spiSettings + * + * \param device Pointer to the Mykonos data structure + * \param rx2DecPower_mdBFS Pointer to store the Rx1 decimated power return. Value returned in mdBFS + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRx2DecPower(mykonosDevice_t *device, uint16_t *rx2DecPower_mdBFS) +{ + uint8_t rx2DecPower_dBFS = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2DecPower()\n"); +#endif + + /* read Rx2 Dec Power Measurement */ + if (rx2DecPower_mdBFS != NULL) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_CH2_DECIMATED_PWR, &rx2DecPower_dBFS); + *rx2DecPower_mdBFS = (uint16_t)(rx2DecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */ + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM)); + return MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM; + } + + return MYKONOS_ERR_OK; +} + +/* + ***************************************************************************** + * Observation Rx Data path functions + ***************************************************************************** + */ + +/** + * \brief Sets the default Obs Rx channel to enter when device moves from + * radioOff to radioOn + * + * By default, the observation receiver remains powered down when the device + * moves into the radioOn state. If the BBIC prefers a particular ObsRx + * channel to be enabled, this function can be called in radioOff to set + * the default channel to power up when the device moves to radioOn. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->obsRx->defaultObsRxChannel + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param defaultObsRxCh is mykonosObsRxChannels_t enum type which selects the desired observation receive path to power up + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SETDEFOBSRXPATH_NULL_OBSRX_STRUCT Observation profile not valid, device->obsRx structure is NULL + * \retval MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT Invalid defaultObsRxCh function parameter + */ +mykonosErr_t MYKONOS_setDefaultObsRxPath(mykonosDevice_t *device, mykonosObsRxChannels_t defaultObsRxCh) +{ + uint8_t orxEntryMode[1] = {0}; + uint16_t byteOffset = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDefaultObsRxPath()\n"); +#endif + + if (device->obsRx == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT, + getMykonosErrorMessage(MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT)); + return MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT; + } + + if (((defaultObsRxCh > OBS_RX2_SNIFFERLO) && (defaultObsRxCh != OBS_SNIFFER_A) && (defaultObsRxCh != OBS_SNIFFER_B) && (defaultObsRxCh != OBS_SNIFFER_C))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM)); + return MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM; + } + + device->obsRx->defaultObsRxChannel = defaultObsRxCh; + orxEntryMode[0] = ((uint8_t)device->obsRx->defaultObsRxChannel & 0xFF); + + byteOffset = 6; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_RADIO_CONTROL, byteOffset, &orxEntryMode[0], 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Powers up or down the Observation Rx signal chain in the radioOn state + * + * When the ARM radio control is in ARM command mode, this + * function allows the user to selectively power up or down the desired ObsRx + * data path. If this function is called when the ARM is expecting GPIO pin + * control of the ObsRx path source, an error will be returned. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxCh is mykonosObsRxChannels_t enum type which selects the desired observation receive path to power up + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM Invalid obsRxCh function parameter + * \retval MYKONOS_ERR_PU_OBSRXPATH_ARMERROR ARM returned an error while trying to set the ObsRx Path source + */ +mykonosErr_t MYKONOS_setObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh) +{ + uint8_t cmdStatByte = 0; + uint32_t timeoutMs = 0; + uint8_t payload[2] = {0, 0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxPathSource()\n"); +#endif + + if (((obsRxCh > OBS_RX2_SNIFFERLO) && (obsRxCh != OBS_SNIFFER_A) && (obsRxCh != OBS_SNIFFER_B) && (obsRxCh != OBS_SNIFFER_C))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM)); + return MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM; + } + + payload[0] = MYKONOS_ARM_OBJECTID_ORX_MODE; + payload[1] = (uint8_t)(obsRxCh); + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &payload[0], sizeof(payload)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; /* wait max of 1sec for command to complete */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_ARMERROR)); + return MYKONOS_ERR_PU_OBSRXPATH_ARMERROR; + } + + return retVal; + } + + /* Verify ARM command did not return an error */ + if (cmdStatByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_ARMERROR)); + return MYKONOS_ERR_PU_OBSRXPATH_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads back the currently enabled Observation Rx channel in the + * radioOn state + * + * In pin mode, the pin could change asynchronous to reading back the + * current enable ObsRx path. Calling this function while in radioOff will + * return OBS_RXOFF since all radio channels are powered down. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxCh Parameter to return enum of the current observation receive + * path powered up + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR ARM returned an error while trying to get the ObsRx Path source + */ +mykonosErr_t MYKONOS_getObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t *obsRxCh) +{ + uint8_t extData[1] = {MYKONOS_ARM_OBJECTID_ORX_MODE}; + uint8_t cmdStatusByte = 0; + uint8_t armData[1] = {0}; + uint32_t timeoutMs = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxPathSource()\n"); +#endif + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR)); + return MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR; + } + + return retVal; + } + + /* read 64-bit frequency from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 1, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR)); + return MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR; + } + + *obsRxCh = (mykonosObsRxChannels_t)(armData[0]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the Rx gain of the ObsRx channel + * + * The ObsRx channel can have different RF inputs (ORx1/ORx2/SnRx A,B,C) + * This function sets the ObsRx gain index independently for ORx1/ORx2, or SnRx. + * SnRx A, B, and C share the same gain index. Please note that ORx1/ORx2 share a gain + * table, as does SnRx A, B, and C. The maximum index is 255 + * and the minimum index is application specific. + * + * Dependencies + * - device->spiSettings + * - device->obsRx->orxGainCtrl->maxGainIndex + * - device->obsRx->orxGainCtrl->minGainIndex + * - device->obsRx->orxGainCtrl->orx1GainIndex + * - device->obsRx->orxGainCtrl->orx2GainIndex + * - device->obsRx->snifferGainCtrl->maxGainIndex + * - device->obsRx->snifferGainCtrl->minGainIndex + * - device->obsRx->snifferGainCtrl->gainIndex + * + * \param device Pointer to the Mykonos device data structure + * \param obsRxCh is an enum type mykonosObsRxChannels_t to identify the desired RF input for gain change + * \param gainIndex Desired manual gain table index to set + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN Invalid gain requested for ORx1: outside gain table min/max index + * \retval MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN Invalid gain requested for ORx2: outside gain table min/max index + * \retval MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN Invalid gain requested for Sniffer: outside gain table min/max index + * \retval MYKONOS_ERR_SETORXGAIN_INV_CHANNEL Function parameter obsRxCh has an invalid enum value + */ +mykonosErr_t MYKONOS_setObsRxManualGain(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh, uint8_t gainIndex) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxManualGain()\n"); +#endif + + if ((obsRxCh == OBS_RX1_TXLO) || (obsRxCh == OBS_RX1_SNIFFERLO)) + { + if (gainIndex <= device->obsRx->orxGainCtrl->maxGainIndex && gainIndex >= device->obsRx->orxGainCtrl->minGainIndex) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX1_MANUAL_GAIN_INDEX, (gainIndex - MIN_ORX_GAIN_TABLE_INDEX)); + device->obsRx->orxGainCtrl->orx1GainIndex = gainIndex; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN, + getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN)); + return MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN; + } + } + else if ((obsRxCh == OBS_RX2_TXLO) || (obsRxCh == OBS_RX2_SNIFFERLO)) + { + if (gainIndex <= device->obsRx->orxGainCtrl->maxGainIndex && gainIndex >= device->obsRx->orxGainCtrl->minGainIndex) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX2_MANUAL_GAIN_INDEX, (gainIndex - MIN_ORX_GAIN_TABLE_INDEX)); + device->obsRx->orxGainCtrl->orx2GainIndex = gainIndex; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN, + getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN)); + return MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN; + } + + } + else if (obsRxCh == OBS_SNIFFER_A || obsRxCh == OBS_SNIFFER_B || obsRxCh == OBS_SNIFFER_C || obsRxCh == OBS_SNIFFER) + { + if (gainIndex <= device->obsRx->snifferGainCtrl->maxGainIndex && gainIndex >= device->obsRx->snifferGainCtrl->minGainIndex) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SNRX_MANUAL_GAIN_INDEX, (gainIndex - MIN_SNRX_GAIN_TABLE_INDEX)); + device->obsRx->snifferGainCtrl->gainIndex = gainIndex; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN, + getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN)); + return MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN; + } + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_CHANNEL)); + return MYKONOS_ERR_SETORXGAIN_INV_CHANNEL; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Gets the gain index of the currently enabled ObsRx channel + * + * The ObsRx data path can have multiple RF sources. This function will + * read back the gain index of the currently enabled RF source. If the ObsRx + * data path is disabled, an error is returned. If the functions uint8_t *gainIndex + * parameter is a valid pointer, the gain index is returned at the pointers + * address. Else, if the uint8_t *gainIndex pointer is NULL, the gainIndex read back + * is stored in the device data structure. + * + * NOTE: if the observation source is chosen by ORX_MODE pins, it is possible that + * the readback value will be incorrect if the obsRx channel changes while this function + * reads the gain. + * + * Dependencies + * - device->spiSettings + * - device->profilesValid + * - device->obsRx->orxGainCtrl->orx1GainIndex + * - device->obsRx->orxGainCtrl->orx2GainIndex + * - device->obsRx->snifferGainCtrl->gainIndex + * + * \param device Pointer to the Mykonos device data structure + * \param gainIndex Return value of the current gain index for the currently enabled ObsRx channel. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETORX1GAIN_INV_POINTER The ObsRx profile is not valid in the device data structure + * \retval MYKONOS_ERR_GETORX2GAIN_INV_POINTER The ObsRx profile is not valid in the device data structure + * \retval MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER The sniffer profile is not valid in the device data structure + * \retval MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED The observation receiver is currently disabled, can not read back gain index. + */ +mykonosErr_t MYKONOS_getObsRxGain(mykonosDevice_t *device, uint8_t *gainIndex) +{ + /* Potential issue, if ARM is using loopback path when this function is called, it will likely readback loopback gain */ + uint8_t readObsRxPathEnabled = 0; + uint8_t readObsRxGain = 0; + + const uint8_t ORX1_EN = 0x01; + const uint8_t ORX2_EN = 0x02; + const uint8_t SNRX_EN = 0x04; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxGain()\n"); +#endif + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_1, &readObsRxPathEnabled); + + /* If obsRx channel enabled, then read gain index */ + if (readObsRxPathEnabled > 0) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_ORX_SNRX_GAIN, &readObsRxGain); + + switch (readObsRxPathEnabled) + { + case 0x01: + readObsRxGain += MIN_ORX_GAIN_TABLE_INDEX; + break; + case 0x02: + readObsRxGain += MIN_ORX_GAIN_TABLE_INDEX; + break; + case 0x04: + readObsRxGain += MIN_SNRX_GAIN_TABLE_INDEX; + break; + default: + break; + } + + if (gainIndex != NULL) + { + *gainIndex = readObsRxGain; + } + + /* Store the gain index in the device's gain control data structure. */ + + if (readObsRxPathEnabled == ORX1_EN) + { + /* verify valid data structure pointers */ + if (device->profilesValid & ORX_PROFILE_VALID) + { + device->obsRx->orxGainCtrl->orx1GainIndex = readObsRxGain; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORX1GAIN_INV_POINTER, + getMykonosErrorMessage(MYKONOS_ERR_GETORX1GAIN_INV_POINTER)); + return MYKONOS_ERR_GETORX1GAIN_INV_POINTER; + } + + } + else if (readObsRxPathEnabled == ORX2_EN) + { + /* verify valid pointers */ + if (device->profilesValid & ORX_PROFILE_VALID) + { + device->obsRx->orxGainCtrl->orx2GainIndex = readObsRxGain; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORX2GAIN_INV_POINTER, + getMykonosErrorMessage(MYKONOS_ERR_GETORX2GAIN_INV_POINTER)); + return MYKONOS_ERR_GETORX2GAIN_INV_POINTER; + } + + } + else if (readObsRxPathEnabled == SNRX_EN) + { + /* verify valid pointers */ + if (device->profilesValid & SNIFF_PROFILE_VALID) + { + device->obsRx->snifferGainCtrl->gainIndex = readObsRxGain; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER, + getMykonosErrorMessage(MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER)); + return MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER; + } + } + else + { + /* ignore gain index for Tx loopback input into obsRx channel */ + } + } + else + { + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED, + getMykonosErrorMessage(MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED)); + return MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the device ObsRx Automatic Gain Control (AGC) registers. + * + * Three data structures (of types mykonosAgcCfg_t, mykonosPeakDetAgcCfg_t, mykonosPowerMeasAgcCfg_t) + * must be instantiated prior to calling this function. Valid ranges for data structure members + * must also be provided. + * + * + * Dependencies: + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->obsRx->orxAgcCtrl->agcRx1MaxGainIndex + * - device->obsRx->orxAgcCtrl->agcRx1MinGainIndex + * - device->obsRx->orxAgcCtrl->agcRx2MaxGainIndex + * - device->obsRx->orxAgcCtrl->agcRx2MinGainIndex + * - device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex + * - device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex + * - device->obsRx->orxAgcCtrl->agcObsRxSelect + * - device->obsRx->orxAgcCtrl->agcPeakThresholdMode + * - device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease + * - device->obsRx->orxAgcCtrl->agcGainUpdateCounter + * - device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay + * - device->obsRx->orxAgcCtrl->agcPeakWaitTime + * - device->obsRx->orxAgcCtrl->agcResetOnRxEnable + * - device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter + * - device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh + * - device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh + * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh + * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh + * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh + * - device->obsRx->orxAgcCtrl->peakAgc->apdHighThreshExceededCnt + * - device->obsRx->orxAgcCtrl->peakAgc->apdLowThreshExceededCnt + * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighThreshExceededCnt + * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowThreshExceededCnt + * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt + * - device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack + * - device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery + * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack + * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery + * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery + * - device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack + * - device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack + * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable + * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt + * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt + * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh + * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh + * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh + * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh + * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack + * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack + * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery + * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery + * - device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration + * - device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig + * + * \param device is structure pointer to the Mykonos data structure containing settings + * The pointer to the Mykonos AGC data structure containing settings is checked for a null pointer + * to ensure it has been initialized. If not an error is thrown. + * + * \retval Returns MYKONOS_ERR=pass, !MYKONOS_ERR=fail + * \retval MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT + * \retval MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX + * \retval MYKONOS_ERR_INV_AGC_OBSRX_SELECT + * \retval MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG + * \retval MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE + * \retval MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE + * \retval MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP + * \retval MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE + * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT + * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT + */ +mykonosErr_t MYKONOS_setupObsRxAgc(mykonosDevice_t *device) +{ + /* Current configuration does not support AGC on ORx channel */ + uint8_t decPowerConfig = 0; + uint8_t lower1ThreshGainStepRegValue = 0; + uint8_t powerThresholdsRegValue = 0; + uint8_t hb2OvldCfgRegValue = 0; + uint8_t agcGainUpdateCtr[3] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupObsRxAgc()\n"); +#endif + + /* Check mykonosAgcCfg_t device->obsRx->orxAgcCtrl pointer for initialization */ + if (device->obsRx->orxAgcCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT; + } + + /* Check mykonosPeakDetAgcCfg_t device->orx->orxAgcCtrl->peakAgc pointer for initialization */ + if (device->obsRx->orxAgcCtrl->peakAgc == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT; + } + + /* Check mykonosPowerMeasAgcCfg_t device->obsRx->orxAgcCtrl->powerAgc pointer for initialization */ + if (device->obsRx->orxAgcCtrl->powerAgc == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT)); + return MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT; + } + + /* Range check agcObsRxMaxGainIndex versus gain table limits and agcObsRxMinGainIndex */ + if ((device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex > device->obsRx->snifferGainCtrl->maxGainIndex) || + (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex < device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MAX_GAIN_INDEX, + (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES)); + } + + /* Range check agcObsRxMinGainIndex versus gain table limits and agcObsRxMaxGainIndex */ + if ((device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex < device->obsRx->snifferGainCtrl->minGainIndex) || + (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex < device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX)); + return MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MIN_GAIN_INDEX, + (device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES)); + } + + /* Range check agcObsRxSelect. Sniffer only support. Sniffer is selected if value is 0 or 1. 2 or 3 select ORx1/ORx2 respectively */ + if (device->obsRx->orxAgcCtrl->agcObsRxSelect > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_SELECT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_SELECT)); + return MYKONOS_ERR_INV_AGC_OBSRX_SELECT; + } + else + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ACTIVE, device->obsRx->orxAgcCtrl->agcObsRxSelect); + } + + /* Range check for agcGainUpdateCounter (22-bit) */ + if ((device->obsRx->orxAgcCtrl->agcGainUpdateCounter > 0x3FFFFF) || + (device->obsRx->orxAgcCtrl->agcGainUpdateCounter < 1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM; + } + else + { + /* Split agcGainUpdateCounter into three values */ + agcGainUpdateCtr[0] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter); + agcGainUpdateCtr[1] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter >> 8); + agcGainUpdateCtr[2] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter >> 16); + + /* Write two bytes directly due. Third word has its upper two bits masked off. */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_1, agcGainUpdateCtr[0]); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_2, agcGainUpdateCtr[1]); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_3, agcGainUpdateCtr[2], 0x3F, 0); + } + + /* Range check on agcPeakWaitTime (5-bit) */ + if ((device->obsRx->orxAgcCtrl->agcPeakWaitTime > 0x1F) || + (device->obsRx->orxAgcCtrl->agcPeakWaitTime < 0x02)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM; + } + else + { + /* Write agcPeakWaitTime */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_2, device->obsRx->orxAgcCtrl->agcPeakWaitTime, 0x1F, 0); + } + + /* Range check for agcSlowLoopSettlingDelay (7-bit) */ + if (device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY)); + return MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY; + } + else + { + /* Write agcSlowLoopSettlingDelay */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay, 0x7F, 0); + } + + /* Range check for pmdMeasDuration */ + if ((uint32_t)(1 << (3 + device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration)) >= (device->obsRx->orxAgcCtrl->agcGainUpdateCounter)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION; + } + else + { + /* Write pmdMeasDuration */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_SNIFFER_DEC_POWER_CONFIG_2, device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration, 0x0F, 0); + } + + /* Range check for pmdMeasConfig */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig > 0x3) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG; + } + else + { + if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 0) + { + decPowerConfig = 0x0; /* Dec Pwr measurement disable */ + } + else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 1) + { + decPowerConfig = 0x3; /* Dec Pwr measurement enable, HB2 for decPwr measurement */ + } + else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 2) + { + decPowerConfig = 0x5; /* Dec Pwr measurement enable, RFIR for decPwr measurement */ + } + else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 3) + { + decPowerConfig = 0x11; /* Dec Pwr measurement enable, BBDC2 for decPwr measurement */ + } + /* Write pmdMeasConfig */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_SNIFFER_DEC_POWER_CONFIG_1, decPowerConfig); + } + + /* Range check agcLowThsPreventGainIncrease (1-bit) */ + if (device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC)); + return MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC; + } + else + { + /* Write agcLowThsPreventGainIncrease */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOCK_LEV_THRSH, device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease, 0x80, 7); + } + + /* Range check agcPeakThresholdMode (1-bit), */ + if (device->obsRx->orxAgcCtrl->agcPeakThresholdMode > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE)); + return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE; + } + else + { + /* Save to lower1ThreshGainStepRegValue register variable */ + lower1ThreshGainStepRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->agcPeakThresholdMode << 5); + } + + /* Range check agcResetOnRxEnable (1-bit) */ + if (device->obsRx->orxAgcCtrl->agcResetOnRxEnable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE)); + return MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE; + } + else + { + /* Write agcResetOnRxEnable */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_3, (uint8_t)(device->obsRx->orxAgcCtrl->agcResetOnRxEnable << 7), 0x80, 0); + } + + /* Range check agcEnableSyncPulseForGainCounter (1-bit) */ + if (device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER)); + return MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER; + } + else + { + /* Write agcEnableSyncPulseForGainCounter */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, (uint8_t)(device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter << 7), 0x80, 0); + } + + /* WRITE REGISTERS FOR THE AGC POWER MEASUREMENT DETECTOR (PMD) STRUCTURE */ + + /* Range check pmdLowerHighThresh (7-bit) vs 0x7F and pmdUpperLowThresh */ + if ((device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh <= device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh) || + device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH; + } + else + { + /* Write pmdLowerHighThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOCK_LEV_THRSH, device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh, 0x7F, 0); + } + + /* Range check pmdUpperLowThresh (7-bit): Comparison to pmdLowerHigh done earlier */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh > 0x7F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH; + } + else + { + /* Write pmdUpperLowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_LOCK_LEVEL, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh); + } + + /* Range check pmdLowerLowThresh (4-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH; + } + else + { + /* Write pmdUpperLowThresh to temp variable */ + powerThresholdsRegValue |= device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh; + } + + /* Range check pmdUpperHighThresh (4-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH; + } + else + { + /* Write pmdUpperHighThresh to temp var, then to register */ + powerThresholdsRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh << 4); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_POWER_THRSH, powerThresholdsRegValue); + } + + /* Range check pmdUpperHighGainStepAttack (5-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP; + } + else + { + /* Write pmdUpperHighGainStepAttack */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER1_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack, 0x1F, 0); + } + + /* Range check pmdLowerLowGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + lower1ThreshGainStepRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery); + } + + /* Range check pmdUpperLowGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP; + } + else + { + /* Write pmdUpperLowGainStepRecovery to register */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER0_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack); + } + + /* Range check pmdLowerHighGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP)); + return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER0_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery); + } + + /* WRITE REGISTERS FOR THE AGC PEAK DETECTOR (APD/HB2) STRUCTURE */ + + /* Range check apdFastAttack and hb2FastAttack (1-bit) */ + if ((device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack > 0x1) || + (device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack > 0x1)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE)); + return MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE; + } + else + { + /* Write pmdLowerLowGainStepRecovery to temp var, then to register */ + lower1ThreshGainStepRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack << 7); + lower1ThreshGainStepRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack << 6); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER1_THRSH_GAIN_STEP, lower1ThreshGainStepRegValue); + } + + /* Range check apdHighThresh */ + if ((device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh > 0x3F) || + (device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh <= device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM; + } + else + { + /* Write apdHighThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ULB_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh, 0X3F, 0); + } + + /* Range check apdLowThresh */ + if ((device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh > 0x3F) || + (device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh < device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM; + } + else + { + /* write apdLowThresh */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_LLB_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh, 0x3F, 0); + } + + /* Range check hb2HighThresh */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh < device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM; + } + else + { + /* write hb2HighThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_UPPER_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh); + } + + /* Range check hb2LowThresh */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh > device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM; + } + else + { + /* write hb2LowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_LOWER_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh); + } + + /* Range check hb2VeryLowThresh */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh > device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM; + } + else + { + /* write hb2VeryLowThresh */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_VERYLOW_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh); + } + + /* Write threshold counter values for apdHigh/apdLow/hb2High/hb2Low/hb2VeryLow */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ULB_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdHighThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LLB_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdLowThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_HIGH_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2HighThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_LOW_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2LowThreshExceededCnt); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_VERYLOW_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt); + + /* Range check on apdHighGainStepAttack (5-bit) */ + if (device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM; + } + else + { + /* Write apdHighGainStepAttack */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_1, device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack); + } + + /* Range check on apdLowGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM; + } + else + { + /* Write apdLowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_4, device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery); + } + + /* Range check on hb2HighGainStepAttack (5-bit) */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM; + } + else + { + /* Write hb2HighGainStepAttack */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_2, device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack); + } + + /* Range check on hb2LowGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM; + } + else + { + /* Write hb2LowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_5, device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery); + } + + /* Range check on hb2VeryLowGainStepRecovery (5-bit) */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM; + } + else + { + /* Write hb2VeryLowGainStepRecovery */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_6, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery); + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable > 0x1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE; + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt > 0x7) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT; + } + + /* Range Check on hb2OverloadDetectEnable */ + if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt > 0xF) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT, + getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT)); + return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT; + } + else + { + /* Write the hb2OvldCfgRegValue, the combination of hb2OverloadThreshCnt, hb2OverloadDurationCnt, and hb2OverloadDetectEnable */ + hb2OvldCfgRegValue = (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt) | + (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt << 4) | + (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable << 7); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_CFG, hb2OvldCfgRegValue); + } + + /* Hard-coded value for the ADC overload configuration. Sets the HB2 offset to -6dB.*/ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_ADC_OVRLD_CFG, 0x18); + /* Hard-coded value for APD decay setting. Setting allows for the quickest settling time of peak detector */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_BLOCK_DET_DECAY, 0x0); + + /* performing a soft reset */ + return MYKONOS_resetRxAgc(device); +} + +/** + * \brief Enables or disables the ObsRx slow loop gain counter to use the sync pulse + * + * Dependencies: + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing the device SPI settings + * \param enable is a uint8_t data type where '0' = disable ObsRx gain counter from using sync pulse, '1' = enable ObsRx gain. All other values will throw an error. + * counter to use the sync pulse. This value is written back to the device data structure for storage. + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableObsRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable) +{ + const uint8_t syncPulseBitMask = 0x80; + uint8_t enableBit = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxGainCtrSyncPulse()\n"); +#endif + + enableBit = (enable > 0) ? 1 : 0; + + /* read, modify, write ObsRx gain counter sync pulse enable bit */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, enableBit, syncPulseBitMask, 7); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Configures the ObsRx gain control mode + * + * Dependencies: + * - device->spiSettings + * - device->obsRx->orxGainCtrl->gainMode + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param mode is a mykonosGainMode_t enumerated gain control mode type + * + * When the mode enumerated type is passed, the ObsRx gain mode is set to this value and the + * ObsRX agcType mykonosAgcCfg_t structure member is updated with the new value + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM Invalid Observation Rx Gain control mode selected (use mykonosGainMode_t ENUM values) + */ +mykonosErr_t MYKONOS_setObsRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode) +{ + const uint8_t ORX_GAIN_TYPE_MASK = 0x3; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxGainControlMode()\n"); +#endif + + /* performing gain type check */ + switch (mode) + { + case MGC: + break; + case AGC: + break; + case HYBRID: + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM)); + return MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_1, mode, ORX_GAIN_TYPE_MASK, 0); + + /* writing mode setting to data structure */ + if ((device->profilesValid & ORX_PROFILE_VALID) > 0) + { + device->obsRx->orxGainCtrl->gainMode = mode; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs a power measurement in the ObsRx digital data path. + * + * Due to interdependencies between the AGC and power measurement the power measurement duration and + * where the measurement is taken is variable. + * The location of the power measurement is given by device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig + * The number of samples the power measurement uses is given by 8*2^(device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig) at the IQ rate, + * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter. + * If the receiver is disabled during the power measurement, this function returns a 0 value for rx2DecPower_mdBFS + * + * The resolution of this function is 0.25dB. + * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately. + * + * Dependencies + * - device->spiSettings + * - device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig + * - device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig + * + * \param device Pointer to the Mykonos data structure + * \param obsRxDecPower_mdBFS Pointer to store the Rx1 decimated power return. Value returned in mdBFS + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getObsRxDecPower(mykonosDevice_t *device, uint16_t *obsRxDecPower_mdBFS) +{ + uint8_t obsRxDecPower_dBFS = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxDecPower()\n"); +#endif + + /* read ObsRx Dec Power Measurement */ + if (obsRxDecPower_mdBFS != NULL) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_SNIFFER_DECIMATED_PWR, &obsRxDecPower_dBFS); + *obsRxDecPower_mdBFS = (uint16_t)(obsRxDecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */ + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM)); + return MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM; + } + + return MYKONOS_ERR_OK; +} + +/* + ***************************************************************************** + * Tx Data path functions + ***************************************************************************** + */ + +/** + * \brief Sets the Tx1 RF output Attenuation + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->tx->txAttenStepSize + * + * \param device Pointer to the Mykonos device's data structure + * \param tx1Attenuation_mdB The desired TxAttenuation in milli-dB (Range: 0 to 41950 mdB) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SETTX1ATTEN_INV_PARM tx1Attenuation_mdB parameter is out of range (0 - 41950) + * \retval MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM device->tx->txAttenStepSize is not a valid enum value + */ +mykonosErr_t MYKONOS_setTx1Attenuation(mykonosDevice_t *device, uint16_t tx1Attenuation_mdB) +{ + uint16_t data = 0; + uint16_t attenStepSizeDiv = 50; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTx1Attenuation()\n"); +#endif + + /* check input parameter is in valid range */ + if (tx1Attenuation_mdB > 41950) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX1ATTEN_INV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETTX1ATTEN_INV_PARM)); + return MYKONOS_ERR_SETTX1ATTEN_INV_PARM; + } + + switch (device->tx->txAttenStepSize) + { + case TXATTEN_0P05_DB: + attenStepSizeDiv = 50; + break; + case TXATTEN_0P1_DB: + attenStepSizeDiv = 100; + break; + case TXATTEN_0P2_DB: + attenStepSizeDiv = 200; + break; + case TXATTEN_0P4_DB: + attenStepSizeDiv = 400; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM)); + return MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM; + + } + + data = (tx1Attenuation_mdB / attenStepSizeDiv); + + /* Write MSB bits followed by LSB bits, TxAtten updates when [7:0] written */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1, ((data >> 8) & 0x03)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_0, (data & 0xFF)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the Tx2 RF output Attenuation (Step size is 0.05dB.) + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->tx->txAttenStepSize + * + * \param device Pointer to the Mykonos device's data structure + * \param tx2Attenuation_mdB The desired TxAttenuation in milli-dB + * (Range: 0 to 41950 mdB) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SETTX2ATTEN_INV_PARM tx2Attenuation_mdB parameter is out of range (0 - 41950) + * \retval MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM device->tx->txAttenStepSize is not a valid enum value + */ +mykonosErr_t MYKONOS_setTx2Attenuation(mykonosDevice_t *device, uint16_t tx2Attenuation_mdB) +{ + uint16_t attenStepSizeDiv = 50; + uint16_t data = 0; + //const uint8_t SPI_TXATTEN_MODE = 0x01; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTx2Attenuation()\n"); +#endif + + /* check input parameter is in valid range */ + if (tx2Attenuation_mdB > 41950) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX2ATTEN_INV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETTX2ATTEN_INV_PARM)); + return MYKONOS_ERR_SETTX2ATTEN_INV_PARM; + } + + switch (device->tx->txAttenStepSize) + { + case TXATTEN_0P05_DB: + attenStepSizeDiv = 50; + break; + case TXATTEN_0P1_DB: + attenStepSizeDiv = 100; + break; + case TXATTEN_0P2_DB: + attenStepSizeDiv = 200; + break; + case TXATTEN_0P4_DB: + attenStepSizeDiv = 400; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM)); + return MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM; + } + + data = (tx2Attenuation_mdB / attenStepSizeDiv); + + /* Write MSB bits followed by LSB bits, TxAtten updates when [7:0] written */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1, ((data >> 8) & 0x03)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_0, (data & 0xFF)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads back the Tx1 RF output Attenuation + * + * This function reads back the TxAttenuation setting currently applied to the transmit chain. + * The function will work with SPI mode or pin controlled TxAtten mode using the increment/decrement GPIO + * pins. For the readback value to be valid the Tx data path must be powered up. If the Tx data path + * is powered down or radioOff state, the last TxAtten setting while the Tx was powered up will be + * read back. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device's data structure + * \param tx1Attenuation_mdB The readback value of the Tx1 Attenuation in milli-dB (Range: 0 to 41950 mdB) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETTX1ATTEN_NULL_PARM tx1Attenuation_mdB return parameter has NULL pointer + */ +mykonosErr_t MYKONOS_getTx1Attenuation(mykonosDevice_t *device, uint16_t *tx1Attenuation_mdB) +{ + uint8_t txAttenLsb = 0; + uint8_t txAttenMsb = 0; + uint16_t attenStepSizeDiv = 50; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTx1Attenuation()\n"); +#endif + + /* check return parameter pointer is not NULL pointer */ + if (tx1Attenuation_mdB == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1ATTEN_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GETTX1ATTEN_NULL_PARM)); + return MYKONOS_ERR_GETTX1ATTEN_NULL_PARM; + } + + /* Write TxAtten read back reg to update readback values, then read Tx1Atten */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1_READBACK, 0x00); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_0_READBACK, &txAttenLsb, 0xFF, 0); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1_READBACK, &txAttenMsb, 0x03, 0); + + /* Readback word always reads back with 0.05dB resolution */ + *tx1Attenuation_mdB = (uint16_t)(((uint16_t)(txAttenLsb) | ((uint16_t)(txAttenMsb) << 8)) * attenStepSizeDiv); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads back the Tx2 RF output Attenuation + * + * This function reads back the TxAttenuation setting currently applied to the transmit chain. + * The function will work with SPI mode or pin controlled TxAtten mode using the increment/decrement GPIO + * pins. For the readback value to be valid the Tx data path must be powered up. If the Tx data path + * is powered down or radioOff state, the last TxAtten setting while the Tx was powered up will be + * read back. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device's data structure + * \param tx2Attenuation_mdB The readback value of the Tx2 Attenuation in milli-dB (Range: 0 to 41950 mdB) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETTX2ATTEN_NULL_PARM tx2Attenuation_mdB return parameter pointer is NULL + */ +mykonosErr_t MYKONOS_getTx2Attenuation(mykonosDevice_t *device, uint16_t *tx2Attenuation_mdB) +{ + uint8_t txAttenLsb = 0; + uint8_t txAttenMsb = 0; + uint16_t attenStepSizeDiv = 50; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTx2Attenuation()\n"); +#endif + + /* check return parameter pointer is not NULL pointer */ + if (tx2Attenuation_mdB == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2ATTEN_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GETTX2ATTEN_NULL_PARM)); + return MYKONOS_ERR_GETTX2ATTEN_NULL_PARM; + } + + /* Write TxAtten read back reg to update readback values, then read Tx1Atten */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1_READBACK, 0x00); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_0_READBACK, &txAttenLsb, 0xFF, 0); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1_READBACK, &txAttenMsb, 0x03, 0); + + /* Readback word always reads back with 0.05dB resolution */ + *tx2Attenuation_mdB = (uint16_t)(((uint16_t)(txAttenLsb) | ((uint16_t)(txAttenMsb) << 8)) * attenStepSizeDiv); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Checks the Tx Filter over-range bit assignments for digital clipping in the Tx data path + * + * Dependencies + * - device->spiSettings + * + * txFilterStatus bit-field assignments are: + * txFilterStatus[0] = TFIR Ch1 Overflow + * txFilterStatus[1] = HB1 Ch1 Overflow + * txFilterStatus[2] = HB2 Ch1 Overflow + * txFilterStatus[3] = QEC Ch1 Overflow + * txFilterStatus[4] = TFIR Ch2 Overflow + * txFilterStatus[5] = HB1 Ch2 Overflow + * txFilterStatus[6] = HB2 Ch2 Overflow + * txFilterStatus[7] = QEC Ch2 Overflow + * + * \param device Pointer to the Mykonos device's data structure + * \param txFilterStatus is an 8-bit Tx filter over-range status bit-field + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM Function txFilterStatus parameter pointer is NULL + */ +mykonosErr_t MYKONOS_getTxFilterOverRangeStatus(mykonosDevice_t *device, uint8_t *txFilterStatus) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxFilterOverRangeStatus()\n"); +#endif + + if (txFilterStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM)); + return MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_FILTER_OVERFLOW, txFilterStatus); + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables/Disables the Tx NCO test tone + * + * This function enables/disables a digital numerically controlled oscillator + * in the Mykonos Digital to create a test CW tone on Tx1 and Tx2 RF outputs. + * + * The TxAttenuation is forced in this function to max analog output power, but + * the digital attenuation is backed off 6dB to make sure the digital filter + * does not clip and cause spurs in the tx spectrum. + * + * Dependencies + * - device->spiSettings + * - device->profilesValid + * - device->tx->txProfile->iqRate_kHz + * + * \param device Pointer to the Mykonos device's data structure + * \param enable 0 = Disable Tx NCO, 1 = Enable Tx NCO on both transmitters + * \param tx1ToneFreq_kHz Signed frequency in kHz of the desired Tx1 tone + * \param tx2ToneFreq_kHz Signed frequency in kHz of the desired Tx2 tone + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID Can not enable Tx NCO when Tx Profile is not enabled/valid + * \retval MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID Tx1 NCO Tone frequency out of range (-IQrate/2 to IQrate/2) + * \retval MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID Tx2 NCO Tone frequency out of range (-IQrate/2 to IQrate/2) + */ +mykonosErr_t MYKONOS_enableTxNco(mykonosDevice_t *device, uint8_t enable, int32_t tx1ToneFreq_kHz, int32_t tx2ToneFreq_kHz) +{ + int16_t tx1NcoTuneWord = 0; + int16_t tx2NcoTuneWord = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableTxNco()\n"); +#endif + + if (enable > 0) + { + if ((device->profilesValid & TX_PROFILE_VALID) == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID, + getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID)); + return MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID; + } + + if ((tx1ToneFreq_kHz > ((int32_t)(device->tx->txProfile->iqRate_kHz) / 2)) || (tx1ToneFreq_kHz < ((int32_t)(device->tx->txProfile->iqRate_kHz) * -1 / 2))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID, + getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID)); + return MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID; + } + + if ((tx2ToneFreq_kHz > ((int32_t)(device->tx->txProfile->iqRate_kHz) / 2)) || (tx2ToneFreq_kHz < ((int32_t)(device->tx->txProfile->iqRate_kHz) * -1 / 2))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID, + getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID)); + return MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID; + } + + /* Force Tx output power to max analog output power, but 6dB digital */ + /* backoff to prevent the NCO from clipping the Tx PFIR filter */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_0, 0x78); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_1, 0x00, 0x3F, 0); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_2, 0x0); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_0, 0x78); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_1, 0x00, 0x3F, 0); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_2, 0x0); + + /* Enable manual Tx output power mode */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x0A, 0x0F, 0); + + /* Set Tx NCO tuning words */ + tx1NcoTuneWord = (int16_t)(((int64_t)(tx1ToneFreq_kHz) << 16) / device->tx->txProfile->iqRate_kHz * -1); + tx2NcoTuneWord = (int16_t)(((int64_t)(tx2ToneFreq_kHz) << 16) / device->tx->txProfile->iqRate_kHz * -1); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_MSB, (uint8_t)((uint16_t)tx1NcoTuneWord >> 8)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_LSB, (tx1NcoTuneWord & 0xFF)); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_MSB, (uint8_t)((uint16_t)tx2NcoTuneWord >> 8)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_LSB, (tx2NcoTuneWord & 0xFF)); + + /* Enable Tx NCO - set [7] = 1 */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DIGITAL_TEST_BYTE_0, 1, 0x80, 7); + } + else + { + /* Disable Tx NCO - set [7] = 0 */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DIGITAL_TEST_BYTE_0, 0, 0x80, 7); + + /* Enable normal Tx Atten table mode */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x05, 0x0F, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Writes Mykonos device registers with settings for the PA Protection block. + * + * This function writes register settings for the Mykonos PA Protection Block. + * This function does not enable the PA Protection functionality. + * Note that independent control of PA protection for both Tx channels is not possible. + * The PA Protection block allows for error flags to go high if the accumulated TX power in the data path + * exceeds a programmable threshold level based on samples taken in a programmable duration. + * + * \post After calling this function the user will need to call MYKONOS_enablePaProtection(...) + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device's data structure + * \param powerThreshold PA Protection Threshold sets the power level that, if detected in the TX data path, raises the PA error flags. The range is 0 to 4096. + * To calculate the required setting for the power threshold: + * powerThreshold = MAX_DAC_CODE * (10^((txPowerThresh_dBFS/10))) + * For example: If the required dBFS for the threshold is -10 dBFS, then the powerThreshold passed should be 409. + * + * \param attenStepSize Attenuation Step Size sets the size of the attenuation step when Tx Atten Control is Enabled. The range is 0 to 128 with a resolution is 0.2dB/LSB. + * \param avgDuration Averaging Duration for the TX data path power measurement. The range is 0 to 14 specified in number of cycles of the TX IQ Rate. + * \param stickyFlagEnable "1" Enables the PA Error Flags to stay high after being triggered, even if the power decreases below threshold. "0" disables this functionality. + * \param txAttenControlEnable "1" Enables autonomous attenuation changes in response to PA error flags. "0" disables this functionality. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION avgDuration parameter invalid (valid 0-15) + * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP attenStepSize function parameter invalid (valid 0-127) + */ +mykonosErr_t MYKONOS_setupPaProtection(mykonosDevice_t *device, uint16_t powerThreshold, uint8_t attenStepSize, uint8_t avgDuration, uint8_t stickyFlagEnable, uint8_t txAttenControlEnable) +{ + uint8_t paProtectConfig = 0; + uint8_t paProtectAttenCntl = 0; + + const uint8_t PROTECT_AVG_DUR_MASK = 0x1E; + const uint8_t STICKY_FLAG_EN_MASK = 0x40; + const uint8_t ATT_STEP_MASK = 0xFE; + const uint8_t PROTECT_ATT_EN_MASK = 0x01; + const uint8_t AVG_DUR_MASK = 0x0F; + const uint8_t ATT_STEP_SIZE = 0x7F; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupPaProtection()\n"); +#endif + + /* Overwrite PA Protection Config register data with averaging duration and sticky flag. Also performing range check on stickyFlagEnable and avgDuration */ + if (avgDuration > AVG_DUR_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION, + getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION)); + return MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION; + } + + if (attenStepSize > ATT_STEP_SIZE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP, + getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP)); + return MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP; + } + + paProtectConfig = (PROTECT_AVG_DUR_MASK & (avgDuration << 1)); + + if (stickyFlagEnable > 0) + { + paProtectConfig |= (STICKY_FLAG_EN_MASK); + } + + paProtectAttenCntl = ATT_STEP_MASK & (attenStepSize << 1); + + if (txAttenControlEnable > 0) + { + paProtectAttenCntl |= (PROTECT_ATT_EN_MASK); + } + + /* Clear and write all PA Protection setup registers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_ATTEN_CONTROL, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_LSB, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_MSB, 0x00); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_ATTEN_CONTROL, paProtectAttenCntl); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, paProtectConfig); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_LSB, (powerThreshold & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_MSB, ((powerThreshold >> 8) & 0x0F)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables the Mykonos PA Protection block according to the parameters passed in MYKONOS_setupPaProtection(...). + * + * This function enables the PA Protection block according to the parameters passed in MYKONOS_setupPaProtection(...) + * The paProtectEnable signal enables the PA Protection block, allowing usage of the PA protection functions. + * + * \pre Before calling this function the user needs to setup the PA protection by calling MYKONOS_setupPaProtection(...) + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device's data structure + * \param paProtectEnable "1" Enables the PA Protection block. "0" Disables the PA Protection block + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enablePaProtection(mykonosDevice_t *device, uint8_t paProtectEnable) +{ + uint8_t paProtectEnableReg = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enablePaProtection()\n"); +#endif + + paProtectEnableReg = (paProtectEnable > 0) ? 1 : 0; + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, paProtectEnableReg, 0x01, 0); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Obtains an estimate of a TX channel's accumulated power over the sample duration provided in MYKONOS_setupPaProtection(...) + * + * This function uses the 'avgDuration' parameter provided in MYKONOS_setupPaProtection to set the number of samples to accumulate + * to obtain an estimate for a TX channel specified by the 'channel' parameter. + * A 12-bit field estimating the channel power is returned in the '*channelPower' pointer. + * To obtain the dBFS value of the reading: + * dBFS value = 10*log10(channelPower/MAX_DAC_CODE) + * where MAX_DAC_CODE = 2^12 = 4096 + * For example: If channelPower is reading 409 then the channel power in dBFS is -10dBFS. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Point to the Mykonos device's data structure + * \param channel Select the channel of interest. Only use TX1 (1) or TX2 (2) of mykonosTxChannels_t + * \param *channelPower A pointer that stores the selected channels power. Read back is provided as a 12 bit value. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GET_DAC_PWR_INV_POINTER Function channelPower parameter is a NULL pointer + * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL Invalid Tx Channel passed in function channel parameter (TX1 or TX2) + */ +mykonosErr_t MYKONOS_getDacPower(mykonosDevice_t *device, mykonosTxChannels_t channel, uint16_t *channelPower) +{ + uint8_t channelPowerLsb = 0; + uint8_t channelPowerMsb = 0; + + const uint8_t CHAN_POWER_MSB_MASK = 0xF; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDacPower()\n"); +#endif + + if (channelPower == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_DAC_PWR_INV_POINTER, + getMykonosErrorMessage(MYKONOS_ERR_GET_DAC_PWR_INV_POINTER)); + return MYKONOS_ERR_GET_DAC_PWR_INV_POINTER; + } + + /* Set bit D5 to read the appropriate channel power */ + switch (channel) + { + case TX1: + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 0, 0x20, 5); + break; + case TX2: + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 1, 0x20, 5); + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL)); + return MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL; + } + + /* SPI Write to register PA Protection power readback registers (write strobe) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, 0x00); + + /* SPI Read of the PA Protection power readback registers */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, &channelPowerLsb); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_MSB, &channelPowerMsb); + + *channelPower = (channelPowerLsb | (((uint16_t)(channelPowerMsb & CHAN_POWER_MSB_MASK)) << 8)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns PA Protection Error Flag Status + * + * This function provides a readback of the PA protection Error Flag Status through the '*errorFlagStatus' pointer + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Point to the Mykonos device's data structure + * \param errorFlagStatus Pointer to store the error flag status. + * errorFlagStatus | error + * -----------------|------------ + * 0 | indicates no PA Error Flags are high + * 1 | indicates TX1 Error Flag + * 2 | indicates TX2 Error Flag + * 3 | indicates TX1 and TX2 Error Flags are high + * + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER Function errorFlagStatus parameter has NULL pointer + */ +mykonosErr_t MYKONOS_getPaProtectErrorFlagStatus(mykonosDevice_t *device, uint8_t *errorFlagStatus) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPaProtectErrorFlagStatus()\n"); +#endif + + if (errorFlagStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER, + getMykonosErrorMessage(MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER)); + return MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER; + } + + /* SPI Write to register PA Protection power readback registers (write strobe) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, 0x00); + + /* SPI Read of the PA Protection power readback registers */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_MSB, errorFlagStatus, 0x60, 5); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Manually clears the PA Protection Error Flags. + * + * This function manually clears the PA Error Flags. The user must setup the PA Protection block to enable + * sticky error flags. Sticky error flags require the user to clear the bit manually even if the accumulated power is + * below the power threshold for the PA protection block. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device's data structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_clearPaErrorFlag(mykonosDevice_t *device) +{ + uint8_t paProtectConfig = 0; + + const uint8_t PA_ERROR_CLEAR_MASK = 0x80; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_clearPaErrorFlag()\n"); +#endif + + /* SPI Read of the PA Protection power readback registers */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, &paProtectConfig); + + /* SPI Write to self clear the PA Error Flags */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, (paProtectConfig | PA_ERROR_CLEAR_MASK)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Helper function for return of character string based on 32-bit mykonosErr_t enum value + * + * To save codespace, these error strings are ifdef'd out unless the user + * adds a define MYKONOS_VERBOSE to their workspace. This function can be + * useful for debug. Each function also returns unique error codes to + * make it easier to determine where the code broke. + * + * \param errorCode is enumerated error code value + * + * \return Returns character string based on enumerated value + */ +const char* getMykonosErrorMessage(mykonosErr_t errorCode) +{ +#ifndef MYKONOS_VERBOSE + return ""; + +#else + + switch (errorCode) + { + case MYKONOS_ERR_OK: + return ""; + case MYKONOS_ERR_INV_PARM: + return "Mykonos: Invalid parameter\n"; + case MYKONOS_ERR_FAILED: + return "Mykonos: General Failure\n"; + case MYKONOS_ERR_WAITFOREVENT_INV_PARM: + return "waitForEvent had invalid parameter.\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT: + return "waitForEvent timed out.\n"; + case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_WAIT: + return "Requested new ENSM state is invalid from the WAIT state.\n"; + case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_ALERT: + return "Requested new ENSM state is invalid from the ALERT state.\n"; + case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_TXRX: + return "Requested new ENSM state is invalid from the TXRX state.\n"; + case MYKONOS_ERR_SETENSM_INVALIDSTATE: + return "Current ENSM state is an invalid state or calibration state.\n"; + case MYKONOS_ERR_PU_RXPATH_INV_PARAM: + return "Invalid Rx channel was requested to be powered up.\n"; + case MYKONOS_ERR_PU_TXPATH_INV_PARAM: + return "Invalid Tx channel was requested to be powered up.\n"; + case MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM: + return "Invalid ObsRx channel was requested to be powered up.\n"; + case MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT: + return "Invalid default ObsRx channel was requested to be powered up.\n"; + case MYKONOS_ERR_INIT_INV_ORXCHAN: + return "Invalid ObsRx channel requested during initialize().\n"; + case MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE: + return "Invalid combination for rxsyncb and orxsyncb, if shared syncb they should have the CMOS/LVDS mode\n"; + case MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION: + return "Invalid TxFIR interpolation value.(Valid: 1,2,4)\n"; + case MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION: + return "Invalid TXHB2 interpolation value.(Valid: 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION: + return "Invalid TXHB1 interpolation value.(Valid: 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION: + return "Invalid RxFIR decimation value.(Valid: 1,2,4)\n"; + case MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION: + return "Invalid Rx DEC5 decimation value.(Valid: 4 or 5)\n"; + case MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION: + return "Invalid RxHB1 decimation value.(Valid: 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_SNIFFER_RHB1: + return "Invalid Sniffer HB1 decimation value (Valid 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC: + return "Invalid Sniffer RFIR decimation value (Valid 1,2,4)\n"; + case MYKONOS_ERR_INIT_INV_ORX_RHB1: + return "Invalid ORx HB1 decimation value (Valid 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC: + return "Invalid ORx RFIR decimation value. (Valid 1,2,4)\n"; + case MYKONOS_ERR_INIT_INV_ADCDIV: + return "Invalid Rx ADC divider. (Valid 1 or 2)\n"; + case MYKONOS_ERR_INIT_INV_DACDIV: + return "Invalid Tx DAC divider. Use enum DACDIV_2, DACDIV_2p5 or DACDIV_4.\n"; + case MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV: + return "Invalid ObsRx ADC div. (Valid 1 or 2)\n"; + case MYKONOS_ERR_CLKPLL_INV_HSDIV: + return "Invalid CLKPLL HSDIV. (Valid 4 or 5)\n"; + case MYKONOS_ERR_CLKPLL_INV_VCODIV: + return "Invalid CLKPLL VCODIV. Use enum VCODIV_1, VCODIV_1p5, VCODIV_2, VCODIV_3\n"; + case MYKONOS_ERR_CLKPLL_INV_RXTXPROFILES: + return "No Rx or Tx profile is specified.\n"; + case MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX: + return "CLKPLL VCO frequency out of range.\n"; + case MYKONOS_ERR_SETCLKPLL_INV_FRACWORD: + return "CLKPLL fractional word is non zero.\n"; + case MYKONOS_ERR_SETRFPLL_INV_PLLNAME: + return "Invalid pllName requested in setRfPllFreuquency()\n"; + case MYKONOS_ERR_SETRFPLL_INV_LO_PARM: + return "RF PLL frequency out of range\n"; + case MYKONOS_ERR_GETRFPLL_INV_PLLNAME: + return "Invalid pllName requested in getRfPllFrequency()\n"; + case MYKONOS_ERR_GETRFPLL_ARMERROR: + return "ARM Command Error in MYKONOS_getRfPllFrequency()\n"; + case MYKONOS_ERR_GETRFPLL_NULLPARAM: + return "NULL pointer in function parameter for MYKONOS_setRfPllFrequency()\n"; + case MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM: + return "Could not scale device clock into range 40MHz to 80Mhz.\n"; + case MYKONOS_ERR_SETRFPLL_INV_VCOINDEX: + return "RFPLL VCO frequency out of range.\n"; + case MYKONOS_ERR_SETRFPLL_INV_REFCLK: + return "Unsupported PLL reference clock or refclk out of range.\n"; + case MYKONOS_ERR_SETORXGAIN_INV_CHANNEL: + return "Invalid ObsRx channel in setObsRxManualGain().\n"; + case MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN: + return "Invalid gain requested in setObsRxManualGain() for ORX1\n"; + case MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN: + return "Invalid gain requested in setObsRxManualGain() for ORX2\n"; + case MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN: + return "Invalid gain requested in setObsRxManualGain() for Sniffer\n"; + case MYKONOS_ERR_GETORX1GAIN_INV_POINTER: + return "Cannot return ORx1 gain to gain control data structure (invalid pointer).\n"; + case MYKONOS_ERR_GETORX2GAIN_INV_POINTER: + return "Cannot return ORx2 gain to gain control data structure (invalid pointer).\n"; + case MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER: + return "Cannot return Sniffer gain to gain control data structure (invalid pointer).\n"; + case MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED: + return "Cannot read ObsRx gain index. ObsRx Channel is disabled.\n"; + case MYKONOS_ERR_SETTX1ATTEN_INV_PARM: + return "Tx1 attenuation is out of range (0 - 41950 mdB).\n"; + case MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM: + return "Invalid Tx1Atten stepsize. Use enum mykonosTxAttenStepSize_t\n"; + case MYKONOS_ERR_SETTX2ATTEN_INV_PARM: + return "Tx2 attenuation is out of range (0 - 41950 mdB).\n"; + case MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM: + return "Invalid Tx2Atten stepsize. Use enum mykonosTxAttenStepSize_t\n"; + case MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM: + return "Invalid number of FIR taps\n"; + case MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM: + return "Invalid number of FIR taps read for the selected Filter\n"; + case MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM: + return "Invalid FIR filter name requested. use enum mykonosfirName_t\n"; + case MYKONOS_ERR_RXFIR_INV_GAIN_PARM: + return "Rx FIR filter has invalid gain setting\n"; + case MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM: + return "ObsRx FIR filter A (ORx) has invalid gain setting\n"; + case MYKONOS_ERR_SRXFIR_INV_GAIN_PARM: + return "ObsRx FIR filter B (Sniffer) has invalid gain setting\n"; + case MYKONOS_ERR_TXFIR_INV_GAIN_PARM: + return "Tx FIR filter has invalid gain setting\n"; + case MYKONOS_ERR_READFIR_NULL_PARM: + return "MYKONOS_readFir() has a null *firFilter parameter\n"; + case MYKONOS_ERR_READFIR_COEFS_NULL: + return "MYKONOS_readFir() has a null coef array in *firFilter structure\n"; + case MYKONOS_ERR_READFIR_INV_FIRNAME_PARM: + return "Invalid FIR filter name requested. use enum mykonosfirName_t\n"; + case MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM: + return "Rx1 manual gain index out of range of gain table\n"; + case MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM: + return "Rx2 manual gain index out of range of gain table\n"; + case MYKONOS_ERR_INITSER_INV_VCODIV_PARM: + return "Found invalid VCO divider value during setupSerializers()\n"; + case MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM: + return "CLKPLL VCO frequency exceeded max(8Ghz) in VCO divider /1 case ()\n"; + case MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM: + return "CLKPLL VCO frequency exceeded max(9.216Ghz) in VCO divider /1.5 case ()\n"; + case MYKONOS_ERR_INITDES_INV_VCODIV_PARM: + return "Found invalid VCO divider value during setupDeserializers()\n"; + case MYKONOS_ERR_SER_INV_M_PARM: + return "Invalid JESD Framer M parameter during setupSerializers()\n"; + case MYKONOS_ERR_SER_INV_L_PARM: + return "Invalid JESD Framer L parameter during setupSerializers()\n"; + case MYKONOS_ERR_SER_INV_LANERATE_PARM: + return "Invalid Lanerate frequency in setupSerializer()\n"; + case MYKONOS_ERR_SER_INV_LANEEN_PARM: + return "Invalid number of JESD204 lanes enabled.\n"; + case MYKONOS_ERR_SER_INV_AMP_PARM: + return "Invalid JESD204 serializer amplitude\n"; + case MYKONOS_ERR_SER_INV_PREEMP_PARM: + return "Invalid JESD204 serializer preemphasis setting\n"; + case MYKONOS_ERR_SER_INV_LANEPN_PARM: + return "Invald JESD204 serializer PN invert setting\n"; + case MYKONOS_ERR_SER_LANE_CONFLICT_PARM: + return "Rx framer and ObsRx framer are attempting to use the same physical lanes\n"; + case MYKONOS_ERR_SER_INV_TXSER_DIV_PARM: + return "Invalid serializer lane clock divider\n"; + case MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM: + return "Rx lane and ObsRx lane rate must match\n"; + case MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM: + return "Framer M can only =1 if Real IF data option is enabled\n"; + case MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT: + return "Serializer HSCLK and lane clock are not integer multiples\n"; + case MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT: + return "Deserializer HSCLK and lane clock are not integer multiples\n"; + case MYKONOS_ERR_DESER_INV_M_PARM: + return "Invalid deserializer M value. (Valid 2 or 4)\n"; + case MYKONOS_ERR_DESER_INV_L_PARM: + return "Invalid deserializer L value. (Valid 1,2,4)\n"; + case MYKONOS_ERR_DESER_INV_HSCLK_PARM: + return "Invalid HSCLK in setupDeserializer()\n"; + case MYKONOS_ERR_DESER_INV_LANERATE_PARM: + return "Invalid deserializer lane rate\n"; + case MYKONOS_ERR_DESER_INV_LANEEN_PARM: + return "Invalid number of deserializer lanes enabled\n"; + case MYKONOS_ERR_DESER_INV_EQ_PARM: + return "Invalid deserializer EQ setting"; + case MYKONOS_ERR_DESER_INV_LANEPN_PARM: + return "Invalid deserializer invert Lane PN setting\n"; + case MYKONOS_ERR_FRAMER_INV_M_PARM: + return "Invalid Rx framer M setting\n"; + case MYKONOS_ERR_FRAMER_INV_BANKID_PARM: + return "Invalid Rx framer Bank ID\n"; + case MYKONOS_ERR_FRAMER_INV_LANEID_PARM: + return "Invalid Rx framer Lane ID\n"; + case MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM: + return "Invalid Rx framer LMFC offset\n"; + case MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM: + return "Invalid Rx framer Real IF setting\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM: + return "Invalid ObsRx Framer M value\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM: + return "Invalid ObsRx Framer Bank ID\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM: + return "Invalid ObsRx framer Lane ID\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM: + return "Invalid ObsRx framer LMFC offset\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM: + return "Invalid ObsRx framer Real IF setting, M must =1\n"; + case MYKONOS_ERR_DEFRAMER_INV_M_PARM: + return "Invalid Deframer M setting\n"; + case MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM: + return "Invalid Deframer Bank ID\n"; + case MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM: + return "Invalid Deframer Lane ID\n"; + case MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM: + return "Invalid Deframer LMFC offset"; + case MYKONOS_ERR_DEFRAMER_INV_K_PARAM: + return "Invalid Deframer K setting\n"; + case MYKONOS_ERR_DEFRAMER_INV_FK_PARAM: + return "Invalid Deframer F*K value\n"; + case MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM: + return "Invalid polyOrder parameter in enableRxFramerPrbs()\n"; + case MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM: + return "Invalid polyOrder parameter in enableObsRxFramerPrbs()\n"; + case MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM: + return "Invalid enable parameter value in enableDeframerPrbsChecker()\n"; + case MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM: + return "Invalid polyOrder parameter in enableDeframerPrbsChecker()\n"; + case MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM: + return "Invalid lane counter select in readDeframerPrbsCounters()\n"; + case MYKONOS_ERR_INITARM_INV_DATARATE_PARM: + return 0; + case MYKONOS_ERR_INITARM_INV_VCODIV: + return "Invalid ARM VCO divider\n"; + case MYKONOS_ERR_INITARM_INV_REGCLK: + return "Invalid ARM SPI register clock rate\n"; + case MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM: + return "Invalid ARM clock rate\n"; + case MYKONOS_ERR_LOADHEX_INV_CHARCOUNT: + return "LoadHex() char count = 0\n"; + case MYKONOS_ERR_LOADHEX_INVALID_FIRSTCHAR: + return "LoadHex() First char is not :\n"; + case MYKONOS_ERR_LOADHEX_INVALID_CHKSUM: + return "LoadHex() line checksum is invalid\n"; + case MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT: + return "Invalid byte count passed to function MYKONOS_loadArmFromBinary()"; + case MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT: + return "Invalid byte count passed to function MYKONOS_loadArmConcurrent()"; + case MYKONOS_ERR_ARM_INVALID_BUILDCHKSUM: + return "Verify ARM checksum failed\n"; + case MYKONOS_ERR_READARMMEM_INV_ADDR_PARM: + return "ReadArmMem() was given an invalid memory address\n"; + case MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM: + return "WriteArmMem() was given an invalid memory address\n"; + case MYKONOS_ERR_ARM_INV_ADDR_PARM: + return "Invalid memory address in MYKONOS_loadArmConcurrent()"; + case MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM: + return "Invalid ARM opcode given to sendArmCommand()\n"; + case MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM: + return "Invalid number of extended data in sendArmCommand()\n"; + case MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM: + return "Invalid opcode given to waitArmCmdStatus()\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER: + return "Pointer to Mykonos device data structure is NULL\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_SPI: + return "Invalid spiSettings pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_RX: + return "Invalid device->rx pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB: + return "Invalid pointer within device->rx data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR: + return "Invalid RXFIR pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_TX: + return "Invalid device->tx pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB: + return "Invalid pointer within device->tx data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR: + return "Invalid TXFIR pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX: + return "Invalid device->obsRx pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXSUB: + return "Invalid pointer within device->obsRx data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR: + return "Invalid Sniffer FIR pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR: + return "Invalid ORX FIR pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL: + return "Invalid Orx gain control pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL: + return "Invalid Sniffer gain control pointer in device data structure\n"; + case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER: + return "Invalid obsRx framer pointer in device data structure\n"; + case MYKONOS_ERR_INITSER_INV_PROFILE: + return "Invalid RX profile within device data structure detected in MYKONOS_setupSerializers()\n"; + case MYKONOS_ERR_INITDES_INV_TXPROFILE: + return "Invalid TX profile within device data structure detected in MYKONOS_setupDeserializers()\n"; + case MYKONOS_ERR_JESD204B_ILAS_MISMATCH: + return "Mismatch detected in MYKONOS_jesd204bIlasCheck()\n"; + case MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL: + return "Invalid channel specified in MYKONOS_programRxGainTable()\n"; + case MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE: + return "Invalid numGainIndicesinTable greater than possible number of gain indices for channel. \n"; + case MYKONOS_ERR_WRITE_CFG_MEMORY_FAILED: + return "Failed write to ARM memory in MYKONOS_writeArmProfile()\n"; + case MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM: + return "Invalid PCLKDIV parameter detected in MYKONOS_setupSerializers()\n"; + case MYKONOS_ERR_RXFRAMER_INV_FK_PARAM: + return "Invalid FK parameter detected in MYKONOS_setupJesd204bFramer()\n"; + case MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM: + return "Invalid FK paramter detected in MYKONOS_setupJesd204bObsRxFramer()\n"; + case MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM: + return "Invalid PCLKDIV paramter detected in MYKONOS_setupSerializers()\n"; + case MYKONOS_ERR_PU_OBSRXPATH_INV_LOSOURCE_PARAM: + return "Invalid LO Source for OBSRX data path \n"; + case MYKONOS_ERR_ARM_RADIOON_FAILED: + return "ARM command to move to radioOn state failed. \n"; + case MYKONOS_ERR_ARM_RADIOOFF_FAILED: + return "ARM command to move to radioOff state failed. \n"; + case MYKONOS_ERR_INV_RX_GAIN_MODE_PARM: + return "Invalid gain control mode detected in MYKONOS_setRxGainControlMode()\n"; + case MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM: + return "Invalid gain control mode detected in MYKONOS_setObsRxGainControlMode()\n"; + case MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT: + return "Invalid RX AGC structure detected at &device->rx->rxAgcCtrl in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM: + return "device->rx->rxAgcCtrl->agcPeakWaitTime out of range in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM: + return "device->rx->rxAgcCtrl->agcGainUpdateTime_us out of range in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM: + return "device->rx->rxAgcCtrl->apdHighThresh out of range in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM: + return "device->rx->rxAgcCtrl->apdLowThresh out of range in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_BLOCK_DET_DECAY_PARM: + return "device->rx->rxAgcCtrl->apdDecay out of range in MYKONOS_setupRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT: + return "Data structure for peakAgc not initialized when used in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT: + return "Data structure for powerAgc not initialized when used in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX: + return "device->rx->rxAgcCtrl->agcRx1MaxGainIndex out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX: + return "device->rx->rxAgcCtrl->agcRx1MinGainIndex out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX: + return "device->rx->rxAgcCtrl->agcRx2MaxGainIndex out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX: + return "device->rx->rxAgcCtrl->agcRx2MinGainIndex out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY: + return "device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION: + return "device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG: + return "device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC: + return "device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE: + return "device->rx->rxAgcCtrl->agcPeakThresholdMode out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE: + return "device->rx->rxAgcCtrl->agcResetOnRxEnable out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER: + return "device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH: + return "device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH: + return "device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH: + return "device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH: + return "device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP: + return "device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP: + return "device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP: + return "device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP: + return "device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE: + return "device->rx->rxAgcCtrl->peakAgc->apdFastAttack or hb2FastAttack out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2HighThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2LowThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM: + return "device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM: + return "device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM: + return "device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE: + return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadEnable out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT: + return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT: + return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt out of range in MYKONOS_setupRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT: + return "Invalid OBSRX AGC structure detected at &device->obsRx->orxAgcCtrl in MYKONOS_setupObsRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT: + return "Data structure for obsRx->orxAgcCtrl->peakAgc not initialized when used in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT: + return "Data structure for obsRx->orxAgcCtrl->powerAgc not initialized when used in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX: + return "device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX: + return "device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_SELECT: + return "device->obsRx->orxAgcCtrl->agcObsRxSelect out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM: + return "device->obsRx->orxAgcCtrl->agcGainUpdateTime_us out of range in MYKONOS_setupObsRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM: + return "device->obsRx->orxAgcCtrl->agcPeakWaitTime out of range in MYKONOS_setupObsRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY: + return "device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC: + return "device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE: + return "device->obsRx->orxAgcCtrl->agcPeakThresholdMode out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE: + return "device->obsRx->orxAgcCtrl->agcResetOnRxEnable out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER: + return "device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE: + return "device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack or hb2FastAttack out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM: + return "device->obsRx->orxAgcCtrl->apdHighThresh out of range in MYKONOS_setupObsRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM: + return "device->obsRx->orxAgcCtrl->apdLowThresh out of range in MYKONOS_setupObsRxAgc()\n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadEnable out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT: + return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThresholdCnt out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP: + return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CALPLL_LOCK: + return "CAL PLL Lock event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLLCP: + return "Clock PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLL_LOCK: + return "Clock PLL Lock event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLLCP: + return "RX PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLL_LOCK: + return "RX PLL Lock event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLLCP: + return "TX PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLL_LOCK: + return "TX PLL Lock event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLLCP: + return "Sniffer PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLL_LOCK: + return "Sniffer PLL Lock event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXBBFCALDONE: + return "RX Baseband Filter Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXBBFCALDONE: + return "TX Baseband Filter Cal timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RFDCCALDONE: + return "RF DC Offset Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ADCTUNECALDONE: + return "ADC Tuner Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX1ADCPROFILE: + return "Rx1 ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX2ADCPROFILE: + return "Rx2 ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ORXADCPROFILE: + return "ObsRx ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RCALDONE: + return "Resistor Cal event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ARMBUSY: + return "ARM Busy event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_INITARMDONE: + return "Initialize ARM event timed out in MYKONOS_waitForEvent()\n"; + case MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY: + return "ARM Mailbox Busy. Command not executed in MYKONOS_sendArmCommand()\n"; + case MYKONOS_ERR_PU_OBSRXPATH_ARMERROR: + return "ARM Command Error in MYKONOS_setObsRxPathSource()\n"; + case MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR: + return "Device not in radioOff/IDLE state. Error in MYKONOS_enableTrackingCals()\n"; + case MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR: + return "ARM command Error in MYKONOS_setRadioControlPinMode()\n"; + case MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR: + return "ARM Command Error in MYKONOS_enableTrackingCals()\n"; + case MYKONOS_ERR_SETRFPLL_ARMERROR: + return "ARM Command Error in MYKONOS_setRfPllFrequency()\n"; + case MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM: + return "device->tx->txProfile->txInputHbInterpolation out of range in MYKONOS_initialize(): valid = 1,2 or 4\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV: + return "device->clocks->clkPllVcoDiv value not supported in MYKONOS_loadAdcProfiles\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED: + return "Custom RX ADC Profile required\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED: + return "Custom ORX ADC Profile required\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED: + return "Custom SNRX ADC Profile required\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED: + return "Custom Loopback ADC profile required\n"; + case MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED: + return "WriteArmMemory call failed while writing the Loopback ADC profile into ARM memory\n"; + case MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED: + return "WriteArmMemory call failed while writing the Sniffer ADC profile into ARM memory\n"; + case MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED: + return "WriteArmMemory call failed while writing the ObsRx ADC profile into ARM memory\n"; + case MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED: + return "WriteArmMemory call failed while writing the RX ADC profile into ARM memory\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO: + return "SnRx profile has invalid ADC divider of 0, causing a divide by zero\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO: + return "ORx profile has invalid ADC divider of 0, causing a divide by zero\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO: + return "Rx profile has invalid ADC divider of 0, causing a divide by zero\n"; + case MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE: + return "If Tx Profile is valid, a matching ORx profile must be provided to set ADC divider and digital filtering for loopback calibrations\n"; + case MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION: + return "Invalid setting for avgDuration in MYKONOS_setupPaProtection(...)\n"; + case MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP: + return "Invalid setting for attenStepSize in MYKONOS_setupPaProtection(...)\n"; + case MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_ENABLE: + return "Invalid setting for txAttenControlEnable in MYKONOS_setupPaProtection(...)\n"; + case MYKONOS_ERR_SETUP_PA_PROT_INV_POWER_THRESH: + return "Invalid setting for powerThreshold in MYKONOS_setupPaProtection(...)\n"; + case MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL: + return "Invalid TX channel selected for MYKONOS_getDacPower(...)\n"; + case MYKONOS_ERR_GET_DAC_PWR_INV_POINTER: + return "Cannot return DAC Power information (invalid pointer)\n"; + case MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER: + return "Cannot return PA Protection Flag Status information (invalid pointer)\n"; + case MYKONOS_ERR_GET_OBSRX_OVERLOADS_NULL_PARM: + return "MYKONOS_getObsRxPathOverloads() has null *obsRxOverloads parameter\n"; + case MYKONOS_ERR_GET_RX1_OVERLOADS_NULL_PARM: + return "MYKONOS_getRxPathOverloads() has null *rx1Overloads parameter\n"; + case MYKONOS_ERR_GET_RX2_OVERLOADS_NULL_PARM: + return "MYKONOS_getRxPathOverloads() has null *rx2Overloads parameter\n"; + case MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM: + return "MYKONOS_getRadioState() has null *radioStatus parameter\n"; + case MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM: + return "MYKONOS_abortInitCals() has null *calsCompleted parameter\n"; + case MYKONOS_ERR_WAIT_INITCALS_ARMERROR: + return "MYKONOS_waitInitCals() returned an ARM error\n"; + case MYKONOS_ERR_WAIT_INITCALS_NULL_PARAM: + return "MYKONOS_waitInitCals() has one or more null parameters\n"; + case MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM: + return "MYKONOS_checkPllsLockStatus() has a null *pllLockStatus parameter\n"; + case MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM: + return "MYKONOS_getTxFilterOverRangeStatus() has a null *txFilterStatus parameter\n"; + case MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM: + return "MYKONOS_programRxGainTable() has a null *gainTablePtr parameter\n"; + case MYKONOS_ERR_PROGRAMFIR_NULL_PARM: + return "MYKONOS_programFir() has a null *firFilter parameter\n"; + case MYKONOS_ERR_PROGRAMFIR_COEFS_NULL: + return "MYKONOS_programFir() has a null coef array in *firFilter structure\n"; + case MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM: + return "MYKONOS_readDeframerStatus() has a null *deframerStatus parameter\n"; + case MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM: + return "MYKONOS_readDeframerPrbscounters() has a null *prbsErrorCount parameter\n"; + case MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM: + return "MYKONOS_readOrxFramerStatus() has a null *obsFramerStatus parameter\n"; + case MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM: + return "MYKONOS_readRxFramerStatus() has a null *framerStatus parameter\n"; + case MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM: + return "MYKONOS_waitArmCmdStatus() has a null *cmdStatByte parameter\n"; + case MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM: + return "MYKONOS_readArmCmdStatus() has one or more null pointer parameters\n"; + case MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM: + return "MYKONOS_readArmCmdStatusByte() has an invalid opcode parameter\n"; + case MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM: + return "MYKONOS_readArmCmdStatusByte() has a null *cmdStatByte parameter\n"; + case MYKONOS_ERR_ARMCMD_NULL_PARM: + return "MYKONOS_sendArmCommand() has a null *extendedData parameter\n"; + case MYKONOS_ERR_WRITEARMMEM_NULL_PARM: + return "MYKONOS_writeArmMem() has a null *data parameter\n"; + case MYKONOS_ERR_LOADBIN_NULL_PARAM: + return "MYKONOS_loadArmFromBinary() has a null *binary parameter\n"; + case MYKONOS_ERR_LOADARMCON_NULL_PARAM: + return "MYKONOS_loadArmConcurrent() has a null *binary parameter\n"; + case MYKONOS_ERR_GETTX1ATTEN_NULL_PARM: + return "MYKONOS_getTx1Attenuation() has NULL tx1Attenuation_mdB parameter\n"; + case MYKONOS_ERR_GETTX2ATTEN_NULL_PARM: + return "MYKONOS_getTx2Attenuation() has NULL tx2Attenuation_mdB parameter\n"; + case MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM: + return "Invalid serializer Lanes Enable parameter in Rx framer structure\n"; + case MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM: + return "Invalid serializer Lanes Enable parameter in ObsRx framer structure\n"; + case MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID: + return "Can not enable Tx NCO when Tx Profile is invalid\n"; + case MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID: + return "Invalid Tx1 NCO frequency\n"; + case MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID: + return "Invalid Tx2 NCO frequency\n"; + case MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM: + return "Function parameter has NULL pointer in MYKONOS_jesd204bIlasCheck()\n"; + case MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV: + return "CLKPLL refclk divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n"; + case MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV: + return "CLKPLL HSDIV divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n"; + case MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV: + return "CLKPLL VCODIV divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n"; + case MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM: + return "MYKONOS_getRx1DecPower() has a null *rx1DecPower_mdBFS parameter\n"; + case MYKONOS_ERR_GET_RX1_DEC_POWER_NUM_SAMPLES: + return "MYKONOS_getRx1DecPower() numSamples greater than agcGainUpdateCounter\n"; + case MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM: + return "MYKONOS_getRx2DecPower() has a null *rx2DecPower_mdBFS parameter\n"; + case MYKONOS_ERR_GET_RX2_DEC_POWER_NUM_SAMPLES: + return "MYKONOS_getRx2DecPower() numSamples greater than agcGainUpdateCounter\n"; + case MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM: + return "MYKONOS_getObsRxDecPower() has a null *obsRxDecPower_mdBFS parameter\n"; + case MYKONOS_ERR_GET_OBSRX_DEC_POWER_NUM_SAMPLES: + return "MYKONOS_getObsRxDecPower() numSamples greater than agcGainUpdateCounter\n"; + case MYKONOS_ERR_GETARMVER_NULL_PARM: + return "MYKONOS_getArmVersion() has a NULL pointer in one of the function parameters\n"; + case MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR: + return "ARM is not in the RadioOff state before MYKONOS_enableDpdTracking(), call MYKONOS_radioOff()\n"; + case MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE: + return "MYKONOS_restoreDpdModel() supplied DPD Model Data Buffer is incorrect size\n"; + case MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG: + return "The ARM reported a error while in MYKONOS_restoreDpdModel().\n"; + case MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL: + return "MYKONOS_restoreDpdModel() invalid txChannel specified\n"; + case MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE: + return "MYKONOS_saveDpdModel() supplied DPD Model Data Buffer is incorrect size\n"; + case MYKONOS_ERR_SAVDPDMOD_ARMSTATE: + return "ARM is not in the RadioOff state before MYKONOS_saveDpdModel(), call MYKONOS_radioOff()\n"; + case MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL: + return "MYKONOS_saveDpdModel() invalid txChannel specified\n"; + case MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR: + return "ARM is not in the RadioOff state before MYKONOS_enableClgcTracking(), call MYKONOS_radioOff()\n"; + case MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV: + return "Tx or ORx profile is not valid, both are necessary for DPD features in MYKONOS_configDpd()\n"; + case MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT: + return "device->tx->dpdConfig structure has NULL pointer in MYKONOS_configDpd()\n"; + case MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG: + return "The ARM reported a error while writing to an ARM config structure in MYKONOS_writeArmCfgStruct()\n"; + case MYKONOS_ERR_CFGDPD_INV_DPDDAMPING: + return "ERROR: device->tx->dpdConfig->damping parameter is out of range (0-15)\n"; + case MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES: + return "ERROR: device->tx->dpdConfig->samples parameter is out of range (64 - 32768)\n"; + case MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS: + return "ERROR: device->tx->dpdConfig->numWeights parameter is out of range (0-3)\n"; + case MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH: + return "ERROR: device->tx->dpdConfig->outlierThreshold parameter is out of range\n"; + case MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT: + return "ERROR: device->tx->dpdConfig->modelPriorWeight parameter is out of range (Valid 0-32)\n"; + case MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN: + return "ERROR: device->tx->clgcConfig->tx1DesiredGain or tx2DesiredGain parameter is out of range\n"; + case MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT: + return "ERROR: device->tx->clgcConfig->tx1AttenLimit or tx2AttenLimit parameter is out of range\n"; + case MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO: + return "ERROR: device->tx->clgcConfig->tx1ControlRatio or tx2ControlRatio parameter is out of range\n"; + case MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY: + return "ERROR: device->tx->dpdConfig->additionalDelayOffset parameter is out of range\n"; + case MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL: + return "ERROR: device->tx->dpdConfig->pathDelayPnSeqLevel parameter is out of range\n"; + case MYKONOS_ERR_CFGDPD_INV_MODELVERSION: + return "ERROR: device->tx->dpdConfig->modelVersion parameter is out of range\n"; + case MYKONOS_ERR_READARMCFG_ARMERRFLAG: + return "ERROR: MYKONOS_readArmConfig failed due to an ARM error\n"; + case MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM: + return "MYKONOS_getPendingTrackingCals() has NULL function parameter\n"; + case MYKONOS_ERR_ARMCMDSTATUS_ARMERROR: + return "MYKONOS_waitArmCmdStatus() exited due to ARM error for the desired ARM opcode\n"; + case MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT: + return "MYKONOS_waitArmCmdStatus() timed out waiting for the ARM to complete the requested command\n"; + case MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR: + return "ARM returned an error while trying to get the ObsRx Path source in MYKONOS_getObsRxPathSource()\n"; + case MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT: + return "MYKONOS_getDpdConfig() could not complete due to a NULL pointer to device->tx->dpdConfig structure\n"; + case MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV: + return "The Tx and ORx profiles must be valid for DPD related functions\n"; + case MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG: + return "MYKONOS_getDpdStatus() reported an ARM error with the ARM Get command\n"; + case MYKONOS_ERR_GETDPDSTATUS_NULLPARAM: + return "MYKONOS_getDpdStatus() has NULL pointer in the function parameter\n"; + case MYKONOS_ERR_SETDEFOBSRXPATH_NULL_OBSRX_STRUCT: + return "Observation profile not valid, device->obsRx structure is NULL in MYKONOS_setDefaultObsRxPath()\n"; + case MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM: + return "MYKONOS_getClgcStatus() has NULL clgcStatus parameter\n"; + case MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG: + return "ARM reported an error with the ARM GET command during MYKONOS_getClgcStatus()\n"; + case MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM: + return "MYKONOS_getDeframerFifoDepth() function parameter fifoDepth is a NULL pointer\n"; + case MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM: + return "MYKONOS_getDeframerFifoDepth() function parameter readEnLmfcCount is a NULL pointer\n"; + case MYKONOS_ERR_GETDPDSTATUS_INV_CH: + return "MYKONOS_getDpdStatus() txChannel parameter is not valid (TX1 and TX2 are the only valid options)\n"; + case MYKONOS_ERR_GETCLGCSTATUS_INV_CH: + return "MYKONOS_getClgcStatus() txChannel parameter is not valid (TX1 and TX2 are the only valid options)\n"; + case MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE: + return "Invalid Tx profile: When using Tx Input halfband, IQ rate must not exceed 160MSPS\n"; + case MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE: + return "Invalid Tx profile: When using Tx Input halfband 0, IQ rate must not exceed 80MSPS\n"; + case MYKONOS_ERR_RXFIR_TAPSEXCEEDED: + return "Rx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n"; + case MYKONOS_ERR_ORXFIR_TAPSEXCEEDED: + return "ORx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n"; + case MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED: + return "Sniffer Rx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n"; + case MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM: + return "Invalid number of Tx FIR coefficients\n"; + case MYKONOS_ERR_TXFIR_INV_NUMROWS: + return "Invalid number of PFIR coefficient rows\n"; + case MYKONOS_ERR_TXFIR_TAPSEXCEEDED: + return "Too many Tx PFIR taps for the IQ sample rate. FIR processing clock can not run fast enough to handle the number of taps\n"; + case MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM: + return "MYKONOS_getInitCalStatus() has a null pointer in parameter list\n"; + case MYKONOS_ERR_GETINITCALSTATUS_ARMERROR: + return "MYKONOS_getInitCalStatus() returned an ARM error while getting the init cal status information"; + case MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV: + return "Tx and ObsRx profiles must be valid to use the CLGC feature in MYKONOS_configClgc()\n"; + case MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT: + return "CLGC config structure is NULL in device->tx->clgcConfig in MYKONOS_configClgc()\n"; + case MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV: + return "Could not read back CLGC status because Tx and ORx profiles are not valid\n"; + case MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT: + return "Could not read back CLGC status because return structure device->tx->clgcConfig pointer is NULL\n"; + case MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM: + return "device structure pointer is NULL in MYKONOS_calculateDigitalClocks()\n"; + case MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT: + return "device->clocks structure pointer is NULL in MYKONOS_calculateDigitalClocks()\n"; + case MYKONOS_ERR_NULL_DEVICE_PARAM: + return "The device pointer in the calling function's parameter list is a NULL pointer\n"; + case MYKONOS_ERR_CALCDEVCLK_NULLPARAM: + return "MYKONOS_calculateScaledDeviceClk_kHz() has a NULL pointer in one of the function parameters\n"; + case MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY: + return "CLGC Additional Delay parameter is out of range in MYKONOS_configClgc\n"; + case MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL: + return "CLGC PN Sequence level parameter is out of range in MYKONOS_configClgc\n"; + case MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV: + return "The Tx and ORx profiles must be valid to use the VSWR feature in MYKONOS_configVswr()\n"; + case MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR: + return "ARM must be in radioOff state to configure the VSWR config parameters in MYKONOS_configVswr()\n"; + case MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN: + return "VSWR 3.3v GPIO pin selection is out of range (0-11) in MYKONOS_configVswr()\n"; + case MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL: + return "VSWR init PN sequence level is out of range in MYKONOS_configVswr()\n"; + case MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY: + return "VSWR additionalDelay member is out of range in MYKONOS_configVswr()\n"; + case MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT: + return "device->tx->vswrConfig pointer is null in MYKONOS_confgiVswr()\n"; + case MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT: + return "device->tx->vswrConfig pointer is null in MYKONOS_getVswrConfig()\n"; + case MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV: + return "Tx and ORx profiles must be valid in MYKONOS_getVswrConfig()\n"; + case MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG: + return "ARM returned an error while attempting to read the VSWR status structure\n"; + case MYKONOS_ERR_GETVSWRSTATUS_INV_CH: + return "Invalid Tx channel parameter passed to MYKONOS_getVswrStatus()\n"; + case MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM: + return "vswrStatus function parameter is null in MYKONOS_getVswrStatus\n"; + case MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX: + return "Max gain index bigger than max gain index loaded table in MYKONOS_setRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX: + return "Min gain index lower than min gain index loaded table in MYKONOS_setRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL: + return "Wrong RX channel selected in MYKONOS_setRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL: + return "Wrong read back channel in MYKONOS_setObsRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX: + return "Max gain index bigger than max gain index loaded table in MYKONOS_setObsRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX: + return "Min gain index lower than min gain index loaded table in MYKONOS_setObsRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL: + return "Wrong observation channel selected in MYKONOS_setObsRxAgcMinMaxGainIndex().\n"; + case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE: + return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setRx1TempGainComp().\n"; + case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP: + return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setRx1TempGainComp().\n"; + case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE: + return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setRx2TempGainComp().\n"; + case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP: + return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setRx2TempGainComp().\n"; + case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE: + return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setObsRxTempGainComp().\n"; + case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP: + return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setObsRxTempGainComp().\n"; + case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL: + return "rx1TempCompGain_mdB pointer is null MYKONOS_getRx1TempGainComp().\n"; + case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL: + return "rx2TempCompGain_mdB pointer is null MYKONOS_getRx2TempGainComp().\n"; + case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL: + return "obsRxTempCompGain_mdB pointer is null MYKONOS_getObsRxTempGainComp().\n"; + case MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM: + return "Function parameter mykonosOrxQecStatus_t is a NULL pointer in MYKONOS_getOrxQecStatus().\n"; + case MYKONOS_ERR_GETORXQECSTATUS_INV_CH: + return "Channel selection not valid in MYKONOS_getOrxQecStatus().\n"; + case MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG: + return "ARM command error in MYKONOS_getOrxQecStatus().\n"; + case MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM: + return "Function parameter mykonosRxQecStatus_t is a NULL pointer in MYKONOS_getRxQecStatus().\n"; + case MYKONOS_ERR_GETRXQECSTATUS_INV_CH: + return "Channel selection not valid in MYKONOS_getRxQecStatus().\n"; + case MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG: + return "ARM command error in MYKONOS_getRxQecStatus().\n"; + case MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM: + return "Function parameter mykonosTxQecStatus_t is a NULL pointer in MYKONOS_getRxQecStatus().\n"; + case MYKONOS_ERR_GETTXQECSTATUS_INV_CH: + return "Channel selection not valid in MYKONOS_getTxQecStatus().\n"; + case MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG: + return "ARM command error in MYKONOS_getTxQecStatus().\n"; + case MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM: + return "Function parameter mykonosTxLolStatus_t is a NULL pointer in MYKONOS_getTLolStatus().\n"; + case MYKONOS_ERR_GETTXLOLSTATUS_INV_CH: + return "Channel selection not valid in MYKONOS_getTLolStatus().\n"; + case MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG: + return "ARM command error in MYKONOS_getTLolStatus().\n"; + case MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV: + return "Not valid calibration passed to MYKONOS_rescheduleTrackingCal().\n"; + case MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG: + return "ARM error in MYKONOS_rescheduleTrackingCal().\n"; + case MYKONOS_ERR_ARMSTATE_EXCEPTION: + return "ARM system problem has been detected.\n"; + case MYKONOS_ERR_ARMSTATE_CAL_ERROR: + return "ARM has detected an error in the tracking calibrations.\n"; + case MYKONOS_ERR_ARMSTATE_PROFILE_ERROR: + return "ARM has detected an illegal profile.\n"; + case MYKONOS_ERR_WAITARMCSTATE_TIMEOUT: + return "Timeout occurred in MYKONOS_checkArmState().\n"; + case MYKONOS_ERR_GET_API_VERSION_NULL_PARAM: + return "Null parameter passed to the function MYKONOS_getApiVersion().\n"; + case MYKONOS_ERR_GETPRODUCTID_NULL_PARAM: + return "Null parameter passed to the function MYKONOS_getProductId().\n"; + case MYKONOS_ERR_TXPROFILE_IQRATE: + return "Tx Profile IQ rate out of range.\n"; + case MYKONOS_ERR_TXPROFILE_RFBW: + return "Tx Profile RF bandwidth out of range.\n"; + case MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION: + return "Tx Filter interpolation not valid.\n"; + case MYKONOS_ERR_TXPROFILE_FIR_COEFS: + return "Tx FIR filter not valid.\n"; + case MYKONOS_ERR_RXPROFILE_RXCHANNEL: + return " Rx channel is not valid.\n"; + case MYKONOS_ERR_RXPROFILE_IQRATE: + return "Receiver profile out of range IQ rate.\n"; + case MYKONOS_ERR_RXPROFILE_RFBW: + return "Receiver profile out of range RF bandwidth.\n"; + case MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION: + return "Receiver profile not valid filter decimation setting.\n"; + case MYKONOS_ERR_RXPROFILE_FIR_COEFS: + return "Receiver profile FIR filter not valid.\n"; + case MYKONOS_ERR_RXPROFILE_ADCDIV: + return "Receiver profile not valid ADC divider.\n"; + case MYKONOS_ERR_PROFILES_HSDIGCLK: + return "Profile combinations loaded are not valid.\n"; + case MYKONOS_ERR_RESET_TXLOL_INV_PARAM: + return "Selected channel is not valid.\n"; + case MYKONOS_ERR_RESET_TXLOL_ARMERROR: + return "ARM command error in MYKONOS_resetExtTxLolChannel().\n"; + case MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV: + return "Not valid calibration mask passed for trackCals.\n"; + case MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG: + return "ARM error flag set.\n"; + case MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG: + return "ARM error flag set.\n"; + case MYKONOS_ERR_GETSTATEALL_TRACK_ARMERROR: + return "ARM command error.\n"; + case MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM: + return "Null parameter passed for trackCals.\n"; + case MYKONOS_ERR_SETSTATE_TRACK_CAL_INV: + return "Not valid calibration passed.\n"; + case MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG: + return "ARM command error.\n"; + case MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM: + return "Null parameter passed to trackCalState.\n"; + case MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG: + return "ARM command error flag set.\n"; + case MYKONOS_ERR_GETSTATE_TRACK_ARMERROR: + return "ARM command error.\n"; + case MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL: + return "Tx channel is not valid (Valid ENUM values: TX1 or TX2 only).\n"; + case MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG: + return "ARM command flag error set.\n"; + case MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN: + return "CLGC gain parameter is out of range, valid range is from -10000 to 10000.\n"; + case MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL: + return "Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2).\n"; + case MYKONOS_ERR_SETDPDACT_INV_STATE: + return "Invalid Actuator state, valid states are 0-disable and 1-enable.\n"; + case MYKONOS_ERR_SETDPDACT_ARMERRFLAG: + return "ARM command flag error set.\n"; + case MYKONOS_ERR_SETRFPLL_LF_PLLNAME: + return "Invalid pllName requested in MYKONOS_setRfPllLoopFilter()\n"; + case MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY: + return "Invalid stability value requested in MYKONOS_setRfPllLoopFilter()\n"; + case MYKONOS_ERR_SETRFPLL_LF_ARMERROR: + return "ARM Command Error in MYKONOS_setRfPllLoopFilter()\n"; + case MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH: + return "Invalid Tx/Rx value bandwith requested in MYKONOS_setRfPllLoopFilter()\n"; + case MYKONOS_ERR_SETRFPLL_LF_INV_SNF_LOOPBANDWIDTH: + return "Invalid Sniffer value bandwith in MYKONOS_setRfPllLoopFilter()\n"; + case MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME: + return "Invalid pllName requested in MYKONOS_getRfPllLoopFilter()\n"; + case MYKONOS_ERR_GETRFPLL_LF_ARMERROR: + return "ARM Command Error in MYKONOS_getRfPllLoopFilter()\n"; + case MYKONOS_ERR_GETRFPLL_LF_NULLPARAM: + return "NULL pointer in function parameter for MYKONOS_getRfPllLoopFilter()\n"; + case MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT: + return "Invalid value passed as parameter for measureCount to function MYKONOS_setRfDcOffsetCnt().\n"; + case MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT: + return "The measureCount value passed to function MYKONOS_setRfDcOffsetCnt() is less than the minimum limit allowed.\n"; + case MYKONOS_ERR_DC_OFFSET_INV_CHAN: + return "Invalid channel passed as parameter, for valid channel refer mykonosDcOffsetChannels_t enum.\n"; + case MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT: + return "Null parameter passed for measureCount MYKONOS_getRfDcOffsetCnt().\n"; + case MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT: + return "Invalid MShift value passed as parameter to function MYKONOS_setDigDcOffsetMShift().\n"; + case MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT: + return "MShift passed to the function MYKONOS_getDigDcOffsetMShift() is NULL.\n"; + case MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK: + return "Invalid enable mask passed to the function MYKONOS_setDigDcOffsetEn().\n"; + case MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK: + return "Enable mask passed to the function MYKONOS_getDigDcOffsetEn() is NULL.\n"; + case MYKONOS_ERR_RESETDPD_WRONG_PARAM: + return "reset parameter passed to function MYKONOS_resetDpd() is not valid, possible values are: MYK_DPD_RESET_FULL, MYK_DPD_RESET_PRIOR or MYK_DPD_RESET_CORRELATOR \n"; + case MYKONOS_ERR_RESETDPD_ARMERRFLAG: + return "ARM command flag error set in function MYKONOS_resetDpd().\n"; + case MYKONOS_ERR_CFGCLGC_INV_THRESHOLD: + return "tx1RelThreshold or tx2RelThreshold parameter is out of range in function MYKONOS_configClgc().\n"; + case MYKONOS_ERR_RESETDPD_INV_TXCHANNEL: + return "Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2 in function MYKONOS_resetDpd().\n"; + case MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM: + return "pathDelay structure is null in function MYKONOS_setPathDelay().\n"; + case MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE: + return "path delay not valid range in MYKONOS_setPathDelay(), valid ranges are from 0 to 4095 at 1/16 sample resolution of ORx sample rate.\n"; + case MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM: + return "pathDelay structure is null in function MYKONOS_getPathDelay().\n"; + case MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION: + return "invalid selection for getting the path delay, valid selections are given by mykonosPathDelaySel_t.\n"; + case MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG: + return "Arm error while reading path delay for the selected calibration status.\n"; + case MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM: + return "dpdErrCnt is null in function MYKONOS_getDpdErrorCounters().\n"; + case MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH: + return "invalid selection for getting the error counters tx channel in MYKONOS_getDpdErrorCounters().\n"; + case MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG: + return "Arm error while reading the error counters for the DPD status MYKONOS_getDpdErrorCounters().\n"; + case MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT: + return "Passed structure is null in MYKONOS_setDpdBypassConfig().\n"; + case MYKONOS_ERR_SETDPDACT_INV_ACTMODE: + return "Invalid mode passed detected in MYKONOS_setDpdBypassConfig(), actConfig->bypassActuatorMode for valid modes mykonosDpdResetMode_t.\n"; + case MYKONOS_ERR_SETDPDACT_INV_LEVEL: + return "Passed actConfig->bypassActuatorLevel outside the range in MYKONOS_setDpdBypassConfig().\n"; + case MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT: + return "Passed structure is null in MYKONOS_getDpdBypassConfig().\n"; + case MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT: + return "Passed structure is null in MYKONOS_setDpdActuatorCheck().\n"; + case MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE: + return "Invalid mode detected in MYKONOS_setDpdActuatorCheck(), actCheck->actuatorGainCheckMode for valid modes mykonosDpdResetMode_t.\n"; + case MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL: + return "Passed actCheck->actuatorGainCheckLevel outside the range in MYKONOS_setDpdActuatorCheck().\n"; + case MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT: + return "Passed structure is null in MYKONOS_getDpdActuatorCheck().\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT: + return "Passed structure is null in MYKONOS_setClgcAttenTuningConfig().\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE: + return "Invalid mode detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(), for valid modes ::mykonosClgcAttenTuningMode_t.\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET: + return "Invalid AttenTuningPreset detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(), valid range is from 0 to 839 (0 to 41.95dB).\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE: + return "Invalid AttenTuningRange detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(), valid range is from 0 to 420 (0 to 21dB).\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS: + return "Invalid Tx1 AttenTuningRange and AttenTuningPreset combination in MYKONOS_getClgcAttenTuningConfig().\n"; + case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS: + return "Invalid Tx2 AttenTuningRange and AttenTuningPreset combination in MYKONOS_getClgcAttenTuningConfig().\n"; + case MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT: + return "Passed structure is null in MYKONOS_getClgcAttenTuningConfig().\n"; + + default: + return "Unknown error was encountered.\n"; + } + +#endif +} + +/** + * \brief Calculates the scaled device clock frequency at the input of the + * CLKPLL or RFPLL + * + * Use this helper function any time the scaled device clock frequency is needed. + * + * Dependencies + * - device->clocks->deviceClock_kHz + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param scaledRefClk_kHz Output: The returned scaled reference clock for the device's PLLs + * \param deviceClkDiv Output: The device clock divider setting that gets set in the devices SPI register. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_NULL_DEVICE_PARAM Function parameter device pointer is NULL + * \retval MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM The scaled PLL refclk frequency is out of range (40MHz to 80MHz) + * \retval MYKONOS_ERR_CALCDEVCLK_NULLPARAM Function parameter scaledRefClk_kHz or deviceClkDiv has a NULL pointer + */ +static mykonosErr_t MYKONOS_calculateScaledDeviceClk_kHz(mykonosDevice_t *device, uint32_t *scaledRefClk_kHz, uint8_t *deviceClkDiv) +{ + uint32_t deviceClock_kHz = 0; + + if ((device == NULL) || (device->clocks == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_NULL_DEVICE_PARAM, getMykonosErrorMessage(MYKONOS_ERR_NULL_DEVICE_PARAM)); + return MYKONOS_ERR_NULL_DEVICE_PARAM; + } + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_calculateScaledDeviceClk_kHz()\n"); +#endif + + deviceClock_kHz = device->clocks->deviceClock_kHz; + + if ((scaledRefClk_kHz == NULL) || (deviceClkDiv == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CALCDEVCLK_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_CALCDEVCLK_NULLPARAM)); + return MYKONOS_ERR_CALCDEVCLK_NULLPARAM; + } + + /* scaled Ref Clock at input to CLKPLL must be in range 40-80MHz. */ + if (deviceClock_kHz > 20000 && deviceClock_kHz <= 40000) + { + *scaledRefClk_kHz = deviceClock_kHz << 1; + *deviceClkDiv = 3; + } /* x2 */ + else if (deviceClock_kHz > 40000 && deviceClock_kHz <= 80000) + { + *scaledRefClk_kHz = deviceClock_kHz; + *deviceClkDiv = 0; + } /* x1 */ + else if (deviceClock_kHz > 80000 && deviceClock_kHz <= 160000) + { + *scaledRefClk_kHz = deviceClock_kHz >> 1; + *deviceClkDiv = 1; + } /* div2 */ + else if (deviceClock_kHz > 160000 && deviceClock_kHz <= 320000) + { + *scaledRefClk_kHz = deviceClock_kHz >> 2; + *deviceClkDiv = 2; + } /* div4 */ + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM)); + return MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM; + } + return MYKONOS_ERR_OK; +} + +/** + * \brief Resets the JESD204B Deframer + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_resetDeframer(mykonosDevice_t *device) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDeframer()\n"); +#endif + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_RESET, 0x03); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_RESET, 0x00); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the JESD204B Serializers + * + * This function uses the Rx framer and ObsRx framer structures to setup the 4 + * serializer lanes that are shared between the two framers. If the Rx profile is valid + * the serializer amplitude and preEmphasis are used from the Rx framer. If only the ObsRx + * profile is valid, the obsRx framer settings are used. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->rx->framer->M + * - device->rx->framer->serializerAmplitude + * - device->rx->framer->preEmphasis + * - device->rx->framer->serializerLanesEnabled + * - device->rx->framer->invertLanePolarity + * - device->obsRx->framer->serializerLanesEnabled + * - device->obsRx->framer->invertLanePolarity + * - device->obsRx->framer->M + * - device->obsRx->framer->serializerLanesEnabled + * - device->obsRx->framer->serializerAmplitude + * - device->obsRx->framer->preEmphasis + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_INITSER_INV_VCODIV_PARM Mykonos CLKPLL has invalid VCO divider, verify CLKPLL config + * \retval MYKONOS_ERR_SER_LANE_CONFLICT_PARM When both Rx and ObsRx framers are enabled, framers can not share the same physical lane. + * \retval MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM Rx Framer M can only = 1 when Real IF mode is enabled + * \retval MYKONOS_ERR_SER_INV_M_PARM Invalid Rx Framer M (valid 1,2,4) + * \retval MYKONOS_ERR_SER_INV_LANEEN_PARM Invalid Rx framer serializerLanesEnabled (valid 0-15) + * \retval MYKONOS_ERR_SER_INV_AMP_PARM Invalid Rx serializer amplitude (valid 0-31) + * \retval MYKONOS_ERR_SER_INV_PREEMP_PARM Invalid Rx serializer pre-emphesis (valid 0-7) + * \retval MYKONOS_ERR_SER_INV_LANEPN_PARM Invalid Rx serializer PN invert setting (valid 0-15) + * \retval MYKONOS_ERR_SER_INV_L_PARM Invalid Rx serializer lanes enabled (must use 1, 2 or 4 lanes) + * \retval MYKONOS_ERR_SER_INV_LANERATE_PARM Invalid Rx serializer lane rate (valid 614.4Mbps - 6144Mbps) + * + * \retval MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM + * \retval MYKONOS_ERR_SER_INV_LANEEN_PARM + * \retval MYKONOS_ERR_SER_INV_AMP_PARM + * \retval MYKONOS_ERR_SER_INV_PREEMP_PARM + * \retval MYKONOS_ERR_SER_INV_LANEPN_PARM + * \retval MYKONOS_ERR_SER_INV_L_PARM + * \retval MYKONOS_ERR_SER_INV_LANERATE_PARM + * + * \retval MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM Necessary lane rates for Rx and ObsRx framer can not be obtained with possible divider settings + * \retval MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT HSCLK is not an integer multiple of the lane clock rate + * \retval MYKONOS_ERR_SER_INV_TXSER_DIV_PARM No valid Tx serializer divider to obtain desired lane rates + * \retval MYKONOS_ERR_INITSER_INV_PROFILE Rx/ObsRx and sniffer profiles are not valid - can not config serializers + * \retval MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM Invalid Rx framer PCLK divider + * \retval MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM Invalid ORx/Sniffer framer PCLK divider + * + */ +mykonosErr_t MYKONOS_setupSerializers(mykonosDevice_t *device) +{ + uint8_t serializerHalfRateReg = 0; + uint8_t txser_div = 0; + uint8_t txser_div_reg = 0; + uint32_t clkPllVcoFrequency_kHz = 0; + uint32_t hsclkRate_kHz = 0; + uint32_t rxLaneRate_kHz = 0; + uint32_t obsRxLaneRate_kHz = 0; + uint32_t fasterLaneRate_kHz = 0; + uint32_t slowerLaneRate_kHz = 0; + uint8_t modHsLaneRate = 0; + uint8_t rxL = 0; + uint8_t obsRxL = 0; + uint8_t i = 0; + uint8_t amplitudeEmphasis = 0; + uint8_t lanePowerDown = 0x00; + mykonosVcoDiv_t vcoDiv = VCODIV_1; + uint8_t rxLanePn = 0; + uint8_t obsRxLanePn = 0; + + uint32_t hsDigClkdiv4_5_kHz = 0; + uint32_t rxPclkDiv = 0; + uint32_t obsRxPclkDiv = 0; + uint32_t tempPclkDiv = 0; + uint32_t rxFramerPclk_kHz = 0; + uint32_t obsRxFramerPclk_kHz = 0; + uint8_t rxSyncbSelect = 0; + uint8_t obsRxSyncbSelect = 0; + + static const uint32_t MAX_HSCLK_KHZ_IF_VCODIV1P5 = 6144000; /* max VCO /1.5 output is 6144Mhz. This limits VCO to 9216MHz */ + static const uint32_t MAX_HSCLK_KHZ_IF_VCODIV1 = 8000000; /* max VCO div1 output is 8000Mhz. This limits VCO to 8000MHz */ + static const uint32_t MIN_SERIALIZER_RATE_KHZ = 614400; /* max serializer lane rate = 0.6144 Gbps */ + static const uint32_t MAX_SERIALIZER_RATE_KHZ = 6144000; /* max serializer lane rate = 6.144 Gbps */ +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupSerializers()\n"); +#endif + + vcoDiv = device->clocks->clkPllVcoDiv; + clkPllVcoFrequency_kHz = device->clocks->clkPllVcoFreq_kHz; + + switch (vcoDiv) + { + case VCODIV_1: + hsclkRate_kHz = clkPllVcoFrequency_kHz; + + /* max VCO /1 output is 8000Mhz. This limits VCO to 8000MHz */ + if (hsclkRate_kHz > MAX_HSCLK_KHZ_IF_VCODIV1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM)); + return MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM; + } + + break; + + case VCODIV_1p5: + hsclkRate_kHz = (clkPllVcoFrequency_kHz / 15) * 10; + + /* max VCO /1.5 output is 6144Mhz. This limits VCO to 9216MHz */ + if (hsclkRate_kHz > MAX_HSCLK_KHZ_IF_VCODIV1P5) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM)); + return MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM; + } + + break; + + case VCODIV_2: + hsclkRate_kHz = clkPllVcoFrequency_kHz >> 1; + break; + + case VCODIV_3: + hsclkRate_kHz = (clkPllVcoFrequency_kHz / 30) * 10; + break; + + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV_PARM)); + return MYKONOS_ERR_INITSER_INV_VCODIV_PARM; + } + } + + if ((device->profilesValid & RX_PROFILE_VALID) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))) + { + if (device->rx->framer->serializerLanesEnabled & device->obsRx->framer->serializerLanesEnabled) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_LANE_CONFLICT_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_LANE_CONFLICT_PARM)); + return MYKONOS_ERR_SER_LANE_CONFLICT_PARM; + } + } + + lanePowerDown = 0x9F; + if (device->profilesValid & RX_PROFILE_VALID) + { + if (device->rx->framer->M == 1 && !(device->rx->realIfData)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM)); + return MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM; + } + + if (device->rx->framer->M != 1 && device->rx->framer->M != 2 && device->rx->framer->M != 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_M_PARM)); + return MYKONOS_ERR_SER_INV_M_PARM; + } + + for (i = 0; i < 4; i++) + { + rxL += ((device->rx->framer->serializerLanesEnabled >> i) & 0x01); + } + + if (device->rx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEEN_PARM)); + return MYKONOS_ERR_SER_INV_LANEEN_PARM; + } + + if (device->rx->framer->serializerAmplitude > 31) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_AMP_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_AMP_PARM)); + return MYKONOS_ERR_SER_INV_AMP_PARM; + } + + if (device->rx->framer->preEmphasis > 7) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_PREEMP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_PREEMP_PARM)); + return MYKONOS_ERR_SER_INV_PREEMP_PARM; + } + + if (device->rx->framer->invertLanePolarity > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEPN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEPN_PARM)); + return MYKONOS_ERR_SER_INV_LANEPN_PARM; + } + if ((rxL != 1) && (rxL != 2) && (rxL != 4)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_L_PARM)); + return MYKONOS_ERR_SER_INV_L_PARM; + } + + rxLaneRate_kHz = device->rx->rxProfile->iqRate_kHz * 20 * device->rx->framer->M / rxL; + lanePowerDown &= (~(device->rx->framer->serializerLanesEnabled)); + + if ((rxLaneRate_kHz < MIN_SERIALIZER_RATE_KHZ) || (rxLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM)); + return MYKONOS_ERR_SER_INV_LANERATE_PARM; + } + } + + if ((device->obsRx->framer != NULL) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))) + { + if ((device->obsRx->framer->M == 1) && !(device->obsRx->realIfData)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM)); + return MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM; + } + + for (i = 0; i < 4; i++) + { + obsRxL += ((device->obsRx->framer->serializerLanesEnabled >> i) & 0x01); + } + + if (device->obsRx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEEN_PARM)); + return MYKONOS_ERR_SER_INV_LANEEN_PARM; + } + + if (device->obsRx->framer->serializerAmplitude > 31) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_AMP_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_AMP_PARM)); + return MYKONOS_ERR_SER_INV_AMP_PARM; + } + + if (device->obsRx->framer->preEmphasis > 7) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_PREEMP_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_PREEMP_PARM)); + return MYKONOS_ERR_SER_INV_PREEMP_PARM; + } + + if (device->obsRx->framer->invertLanePolarity > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEPN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEPN_PARM)); + return MYKONOS_ERR_SER_INV_LANEPN_PARM; + } + + if ((obsRxL != 0) && (obsRxL != 1) && (obsRxL != 2) && (obsRxL != 4)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_L_PARM)); + return MYKONOS_ERR_SER_INV_L_PARM; + } + + /* check for valid pointer */ + if (obsRxL == 0) + { + /* Allow ORx receiver to work but disable Obs Rx framer link - valid on a DPD-enabled transceiver */ + obsRxLaneRate_kHz = 0; + } + else if (device->profilesValid & ORX_PROFILE_VALID) + { + obsRxLaneRate_kHz = device->obsRx->orxProfile->iqRate_kHz * 20 * device->obsRx->framer->M / obsRxL; + } + else if (device->profilesValid & SNIFF_PROFILE_VALID) + { + obsRxLaneRate_kHz = device->obsRx->snifferProfile->iqRate_kHz * 20 * device->obsRx->framer->M / obsRxL; + } + + lanePowerDown &= (~(device->obsRx->framer->serializerLanesEnabled)); + + if ((obsRxLaneRate_kHz != 0) && ((obsRxLaneRate_kHz < MIN_SERIALIZER_RATE_KHZ) || (obsRxLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM)); + return MYKONOS_ERR_SER_INV_LANERATE_PARM; + } + } + + /* checking for RX and OBSRX effective lane rates match */ + /* Need to account for oversampling, verify that the 2 lane rate are integer related */ + + if ((rxLaneRate_kHz > 0) && (obsRxLaneRate_kHz > 0)) + { + fasterLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (rxLaneRate_kHz) : (obsRxLaneRate_kHz); + slowerLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (obsRxLaneRate_kHz) : (rxLaneRate_kHz); + + /* Verify that lane rates are integer multiples of each other */ + if ((fasterLaneRate_kHz % slowerLaneRate_kHz) != 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM)); + return MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM; + } + } + else + { + fasterLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (rxLaneRate_kHz) : (obsRxLaneRate_kHz); + } + + /* performing integer multiple check on HS clock and lane rate clock */ + if (fasterLaneRate_kHz == 0) + { + /* All serializer lanes are disabled */ + txser_div = 1; + txser_div_reg = 0; + serializerHalfRateReg = 0; + } + else + { + if ((fasterLaneRate_kHz > hsclkRate_kHz) || + (fasterLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM)); + return MYKONOS_ERR_SER_INV_LANERATE_PARM; + } + + modHsLaneRate = (uint8_t)(hsclkRate_kHz % fasterLaneRate_kHz); + if (modHsLaneRate != 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT, + getMykonosErrorMessage(MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT)); + return MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT; + } + + txser_div = (uint8_t)(hsclkRate_kHz / fasterLaneRate_kHz); /* Total serializer Divider (1,2,4,8) */ + switch (txser_div) + { + case 1: + txser_div_reg = 0; /* Divide hsclk by 1 */ + serializerHalfRateReg = 0; /* 0 = divide serializer clock by 1 */ + break; + case 2: + txser_div_reg = 1; /* Divide hsclk by 2 */ + serializerHalfRateReg = 0; /* 0 = divide serializer clock by 1 */ + break; + case 4: + txser_div_reg = 2; /* Divide hsclk by 4 */ + serializerHalfRateReg = 0; /* 0 = divide serializer clock by 1 */ + break; + case 8: + txser_div_reg = 2; /* Divide hsclk by 4 */ + serializerHalfRateReg = 1; /* 1 = divide serializer clock by 2 */ + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_TXSER_DIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_SER_INV_TXSER_DIV_PARM)); + return MYKONOS_ERR_SER_INV_TXSER_DIV_PARM; + } + } + + if (device->profilesValid & RX_PROFILE_VALID) + { + amplitudeEmphasis = ((device->rx->framer->serializerAmplitude & 0x1f) << 3) | (device->rx->framer->preEmphasis & 0x07); + } + else if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)) + { + amplitudeEmphasis = ((device->obsRx->framer->serializerAmplitude & 0x1f) << 3) | (device->obsRx->framer->preEmphasis & 0x07); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_PROFILE, getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_PROFILE)); + return MYKONOS_ERR_INITSER_INV_PROFILE; + } + + if (device->profilesValid & RX_PROFILE_VALID) + { + rxSyncbSelect = (device->rx->framer->obsRxSyncbSelect > 0) ? 1 : 0; + rxLanePn = (uint8_t)(rxSyncbSelect << 7) | (device->rx->framer->invertLanePolarity & 0xF); + } + + if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)) + { + obsRxSyncbSelect = (device->obsRx->framer->obsRxSyncbSelect > 0) ? 1 : 0; + obsRxLanePn = (uint8_t)(obsRxSyncbSelect << 7) | (device->obsRx->framer->invertLanePolarity & 0xF); + } + + /* Serializer lane clock frequency */ + /* serLaneClock_kHz = fasterLaneRate_kHz / txser_div / 20; */ + if (device->profilesValid & RX_PROFILE_VALID) + { + /* calculate manual PCLK frequency for Rx framer = Rx IQrate * F, where F = (2*M/L) or PCLK = lanerate /10 */ + if (device->rx->framer->overSample) + { + rxFramerPclk_kHz = fasterLaneRate_kHz / 10; + } + else + { + rxFramerPclk_kHz = rxLaneRate_kHz / 10; + } + + hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->rx->rxProfile->rxDec5Decimation; + + /* PCLKDiv: 0=4x, 1=2x, 2=1x, 3=/2, 4=/4, 5=/8, 6=/16 */ + if (hsDigClkdiv4_5_kHz == rxFramerPclk_kHz) + { + rxPclkDiv = 2; + } + else if (hsDigClkdiv4_5_kHz > rxFramerPclk_kHz) + { + if (rxFramerPclk_kHz == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM; + } + + tempPclkDiv = hsDigClkdiv4_5_kHz / rxFramerPclk_kHz; + switch (tempPclkDiv) + { + case 2: + rxPclkDiv = 3; + break; + case 4: + rxPclkDiv = 4; + break; + case 8: + rxPclkDiv = 5; + break; + case 16: + rxPclkDiv = 6; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM; + } + } + } + else if (hsDigClkdiv4_5_kHz < rxFramerPclk_kHz) + { + tempPclkDiv = rxFramerPclk_kHz / hsDigClkdiv4_5_kHz; + switch (tempPclkDiv) + { + case 2: + rxPclkDiv = 1; + break; + case 4: + rxPclkDiv = 0; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM; + } + } + } + } + + if (obsRxL == 0) + { + /* Make sure PCLK is set as low as possible because it interacts with Rx Framer logic, */ + /* even though ObsRx Framer disabled */ + obsRxPclkDiv = 6; + } + else if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)) + { + /* calculate manual PCLK frequency for obsRx framer = obsRx IQrate * F, where F = (2*M/L) */ + if (device->profilesValid & ORX_PROFILE_VALID) + { + if (device->obsRx->framer->overSample) + { + obsRxFramerPclk_kHz = fasterLaneRate_kHz / 10; + } + else + { + obsRxFramerPclk_kHz = obsRxLaneRate_kHz / 10; + } + + hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->obsRx->orxProfile->rxDec5Decimation; + } + else if (device->profilesValid & SNIFF_PROFILE_VALID) + { + if (device->obsRx->framer->overSample) + { + obsRxFramerPclk_kHz = fasterLaneRate_kHz / 10; + } + else + { + obsRxFramerPclk_kHz = obsRxLaneRate_kHz / 10; + } + + hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->obsRx->snifferProfile->rxDec5Decimation; + } + + /* PCLKDiv: 0=4x, 1=2x, 2=1x, 3=/2, 4=/4, 5=/8, 6=/16 */ + if (hsDigClkdiv4_5_kHz == obsRxFramerPclk_kHz) + { + obsRxPclkDiv = 2; + } + else if ((hsDigClkdiv4_5_kHz > obsRxFramerPclk_kHz) && (obsRxFramerPclk_kHz != 0)) + { + tempPclkDiv = hsDigClkdiv4_5_kHz / obsRxFramerPclk_kHz; + switch (tempPclkDiv) + { + case 2: + obsRxPclkDiv = 3; + break; + case 4: + obsRxPclkDiv = 4; + break; + case 8: + obsRxPclkDiv = 5; + break; + case 16: + obsRxPclkDiv = 6; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM; + } + } + } + else if (hsDigClkdiv4_5_kHz < obsRxFramerPclk_kHz) + { + if (hsDigClkdiv4_5_kHz == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM; + } + + tempPclkDiv = obsRxFramerPclk_kHz / hsDigClkdiv4_5_kHz; + switch (tempPclkDiv) + { + case 2: + obsRxPclkDiv = 1; + break; + case 4: + obsRxPclkDiv = 0; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM)); + return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM; + } + } + } + } + + /* set lane rate divide setting */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_3, txser_div_reg, 0x03, 0); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_2, amplitudeEmphasis); + + /* Serializer: Release Reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_SPECIAL, 0x03); + + /* Serializer: txser clk enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_HS_DIV_TXSER_CLK_EN, 0x01); + + /* Serializer: Enable 2 to 1 serializer */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_3, 0x20 | serializerHalfRateReg); + + /* power up desired serializer lanes */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, lanePowerDown); + + /* apply desired lane PN inversions to the TX and OBSRX framers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_DATA_CTL, rxLanePn); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_DATA_CTL, obsRxLanePn); + + /* set Rx framer manual PCLK frequency based on lane rate of the serializers */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, (uint8_t)rxPclkDiv, 0x70, 4); + + /* enable bit repeat mode in Rx framer - since manual PCLK, oversample will still work */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0, 0x80, 7); + + /* enable manual PCLK mode in Rx framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 1, 0x04, 2); + + /* set obsRx framer manual PCLK frequency based on lane rate of the serializers */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, (uint8_t)obsRxPclkDiv, 0x70, 4); + + /* enable bit repeat mode in ObsRx framer - since manual PCLK, oversample will still work */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x80, 7); + + /* enable manual PCLK mode in ObsRx framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 1, 0x04, 2); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the JESD204B Deserializers + * + * This function enables the necessary deserializer lanes, sets the deserializer clocks + * PN inversion settings, and EQ settings based on the info found in the device data structure. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->tx->txProfile->clkPllVcoDiv + * - device->tx->txProfile->vcoFreq_kHz + * - device->tx->txProfile->txIqRate_kHz + * - device->tx->deframer->M + * - device->tx->deframer->deserializerLanesEnabled + * - device->tx->deframer->invertLanePolarity + * - device->tx->deframer->EQSetting + * + * \param device Pointer to the device settings structure + + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_INITDES_INV_TXPROFILE Tx Profile is not valid in data structure - can not setup deserializer + * \retval MYKONOS_ERR_INITDES_INV_VCODIV_PARM Mykonos CLKPLL VCO divider is invalid + * \retval MYKONOS_ERR_DESER_INV_M_PARM Invalid M (valid 2 or 4) + * \retval MYKONOS_ERR_DESER_INV_L_PARM Invalid L (valid 1,2,4) + * \retval MYKONOS_ERR_DESER_INV_HSCLK_PARM Invalid HSCLK, must be 6.144G or less after CLKPLL VCO divider - verify CLKPLL config + * \retval MYKONOS_ERR_DESER_INV_LANERATE_PARM Invalid lanerate, must be between 614.4 Mbps to 6144 Mbps + * \retval MYKONOS_ERR_DESER_INV_LANEEN_PARM Invalid deserializerLanesEnabled (valid 0-15 in 1,2,4 lane combinations) + * \retval MYKONOS_ERR_DESER_INV_EQ_PARM Invalid EQ parameter (valid 0-4) + * \retval MYKONOS_ERR_DESER_INV_LANEPN_PARM Invalid PN invert setting, (valid 0-15, invert bit per lane) + * \retval MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT Invalid clock settings, HSCLK is not an integer multiple of lane rate + * + */ +mykonosErr_t MYKONOS_setupDeserializers(mykonosDevice_t *device) +{ + uint8_t lanePowerDown = 0xF; + uint8_t des_div = 0; + uint8_t des_div_bitfield = 0; + uint8_t rxcdr_div = 0; + uint8_t rxcdr_div_bitfield = 0; + uint32_t hsclkRate_kHz = 0; + uint8_t i = 0; + uint8_t L = 0; + uint32_t laneRate_kHz = 0; + uint8_t invertLanePolarity = 0; + uint8_t modHsLaneRate = 0; + + const uint32_t MAX_HSCLKRATE_KHZ = 12288000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupDeserializers()\n"); +#endif + + if ((device->profilesValid & TX_PROFILE_VALID) == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITDES_INV_TXPROFILE, + getMykonosErrorMessage(MYKONOS_ERR_INITDES_INV_TXPROFILE)); + return MYKONOS_ERR_INITDES_INV_TXPROFILE; + } + + if (device->tx->deframer->M != 2 && device->tx->deframer->M != 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_M_PARM)); + return MYKONOS_ERR_DESER_INV_M_PARM; + } + + for (i = 0; i < 4; i++) + { + L += ((device->tx->deframer->deserializerLanesEnabled >> i) & 0x01); + } + + if ((L == 0) || (L == 3) || (L > 4)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_L_PARM)); + return MYKONOS_ERR_DESER_INV_L_PARM; + } + + //laneRate_kHz calculation and checks + laneRate_kHz = device->tx->txProfile->iqRate_kHz * 20 * device->tx->deframer->M / L; + + if ((laneRate_kHz < 614400) || (laneRate_kHz > 6144000)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANERATE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANERATE_PARM)); + return MYKONOS_ERR_DESER_INV_LANERATE_PARM; + } + + if (device->tx->deframer->deserializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEEN_PARM)); + return MYKONOS_ERR_DESER_INV_LANEEN_PARM; + } + + if ((device->tx->deframer->deserializerLanesEnabled == 0x7) || (device->tx->deframer->deserializerLanesEnabled == 0xB) + || (device->tx->deframer->deserializerLanesEnabled == 0xD) || (device->tx->deframer->deserializerLanesEnabled == 0xE)) + { + /* 3 lanes not valid, only 1,2, or 4 lanes */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEEN_PARM)); + return MYKONOS_ERR_DESER_INV_LANEEN_PARM; + } + + if (device->tx->deframer->EQSetting > 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_EQ_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_EQ_PARM)); + return MYKONOS_ERR_DESER_INV_EQ_PARM; + } + + if (device->tx->deframer->invertLanePolarity > 15) + { + /* only lower 4 bits of parameter are valid */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEPN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEPN_PARM)); + return MYKONOS_ERR_DESER_INV_LANEPN_PARM; + } + + //hsclkRate_kHz calculations + switch (device->clocks->clkPllVcoDiv) + { + case VCODIV_1: + hsclkRate_kHz = device->clocks->clkPllVcoFreq_kHz; + break; + case VCODIV_1p5: + hsclkRate_kHz = (device->clocks->clkPllVcoFreq_kHz / 15) * 10; + break; + case VCODIV_2: + hsclkRate_kHz = device->clocks->clkPllVcoFreq_kHz >> 1; + break; + case VCODIV_3: + hsclkRate_kHz = (device->clocks->clkPllVcoFreq_kHz / 30) * 10; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITDES_INV_VCODIV_PARM, + getMykonosErrorMessage(MYKONOS_ERR_INITDES_INV_VCODIV_PARM)); + return MYKONOS_ERR_INITDES_INV_VCODIV_PARM; + } + + /* The deserializer clock needs to be in the range 3.8GHz to 6.144 GHz in reg x107. The rest of the division is in xDD */ + if (hsclkRate_kHz <= 6144000) + { + rxcdr_div = 1; + } + else if ((hsclkRate_kHz > 6144000) && (hsclkRate_kHz <= MAX_HSCLKRATE_KHZ)) + { + rxcdr_div = 2; + } + else if ((hsclkRate_kHz > MAX_HSCLKRATE_KHZ) && (hsclkRate_kHz < 24576000)) + { + rxcdr_div = 4; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_HSCLK_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_HSCLK_PARM)); + return MYKONOS_ERR_DESER_INV_HSCLK_PARM; + } + + switch (rxcdr_div) + { + case 1: + rxcdr_div_bitfield = 0; + break; + case 2: + rxcdr_div_bitfield = 1; + break; + + default: + /* Default case is when rxcdr_div == 4 */ + rxcdr_div_bitfield = 2; + break; + } + + /* performing integer multiple check on HS clock and lane rate clock */ + modHsLaneRate = (uint8_t)(hsclkRate_kHz % laneRate_kHz); + if (modHsLaneRate) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT, + getMykonosErrorMessage(MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT)); + return MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT; + } + + des_div = (uint8_t)(hsclkRate_kHz / laneRate_kHz / rxcdr_div); + + switch (des_div) + { + case 1: + des_div_bitfield = 0; + break; + case 2: + des_div_bitfield = 1; + break; + case 4: + des_div_bitfield = 2; + break; + case 8: + des_div_bitfield = 3; + break; + default: + des_div_bitfield = 0; + break; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_3, rxcdr_div_bitfield, 0x0C, 0x02); + + invertLanePolarity = (device->tx->deframer->invertLanePolarity & 0xF); + + lanePowerDown = (~(device->tx->deframer->deserializerLanesEnabled)) & 0xF; + + /* Deserializer: PLL clock enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_HS_DIV_RXCDR_CLK_EN, 0x01); + + /* Deserializer: Set Pdet control */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_PDET_CTL, 0x09); + + /* Deserializer: Set Power down control */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_CTL_0, (0x80U | lanePowerDown | (uint8_t)(des_div_bitfield << 4))); + + /* Deserializer: Set Sine Shape */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_0, 0x00); + + /* Deserializer: Set ss gain and vga */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_1, 0x00); + + /* Deserializer: Enable EQ, AC coupled JESD204B lanes */ + /* TODO: add ability to set this for AC coupling or DC coupling */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1, 0x07); + + /* Deserializer: Clear Data present at negedge, disable peak adjust */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_MISC_CTL, 0x04); + + /* Deserializer: Set Equalizer for lanes 1 and 0 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1_TO_0, ((uint8_t)(device->tx->deframer->EQSetting << 3) | device->tx->deframer->EQSetting)); + + /* Deserializer: Set Equalizer for lanes 2 and 3 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_3_TO_2, ((uint8_t)(device->tx->deframer->EQSetting << 3) | device->tx->deframer->EQSetting)); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_DATA_CTL, invertLanePolarity); + + /* Reset Deserializers - toggle resetb bit in [0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SPECIAL, 0x00); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SPECIAL, 0x01); + + /* Start ALC cal */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_CDR_CAL_CTL, 0x02); + + /* Deframer: Enable clocks and lane clocks */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CLK_EN, 0x03); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the JESD204B Framer + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->rx->framer->M + * - device->rx->realIfData + * - device->rx->framer->bankId + * - device->rx->framer->lane0Id + * - device->rx->framer->serializerLanesEnabled + * - device->rx->framer->obsRxSyncbSelect + * - device->rx->framer->K + * - device->rx->framer->externalSysref + * - device->rx->rxChannels + * - device->rx->framer->newSysrefOnRelink + * - device->rx->framer->enableAutoChanXbar + * - device->rx->framer->lmfcOffset + * - device->rx->framer->scramble + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM Invalid framer M, M can only = 1 in real IF mode + * \retval MYKONOS_ERR_FRAMER_INV_M_PARM Invalid framer M (valid 1,2,4) + * \retval MYKONOS_ERR_FRAMER_INV_BANKID_PARM Invalid BankId (valid 0-15) + * \retval MYKONOS_ERR_FRAMER_INV_LANEID_PARM Invalid Lane0Id (valid 0-31) + * \retval MYKONOS_ERR_RXFRAMER_INV_FK_PARAM + * \retval MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM + */ +mykonosErr_t MYKONOS_setupJesd204bFramer(mykonosDevice_t *device) +{ + uint8_t i = 0; + uint8_t fifoLaneEnable = 0; + uint8_t L = 0; + uint8_t ML = 0; + uint8_t framerConfigF = 0; + + uint8_t subaddr[29] = {0}; /* holds address to framer sub register map */ + uint8_t subdata[29] = {0}; /* holds data for framer sub register map */ + + /* Setup submap registers */ + uint8_t SUBCLASSV = 1; /* JESD subclass 1 */ + uint8_t JESDV = 1; /* Version: JESD204B */ + uint8_t DID = 0; + uint8_t BID = 0; + uint8_t LID0 = 0; + uint8_t LID1 = 1; + uint8_t LID2 = 2; + uint8_t LID3 = 3; + uint8_t CS = 0; + uint8_t N = 0x0F; + uint8_t Np = 0x0F; + uint8_t S = 0; + uint8_t CF = 0; + uint8_t K = 31; + uint8_t HD = 0; + uint8_t FramerL = 1; + uint8_t FramerM = 2; + uint8_t FramerF = 1; + uint8_t framerADC_XBar = 0xE4; + uint16_t FK = 0; + + uint8_t regE0 = 0; + uint8_t regE2 = 0; + uint8_t framerLaneXbar = 0xE4; + uint16_t CheckSum = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bFramer()\n"); +#endif + + if (device->rx->framer->M == 1 && !(device->rx->realIfData)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM, + getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM)); + return MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM; + } + + if (device->rx->framer->M != 1 && device->rx->framer->M != 2 && device->rx->framer->M != 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_M_PARM)); + return MYKONOS_ERR_FRAMER_INV_M_PARM; + } + + if (device->rx->framer->bankId > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_BANKID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_BANKID_PARM)); + return MYKONOS_ERR_FRAMER_INV_BANKID_PARM; + } + + /* no need to check deviceId, its range is full uint8_t range */ + if (device->rx->framer->lane0Id > 31) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_LANEID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_LANEID_PARM)); + return MYKONOS_ERR_FRAMER_INV_LANEID_PARM; + } + + //count number of lanes + L = 0; + ML = 0; + + for (i = 0; i < 4; i++) + { + L += ((device->rx->framer->serializerLanesEnabled >> i) & 0x01); + } + ML = (uint8_t)(device->rx->framer->M * 10) + L; + + FK = (uint16_t)(device->rx->framer->K * 2 * device->rx->framer->M / L); + + if (FK < 20 || FK > 256 || FK % 4 != 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFRAMER_INV_FK_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_RXFRAMER_INV_FK_PARAM)); + return MYKONOS_ERR_RXFRAMER_INV_FK_PARAM; + } + + if (device->rx->framer->externalSysref == 0) + { + /* Framer: Generate SYSREF internally */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_TEST_CNTR_CTL, 0x20); + } + + framerADC_XBar = 0xB1; + if (ML == 24) + { + if (device->rx->rxChannels == RX1) + { + /* adc 0 and 2 used */ + framerADC_XBar = ((framerADC_XBar & 0x0C) << 2) | (framerADC_XBar & 0x03); + } + else if (device->rx->rxChannels == RX2) + { + /* swap ADC xbar for Rx1 and Rx2 */ + framerADC_XBar = ((framerADC_XBar & 0xF) << 4) | ((framerADC_XBar & 0xF0) >> 4); + /* adc 0 and 2 used */ + framerADC_XBar = ((framerADC_XBar & 0x0C) << 2) | (framerADC_XBar & 0x03); + } + + /* Framer: Set ADC Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADC_XBAR_SEL, framerADC_XBar); + } + else + { + /* Framer: Set ADC Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADC_XBAR_SEL, framerADC_XBar); + } + + if (device->rx->framer->enableManualLaneXbar == 1) + { + framerLaneXbar = device->rx->framer->serializerLaneCrossbar; + } + else + { + if (ML == 42) + { + /* uses framer outputs 0 and 2 instead of 0 and 1...fix framer lane XBar */ + /* only 2 lane cases here */ + switch ((device->rx->framer->serializerLanesEnabled & 0x0F)) + { + case 3: + framerLaneXbar = 0x08; + break; + case 5: + framerLaneXbar = 0x20; + break; + case 6: + framerLaneXbar = 0x20; + break; + case 9: + framerLaneXbar = 0x80; + break; + case 10: + framerLaneXbar = 0x80; + break; + case 12: + framerLaneXbar = 0x80; + break; + default: + /* default to valid setting for Lane 0 */ + framerLaneXbar = 0x08; + break; + } + } + else + { + switch ((device->rx->framer->serializerLanesEnabled & 0x0F)) + { + /* all 4 lanes get framer 0 output */ + case 1: + framerLaneXbar = 0x00; + break; + case 2: + framerLaneXbar = 0x00; + break; + case 3: + framerLaneXbar = 0x04; + break; + case 4: + framerLaneXbar = 0x00; + break; + case 5: + framerLaneXbar = 0x10; + break; + case 6: + framerLaneXbar = 0x10; + break; + case 8: + framerLaneXbar = 0x00; + break; + case 9: + framerLaneXbar = 0x40; + break; + case 10: + framerLaneXbar = 0x40; + break; + case 12: + framerLaneXbar = 0x40; + break; + case 15: + framerLaneXbar = 0xE4; + break; + default: + /* default to valid setting for all Lanes */ + framerLaneXbar = 0xE4; + break; + } + } + } + + /* Framer: Set Lane Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_XBAR_SEL, framerLaneXbar); + + if (ML == 24) + { + /* Framer: Clear ADC Xbar channel auto switch */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x00); + } + else + { + /* Framer: Set ADC Xbar channel auto switch */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x04); + } + + /* enabling the SYSREF for relink if newSysrefOnRelink is set */ + if (device->rx->framer->newSysrefOnRelink) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6); + } + + /* enabling auto channel if the enableAutoChanXbar structure member is set */ + if (device->rx->framer->enableAutoChanXbar) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x01, 0x04, 2); + } + + /* determining F octets per frame based on 2*M/L */ + framerConfigF = (uint8_t)(2 * (device->rx->framer->M / L)); + + /* Framer: Soft Reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x03); + + /* Framer: Clear Soft Reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x00); + + /* Framer: Set F (Octets in Frame) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_F, framerConfigF); + + /* Framer: Enable framer clock and lane clocks */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0x03, 0x03, 0); + + /* Set Framer lane FIFO enable for each lane enabled */ + fifoLaneEnable = (((device->rx->framer->serializerLanesEnabled & 0x0F) << 4) | 0x01); + + /* Framer: Enable Lane FIFOs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_CTL, fifoLaneEnable); + + /* Setup submap registers */ + SUBCLASSV = 1; /* JESD subclass 1 */ + JESDV = 1; /* Version: JESD204B */ + DID = device->rx->framer->deviceId; + BID = device->rx->framer->bankId; + LID0 = device->rx->framer->lane0Id; + LID1 = device->rx->framer->lane0Id + 1; + LID2 = device->rx->framer->lane0Id + 2; + LID3 = device->rx->framer->lane0Id + 3; + + CS = 0; + N = 0x0F; + Np = 0x0F; + S = 0; + CF = 0; + HD = 0; + K = device->rx->framer->K - 1; + FramerL = L - 1; + FramerM = device->rx->framer->M - 1; + FramerF = (uint8_t)(2 * device->rx->framer->M / L) - 1; + + if (ML == 11) + { + regE0 = 0x01; + regE2 = 0x01; + } + else if (ML == 12) + { + regE0 = 0x01; + regE2 = 0x03; + HD = 0x01; + } + else if (ML == 21) + { + regE0 = 0x03; + regE2 = 0x01; + } + else if (ML == 22) + { + regE0 = 0x03; + regE2 = 0x03; + } + else if (ML == 24) + { + regE0 = 0x05; + regE2 = 0x0F; + HD = 0x01; + } + else if (ML == 41) + { + regE0 = 0x0F; + regE2 = 0x01; + } + else if (ML == 42) + { + regE0 = 0x0F; + regE2 = 0x05; + } + else if (ML == 44) + { + regE0 = 0x0F; + regE2 = 0x0F; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_M_PARM)); + return MYKONOS_ERR_FRAMER_INV_M_PARM; + } + + /* setting K offset for framer */ + if (device->rx->framer->lmfcOffset < device->rx->framer->K) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LMFC_K_OFFSET, device->rx->framer->lmfcOffset); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM)); + return MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM; + } + + subaddr[0] = 0x00; + subdata[0] = (DID & 0xFF); /* Device ID */ + subaddr[1] = 0x01; + subdata[1] = (BID & 0x0F); /* Bank ID */ + subaddr[2] = 0x02; + subdata[2] = (LID0 & 0x1F); /* Lane 0 ID */ + subaddr[3] = 0x03; + subdata[3] = (uint8_t)(device->rx->framer->scramble << 7) | (FramerL & 0x1F); /* [7] Scramble, #Lanes[4:0]-1 */ + subaddr[4] = 0x04; + subdata[4] = (FramerF & 0xFF); /* F[7:0]-1 */ + subaddr[5] = 0x05; + subdata[5] = (K & 0x1F); /* K[4:0]-1 */ + subaddr[6] = 0x06; + subdata[6] = (FramerM & 0xFF); /* M[7:0]-1 */ + subaddr[7] = 0x07; + subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0]-1 */ + subaddr[8] = 0x08; + subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* NP[4:0] -1 */ + subaddr[9] = 0x09; + subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0]-1 */ + subaddr[10] = 0x0A; + subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7] = HD, CF[4:0] */ + subaddr[11] = 0x0B; + subdata[11] = 0x00; /* reserved */ + subaddr[12] = 0x0C; + subdata[12] = 0x00; /* reserved */ + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 0 */ + subaddr[13] = 0x0D; + subdata[13] = CheckSum & 0xFF; + + /* in JESD204B ML=42 case, framer ip lanes 0 and 2 are used, write lane 1 id and checksum to ip lane 2 regs */ + if (ML == 42) + { + /* Lane 1 ID */ + subaddr[14] = 0x1A; + subdata[14] = LID1; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 1 */ + subaddr[15] = 0x1D; + subdata[15] = CheckSum & 0xFF; + } + else + { + /* Lane 1 ID */ + subaddr[14] = 0x12; + subdata[14] = LID1; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 1 */ + subaddr[15] = 0x15; + subdata[15] = CheckSum & 0xFF; + + /* Lane 2 ID */ + subaddr[16] = 0x1A; + subdata[16] = LID2; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID2 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 2 */ + subaddr[17] = 0x1D; + subdata[17] = CheckSum & 0xFF; + + /* Lane 3 ID */ + subaddr[18] = 0x22; + subdata[18] = LID3; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID3 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + subaddr[19] = 0x25; + subdata[19] = CheckSum & 0xFF; + } + + subaddr[20] = 0xE0; + subdata[20] = regE0; /* Enable converter n logic */ + subaddr[21] = 0xE2; + subdata[21] = regE2; /* Enable Lane n logic */ + subaddr[22] = 0xE4; + subdata[22] = 0x00; + subaddr[23] = 0xE6; + subdata[23] = 0x00; + subaddr[24] = 0xF0; + subdata[24] = 0x00; /* #multiframes in ILAS */ + subaddr[25] = 0xF2; + subdata[25] = 0x00; + subaddr[26] = 0xF3; + subdata[26] = 0x00; + subaddr[27] = 0xF4; + subdata[27] = 0x00; + subaddr[28] = 0xC0; + subdata[28] = 0x03; /* Framer enable, both sides perform lane sync */ + + for (i = 0; i <= 28; i++) + { + /* Set framer sub register map address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADDR, subaddr[i]); + + /* Set framer sub register map data word */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_DATA, subdata[i]); + + /* Write enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_WRITE_EN, 0x01); + } + + if (device->rx->framer->externalSysref > 0) + { + /* Framer: Enable lane FIFO sync (Enable CGS) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x30); + } + else + { + /* Framer: Enable lane FIFO sync (Enable CGS) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x10); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the JESD204B OBSRX Framer + * + * Dependencies + * - device->rxChannels + * - device->spiSettings->chipSelectIndex + * - device->obsRx->framer->bankId + * - device->obsRx->framer->M + * - device->obsRx->framer->serializerLanesEnabled + * - device->obsRx->framer->externalSysref + * - device->spiSettings + * - device->obsRx->framer->deviceId + * - device->obsRx->framer->lane0Id + * - device->obsRx->framer->K + * - device->obsRx->framer->lmfcOffset + * - device->obsRx->framer->scramble + * - device->obsRx->framer->obsRxSyncbSelect + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM M parameter can only be 1 when real IF data mode is enabled + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM ObsRx Framer M parameter can only be 1 or 2 + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM Invalid BankId (0-15) + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM Invalid lane0Id (0-31) + * \retval MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM Invalid F*K value (F * K must be > 20 and divisible by 4) + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM Invalid K offset, must be less than K + */ +mykonosErr_t MYKONOS_setupJesd204bObsRxFramer(mykonosDevice_t *device) +{ + uint8_t i = 0; + uint8_t laneFifoEnable = 0; + uint8_t L = 1; + uint8_t ML = 2; + uint8_t framerConfigF = 0; + + uint8_t subaddr[29] = {0}; /* holds address to framer sub register map */ + uint8_t subdata[29] = {0}; /* holds data for framer sub register map */ + + /* Setup submap registers */ + uint8_t SUBCLASSV = 1; /* JESD subclass 1 */ + uint8_t JESDV = 1; /* Version: JESD204B */ + uint8_t DID = 0; + uint8_t BID = 0; + uint8_t LID0 = 0; + uint8_t LID1 = 1; + uint8_t LID2 = 2; + uint8_t LID3 = 3; + uint8_t CS = 0; + uint8_t N = 0x0F; + uint8_t Np = 0x0F; + uint8_t S = 0; + uint8_t CF = 0; + uint8_t K = 31; + uint8_t HD = 0; + uint8_t FramerL = 1; + uint8_t FramerM = 2; + uint8_t FramerF = 1; + uint8_t framerADC_XBar = 0xE4; + uint8_t regE0 = 0; + uint8_t regE2 = 0; + uint8_t framerLaneXbar = 0xE4; + uint16_t CheckSum = 0; + uint16_t FK = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bObsRxFramer()\n"); +#endif + + if (device->obsRx->framer->M == 1 && !(device->obsRx->realIfData)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM; + } + + if (device->obsRx->framer->M != 1 && device->obsRx->framer->M != 2) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM; + } + + if (device->obsRx->framer->bankId > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM; + } + + /* no need to check deviceId, its range is full uint8_t range */ + if (device->obsRx->framer->lane0Id > 31) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM; + } + + //count number of lanes + L = 0; + ML = 0; + + for (i = 0; i < 4; i++) + { + L += ((device->obsRx->framer->serializerLanesEnabled >> i) & 0x01); + } + + ML = (uint8_t)(device->obsRx->framer->M * 10 + L); + + if (L == 0) + { + /* Disable framer and return successfully */ + /* Disable framer clock and lane clocks */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x03, 0); + + /* Disable lane FIFO enables */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_CTL, 0, 0xF0, 4); + return MYKONOS_ERR_OK; + } + + FK = (uint16_t)(device->obsRx->framer->K * 2 * device->obsRx->framer->M / L); + if (FK < 20 || FK > 256 || FK % 4 != 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM)); + return MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM; + } + + if (device->obsRx->framer->externalSysref == 0) + { + /* Framer: Generate SYSREF internally */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_TEST_CNTR_CTL, 0x20); + } + + /* Framer: Set ADC Crossbar */ + framerADC_XBar = 0xB1; + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_ADC_XBAR_SEL, framerADC_XBar); + + if (device->obsRx->framer->enableManualLaneXbar == 1) + { + framerLaneXbar = device->obsRx->framer->serializerLaneCrossbar; + } + else + { + if (ML == 42) + { + /* uses framer outputs 0 and 2 instead of 0 and 1...fix framer lane XBar */ + /* only 2 lane cases here */ + switch ((device->obsRx->framer->serializerLanesEnabled & 0x0F)) + { + case 3: + framerLaneXbar = 0x08; + break; + case 5: + framerLaneXbar = 0x20; + break; + case 6: + framerLaneXbar = 0x20; + break; + case 9: + framerLaneXbar = 0x80; + break; + case 10: + framerLaneXbar = 0x80; + break; + case 12: + framerLaneXbar = 0x80; + break; + default: + /* default to valid setting for Lane 0 */ + framerLaneXbar = 0x08; + break; + } + } + else + { + switch ((device->obsRx->framer->serializerLanesEnabled & 0x0F)) + { + /* all 4 lanes get framer 0 output */ + case 1: + framerLaneXbar = 0x00; + break; + case 2: + framerLaneXbar = 0x00; + break; + case 3: + framerLaneXbar = 0x04; + break; + case 4: + framerLaneXbar = 0x00; + break; + case 5: + framerLaneXbar = 0x10; + break; + case 6: + framerLaneXbar = 0x10; + break; + case 8: + framerLaneXbar = 0x00; + break; + case 9: + framerLaneXbar = 0x40; + break; + case 10: + framerLaneXbar = 0x40; + break; + case 12: + framerLaneXbar = 0x40; + break; + case 15: + framerLaneXbar = 0xE4; + break; + default: + /* default to valid setting for all Lanes */ + framerLaneXbar = 0xE4; + break; + } + } + } + + /* Framer: set Lane Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_XBAR_SEL, framerLaneXbar); + + /* Framer: determine the framerConfigF value (2*M/L) */ + framerConfigF = (uint8_t)(2 * (device->obsRx->framer->M/L)); + + /* Framer: Soft Reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x03); + + /* Framer: Clear Soft Reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x00); + + /* Framer: Set F (Octets in Frame) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_F, framerConfigF); + + /* Framer: Enable framer clock and lane clocks */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0x03, 0x03, 0); + + /* Set Framer lane FIFO enable for each lane enabled */ + laneFifoEnable = (uint8_t)(((device->obsRx->framer->serializerLanesEnabled & 0x0F) << 4) | 0x01); + + /* Framer: Enable Lane FIFOs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_CTL, laneFifoEnable); + + /* enabling the SYSREF for relink if newSysrefOnRelink is set */ + if (device->obsRx->framer->newSysrefOnRelink) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6); + } + + /* enabling auto channel if the enableAutoChanXbar structure member is set */ + if (device->obsRx->framer->enableAutoChanXbar) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x01, 0x04, 2); + } + + /* Setup submap registers */ + SUBCLASSV = 1; /* JESD subclass 1 */ + JESDV = 1; /* Version: JESD204B */ + DID = device->obsRx->framer->deviceId; + BID = device->obsRx->framer->bankId; + LID0 = device->obsRx->framer->lane0Id; + LID1 = device->obsRx->framer->lane0Id + 1; + LID2 = device->obsRx->framer->lane0Id + 2; + LID3 = device->obsRx->framer->lane0Id + 3; + + CS = 0; + N = 0x0F; + Np = 0x0F; + S = 0; + CF = 0; + K = device->obsRx->framer->K - 1; + HD = 0; + FramerL = L - 1; + FramerM = device->obsRx->framer->M - 1; + FramerF = (uint8_t)((2*device->obsRx->framer->M/L) - 1); + + if (ML == 11) + { + regE0 = 0x1; + regE2 = 0x1; + } + else if (ML == 12) + { + regE0 = 0x1; + regE2 = 0x3; + HD = 1; + } + else if (ML == 21) + { + regE0 = 0x3; + regE2 = 0x1; + } + else if (ML == 22) + { + regE0 = 0x3; + regE2 = 0x3; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM; + } + + /* setting K offset for framer */ + if (device->obsRx->framer->lmfcOffset < device->rx->framer->K) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LMFC_K_OFFSET, device->obsRx->framer->lmfcOffset); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM; + } + + subaddr[0] = 0x00; + subdata[0] = (DID & 0xFF); /* Device ID */ + subaddr[1] = 0x01; + subdata[1] = (BID & 0x0F); /* Bank ID */ + subaddr[2] = 0x02; + subdata[2] = (LID0 & 0x1F); /* Lane 0 ID */ + subaddr[3] = 0x03; + subdata[3] = (uint8_t)(device->obsRx->framer->scramble << 7) | (FramerL & 0x1F); /* [7] Scramble, #Lanes[4:0]-1 */ + subaddr[4] = 0x04; + subdata[4] = (FramerF & 0xFF); /* F[7:0]-1 */ + subaddr[5] = 0x05; + subdata[5] = (K & 0x1F); /* K[4:0]-1 */ + subaddr[6] = 0x06; + subdata[6] = (FramerM & 0xFF); /* M[7:0]-1 */ + subaddr[7] = 0x07; + subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0]-1 */ + subaddr[8] = 0x08; + subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* NP[4:0] -1 */ + subaddr[9] = 0x09; + subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0]-1 */ + subaddr[10] = 0x0a; + subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7] = HD, CF[4:0] */ + subaddr[11] = 0x0b; + subdata[11] = 0x00; /* reserved */ + subaddr[12] = 0x0c; + subdata[12] = 0x00; /* reserved */ + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 0 */ + subaddr[13] = 0x0d; + subdata[13] = CheckSum & 0xFF; + + /* Lane 1 ID */ + subaddr[14] = 0x12; + subdata[14] = LID1; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 1 */ + subaddr[15] = 0x15; + subdata[15] = CheckSum & 0xFF; + + /* Lane 2 ID */ + subaddr[16] = 0x1a; + subdata[16] = LID2; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID2 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + /* Checksum Lane 2 */ + subaddr[17] = 0x1d; + subdata[17] = CheckSum & 0xFF; + + /* Lane 3 ID */ + subaddr[18] = 0x22; + subdata[18] = LID3; + + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID3 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + + subaddr[19] = 0x25; + subdata[19] = CheckSum & 0xFF; + + subaddr[20] = 0xe0; + subdata[20] = regE0; /* Enable converter n logic */ + subaddr[21] = 0xe2; + subdata[21] = regE2; /* Enable Lane n logic */ + subaddr[22] = 0xe4; + subdata[22] = 0x00; + subaddr[23] = 0xe6; + subdata[23] = 0x00; + subaddr[24] = 0xf0; + subdata[24] = 0x00; /* #multiframes in ILAS */ + subaddr[25] = 0xf2; + subdata[25] = 0x00; + subaddr[26] = 0xf3; + subdata[26] = 0x00; + subaddr[27] = 0xf4; + subdata[27] = 0x00; + subaddr[28] = 0xc0; + subdata[28] = 0x03; /* Framer enable, both sides perform lane sync */ + + for (i = 0; i <= 28; i++) + { + /* Set framer sub register map address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_ADDR, subaddr[i]); + + /* Set framer sub register map data word */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_DATA, subdata[i]); + + /* Write enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_WRITE_EN, 0x01); + } + + if (device->obsRx->framer->externalSysref > 0) + { + /* Framer: Enable lane FIFO sync (Enable CGS) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x30); + } + else + { + /* Framer: Enable lane FIFO sync (Enable CGS) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x10); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables/Disables the JESD204B Rx Framer + * + * This function is normally not necessary. In the event that the link needs to be reset, this + * function allows the Rx framer to be disabled and re-enabled. + * + * Dependencies + * - device->spiSettings + * - device->rx->framer->serializerLanesEnabled + * + * \param device is a pointer to the device settings structure + * \param enable 0 = Disable the selected framer, 1 = enable the selected framer link + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM Invalid serializerLanesEnabled parameter in device data structure + */ +mykonosErr_t MYKONOS_enableRxFramerLink(mykonosDevice_t *device, uint8_t enable) +{ + uint8_t enableLink = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableFramerLink()\n"); +#endif + + enableLink = (enable > 0) ? 1 : 0; + + if (enableLink) + { + /* Power Up serializer lanes */ + if (device->rx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM)); + return MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, ((~device->rx->framer->serializerLanesEnabled) & 0x0F), + device->rx->framer->serializerLanesEnabled, 0); + + /* Enable Clocks to Framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 3, 0x03, 0); + + /* Release reset to framer and lane FIFOs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x00); + } + else + { + /* Disable Link */ + /* Hold Rx framer in reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x03); + + /* Disable Clocks to Framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0, 0x03, 0); + + /* Power down serializer lanes */ + if (device->rx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM)); + return MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, device->rx->framer->serializerLanesEnabled, device->rx->framer->serializerLanesEnabled, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables/Disables the JESD204B ObsRx Framer + * + * This function is normally not necessary. In the event that the link needs to be reset, this + * function allows the ObsRx framer to be disabled and re-enabled. + * + * Dependencies + * - device->spiSettings + * - device->obsRx->framer->serializerLanesEnabled + * + * \param device is a pointer to the device settings structure + * \param enable 0 = Disable the selected framer, 1 = enable the selected framer link + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM Invalid serializerLanesEnabled parameter in device data structure (Valid 0-15) + */ +mykonosErr_t MYKONOS_enableObsRxFramerLink(mykonosDevice_t *device, uint8_t enable) +{ + uint8_t enableLink = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxFramerLink()\n"); +#endif + + enableLink = (enable > 0) ? 1 : 0; + + if (enableLink) + { + /* Power Up serializer lanes */ + if (device->rx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM)); + return MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, ((~device->obsRx->framer->serializerLanesEnabled) & 0x0F), + device->obsRx->framer->serializerLanesEnabled, 0); + + /* Enable Clocks to Framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 3, 0x03, 0); + + /* Release reset to framer and lane FIFOs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x00); + } + else + { + /* Disable Link */ + /* Hold Rx framer in reset */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x03); + + /* Disable Clocks to Framer */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x03, 0); + + /* Power down serializer lanes */ + if (device->obsRx->framer->serializerLanesEnabled > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM)); + return MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, device->obsRx->framer->serializerLanesEnabled, + device->obsRx->framer->serializerLanesEnabled, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the JESD204B Deframer + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->tx->deframer->M + * - device->tx->deframer->bankId + * - device->tx->deframer->lane0Id + * - device->tx->deframer->K + * - device->tx->deframer->deserializerLanesEnabled + * - device->tx->deframer->externalSysref + * - device->tx->deframer->newSysrefOnRelink + * - device->tx->deframer->enableAutoChanXbar + * - device->tx->deframer->lmfcOffset + * - device->tx->deframer->scramble + * + * \param device Pointer to device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_DEFRAMER_INV_M_PARM Invalid M parameter in deframer structure + * \retval MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM Invalid BankId parameter in deframer structure (Valid 0-15) + * \retval MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM Invalid Lane0Id parameter in deframer structure (Valid 0-31) + * \retval MYKONOS_ERR_DEFRAMER_INV_K_PARAM Invalid K parameter in deframer structure (valid 1-32 with other constraints) + * \retval MYKONOS_ERR_DEFRAMER_INV_FK_PARAM Invalid F*K parameter (Valid F*K > 20, F*K must be divisible by 4), K must be <= 32 + * \retval MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM Invalid K offset parameter in deframer structure (must be less than K) + */ +mykonosErr_t MYKONOS_setupJesd204bDeframer(mykonosDevice_t *device) +{ + uint8_t i = 0; + uint8_t temp = 0; + uint8_t reg080 = 0; + uint8_t laneXbar = 0; + uint8_t L = 0; + uint8_t ML = 0; + + /* Setup submap registers */ + uint8_t SUBCLASSV = 1; + uint8_t JESDV = 1; + uint8_t DID = 0; + uint8_t BID = 0; + uint8_t LID0 = 0; + uint8_t CS = 2; /* 2 control bits */ + uint8_t N = 0x0D; /* 14 bits */ + uint8_t Np = 0x0F; /* 16 bits */ + uint8_t S = 0; + uint8_t CF = 0; + uint8_t K = 0x1F; + uint16_t FK = 0; + uint8_t HD = 0; /* only one case has HD == 1 */ + uint8_t CTRLREG0 = 0; + uint8_t DeframerL = 1; + uint8_t DeframerM = 2; + uint8_t DeframerF = 0; + uint8_t CTRLREG1 = 0; + uint8_t CTRLREG2 = 0; + uint8_t DeframerLaneEnable = 0x00; + uint16_t CheckSum = 0; + uint8_t subaddr[25] = {0}; + uint8_t subdata[25] = {0}; + + uint8_t deframerInput = 0; + uint8_t lane = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bDeframer()\n"); +#endif + + if (device->tx->deframer->M != 0 && device->tx->deframer->M != 2 && device->tx->deframer->M != 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_M_PARM)); + return MYKONOS_ERR_DEFRAMER_INV_M_PARM; + } + + if (device->tx->deframer->bankId > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM)); + return MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM; + } + + if (device->tx->deframer->lane0Id > 31) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM)); + return MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM; + } + + //count number of lanes + L = 0; + ML = 0; + + for (i = 0; i < 4; i++) + { + L += ((device->tx->deframer->deserializerLanesEnabled >> i) & 0x01); + } + + ML = (uint8_t)(device->tx->deframer->M * 10 + L); + + if (device->tx->deframer->K > 32) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_K_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_K_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_K_PARAM; + } + + FK = (uint16_t)(device->tx->deframer->K * 2 * device->tx->deframer->M / L); + + if (FK < 20 || FK > 256 || FK % 4 != 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_FK_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_FK_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_FK_PARAM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYNC_REQ_RETIME, (device->tx->deframer->K - 1), 0x1F, 0x00); + + if (!device->tx->deframer->externalSysref) + { + /* Deframer: Generate SYSREF internally */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_TEST, 0x02); + } + + /* enabling the SYSREF for relink if newSysrefOnRelink is set */ + if (device->tx->deframer->newSysrefOnRelink) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6); + } + + /* enabling auto channel if the enableAutoChanXbar structure member is set */ + if (device->tx->deframer->enableAutoChanXbar) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_STRT_DAC_XBAR_REV, 0x01, 0x04, 2); + } + + /* Fix bad default bit to allow deterministic latency on deframer (Clear bit 4)*/ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_STRT_DAC_XBAR_REV, 0x00, 0x10, 4); + + /* Deframer: Set DAC Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DAC_XBAR_SEL, 0xB1); + + if (device->tx->deframer->enableManualLaneXbar == 1) + { + laneXbar = device->tx->deframer->deserializerLaneCrossbar; + } + else + { + /* Lane crossbar - Allow user to reorder lanes in deframer->deserializerLaneCrossbar, but this code still */ + /* maps used lanes to deframer inputs */ + deframerInput = 0; + for (lane = 0; lane < 4; lane++) + { + if ((device->tx->deframer->deserializerLanesEnabled >> lane) & 1) + { + laneXbar |= (uint8_t)(((device->tx->deframer->deserializerLaneCrossbar >> (lane << 1)) & 3) << (deframerInput << 1)); + deframerInput += 1; + } + } + + if (ML == 42) + { + /* M4L2 uses internal deframer ports 0 and 2 */ + /* swap bits 3:2 and 5:4, keep 1:0 and 7:6 in place */ + laneXbar = (laneXbar & 0xC3U) | ((laneXbar & 0x30) >> 2) | ((laneXbar & 0x0C) << 2); + } + } + + /* Deframer: Set Lane Crossbar */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_XBAR_SEL, laneXbar); + + //Find value for Framer F depending on M and L + switch (ML) + { + case 21: + reg080 = 0x04; + break; + case 22: + reg080 = 0x22; + break; + case 24: + reg080 = 0x41; + break; + case 41: + reg080 = 0x18; + break; + case 42: + reg080 = 0x34; + break; + case 44: + reg080 = 0x52; + break; + default: + reg080 = 0x04; + break; + } + + /* Deframer: Set F (Octets in Frame) */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CONFIG_F, reg080); + + /* Deframer: Enable clocks and lane clocks */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CLK_EN, 0x03); + + /* Set deframer lane FIFO enable for each lane enabled */ + temp = (device->tx->deframer->deserializerLanesEnabled & 0x0F); + + /* Deframer: Enable Lane FIFOs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_FIFO_CTL, temp); + + /* Setup submap registers */ + SUBCLASSV = 1; /* JESD subclass 1 */ + JESDV = 1; /* Version: JESD204B */ + DID = device->tx->deframer->deviceId; + BID = device->tx->deframer->bankId; + LID0 = device->tx->deframer->lane0Id; + CS = 2; /* 2 control bits */ + N = 0x0D; /* 14 bits */ + Np = 0x0F; + S = 0; + CF = 0; + K = device->tx->deframer->K - 1; + HD = 0; /* only one case has HD = 1 */ + CTRLREG0 = 1; + DeframerL = L - 1; + DeframerM = device->tx->deframer->M - 1; + DeframerF = (uint8_t)((2*device->tx->deframer->M/L) - 1); + CheckSum = 0; + + if (ML == 21) + { + CTRLREG1 = 4; + CTRLREG2 = 0x14; + DeframerLaneEnable = 1; + } + else if (ML == 22) + { + CTRLREG1 = 2; + CTRLREG2 = 4; + DeframerLaneEnable = 3; + } + else if (ML == 24) + { + HD = 1; + CTRLREG1 = 1; + CTRLREG2 = 0; + DeframerLaneEnable = 0x0F; + } + else if (ML == 41) + { + CTRLREG1 = 8; + CTRLREG2 = 0; + DeframerLaneEnable = 1; + } + else if (ML == 42) + { + CTRLREG1 = 4; + CTRLREG2 = 0; + DeframerLaneEnable = 5; + } + else if (ML == 44) + { + CTRLREG1 = 2; + CTRLREG2 = 0; + DeframerLaneEnable = 0x0F; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_M_PARM)); + return MYKONOS_ERR_DEFRAMER_INV_M_PARM; + } + + /* LMFC offset limit check */ + if (device->tx->deframer->lmfcOffset < device->tx->deframer->K) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LMFC_K_OFFSET, device->tx->deframer->lmfcOffset); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM; + } + + subaddr[0] = 0x50; + subdata[0] = DID & 0xFFU; /* Device ID */ + subaddr[1] = 0x51; + subdata[1] = BID & 0x0F; /* Bank ID */ + subaddr[2] = 0x52; + subdata[2] = LID0 & 0x1F; /* Lane 0 ID */ + subaddr[3] = 0x53; + subdata[3] = (uint8_t)(device->tx->deframer->scramble << 7) | (DeframerL & 0x1F); /* [7] = Scramble Enable, #Lanes[4:0] */ + subaddr[4] = 0x54; + subdata[4] = DeframerF & 0xFFU; /* F[7:0] */ + subaddr[5] = 0x55; + subdata[5] = K & 0x1F; /* K[4:0] */ + subaddr[6] = 0x56; + subdata[6] = DeframerM & 0xFFU; /* M[7:0] */ + subaddr[7] = 0x57; + subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0] */ + subaddr[8] = 0x58; + subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* Np[4:0] */ + subaddr[9] = 0x59; + subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0] */ + subaddr[10] = 0x5A; + subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7]=HD, CF[4:0] */ + subaddr[11] = 0x5B; + subdata[11] = 0x00; /* reserved */ + subaddr[12] = 0x5C; + subdata[12] = 0x00; /* reserved */ + CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->tx->deframer->scramble) + (DeframerL & 0x1F) + (DeframerF & 0xFF) + (K & 0x1F) + (DeframerM & 0xFF) + + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7); + subaddr[13] = 0x5D; + subdata[13] = CheckSum & 0xFFU; /* Checksum Lane 0 */ + subaddr[14] = 0x6D; + subdata[14] = 0xA0U; /* Bad Disparity setup */ + subaddr[15] = 0x6E; + subdata[15] = 0xA0U; /* Not in Table setup */ + subaddr[16] = 0x6F; + subdata[16] = 0xA0U; /* UnExpected K character setup */ + subaddr[17] = 0x75; + subdata[17] = CTRLREG0; /* CTRLREG 0 */ + subaddr[18] = 0x76; + subdata[18] = CTRLREG1; /* CTRLREG 1 (Bytes per frame) */ + subaddr[19] = 0x77; + subdata[19] = CTRLREG2; /* CTRLREG 2 */ + subaddr[20] = 0x78; + subdata[20] = 0x01; /* # 4*K multiframes during ILAS */ + subaddr[21] = 0x7A; + subdata[21] = 0xE0U; /* Setup JESD interrupt sources */ + subaddr[22] = 0x7B; + subdata[22] = 0x08U; /* Sync assertion setup */ + subaddr[23] = 0x7C; + subdata[23] = 0xFFU; /* Error count threshold */ + subaddr[24] = 0x7D; + subdata[24] = DeframerLaneEnable & 0xFFU; /* Lane enable */ + + for (i = 0; i <= 24; i++) + { + /* Set deframer sub-register map address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, subaddr[i]); + + /* Set deframer sub-register map data word */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, subdata[i]); + + /* Set write enable to latch data into deframer sub register map */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_WR_EN, 0x01); + } + + /* Deframer: Enable lane FIFO sync */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x10, 4); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets up the chip for multichip sync, and cleans up after MCS. + * + * When working with multiple transceivers or even only one transceiver that requires deterministic + * latency between the Tx and observation and or main Rx JESD204B data path, Multichip sync is + * necessary. This function should be run after all transceivers are initialized. + * + * After the SYSREF pulses have been sent, call the MYKONOS_enableMultichipSync() function again with the + * enableMcs parameter set to 0. When enableMcs = 0, the MCS status will be returned in the mcsStatus + * parameter. + * + * Typical sequence: + * 1) Initialize all Mykonos devices in system using MYKONOS_initialize() + * 2) Run MYKONOS_enableMultichipSync with enableMcs = 1 + * 3) Send at least 3 SYSREF pulses + * 4) Run MYKONOS_enableMultichipSync with enableMcs = 0 + * 5) Load ARM, run ARM cals and continue to active Transmit/Receive + * + * mcsStatus | bit Description + * -----------|-------------------------------------------------------- + * [0] | MCS JESD SYSREF Status (1 = sync occurred) + * [1] | MCS Digital Clocks Sync Status (1 = sync occurred) + * [2] | MCS CLKPLL SDM Sync Status (1 = sync occurred) + * [3] | MCS Device Clock divider Sync Status (1 = sync occurred) + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param enableMcs =1 will enable the MCS state machine, =0 will allow reading back MCS status + * \param mcsStatus optional parameter, if pointer is not null the function Which will be populated with the mcsStatus word described in the table above. + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableMultichipSync(mykonosDevice_t *device, uint8_t enableMcs, uint8_t *mcsStatus) +{ + uint8_t clkPllSdmBypass = 0; + uint8_t mcsEnable = 0x9B; /* [7] Keeps RF LO divider enabled, Enable MCS[4] and reset Device Clock divider[3], Digital clocks[1], and JESD204 SYSREF[0] */ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableMultichipSync()\n"); +#endif + + if (enableMcs) + { + /* If CLKPLL SDM not bypassed, reset CLKPLL SDM as well. */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, &clkPllSdmBypass, 0x40, 6); + + if (clkPllSdmBypass == 0) + { + mcsEnable |= 0x04; /* enable MCS for CLKPLL SDM */ + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_MCS_CONTROL, mcsEnable); + } + + /* if mcsStatus is a valid pointer, return the MCS status */ + if (mcsStatus != NULL) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_MCS_STATUS, mcsStatus); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables or disables SYSREF to the transceiver's RX framer + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param enable = '1' enables SYSREF to RX framer, '0' disables SYSREF to framer + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableSysrefToRxFramer(mykonosDevice_t *device, uint8_t enable) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToRxFramer()\n"); +#endif + + if (enable) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0); + } + else + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables or disables SYSREF to the transceiver's Observation RX framer + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param enable = '1' enables SYSREF to OBSRX framer, '0' disables SYSREF to framer + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableSysrefToObsRxFramer(mykonosDevice_t *device, uint8_t enable) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToObsRxFramer()\n"); +#endif + + if (enable) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0); + } + else + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enables or disables SYSREF to the transceiver's deframer + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param enable = '1' enables SYSREF to deframer, '0' disables SYSREF to deframer + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_enableSysrefToDeframer(mykonosDevice_t *device, uint8_t enable) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToDeframer()\n"); +#endif + + if (enable) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0); + } + else + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the transceiver's RX framer status + * + * Dependencies + * - device->spiSettings + * + * framerStatus | Description + * -------------|----------------------------------------------------------------------------- + * [7] | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing. + * [6] | Framer lane FIFO read/write pointer delta has changed. Can help debug issues with deterministic latency. + * [5] | Framer has received the SYSREF and has retimed its LMFC + * [4:2] | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete + * [1:0] | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data + * + * \param device is a pointer to the device settings structure + * \param framerStatus is the RX framer status byte read + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM Function parameter framerStatus has NULL pointer + */ +mykonosErr_t MYKONOS_readRxFramerStatus(mykonosDevice_t *device, uint8_t *framerStatus) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readRxFramerStatus()\n"); +#endif + + if (framerStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM)); + return MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS_STRB, 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS_STRB, 0x00); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS, framerStatus); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the transceiver's Observation RX framer status + * + * Dependencies + * * - device->spiSettings + * + * obsFramerStatus | Description + * ----------------|----------------------------------------------------------------------------- + * [7] | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing. + * [6] | Framer lane FIFO read/write pointer delta has changed. Can help debug issues with deterministic latency. + * [5] | Framer has received the SYSREF and has retimed its LMFC + * [4:2] | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete + * [1:0] | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data + * + * \param device is a pointer to the device settings structure + * \param obsFramerStatus is the OBSRX framer status byte read + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM Function parameter obsFramerStatus has NULL pointer + */ +mykonosErr_t MYKONOS_readOrxFramerStatus(mykonosDevice_t *device, uint8_t *obsFramerStatus) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readOrxFramerStatus()\n"); +#endif + + if (obsFramerStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM)); + return MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS_STRB, 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS_STRB, 0x00); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS, obsFramerStatus); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the transceiver's deframer status + * + * Dependencies + * - device->spiSettings + * + * deframerStatus | Bit Name | Description + * ----------------|--------------------------|--------------------------------------------- + * [7] | Unused | Unused + * [6] | Deframer IRQ | This bit indicates that the IRQ interrupt was asserted. + * [5] | Deframer SYSREF Received | When this bit is set, it indicates that the SYSREF pulse was received by the deframer IP + * [4] | Deframer Receiver Error | This bit is set when PRBS has received an error. + * [3] | Valid Checksum | This bit is set when the received ILAS checksum is valid. + * [2] | EOF Event | This bit captures the internal status of the framer End of Frame event. Value =1 if framing error during ILAS + * [1] | EOMF Event | This bit captures the internal status of the framer End of Multi-Frame event. Value =1 if framing error during ILAS + * [0] | FS Lost | This bit captures the internal status of the framer Frame Symbol event. Value =1 if framing error during ILAS or user data (invalid replacement characters) + * + * + * \param device is a pointer to the device settings structure + * \param deframerStatus is the deframer status byte read + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM Function parameter deframerStatus has NULL pointer + */ +mykonosErr_t MYKONOS_readDeframerStatus(mykonosDevice_t *device, uint8_t *deframerStatus) +{ + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readDeframerStatus()\n"); +#endif + + if (deframerStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM)); + return MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x00); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT, deframerStatus); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the Mykonos JESD204b Deframer determinstic FIFO depth + * + * To verify that the deterministic latency FIFO is not close to a underflow or + * overflow condition, it is recommended to check the FIFO depth. If the FIFO + * is close to an overflow or underflow condition, it is possible that from + * power up to powerup, deterministic latency may not be met. If a underflow + * or overflow occurred, the data would still be correct, but would possibly + * slip by 1 multiframe (losing deterministic latency). To correct for an + * overflow/underflow, the BBIC would need to add delay from SYSREF until + * the first symbol in a multiframe + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param fifoDepth Return value that describes the depth of the Mykonos + * deterministic latency deframer FIFO. + * \param readEnLmfcCount Returns the LMFC count value when the deterministic FIFO read enable was asserted. + * Counts at the Mykonos internal deframer PCLK frequency. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM Error: function parameter fifoDepth is a NULL pointer + * \retval MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM Error: function parameter readEnLmfcCount is a NULL pointer + * + */ +mykonosErr_t MYKONOS_getDeframerFifoDepth(mykonosDevice_t *device, uint8_t *fifoDepth, uint8_t *readEnLmfcCount) +{ + uint8_t fifoReadPtr = 0; + uint8_t fifoWritePtr = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDeframerFifoDepth()\n"); +#endif + + if (fifoDepth == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM)); + return MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM; + } + + if (readEnLmfcCount == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM)); + return MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x00); + + /* read/write pointers are 7 bits, (0 - 127) */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_RD_ADDR, &fifoReadPtr, 0x7F, 0); + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_ADDR, &fifoWritePtr, 0x7F, 0); + + /* Adding 128 and modulus 128 handle the wrap cases where the read pointer + * is less than write pointer + */ + *fifoDepth = (((fifoWritePtr + 128) - fifoReadPtr) % 128); + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_PHASE, readEnLmfcCount); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Selects the PRBS type and enables or disables RX Framer PRBS20 generation + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param polyOrder selects the PRBS type based on a two-bit value range from 0-3 + * \param enable '1' = enables PRBS RX framer PRBS generator, '0' = disables PRBS generator + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM Invalid polyOrder parameter, use ENUM + * + */ +mykonosErr_t MYKONOS_enableRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable) +{ + uint8_t wrmask = 0; + uint8_t enableBit = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableRxFramerPrbs()\n"); +#endif + + enableBit = (enable > 0) ? 1 : 0; + + if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31)) + { + wrmask = ((uint8_t)polyOrder << 1) | enableBit; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM)); + return MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, wrmask); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Selects the PRBS type and enables or disables OBSRX Framer PRBS20 generation + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param polyOrder selects the PRBS type based on a two-bit value range from 0-3 + * \param enable '1' = enables PRBS OBSRX framer PRBS generator, '0' = disables PRBS generator + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM polyOrder parameter is not a valid value - use ENUM + */ +mykonosErr_t MYKONOS_enableObsRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable) +{ + uint8_t wrmask = 0; + uint8_t enableBit = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxFramerPrbs()\n"); +#endif + + enableBit = (enable > 0) ? 1 : 0; + + if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31)) + { + wrmask = ((uint8_t)polyOrder << 1) | enableBit; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM)); + return MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, wrmask); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Injects a PRBS error into the RX data path + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_rxInjectPrbsError(mykonosDevice_t *device) +{ + uint8_t prbsControl = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_rxInjectPrbsError()\n"); +#endif + + /* reading current PRBS20 control register contents */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, &prbsControl); + + /* setting bit 4 in framer PRBS20 control register and then clearing it for error injection */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, prbsControl |= 0x10); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, prbsControl &= ~0x10); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Initiates a PRBS error injection into the Observation RX data path + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_obsRxInjectPrbsError(mykonosDevice_t *device) +{ + uint8_t prbsControl = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_obsRxInjectPrbsError()\n"); +#endif + + /* reading current PRBS20 control register contents */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, &prbsControl); + + /* setting bit 4 in framer PRBS20 control register and then clearing it for error injection */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, prbsControl |= 0x10); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, prbsControl &= ~0x10); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Configures and enables or disables the transceiver's deframer PRBS checker + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param lanes selects the lane for PRBS checking based on a 4-bit mask, where each weighted bit + * corresponds with a different lane selection as such: '1' = lane 0, '2' = lane 1, '4' = lane 2, '8' = lane 3 + * \param polyOrder selects the PRBS type based on enum values (MYK_PRBS7, MYK_PRBS15, MYK_PRBS31) + * \param enable '1' = enables checking, '0' = disables checking + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM Invalid polyOrder parameter - use ENUM + * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM Invalid enable (valid 0-1) or lanes (valid 0-15) parameter + */ +mykonosErr_t MYKONOS_enableDeframerPrbsChecker(mykonosDevice_t *device, uint8_t lanes, mykonosPrbsOrder_t polyOrder, uint8_t enable) +{ + uint8_t wrmask = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableDeframerPrbsChecker()\n"); +#endif + + if ((enable <= 0x01) && (lanes <= 0x0F)) + { + if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31)) + { + wrmask = ((lanes << 4) | ((uint8_t)polyOrder << 1) | enable); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM; + } + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, wrmask); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the deframer PRBS counters + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * \param counterSelect selects the PRBS error counter to be read based on values between 0-3 + * If counterSelect exceeds this value an error is thrown. + * + * \param prbsErrorCount is return value after reading the PRBS error count + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM Function parameter prbsErrorCount has NULL pointer + * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM if counterSelect is out of bounds + */ +mykonosErr_t MYKONOS_readDeframerPrbsCounters(mykonosDevice_t *device, uint8_t counterSelect, uint32_t *prbsErrorCount) +{ + uint8_t wrmask = 0x00; + uint8_t errorCnt[3] = {0}; + const uint8_t COUNTER_SATURATE = 0x40; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readDeframerPrbsCounters()\n"); +#endif + + if (prbsErrorCount == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM)); + return MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM; + } + + if (counterSelect & ~0x03) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM)); + return MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM; + } + else + { + wrmask = (uint8_t)(COUNTER_SATURATE | (counterSelect << 4)); + *prbsErrorCount = 0x00000000; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask |= 0x01); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask &= ~0x01); + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_7_TO_0, &errorCnt[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_15_TO_8, &errorCnt[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_23_TO_16, &errorCnt[2]); + + *prbsErrorCount = (uint32_t)(errorCnt[2] << 16) | (uint32_t)(errorCnt[1] << 8) | (uint32_t)(errorCnt[0]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Clears the deframer/deserializer PRBS counters + * + * Dependencies + * - device->spiSettings + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_clearDeframerPrbsCounters(mykonosDevice_t *device) +{ + uint8_t spiReg = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_clearDeframerPrbsCounters()\n"); +#endif + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, &spiReg); + spiReg &= ~0x08; //make sure PRBS clear bit is 0 + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, (spiReg | 0xF8)); //clear counters for all lanes + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, spiReg); //set reg back to previous value + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the lane 0 JESD204B deframer configuration and compares it against the ILAS received values + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param mismatch [15-0] is a bit-encoded word which for mismatch[15] = '0' = no mismatch, '1' = mismatch for one or more parameters + * mismatch bits [14-0] are aligned with the mykonosJesd204bLane0Config_t structure members starting at '0' = DID. The aligned bit is set to + * '1' if the configuration parameter does not agree with its corresponding received ILAS value, otherwise '0' if they agree. + * + * The bit assignments for the 16-bit word are: + * mismatch | bit description + * -----------|-------------------------------------------------------- + * [0] | JESD204B DID: device ID + * [1] | JESD204B BID: bank ID + * [2] | JESD204B LID0: lane ID + * [3] | JESD204B L: lanes per data converter + * [4] | JESD204B SCR: scramble setting + * [5] | JESD204B F: octets per frame + * [6] | JESD204B K: frames per multiframe + * [7] | JESD204B M: number of data converters + * [8] | JESD204B N: data converter sample resolution + * [9] | JESD204B CS: number of control bits transferred per sample per frame + * [10] | JESD204B NP: JESD204B word size based on the highest data converter resolution + * [11] | JESD204B S: number of samples per converter per frame + * [12] | JESD204B CF: '0' = control bits appended to each sample, '1' = control bits appended to end of frame + * [13] | JESD204B HD: high density bit, where '0' = samples are contained with single lane, '1' = samples are divided over more than one lane + * [14] | JESD204B FCHK0: configuration checksum OK bit. where '1' = fail, '0' = pass + * [15] | MISMATCH DETECTED BIT: bits 0-14 are ored together to set this bit + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM Function parameter mismatch has NULL pointer + */ +mykonosErr_t MYKONOS_jesd204bIlasCheck(mykonosDevice_t *device, uint16_t *mismatch) +{ + uint8_t i = 0; + uint8_t ilasdata[15] = {0}; + uint8_t cfgdata[15] = {0}; + mykonosJesd204bLane0Config_t lane0ILAS; + mykonosJesd204bLane0Config_t lane0Cfg; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_jesd204bIlasCheck()\n"); +#endif + + if (mismatch == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM)); + return MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM; + } + + *mismatch = 0; + + /* setting deframer read received ILAS data */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_WR_EN, 0x00); + + /* reading deframer received ILAS register contents into array */ + for (i = 0; i < 15; i++) + { + /* setting the deframer sub-address for received ilas data */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_RECVD + i); + + /* reading the received ILAS data into byte array */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, &ilasdata[i]); + } + + /* reading deframer config register contents into array */ + for (i = 0; i < 15; i++) + { + /* setting the deframer sub-address for received ilas data */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_CFG + i); + + /* reading the received ILAS data into byte array */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, &cfgdata[i]); + } + + /* loading the structures with the read values for easier reading when doing compares */ + lane0ILAS.DID = ilasdata[0]; + lane0ILAS.BID = ilasdata[1] & 0x0F; + lane0ILAS.LID0 = ilasdata[2] & 0x1F; + lane0ILAS.L = ilasdata[3] & 0x1F; + lane0ILAS.SCR = ilasdata[3] >> 7; + lane0ILAS.F = ilasdata[4]; + lane0ILAS.K = ilasdata[5] & 0x1F; + lane0ILAS.M = ilasdata[6]; + lane0ILAS.N = ilasdata[7] & 0x1F; + lane0ILAS.CS = ilasdata[7] >> 6; + lane0ILAS.NP = ilasdata[8] & 0x1F; + lane0ILAS.S = ilasdata[9] & 0x1F; + lane0ILAS.CF = ilasdata[10] & 0x1F; + lane0ILAS.HD = ilasdata[10] >> 7; + lane0ILAS.FCHK0 = ilasdata[13]; + + lane0Cfg.DID = cfgdata[0]; + lane0Cfg.BID = cfgdata[1] & 0x0F; + lane0Cfg.LID0 = cfgdata[2] & 0x0F; + lane0Cfg.L = cfgdata[3] & 0x1F; + lane0Cfg.SCR = cfgdata[3] >> 7; + lane0Cfg.F = cfgdata[4]; + lane0Cfg.K = cfgdata[5] & 0x1F; + lane0Cfg.M = cfgdata[6]; + lane0Cfg.N = cfgdata[7] & 0x1F; + lane0Cfg.CS = cfgdata[7] >> 6; + lane0Cfg.NP = cfgdata[8] & 0x1F; + lane0Cfg.S = cfgdata[9] & 0x1F; + lane0Cfg.CF = cfgdata[10] & 0x1F; + lane0Cfg.HD = cfgdata[10] >> 7; + lane0Cfg.FCHK0 = cfgdata[13]; + + /* performing ILAS mismatch check */ + if (lane0ILAS.DID != lane0Cfg.DID) + { + *mismatch |= 0x0001; + } + + if (lane0ILAS.BID != lane0Cfg.BID) + { + *mismatch |= 0x0002; + } + + if (lane0ILAS.LID0 != lane0Cfg.LID0) + { + *mismatch |= 0x0004; + } + + if (lane0ILAS.L != lane0Cfg.L) + { + *mismatch |= 0x0008; + } + + if (lane0ILAS.SCR != lane0Cfg.SCR) + { + *mismatch |= 0x0010; + } + + if (lane0ILAS.F != lane0Cfg.F) + { + *mismatch |= 0x0020; + } + + if (lane0ILAS.K != lane0Cfg.K) + { + *mismatch |= 0x0040; + } + + if (lane0ILAS.M != lane0Cfg.M) + { + *mismatch |= 0x0080; + } + + if (lane0ILAS.N != lane0Cfg.N) + { + *mismatch |= 0x0100; + } + + if (lane0ILAS.CS != lane0Cfg.CS) + { + *mismatch |= 0x0200; + } + + if (lane0ILAS.NP != lane0Cfg.NP) + { + *mismatch |= 0x0400; + } + + if (lane0ILAS.S != lane0Cfg.S) + { + *mismatch |= 0x0800; + } + + if (lane0ILAS.CF != lane0Cfg.CF) + { + *mismatch |= 0x1000; + } + + if (lane0ILAS.HD != lane0Cfg.HD) + { + *mismatch |= 0x2000; + } + + if (lane0ILAS.FCHK0 != lane0Cfg.FCHK0) + { + *mismatch |= 0x4000; + } + + if (*mismatch) + { + *mismatch |= 0x8000; + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_JESD204B_ILAS_MISMATCH, + getMykonosErrorMessage(MYKONOS_ERR_JESD204B_ILAS_MISMATCH)); + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Select data to inject into the Rx framer input (ADC data or Loopback data from deframer output) + * + * This function allows inputting deframed data (IQ samples) from the Tx data path into the Rx framer. + * For this to work correctly, the IQ data rate of the Tx data path must match the Rx IQ data rate. + * Framer/Deframer JESD204 config parameters can vary as long as the Rx and Tx IQ rates match. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device A pointer to the device settings structure + * \param dataSource 0 = ADC data at Rx Framer input, 1 = Deframed Tx JESD204 IQ samples input into Rx framer + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource) +{ + uint8_t enableLoopBack = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxFramerDataSource()\n"); +#endif + + enableLoopBack = (dataSource > 0) ? 1 : 0; + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, enableLoopBack, 0x10, 4); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Select data to inject into the ObsRx framer input (ADC data or Loopback data from deframer output) + * + * This function allows inputting deframed data (IQ samples) from the Tx data path into the Obs Rx framer. + * For this to work correctly, the IQ data rate of the Tx data path must match the ORx IQ data rate. + * Framer/Deframer JESD204 config parameters can vary as long as the Obs Rx and Tx IQ rates match. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device A pointer to the device settings structure + * \param dataSource 0 = ADC data at ObsRx Framer input, 1 = Deframed Tx JESD204 IQ samples input into Obs Rx framer + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setObsRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource) +{ + uint8_t enableLoopBack = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxFramerDataSource()\n"); +#endif + + enableLoopBack = (dataSource > 0) ? 1 : 0; + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_LOOPBACK_XBAR_REV, enableLoopBack, 0x10, 4); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Runs the Mykonos initialization calibrations + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * ENUM mykonosInitCalibrations_t can be used to OR together to generate the calMask parameter. + * + * calMask Bit | Calibration + * ------------|---------------------- + * 0 | Tx BB Filter + * 1 | ADC Tuner + * 2 | TIA 3dB Corner + * 3 | DC Offset + * 4 | Tx Attenuation Delay + * 5 | Rx Gain Delay + * 6 | Flash Cal + * 7 | Path Delay + * 8 | Tx LO Leakage Internal + * 9 | Tx LO Leakage External + * 10 | Tx QEC Init + * 11 | LoopBack Rx LO Delay + * 12 | LoopBack Rx Rx QEC Init + * 13 | Rx LO Delay + * 14 | Rx QEC Init + * 15 | DPD Init + * 16 | Tx CLGC (Closed Loop Gain Control) + * 17 | Tx VSWR Init + * [31-18] | Ignored - Future space for new calibrations + * + * \param device A pointer to the device settings structure + * \param calMask A bitmask that informs the Mykonos ARM processor which calibrations to run + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_runInitCals(mykonosDevice_t *device, uint32_t calMask) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + const uint8_t RUNINITCALS_OPCODE = 0x02; + uint8_t payload[4] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_runInitCals()\n"); +#endif + + payload[0] = (uint8_t)(calMask & 0xFF); + payload[1] = (uint8_t)((calMask >> 8) & 0xFF); + payload[2] = (uint8_t)((calMask >> 16) & 0xFF); + payload[3] = (uint8_t)((calMask >> 24) & 0xFF); + + retVal = MYKONOS_sendArmCommand(device, RUNINITCALS_OPCODE, &payload[0], sizeof(payload)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Blocking waits for the Mykonos initialization calibrations to complete + * + * The *errorFlag and *errorCode parameters are optional. If the pointers are + * set to null, no values will be returned. If the function returns an error + * that the init calibration failed, use the MYKONOS_getInitCalStatus() function + * to get more detailed information about why the init cal failed. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device A pointer to the device settings structure + * \param timeoutMs A timeout value in Ms to wait for the calibrations to complete + * \param errorFlag A 3bit error flag that helps identify what went wrong in the ARM. 0=No Error + * \param errorCode The value represents the init calibration object ID that caused a failure. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_WAIT_INITCALS_ARMERROR ARM returned error unrelated to init cals + */ +mykonosErr_t MYKONOS_waitInitCals(mykonosDevice_t *device, uint32_t timeoutMs, uint8_t *errorFlag, uint8_t *errorCode) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + mykonosErr_t retValCalStatus = MYKONOS_ERR_OK; + uint8_t cmdStatusByte = 0; + uint8_t _errorFlag = 0; /* Local version of parameter */ + mykonosInitCalStatus_t initCalStatus = {0}; + + const uint8_t INITCALS_CAL_ERROR = 0x07; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitInitCals()\n"); +#endif + + /* Clear before making any calls that can throw errors */ + if (errorFlag != NULL) + { + *errorFlag = 0; + } + + /* Clear before making any calls that can throw errors */ + if (errorCode != NULL) + { + *errorCode = 0; + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_RUNINIT_OPCODE, timeoutMs, &cmdStatusByte); + _errorFlag = cmdStatusByte >> 1; /* remove pending bit in [0], error flag is in bits [3:1] */ + + if (errorFlag != NULL) + { + *errorFlag = _errorFlag; + } + + if (retVal != MYKONOS_ERR_OK) + { + if (_errorFlag == INITCALS_CAL_ERROR) + { + /* return Error code if a calibration had an error */ + retValCalStatus = MYKONOS_getInitCalStatus(device, &initCalStatus); + if (retValCalStatus == MYKONOS_ERR_OK) + { + if (errorCode != NULL) + { + *errorCode = initCalStatus.initErrCal; + } + } + + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_CALFAILED, + getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_CALFAILED)); + return MYKONOS_ERR_WAIT_INITCALS_CALFAILED; + } + else if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_ARMERROR)); + return MYKONOS_ERR_WAIT_INITCALS_ARMERROR; + } + } + + /* Same logic if MYKONOS_waitArmCmdStatus() did not return an error, but cmdStatusByte shows an ARM error */ + if (_errorFlag == INITCALS_CAL_ERROR) + { + /* return Error code if a calibration had an error */ + retValCalStatus = MYKONOS_getInitCalStatus(device, &initCalStatus); + if (retValCalStatus == MYKONOS_ERR_OK) + { + if (errorCode != NULL) + { + *errorCode = initCalStatus.initErrCal; + } + } + + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_CALFAILED, + getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_CALFAILED)); + return MYKONOS_ERR_WAIT_INITCALS_CALFAILED; + } + else if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_ARMERROR)); + return MYKONOS_ERR_WAIT_INITCALS_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Aborts from an on going ARM init calibration operation. + * + * The ARM init calibrations can take several seconds. If for any reason the Baseband processor + * needs to stop the running ARM calibration sequence, call this function. The *calsCompleted + * parameter is an option parameter that will return which cals completed before the abort + * command was received. If *calsCompleted is a null pointer, no value will be returned. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device A pointer to the device settings structure + * \param calsCompleted A bitmask is returned which describes which cals completed during the previous + * MYKONOS_runInitCals() call. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM Function parameter calsCompleted has NULL pointer + */ +mykonosErr_t MYKONOS_abortInitCals(mykonosDevice_t *device, uint32_t *calsCompleted) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; //1 second timeout + uint8_t cmdStatusByte = 0; + uint8_t payload = 0x43; /* object ID to get INIT_CAL_DONE status */ + uint8_t calCompleteBitField[4] = {0, 0, 0, 0}; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_ABORT_OPCODE, 0, 0); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */ + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_ABORT_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if timeout occurred */ + } + + /* Read back Calibration Completion status */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &payload, sizeof(payload)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */ + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if timeout occurred */ + } + + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + 4), &calCompleteBitField[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (calsCompleted != NULL) + { + *calsCompleted = ((uint32_t)(calCompleteBitField[3]) << 24) | ((uint32_t)(calCompleteBitField[2]) << 16) | ((uint32_t)(calCompleteBitField[1]) << 8) + | ((uint32_t)(calCompleteBitField[0])); + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM)); + return MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Gets the device initialization calibration status + * + * This function requests the init cal status information from the Mykonos ARM + * processor. The ARM returns information including a bitmask that describes + * which calibrations have completed during the last cal of runInitCals, as + * well as the init cals that have run successfully since loading the ARM. If + * an ARM error does occur during one of the init calibrations, the initErrCal + * member returns the object ID of the failing calibration. The initErrCode + * returns the specific ARM error code that caused that calibration to fail. + * The calsMinimum structure member describes the minimum set of init calibrations + * required to complete by the ARM before it will allow the device to move to + * the radioOn state. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device A pointer to the device settings structure + * \param initCalStatus Pointer to a structure that returns cal status information such as cals completed since last run, and init error codes + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM if initCalStatus parameter is a NULL pointer + * \retval MYKONOS_ERR_GETINITCALSTATUS_ARMERROR if ARM returned an error while requesting the init cal status information + */ +mykonosErr_t MYKONOS_getInitCalStatus(mykonosDevice_t *device, mykonosInitCalStatus_t *initCalStatus) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t cmdStatusByte = 0; + uint8_t calStatusArray[14] = {0}; + uint8_t payload[1] = {MYKONOS_ARM_OBJECTID_INIT_CAL_DONE}; + + uint32_t timeoutMs = 1000; + + /* Verify function parameter pointer is not NULL */ + if (initCalStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM)); + return MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM; + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &payload[0], sizeof(payload)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */ + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_ARMERROR)); + return MYKONOS_ERR_GETINITCALSTATUS_ARMERROR; + } + + return retVal; /* Will return if timeout occurred */ + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_ARMERROR)); + return MYKONOS_ERR_GETINITCALSTATUS_ARMERROR; + } + + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &calStatusArray[0], sizeof(calStatusArray), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + initCalStatus->calsDoneLifetime = ((uint32_t)(calStatusArray[3]) << 24) | ((uint32_t)(calStatusArray[2]) << 16) | ((uint32_t)(calStatusArray[1]) << 8) + | ((uint32_t)(calStatusArray[0])); + initCalStatus->calsDoneLastRun = ((uint32_t)(calStatusArray[7]) << 24) | ((uint32_t)(calStatusArray[6]) << 16) | ((uint32_t)(calStatusArray[5]) << 8) + | ((uint32_t)(calStatusArray[4])); + initCalStatus->calsMinimum = ((uint32_t)(calStatusArray[11]) << 24) | ((uint32_t)(calStatusArray[10]) << 16) | ((uint32_t)(calStatusArray[9]) << 8) + | ((uint32_t)(calStatusArray[8])); + initCalStatus->initErrCal = calStatusArray[12]; + initCalStatus->initErrCode = calStatusArray[13]; + + return MYKONOS_ERR_OK; +} + +/** + * \brief Instructs the ARM processor to move the radio state to the Radio ON state + * + * When the ARM to the Radio On state, the enabled Rx and Tx signal chains will power up, + * and the ARM tracking calibrations will begin. To exit this state back to a low power, + * offline state, call the MYKONOS_radioOff() function. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ARM_RADIOON_FAILED ARM returned error running this command + */ +mykonosErr_t MYKONOS_radioOn(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; //1 second timeout + uint8_t cmdStatusByte = 0; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_RADIOON_OPCODE, 0, 0); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */ + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_RADIOON_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOON_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOON_FAILED)); + return MYKONOS_ERR_ARM_RADIOON_FAILED; + } + + return retVal; /* Will return if timeout occurred */ + } + + /* If ARM command error flag is 2, the command was not accepted, RUN_INIT must complete first */ + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOON_FAILED, getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOON_FAILED)); + return MYKONOS_ERR_ARM_RADIOON_FAILED; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Instructs the ARM processor to move the radio state to the off state + * + * When the ARM moves from the Radio On state to Radio Off (Idle) the ARM tracking calibrations + * are stopped and the TxEnable/RxEnable, etc GPIO control pins will be ignored. This will also + * keep the receive and transmit chains powered down until the MYKONOS_radioOn() function + * is called again. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ARM_RADIOOFF_FAILED ARM returned error running this command + */ +mykonosErr_t MYKONOS_radioOff(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + const uint8_t ABORTCAL_OPCODE = 0x00; + uint32_t timeoutMs = 1000; //1 second timeout + uint8_t cmdStatusByte = 0; + + retVal = MYKONOS_sendArmCommand(device, ABORTCAL_OPCODE, 0, 0); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */ + } + + retVal = MYKONOS_waitArmCmdStatus(device, ABORTCAL_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOOFF_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOOFF_FAILED)); + return MYKONOS_ERR_ARM_RADIOOFF_FAILED; + } + + return retVal; /* Will return if timeout occurred */ + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOOFF_FAILED, getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOOFF_FAILED)); + return MYKONOS_ERR_ARM_RADIOOFF_FAILED; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the current ARM radio state + * + * Currently, *radioStatus only returns data in the lower 8 bits, but + * is defined as a 32bit status to allow for more information to be returned + * in the future. + * + * radioStatus | Bitfield + * -------------|------------------ + * [1:0] | State[1:0], 0=POWERUP, 1=READY, 2=INIT, 3=RADIO ON + * [3:2] | unused + * [4] | TDD_nFDD , 1= TDD, 0=FDD + * [7:5] | unused + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param radioStatus The current ARM radio state is returned in this parameter + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM Function parameter radioStatus has a NULL pointer + */ +mykonosErr_t MYKONOS_getRadioState(mykonosDevice_t *device, uint32_t *radioStatus) +{ + uint8_t status = 0; + + /* if radioStatus is not null */ + if (radioStatus != NULL) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_0, &status); + *radioStatus = (uint32_t)status; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM)); + return MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets which ARM tracking cals are enabled during the radioOn state. + * + * This command must be called during radioOff state. If called during radioOn, + * an error will be returned. The enum mykonosTrackingCalibrations_t can be used to + * OR together to form the enableMask parameter. + * + * enableMask | Bit description + * ------------|------------ + * [0] | TRACK_RX1_QEC + * [1] | TRACK_RX2_QEC + * [2] | TRACK_ORX1_QEC + * [3] | TRACK_ORX2_QEC + * [4] | TRACK_TX1_LOL + * [5] | TRACK_TX2_LOL + * [6] | TRACK_TX1_QEC + * [7] | TRACK_TX2_QEC + * [8] | TRACK_TX1_DPD + * [9] | TRACK_TX2_DPD + * [10] | TRACK_TX1_CLGC + * [11] | TRACK_TX2_CLGC + * [12] | TRACK_TX1_VSWR + * [13] | TRACK_TX2_VSWR + * [16] | TRACK_ORX1_QEC_SNLO + * [17] | TRACK_ORX2_QEC_SNLO + * [18] | TRACK_SRX_QEC + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param enableMask A bitmask that selects which cals to run during radioOn state. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR Error: Tracking cals can only be enabled in the radioOff state. + * \retval MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR ARM returned error when executing this command + */ +mykonosErr_t MYKONOS_enableTrackingCals(mykonosDevice_t *device, uint32_t enableMask) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[4] = {0, 0, 0, 0}; + uint8_t extData[4] = {MYKONOS_ARM_OBJECTID_CALSCHEDULER, 0x00, 0x00, 0x04}; //Target ARM Object ID, Offset LSB, Offset MSB, Length + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint32_t radioStatus = 0; + uint8_t allowTx1AttenUpdates = 0; + uint8_t allowTx2AttenUpdates = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableTrackingCals()\n"); +#endif + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* throw error if not in radioOff/IDLE state */ + if ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR, + getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR)); + return MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR; + } + + /* In the ARM, DPD tracking and CLGC tracking share the same cal. Must + * set extra enable bits in ARM Memory to tell which cal to run. */ + retVal = enableDpdTracking(device, ((enableMask & (uint32_t)TRACK_TX1_DPD) ? 1 : 0), ((enableMask & (uint32_t)TRACK_TX2_DPD) ? 1 : 0)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (((device->profilesValid & TX_PROFILE_VALID) > 0) && (device->tx->clgcConfig != NULL)) + { + allowTx1AttenUpdates = device->tx->clgcConfig->allowTx1AttenUpdates; + allowTx2AttenUpdates = device->tx->clgcConfig->allowTx2AttenUpdates; + } + else + { + allowTx1AttenUpdates = 0; + allowTx2AttenUpdates = 0; + } + + retVal = enableClgcTracking(device, ((allowTx1AttenUpdates > 0) ? 1 : 0), ((allowTx2AttenUpdates > 0) ? 1 : 0)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + armData[0] = (uint8_t)(enableMask & 0xFF); + armData[1] = (uint8_t)((enableMask >> 8) & 0xFF); + armData[2] = (uint8_t)((enableMask >> 16) & 0xFF); + armData[3] = (uint8_t)((enableMask >> 24) & 0xFF); + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR)); + return MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR)); + return MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reschedules a tracking calibration to run. Can be used to + * override the tracking calibration timer and force a tracking calibration to run. + * Can be used to reschedule a tracking calibration after a tracking calibration + * error has been detected. Only one tracking calibration object can be scheduled + * per channel per function call. + * + * \pre Command can be called in either Radio On or Radio Off state. ARM must be + * initialized. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param trackingCal Selects the tracking calibration to schedule. + * + * \retval MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV Not valid calibration passed + * \retval MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG ARM error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_rescheduleTrackingCal(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extData[3] = {0}; + uint8_t cmdStatusByte = 0; + uint32_t timeoutMs = 1000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_rescheduleTrackingCal()\n"); +#endif + + switch (trackingCal) + { + case TRACK_RX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING; + extData[2] = 0; + break; + + case TRACK_RX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING; + extData[2] = 1; + break; + + case TRACK_ORX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING; + extData[2] = 0; + break; + + case TRACK_ORX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING; + extData[2] = 1; + break; + + case TRACK_TX1_LOL: + extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING; + extData[2] = 0; + break; + + case TRACK_TX2_LOL: + extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING; + extData[2] = 1; + break; + + case TRACK_TX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING; + extData[2] = 0; + break; + + case TRACK_TX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING; + extData[2] = 1; + break; + + case TRACK_TX1_DPD: + extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG; + extData[2] = 0; + break; + + case TRACK_TX2_DPD: + extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG; + extData[2] = 1; + break; + + case TRACK_TX1_CLGC: + extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG; + extData[2] = 0; + break; + + case TRACK_TX2_CLGC: + extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG; + extData[2] = 1; + break; + + case TRACK_TX1_VSWR: + extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG; + extData[2] = 0; + break; + + case TRACK_TX2_VSWR: + extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG; + extData[2] = 1; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV, + getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV)); + return MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV; + } + + extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_PENDING; + + /* sending ARM command */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG; + } + + return retVal; +} + +/** + * \brief Suspend or resume tracking calibrations in RADIO_ON. + * + * This function is used to suspend or resume active tracking calibrations based on the passed mask trackingCals. + * + * \pre Command can be called in Radio On. + * + * trackCals[bit] | Bit description + * ----------------|------------ + * [0] | TRACK_RX1_QEC + * [1] | TRACK_RX2_QEC + * [2] | TRACK_ORX1_QEC + * [3] | TRACK_ORX2_QEC + * [4] | TRACK_TX1_LOL + * [5] | TRACK_TX2_LOL + * [6] | TRACK_TX1_QEC + * [7] | TRACK_TX2_QEC + * [8] | TRACK_TX1_DPD + * [9] | TRACK_TX2_DPD + * [10] | TRACK_TX1_CLGC + * [11] | TRACK_TX2_CLGC + * [12] | TRACK_TX1_VSWR + * [13] | TRACK_TX2_VSWR + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param trackCals Selects the tracking calibrations to suspend or resume during the radio ON state. + * mykonosTrackingCalibrations_t enumerated types are or'd together to form the tracking calibration + * mask word. If the bit is high the calibration will resume, if the bit is low the calibration will be suspended. + * + * \retval MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV Not valid calibration mask passed for trackCals + * \retval MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG ARM error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setAllTrackCalState(mykonosDevice_t *device, uint32_t trackCals) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t cfgData[4] = {0}; + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME, 0x0F, 0}; + uint8_t cmdStatusByte = 0; + uint32_t enTrackCal = 0x00; + uint32_t timeoutMs = 1000; + + const uint32_t TRACKING_MASK = 0x3FFF; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setAllTrackCalState()\n"); +#endif + + /* reading enabled tracking calibrations */ + retVal = MYKONOS_getEnabledTrackingCals(device, &enTrackCal); + + /* trackingCalMask check */ + if (((trackCals | enTrackCal) > enTrackCal) || (trackCals > TRACKING_MASK)) + { + /* invalid cal mask error return, tracking cal not enable so we can not resume it */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV)); + return MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV; + } + + /* convert tracking mask to array of uint8_t type */ + cfgData[0] = (uint8_t)(trackCals & 0xFF); + cfgData[1] = (uint8_t)((trackCals >> 8) & 0xFF); + cfgData[2] = (uint8_t)((trackCals >> 16) & 0x0FF); + cfgData[3] = (uint8_t)((trackCals >> 24) & 0xFF); + + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &cfgData[0], sizeof(cfgData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG; + } + + return retVal; +} + +/** + * \brief Get the Suspended or Resumed state for tracking calibrations + * + * This function is used to get the suspend or resume state of all active tracking calibrations and the state is stored in trackCals. + * + * \pre Command can be called in Radio On. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param trackCals pointer to store the tracking calibration state. + * If the bit is set then the tracking calibration is resumed and if not set then the tracking cal is suspended, the bit field follows: + * + * trackCals[bit] | Bit description + * ---------------|------------ + * [0] | TRACK_RX1_QEC + * [1] | TRACK_RX2_QEC + * [2] | TRACK_ORX1_QEC + * [3] | TRACK_ORX2_QEC + * [4] | TRACK_TX1_LOL + * [5] | TRACK_TX2_LOL + * [6] | TRACK_TX1_QEC + * [7] | TRACK_TX2_QEC + * [8] | TRACK_TX1_DPD + * [9] | TRACK_TX2_DPD + * [10] | TRACK_TX1_CLGC + * [11] | TRACK_TX2_CLGC + * [12] | TRACK_TX1_VSWR + * [13] | TRACK_TX2_VSWR + * + * \retval MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM Null parameter passed for trackCals + * \retval MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG ARM error flag set. + * \retval MYKONOS_ERR_GETSTATEALL_TRACK_ARMERROR ARM command error. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getAllTrackCalState(mykonosDevice_t *device, uint32_t *trackCals) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extData = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME; + uint8_t armData[4] = {0}; + uint8_t cmdStatusByte = 0; + uint32_t timeoutMs = 1000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getAllTrackCalState()\n"); +#endif + + /* Check for passed parameter */ + if (trackCals == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM)); + return MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM; + } + + /* sending ARM command */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData, sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG; + } + + /* read 32-bit tracking state from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + *trackCals = (uint32_t)armData[0] | ((uint32_t)armData[1] << 8) | ((uint32_t)armData[2] << 16) | ((uint32_t)armData[3] << 24); + + return retVal; +} + +/** + * \brief Suspend or resume individual tracking calibration + * + * \pre The tracking calibration must have been enabled with MYKONOS_enableTrackingCals(), this command can be called in Radio On. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param trackingCal Selects the tracking calibration to resume or suspend. + * \param trackCalState if set then the selected tracking calibration will be resumed and if not set then the tracking cal will be suspended + * + * \retval MYKONOS_ERR_SETSTATE_TRACK_CAL_INV Not valid calibration passed + * \retval MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG ARM error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t trackCalState) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extData[2] = {0}; + uint8_t cmdStatusByte = 0; + uint8_t suspendTrack = 0x0F; + uint32_t timeoutMs = 1000; + uint32_t enTrackCal = 0x00; + + const uint8_t CHANNEL_1 = 0x00; + const uint8_t CHANNEL_2 = 0x10; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTrackingCalState()\n"); +#endif + + if (trackCalState > 0) + { + suspendTrack = 0x2F; + } + + /* reading enabled tracking calibrations */ + retVal = MYKONOS_getEnabledTrackingCals(device, &enTrackCal); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* trackingCalMask check */ + if (((uint8_t)trackingCal & enTrackCal) != (uint8_t)trackingCal) + { + /* invalid cal mask error return, tracking cal not enable so we can not resume or suspend it */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_CAL_INV, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_CAL_INV)); + return MYKONOS_ERR_SETSTATE_TRACK_CAL_INV; + } + + switch (trackingCal) + { + case TRACK_RX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_RX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_ORX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_ORX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_TX1_LOL: + extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_TX2_LOL: + extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_TX1_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_TX2_QEC: + extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_TX1_DPD: + extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_TX2_DPD: + extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_TX1_CLGC: + extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_TX2_CLGC: + extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + case TRACK_TX1_VSWR: + extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG & suspendTrack; + extData[1] |= CHANNEL_1; + break; + + case TRACK_TX2_VSWR: + extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG & suspendTrack; + extData[1] |= CHANNEL_2; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_CAL_INV, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_CAL_INV)); + return MYKONOS_ERR_SETSTATE_TRACK_CAL_INV; + } + + extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME; + + /* sending ARM command */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG; + } + } + + return retVal; +} + +/** + * \brief Get the Suspended or Resumed state for individual tracking calibration + * + * \pre Command can be called in Radio On. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param trackingCal Selects the tracking calibration to get the resumed or suspended state. + * \param trackCalState pointer to store the tracking calibration state, + * if set then the selected tracking calibration is resumed and if not set then the tracking cal is suspended + * + * \retval MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM Null parameter passed to trackCalState + * \retval MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG ARM command error flag set. + * \retval MYKONOS_ERR_GETSTATE_TRACK_ARMERROR ARM command error. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t *trackCalState) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extData = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME; + uint8_t armData[4] = {0}; + uint8_t cmdStatusByte = 0; + uint32_t timeoutMs = 1000; + uint32_t trackMask = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTrackingCalState()\n"); +#endif + + /* Check for passed parameter */ + if (trackCalState == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM)); + return MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM; + } + + /* sending ARM command */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData, sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG; + } + + /* read 32-bit tracking state from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + trackMask = (uint32_t)armData[0] | ((uint32_t)armData[1] << 8) | ((uint32_t)armData[2] << 16) | ((uint32_t)armData[3] << 24); + + if (trackMask & (uint32_t)trackingCal) + { + *trackCalState = 1; + } + else + { + *trackCalState = 0; + } + + return retVal; +} + +/** + * \brief Reads back which ARM tracking cals are enabled + * + * enableMask | Bit description + * ------------|---------------------- + * [0] | TRACK_RX1_QEC + * [1] | TRACK_RX2_QEC + * [2] | TRACK_ORX1_QEC + * [3] | TRACK_ORX2_QEC + * [4] | TRACK_TX1_LOL + * [5] | TRACK_TX2_LOL + * [6] | TRACK_TX1_QEC + * [7] | TRACK_TX2_QEC + * [8] | TRACK_TX1_DPD + * [9] | TRACK_TX2_DPD + * [10] | TRACK_TX1_CLGC + * [11] | TRACK_TX2_CLGC + * [12] | TRACK_TX1_VSWR + * [13] | TRACK_TX2_VSWR + * [16] | TRACK_ORX1_QEC_SNLO + * [17] | TRACK_ORX1_QEC_SNLO + * [18] | TRACK_SRX_QEC + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param enableMask Returned bitmask that shows which tracking cals are enabled + * to run during radioOn state. See mykonosTrackingCalibrations_t enum of tracking cals. + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getEnabledTrackingCals(mykonosDevice_t *device, uint32_t *enableMask) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[4] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getEnabledTrackingCals()\n"); +#endif + + /* Ask ARM to read tracking cal enable bits and place in mailbox buffer memory */ + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CALSCHEDULER, 0, &armData[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + *enableMask = ((uint32_t)(armData[0]) | ((uint32_t)(armData[1]) << 8) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[3]) << 24)); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns the tracking calibration pending and error status. + * + * When in radioOn state, the enabled tracking calibrations will set the pending + * flag when the particular calibration is ready to be run, but has not completed + * yet. For Tx tracking cals to complete, the BBIC must set the ObsRx path to + * the INTERNAL CALS mode. If a tracking calibration had an error, the corresponding + * error flag will be asserted. + * + * pendingCalMask | bit Description + * ----------------|-------------------------------------------------------- + * [0] | Rx1 QEC tracking pending + * [1] | Rx1 QEC tracking error + * [2] | Rx2 QEC tracking pending + * [3] | Rx2 QEC tracking error + * [4] | ORx1 QEC tracking pending + * [5] | ORx1 QEC tracking error + * [6] | ORx2 QEC tracking pending + * [7] | ORx2 QEC tracking error + * [8] | Tx1 LOL tracking pending + * [9] | Tx1 LOL tracking error + * [10] | Tx2 LOL tracking pending + * [11] | Tx2 LOL tracking error + * [12] | Tx1 QEC tracking pending + * [13] | Tx1 QEC tracking error + * [14] | Tx2 QEC tracking pending + * [15] | Tx2 QEC tracking error + * [16] | Tx1 DPD tracking pending + * [17] | Tx1 DPD tracking error + * [18] | Tx2 DPD tracking pending + * [19] | Tx2 DPD tracking error + * [20] | Tx1 CLGC tracking pending + * [21] | Tx1 CLGC tracking error + * [22] | Tx2 CLGC tracking pending + * [23] | Tx2 CLGC tracking error + * [24] | Tx1 VSWR tracking pending + * [25] | Tx1 VSWR tracking error + * [26] | Tx2 VSWR tracking pending + * [27] | Tx2 VSWR tracking error + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param pendingCalMask Bit mask that describes which tracking cals are pending + * or had errors + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM Function parameter pendingCalMask is a NULL pointer + */ +mykonosErr_t MYKONOS_getPendingTrackingCals(mykonosDevice_t *device, uint32_t *pendingCalMask) +{ + uint8_t readData[4] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPendingTrackingCals()\n"); +#endif + + if (pendingCalMask == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM)); + return MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_3, &readData[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_4, &readData[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_5, &readData[2]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_6, &readData[3]); + *pendingCalMask = ((uint32_t)readData[3] << 24) | ((uint32_t)readData[2] << 16) | ((uint32_t)readData[1] << 8) | ((uint32_t)readData[0]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns the status of the TxLOL external tracking calibration + * + * The Tx LOL external tracking calibration is run during the radioOn state. + * The function can be called to read back the status of the TxLOL external + * calibration including metrics like error codes, percentage of data + * collected for current cal, the performance of the cal and the number of + * times the cal has run and updated the hardware. + * + * \pre Before the function is called, the device must be initialized, the ARM + * loaded, and init cals run. These functions can be called in radioOff or + * radioOn state. + * + * \param device Pointer to the device settings structure + * \param txChannel The channel (Tx1/Tx2) whose status is to be read back + * \param txLolStatus Status of the TxLOL external calibration, as a structure + * of type mykonosTxLolStatus_t is returned to this pointer address + * + * \retval MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM Function parameter mykonosTxLolStatus_t is a NULL pointer + * \retval MYKONOS_ERR_GETTXLOLSTATUS_INV_CH Channel selection not valid + * \retval MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG ARM command error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getTxLolStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxLolStatus_t *txLolStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_TXLOL_TRACKING, 0}; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + uint32_t timeoutMs = 0; + uint8_t armReadBack[20] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxLolStatus()\n"); +#endif + + if (txLolStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + extData[2] = 0; + break; + case TX2: + extData[2] = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_INV_CH)); + return MYKONOS_ERR_GETTXLOLSTATUS_INV_CH; + } + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Assign to data structure */ + txLolStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]); + txLolStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8) + | ((uint32_t)armReadBack[4]); + txLolStatus->performanceMetric = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8) + | ((uint32_t)armReadBack[8]); + txLolStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]); + txLolStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8) + | ((uint32_t)armReadBack[16]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns the status of the TxQEC tracking calibration + * + * The Tx QEC tracking calibration is run during the radioOn state. + * The function can be called to read back the status of the TxQEC + * calibration including metrics like error codes, percentage of data + * collected for current cal, the performance of the cal and the number of + * times the cal has run and updated the hardware. + * + * \pre Before the function is called, the device must be initialized, the ARM + * loaded, and init cals run. These functions can be called in radioOff or + * radioOn state. + * + * \param device Pointer to the device settings structure + * \param txChannel The channel (Tx1/Tx2) whose status is to be read back + * \param txQecStatus Status of the TxQEC external calibration, as a structure + * of type mykonosTxQecStatus_t is returned to this pointer address + * + * \retval MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM Function parameter txQecStatus is a NULL pointer + * \retval MYKONOS_ERR_GETTXQECSTATUS_INV_CH Channel selection not valid + * \retval MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG ARM command error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getTxQecStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxQecStatus_t *txQecStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_TXQEC_TRACKING, 0}; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + uint32_t timeoutMs = 0; + uint8_t armReadBack[20] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxQecStatus()\n"); +#endif + + if (txQecStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + extData[2] = 0; + break; + case TX2: + extData[2] = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_INV_CH)); + return MYKONOS_ERR_GETTXQECSTATUS_INV_CH; + } + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Assign to data structure */ + txQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]); + txQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8) + | ((uint32_t)armReadBack[4]); + txQecStatus->performanceMetric = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8) + | ((uint32_t)armReadBack[8]); + txQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]); + txQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8) + | ((uint32_t)armReadBack[16]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns the status of the RxQEC tracking calibration + * + * The Rx QEC tracking calibration is run during the radioOn state. + * The function can be called to read back the status of the RxQEC external + * calibration including metrics like error codes, percentage of data + * collected for current cal, the performance of the cal and the number of + * times the cal has run and updated the hardware. + * + * \pre Before the function is called, the device must be initialized, the ARM + * loaded, and init cals run. These functions can be called in radioOff or + * radioOn state. + * + * \param device Pointer to the device settings structure + * \param rxChannel The channel (Rx1/Rx2) whose status is to be read back + * \param rxQecStatus Status of the RxQEC calibration, as a structure + * of type mykonosRxQecStatus_t is returned to this pointer address + * + * \retval MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM Function parameter rxQecStatus is a NULL pointer + * \retval MYKONOS_ERR_GETRXQECSTATUS_INV_CH Channel selection not valid + * \retval MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG ARM command error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRxQecStatus(mykonosDevice_t *device, mykonosRxChannels_t rxChannel, mykonosRxQecStatus_t *rxQecStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_RXQEC_TRACKING, 0}; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + uint32_t timeoutMs = 0; + uint8_t armReadBack[20] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRxQecStatus()\n"); +#endif + + if (rxQecStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM; + } + + switch (rxChannel) + { + case RX1: + extData[2] = 0; + break; + case RX2: + extData[2] = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_INV_CH)); + return MYKONOS_ERR_GETRXQECSTATUS_INV_CH; + } + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Assign to data structure */ + rxQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]); + rxQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8) + | ((uint32_t)armReadBack[4]); + rxQecStatus->selfcheckIrrDb = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8) + | ((uint32_t)armReadBack[8]); + rxQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]); + rxQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8) + | ((uint32_t)armReadBack[16]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Returns the status of the ORxQEC tracking calibration + * + * The ORx QEC tracking calibration is run during the radioOn state. + * The function can be called to read back the status of the ORxQEC external + * calibration including metrics like error codes, percentage of data + * collected for current cal, the performance of the cal and the number of + * times the cal has run and updated the hardware. + * + * \pre Before the function is called, the device must be initialized, the ARM + * loaded, and init cals run. These functions can be called in radioOff or + * radioOn state. + * + * \param device Pointer to the device settings structure + * \param orxChannel The channel whose status is to be read back + * \param orxQecStatus Status of the ORxQEC external calibration, as a structure + * of type mykonosOrxQecStatus_t is returned to this pointer address + * + * \retval MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM Function parameter orxQecStatus is a NULL pointer + * \retval MYKONOS_ERR_GETORXQECSTATUS_INV_CH Channel selection not valid + * \retval MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG ARM command error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getOrxQecStatus(mykonosDevice_t *device, mykonosObsRxChannels_t orxChannel, mykonosOrxQecStatus_t *orxQecStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING, 0}; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + uint32_t timeoutMs = 0; + uint8_t armReadBack[20] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getOrxQecStatus()\n"); +#endif + + if (orxQecStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM; + } + + switch (orxChannel) + { + case OBS_RX1_TXLO: + case OBS_RX1_SNIFFERLO: + extData[2] = 0; + break; + case OBS_RX2_TXLO: + case OBS_RX2_SNIFFERLO: + extData[2] = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_INV_CH)); + return MYKONOS_ERR_GETORXQECSTATUS_INV_CH; + } + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Assign to data structure */ + orxQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]); + orxQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8) + | ((uint32_t)armReadBack[4]); + orxQecStatus->selfcheckIrrDb = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8) + | ((uint32_t)armReadBack[8]); + orxQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) + | ((uint32_t)armReadBack[12]); + orxQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8) + | ((uint32_t)armReadBack[16]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Selects the Sniffer RF input to use for the observation receiver when in ObsRx pin mode and ORX_MODE = SNIFFER(4) + * + * This function is only valid when using the ObsRx Pin mode. In pin mode, 3 GPIO pins select an Observation Rx source. + * See mykonosObsRxChannels_t enum values less than 7. When the ORX_MODE GPIO pins are set to 4 for Sniffer, Sniffer inputs + * A, B, and C can be chosen by calling this function. This function can be called any time after the ARM is loaded and running. + * It can be called in radioOn or radioOff state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param snifferChannel Desired channel to set. This channel will be enabled when ORX_MODE = SNIFFER. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR ARM returned an error + */ +mykonosErr_t MYKONOS_setSnifferChannel(mykonosDevice_t *device, mykonosSnifferChannel_t snifferChannel) +{ + uint8_t armData[2] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + + armData[0] = 0x6A; /* SET SRX_SOURCE ARM object ID */ + armData[1] = (uint8_t)snifferChannel; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &armData[0], sizeof(armData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR)); + retVal = (mykonosErr_t)MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR)); + return (mykonosErr_t)MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Resets the ARM processor and performs initialization + * + * Sets ARM Run = 0, Disables parity checks, sets ARM and SPI reg clock selects, + * resets ARM, and enables ARM SPI register access + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->rx->rxProfile->iqRate_kHz + * - device->deviceClock_kHz + * - device->rx->rxProfile->rfBandwidth_Hz + * - device->tx->txProfile->rfBandwidth_Hz + * - device->rx->rxProfile->rxFirDecimation + * - device->rx->rxProfile->rhb1Decimation + * - device->spiSettings + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_INITARM_INV_VCODIV + * \retval MYKONOS_ERR_INITARM_INV_REGCLK Could not calculate a valid ARM Register clock divider + * \retval MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM Could not calculate a valid ARM clock divider + */ +mykonosErr_t MYKONOS_initArm(mykonosDevice_t *device) +{ + uint8_t regClkSel = 0; + uint8_t armClkSel = 0; + uint32_t hsClkRateDiv4or5_Khz = 0; + uint32_t hb1Clk = 0; + uint32_t vcoDivTimes10 = 1; + uint8_t adcDiv = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initArm()\n"); +#endif + + /* Finish init - this is part of init that must run after Multi Chip Sync */ + retVal = MYKONOS_initSubRegisterTables(device); + if (retVal != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + switch (device->clocks->clkPllVcoDiv) + { + case VCODIV_1: + vcoDivTimes10 = 10; + break; + case VCODIV_1p5: + vcoDivTimes10 = 15; + break; + case VCODIV_2: + vcoDivTimes10 = 20; + break; + case VCODIV_3: + vcoDivTimes10 = 30; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_VCODIV, + getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_VCODIV)); + return MYKONOS_ERR_INITARM_INV_VCODIV; + } + } + + hsClkRateDiv4or5_Khz = device->clocks->clkPllVcoFreq_kHz * 10 / vcoDivTimes10 / 20; + + /* If ADC divider is set, divide hsClkRateDiv4or5_kHz by 2 (ADC divider) */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_1, &adcDiv, 0x01, 0); + hb1Clk = (adcDiv == 1) ? (hsClkRateDiv4or5_Khz >> 1) : (hsClkRateDiv4or5_Khz); + + /* the ARM clock should not exceed 250 Mhz */ + if (hb1Clk <= 250000) + { + armClkSel = 0x00; + } + else if (hb1Clk > 250000 && hb1Clk <= 500000) + { + armClkSel = 0x02; + } + else if (hb1Clk > 500000 && hb1Clk <= 1000000) + { + armClkSel = 0x04; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM)); + return MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM; + } + + /* the SPI read reg clock must be equal or less than 100MHz and the SPI write reg clock must be less equal or less than 200 Mhz*/ + if (hb1Clk <= 100000) + { + regClkSel = 0x00; + } + else if (hb1Clk > 100000 && hb1Clk <= 200000) + { + regClkSel = 0x04; + } + else if (hb1Clk > 200000 && hb1Clk <= 400000) + { + regClkSel = 0x09; + } + else if (hb1Clk > 400000 && hb1Clk <= 800000) + { + regClkSel = 0x0E; + } + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_REGCLK, getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_REGCLK)); + return MYKONOS_ERR_INITARM_INV_REGCLK; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8C); /* arm_debug_enable[7]=1, mem_hresp_mask[3]=1, auto_incr[2]=1, arm_m3_run[0]=0 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CLK_CTL, armClkSel |= 0x41); /* setting the ARM clock rate, resetting the PC, and enabling the ARM clock */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CLK_CTL, armClkSel &= ~0x40); /* maintaining the ARM clock rate, disabling the PC reset, and maintaining ARM clock enable */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BRIDGE_CLK_CTL, regClkSel); /* setting the SPI read and write clock rates */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AHB_SPI_BRIDGE, 0x13); /* blockout_window_size[4:1] = 9, ahb_spi_bridge_enable[0] = 1 */ + + retVal = MYKONOS_writeArmProfile(device); + if (retVal != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + retVal = MYKONOS_loadAdcProfiles(device); + if (retVal != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Loads binary byte array into ARM program memory + * + * This function assumes the ARM auto increment bit is set in 0x0D00[2]. Valid memory + * addresses are: Program Memory (0x01000000 - 0x01017FFF) + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param binary is a byte array containing ARM program memory data bytes (directly from .bin file) + * \param count is the number of bytes in the byte array + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_LOADBIN_NULL_PARAM Function parameter binary has a NULL pointer + * \retval MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT Count parameter must be 98304 bytes + */ +mykonosErr_t MYKONOS_loadArmFromBinary(mykonosDevice_t *device, uint8_t *binary, uint32_t count) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t stackPtr[4] = {0}; + uint8_t bootAddr[4] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadArmFromBinary()\n"); +#endif + + if (binary == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADBIN_NULL_PARAM, getMykonosErrorMessage(MYKONOS_ERR_LOADBIN_NULL_PARAM)); + return MYKONOS_ERR_LOADBIN_NULL_PARAM; + } + + if (count != 98304) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT, + getMykonosErrorMessage(MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT)); + return MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT; + } + else + { + /* extraction of stack pointer and boot address from top of array */ + stackPtr[0] = binary[0]; + stackPtr[1] = binary[1]; + stackPtr[2] = binary[2]; + stackPtr[3] = binary[3]; + + bootAddr[0] = binary[4]; + bootAddr[1] = binary[5]; + bootAddr[2] = binary[6]; + bootAddr[3] = binary[7]; + + /* writing binary data to ARM memory */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR, &binary[0], count); + } + + if (retVal != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + else + { + /* writing the stack pointer address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_0, stackPtr[0]); /* stack pointer [7:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_1, stackPtr[1]); /* stack pointer [15:8] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_2, stackPtr[2]); /* stack pointer [23:16] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_3, stackPtr[3]); /* stack pointer [31:24] */ + + /* writing the boot address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_0, bootAddr[0]); /* boot address [7:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_1, bootAddr[1]); /* boot address [15:8] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_2, bootAddr[2]); /* boot address [23:16] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_3, bootAddr[3]); /* boot address [31:24] */ + + /* setting the ARM run bit */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8D); /* arm_debug_enable[7]=1, mem_hresp_mask[3]=1, auto_incr[2]=1, arm_m3_run[0]=1 */ + } + + /* verifying ARM checksum */ + if ((retVal = MYKONOS_verifyArmChecksum(device)) != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + /* verifying ARM state is in MYKONOS_ARM_READY state, otherwise return error */ + if ((retVal = MYKONOS_checkArmState(device, MYK_ARM_READY)) != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + /* Setup ARM GPIO pins and program ARMs radio control structure */ + if ((retVal = (mykonosErr_t)MYKONOS_setArmGpioPins(device)) != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + if ((retVal = MYKONOS_setRadioControlPinMode(device)) != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + /* Set the default ObsRx Path source for when the device moves to RadioOn */ + if ((retVal = MYKONOS_setDefaultObsRxPath(device, device->obsRx->defaultObsRxChannel)) != MYKONOS_ERR_OK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal)); + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Loads binary byte array into ARM program memory. This API function allows user to load the ARM concurrently. + * This is specially to reduce the system initialization time. + * + * \pre MYKONOS_initArm() function must be called before calling this API. + * + * \post after calling this function the user must verify: + * Arm Checksum using MYKONOS_verifyArmChecksum(mykonosDevice_t *device) + * verify ARM state is in MYKONOS_ARM_READY state using MYKONOS_checkArmState(device, MYK_ARM_READY); + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param binary is a byte array containing ARM program memory data bytes (directly from .bin file) + * \param count is the number of bytes in the byte array + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_LOADARMCON_NULL_PARAM Function parameter binary has a NULL pointer + * \retval MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT Count parameter must be 98304 bytes + * \retval MYKONOS_ERR_ARM_INV_ADDR_PARM Invalid memory address + */ +mykonosErr_t MYKONOS_loadArmConcurrent(mykonosDevice_t *device, uint8_t *binary, uint32_t count) +{ + uint8_t stackPtr[4] = {0}; + uint8_t bootAddr[4] = {0}; + uint32_t i; + uint32_t address = MYKONOS_ADDR_ARM_START_PROG_ADDR; + +#if MYK_ENABLE_SPIWRITEARRAY == 1 + uint32_t addrIndex = 0; + uint32_t dataIndex = 0; + uint32_t spiBufferSize = MYK_SPIWRITEARRAY_BUFFERSIZE; + uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; +#endif + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadArmConcurrent()\n"); +#endif + + if (binary == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADARMCON_NULL_PARAM, getMykonosErrorMessage(MYKONOS_ERR_LOADARMCON_NULL_PARAM)); + return MYKONOS_ERR_LOADARMCON_NULL_PARAM; + } + + if (count != 98304) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT, + getMykonosErrorMessage(MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT)); + return MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT; + } + else + { + /* extraction of stack pointer and boot address from top of array */ + stackPtr[0] = binary[0]; + stackPtr[1] = binary[1]; + stackPtr[2] = binary[2]; + stackPtr[3] = binary[3]; + + bootAddr[0] = binary[4]; + bootAddr[1] = binary[5]; + bootAddr[2] = binary[6]; + bootAddr[3] = binary[7]; + + /* set auto increment address bit */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8C); + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10)); + + /* start write at correct byte offset */ + /* write data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24] */ + /* with address auto increment set, after x407 is written, the address will automatically increment */ + +#if (MYK_ENABLE_SPIWRITEARRAY == 0) + + for (i = 0; i < byteCount; i++) + { + CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), data[i]); + } + +#elif (MYK_ENABLE_SPIWRITEARRAY == 1) + + addrIndex = 0; + dataIndex = 0; + for (i = 0; i < count; i++) + { + addrArray[addrIndex++] = (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)); + + if (addrIndex == spiBufferSize) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &binary[dataIndex], addrIndex); + dataIndex = dataIndex + addrIndex; + addrIndex = 0; + } + } + + if (addrIndex > 0) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &binary[dataIndex], addrIndex); + } + +#endif + + /* writing the stack pointer address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_0, stackPtr[0]); /* stack pointer [7:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_1, stackPtr[1]); /* stack pointer [15:8] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_2, stackPtr[2]); /* stack pointer [23:16] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_3, stackPtr[3]); /* stack pointer [31:24] */ + + /* writing the boot address */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_0, bootAddr[0]); /* boot address [7:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_1, bootAddr[1]); /* boot address [15:8] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_2, bootAddr[2]); /* boot address [23:16] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_3, bootAddr[3]); /* boot address [31:24] */ + + /* setting the ARM run bit */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8D); + + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Verifies the ARM checksum value + * + * The checksum which is written into the .hex file is verified with the calculated checksum + * in the Mykonos ARM after the hex file has been loaded + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_verifyArmChecksum(mykonosDevice_t *device) +{ + uint32_t buildTimeChecksum = 0x00000000; + uint32_t calculatedChecksum = 0x00000000; + uint8_t buildData[4] = {0}; + uint8_t calcData[4] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + + const uint8_t CHECKSUM_BYTES = 0x4; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyArmChecksum()\n"); +#endif + + /* disabling auto increment and reading four (4) bytes at ARM checksum memory location */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_BUILD_CHKSUM_ADDR, buildData, CHECKSUM_BYTES, 0); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + /* determining build time checksum */ + buildTimeChecksum = (((uint32_t)buildData[3] << 24) | ((uint32_t)buildData[2] << 16) | ((uint32_t)buildData[1] << 8) | (uint32_t)buildData[0]); + + /* using 200 msec timeout for exit out of while loop [maximum checksum calculation time = 5 ms] */ + CMB_setTimeout_ms(200); + + /* determining calculated checksum */ + do + { + if ((retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_CALC_CHKSUM_ADDR, calcData, CHECKSUM_BYTES, 0)) != MYKONOS_ERR_OK) + { + return retVal; + } + calculatedChecksum = (((uint32_t)calcData[3] << 24) | ((uint32_t)calcData[2] << 16) | ((uint32_t)calcData[1] << 8) | (uint32_t)calcData[0]); + } while ((!calculatedChecksum) && (!CMB_hasTimeoutExpired())); + + /* performing consistency check */ + if (buildTimeChecksum == calculatedChecksum) + { + return MYKONOS_ERR_OK; + } + else + { + return MYKONOS_ERR_ARM_INVALID_BUILDCHKSUM; + } +} + +/** + * \brief Verifies the ARM status once it is start running + * + * Wait for ARM to go into radio state, if takes longer there is and ARM error + * get error in Application layer calling MYKONOS_getRadioState() + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param armStateCheck if the ARM is not in this state it will return an error, + * + * \retval MYKONOS_ERR_ARMSTATE_EXCEPTION ARM system problem has been detected. + * \retval MYKONOS_ERR_ARMSTATE_CAL_ERROR ARM has detected an error in the tracking calibrations. + * \retval MYKONOS_ERR_ARMSTATE_EXCEPTION ARM has detected an illegal profile. + * \retval MYKONOS_ERR_WAITARMCSTATE_TIMEOUT Timeout occurred in check ARM state. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_checkArmState(mykonosDevice_t *device, mykonosArmState_t armStateCheck) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t armStatus = 0x00; + uint32_t armStatusMapped = 0x00; + uint32_t timeoutMs = 500; /* 500ms timeOut */ + uint8_t endCheck = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_checkArmState()\n"); +#endif + + CMB_setTimeout_ms(timeoutMs); + + do + { + if ((retVal = MYKONOS_getRadioState(device, &armStatus)) != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Mapping of the armStatus bit to the enum value. */ + switch(armStatus) + { + case 0: + armStatusMapped = (uint32_t)MYK_ARM_POWERUP; + break; + case 1: + armStatusMapped = (uint32_t)MYK_ARM_READY; + break; + case 2: + armStatusMapped = (uint32_t)MYK_ARM_IDLE; + break; + case 3: + armStatusMapped = (uint32_t)MYK_ARM_RADIO_ON; + break; + case 4: + armStatusMapped = (uint32_t)MYK_ARM_PROFILE_ERROR; + break; + default: + armStatusMapped = armStatus; + break; + } + + if (armStateCheck && armStatusMapped) + { + retVal = MYKONOS_ERR_OK; + break; + } + + if (CMB_hasTimeoutExpired()) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITARMCSTATE_TIMEOUT, + getMykonosErrorMessage(MYKONOS_ERR_WAITARMCSTATE_TIMEOUT)); + retVal = MYKONOS_ERR_WAITARMCSTATE_TIMEOUT; + break; + } + + switch (armStatusMapped) + { + /* this cases are not ARM errors */ + case MYK_ARM_POWERUP: + case MYK_ARM_READY: + case MYK_ARM_IDLE: + case MYK_ARM_RADIO_ON: + break; + + case MYK_ARM_PROFILE_ERROR: + /* return error directly */ + retVal = MYKONOS_ERR_ARMSTATE_PROFILE_ERROR; + endCheck = 1; + break; + + case MYK_ARM_CAL_ERROR: + /* return error directly */ + retVal = MYKONOS_ERR_ARMSTATE_CAL_ERROR; + endCheck = 1; + break; + + case MYK_ARM_EXCEPTION: + /* return error directly */ + retVal = MYKONOS_ERR_ARMSTATE_EXCEPTION; + endCheck = 1; + break; + + case (uint32_t)MYK_ARM_EXCEPTION | (uint32_t)MYK_ARM_PROFILE_ERROR: + /* return error directly */ + retVal = MYKONOS_ERR_ARMSTATE_EXCEPTION; + endCheck = 1; + break; + + default: + endCheck = 0; + break; + } + + } while (!endCheck); + + return retVal; +} + +/** + * \brief Reads back the version of the ARM binary loaded into the Mykonos ARM memory + * + * This function reads the ARM memory to read back the major.minor.releaseCandidate + * version for the ARM binary loaded into ARM memory. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param majorVer The Major version is returned in this parameter + * \param minorVer The Minor version is returned in this parameter + * \param rcVer The release candidate version (build number) is returned in this parameter + * \param buildType The Type of the build [Debug / Test_Object / Release] + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETARMVER_NULL_PARM One of the function parameters has a NULL pointer + */ +mykonosErr_t MYKONOS_getArmVersion(mykonosDevice_t *device, uint8_t *majorVer, uint8_t *minorVer, uint8_t *rcVer, mykonosBuild_t *buildType) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t ver[5] = {0}; + uint32_t fullVersion = 0; + uint8_t validBuilds = 0x05; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getArmVersion()\n"); +#endif + + if ((majorVer == NULL) || (minorVer == NULL) || (rcVer == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETARMVER_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_GETARMVER_NULL_PARM)); + return MYKONOS_ERR_GETARMVER_NULL_PARM; + } + + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_VERSION, &ver[0], sizeof(ver), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + fullVersion = ((uint32_t)(ver[0]) | (uint32_t)((uint32_t)(ver[1]) << 8) | (uint32_t)((uint32_t)(ver[2]) << 16) | (uint32_t)((uint32_t)(ver[3]) << 24)); + *rcVer = (uint8_t)(fullVersion % 100); + *minorVer = (uint8_t)((fullVersion / 100) % 100); + *majorVer = (uint8_t)(fullVersion / 10000); + + switch (ver[4] & validBuilds) + { + case MYK_BUILD_DEBUG: + *buildType = MYK_BUILD_DEBUG; + break; + case MYK_BUILD_TEST_OBJECT: + *buildType = MYK_BUILD_TEST_OBJECT; + break; + default: + *buildType = MYK_BUILD_RELEASE; + break; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function will configure DPD settings + * + * A DPD-enabled transceiver is required for DPD to be enabled. The DPD has several user + * adjustable settings that can be configured before running the runInitCals + * with the calMask set for the DPD init cal. Call this function with desired + * settings set before running the DPD init cal or enabling DPD tracking. + * + * This function can be called in either Radio On or Off state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->dpdConfig (All members) + * + * + * \retval MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV ERROR: to use these features, a valid Tx and ORx profile must exist in the device data structure + * \retval MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT ERROR: device->tx->dpdConfig is a NULL pointer + * \retval MYKONOS_ERR_CFGDPD_INV_DPDDAMPING ERROR: damping parameter is out of range + * \retval MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES ERROR: samples parameter is out of range + * \retval MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS ERROR: numWeights parameter is out of range (0-3) + * \retval MYKONOS_ERR_CFGDPD_INV_MODELVERSION ERROR: modelVersion parameter is out of range (0-3) + * \retval MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH ERROR: outlierThreshold parameter is out of range + * \retval MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY ERROR: additionalDelayOffset parameter is out of range + * \retval MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL ERROR: pathDelayPnSeqLevel parameter is out of range + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_configDpd(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[6] = {0}; + uint8_t byteOffset = 0; + uint16_t negPnLevel = 0; + uint8_t highPowerModelUpdate = 0; + uint8_t robustModeling = 0; + uint32_t radioStatus = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configDpd()\n"); +#endif + + /* DPD requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV)); + return MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV; + } + + if (device->tx->dpdConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT)); + return MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT; + } + + /* check DPD damping and samples parameters */ + if (device->tx->dpdConfig->damping > 15) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDDAMPING, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDDAMPING)); + return MYKONOS_ERR_CFGDPD_INV_DPDDAMPING; + } + + if ((device->tx->dpdConfig->samples < 64) || (device->tx->dpdConfig->samples > 32768)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES)); + return MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES; + } + + if (device->tx->dpdConfig->numWeights > 3) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS)); + return MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS; + } + + if (device->tx->dpdConfig->modelVersion > 3) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_MODELVERSION, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_MODELVERSION)); + return MYKONOS_ERR_CFGDPD_INV_MODELVERSION; + } + + highPowerModelUpdate = (device->tx->dpdConfig->highPowerModelUpdate > 0) ? 1 : 0; + robustModeling = (device->tx->dpdConfig->robustModeling > 0) ? 1 : 0; + + armFieldValue[0] = (uint8_t)(((device->tx->dpdConfig->numWeights & 3) << 4) | (device->tx->dpdConfig->damping & 0xF)); + armFieldValue[1] = (uint8_t)((robustModeling << 3) | (highPowerModelUpdate << 2) | (device->tx->dpdConfig->modelVersion & 3)); + armFieldValue[2] = (device->tx->dpdConfig->samples & 0xFF); + armFieldValue[3] = ((device->tx->dpdConfig->samples >> 8) & 0xFF); + byteOffset = 0; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set DPD outlier threshold parameter */ + if ((device->tx->dpdConfig->outlierThreshold < 1) || (device->tx->dpdConfig->outlierThreshold > 8192)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH)); + return MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH; + } + + armFieldValue[0] = (device->tx->dpdConfig->outlierThreshold & 0xFF); + armFieldValue[1] = ((device->tx->dpdConfig->outlierThreshold >> 8) & 0xFF); + byteOffset = 10; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set DPD Model Prior Weight parameter */ + if (device->tx->dpdConfig->modelPriorWeight > 32) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT)); + return MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT; + } + armFieldValue[0] = (device->tx->dpdConfig->modelPriorWeight & 0xFF); + armFieldValue[1] = 0; + byteOffset = 12; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* no need to verify weights min/max as all int8 values are valid */ + armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->weights[0].real); + armFieldValue[1] = (uint8_t)(device->tx->dpdConfig->weights[0].imag); + armFieldValue[2] = (uint8_t)(device->tx->dpdConfig->weights[1].real); + armFieldValue[3] = (uint8_t)(device->tx->dpdConfig->weights[1].imag); + armFieldValue[4] = (uint8_t)(device->tx->dpdConfig->weights[2].real); + armFieldValue[5] = (uint8_t)(device->tx->dpdConfig->weights[2].imag); + + byteOffset = 14; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 6); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set DPD additional delay offset parameter */ + if ((device->tx->dpdConfig->additionalDelayOffset < -64) || (device->tx->dpdConfig->additionalDelayOffset > 64)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY)); + return MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY; + } + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Radio state check */ + if (((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_IDLE) || ((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_READY)) + { + armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->additionalDelayOffset & 0xFF); + armFieldValue[1] = (uint8_t)(((uint16_t)device->tx->dpdConfig->additionalDelayOffset >> 8) & 0xFF); + byteOffset = 2; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if ((device->tx->dpdConfig->pathDelayPnSeqLevel < 1) || (device->tx->dpdConfig->pathDelayPnSeqLevel > 8191)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL, + getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL)); + return MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL; + } + + /* Set Path Delay PN sequence amplitude - positive and negative */ + armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->pathDelayPnSeqLevel & 0xFF); + armFieldValue[1] = (uint8_t)((device->tx->dpdConfig->pathDelayPnSeqLevel >> 8) & 0xFF); + + negPnLevel = ((~device->tx->dpdConfig->pathDelayPnSeqLevel) + 1); /* times -1 */ + armFieldValue[2] = (uint8_t)(negPnLevel & 0xFF); + armFieldValue[3] = (uint8_t)(((negPnLevel) >> 8) & 0xFF); + byteOffset = 10; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armFieldValue[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + else + { + /* record warning about not updated members */ + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE, + getMykonosErrorMessage(MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE)); + } + + return MYKONOS_ERR_OK; +} + +/* \brief Reads the DPD config structure from ARM memory + * + * This function reads the DPD structure + * from ARM memory and returns in the device->tx->dpdConfig structure. + * + * A DPD-enabled transceiver is required for DPD to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->dpdConfig (All members) + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for DPD functions + * \retval MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT Error: NULL pointer to device->tx->dpdConfig structure + */ +mykonosErr_t MYKONOS_getDpdConfig(mykonosDevice_t *device) +{ + uint16_t byteOffset = 0; + uint8_t armMem[20] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdConfig()\n"); +#endif + + /* DPD requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV)); + return MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV; + } + + if (device->tx->dpdConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT)); + return MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT; + } + + byteOffset = 0; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armMem[0], 20); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->dpdConfig->damping = (armMem[0] & 0x0F); + device->tx->dpdConfig->numWeights = ((armMem[0] >> 4) & 0x03); + + device->tx->dpdConfig->modelVersion = (armMem[1] & 0x03); + device->tx->dpdConfig->highPowerModelUpdate = ((armMem[1] >> 2) & 0x01); + device->tx->dpdConfig->robustModeling = 0; + device->tx->dpdConfig->samples = ((uint16_t)(armMem[3]) << 8) | (uint16_t)(armMem[2]); + + device->tx->dpdConfig->outlierThreshold = ((uint16_t)(armMem[11]) << 8) | (uint16_t)(armMem[10]); + device->tx->dpdConfig->modelPriorWeight = armMem[12]; + device->tx->dpdConfig->weights[0].real = (int8_t)(armMem[14]); + device->tx->dpdConfig->weights[0].imag = (int8_t)(armMem[15]); + device->tx->dpdConfig->weights[1].real = (int8_t)(armMem[16]); + device->tx->dpdConfig->weights[1].imag = (int8_t)(armMem[17]); + device->tx->dpdConfig->weights[2].real = (int8_t)(armMem[18]); + device->tx->dpdConfig->weights[2].imag = (int8_t)(armMem[19]); + + byteOffset = 2; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->dpdConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + byteOffset = 10; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->dpdConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function reads the DPD calibration status from the Mykonos ARM processor. + * + * The dpdStatus is read back from the ARM processor and returned in the function + * parameter dpdStatus. + * + * A DPD-enabled transceiver is required for this feature to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to read back DPD status for (Valid ENUM values: TX1 or TX2 only) + * \param dpdStatus Pointer to a structure to return the status information to + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETDPDSTATUS_NULLPARAM dpdStatus function parameter is a NULL pointer + * \retval MYKONOS_ERR_GETDPDSTATUS_INV_CH txChannel parameter is a non-supported value. + * \retval MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command + */ +mykonosErr_t MYKONOS_getDpdStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdStatus_t *dpdStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_DPDCONFIG, 0}; + uint8_t armData[64] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint8_t channelSelect = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdStatus()\n"); +#endif + + if (dpdStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETDPDSTATUS_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + channelSelect = 0; + break; + case TX2: + channelSelect = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_INV_CH)); + return MYKONOS_ERR_GETDPDSTATUS_INV_CH; + } + } + + extData[2] = channelSelect; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + dpdStatus->dpdErrorStatus = ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]); /* Only lower 16 bits */ + dpdStatus->dpdTrackCount = ((uint32_t)(armData[11]) << 24) | ((uint32_t)(armData[10]) << 16) | ((uint32_t)(armData[9]) << 8) | (uint32_t)(armData[8]); + dpdStatus->dpdModelErrorPercent = ((uint32_t)(armData[15]) << 24) | ((uint32_t)(armData[14]) << 16) | ((uint32_t)(armData[13]) << 8) | (uint32_t)(armData[12]); + dpdStatus->dpdExtPathDelay = ((uint32_t)(armData[26]) * 16) + (uint32_t)(armData[24]); + dpdStatus->dpdMaxAdaptationCurrent = ((uint16_t)(armData[41]) << 8) + (uint16_t)(armData[40]); + dpdStatus->dpdMaxAdaptation = ((uint16_t)(armData[43]) << 8) + (uint16_t)(armData[42]); + dpdStatus->dpdIterCount = ((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This private helper function called during RadioOff, will allow DPD tracking to be scheduled + * by the ARM when back in the RadioOn state. + * + * This function sets a flag in the ARM memory that if the enableDpd tracking cal mask + * and this setting are both set, then the ARM will schedule DPD tracking to occur + * in the radioOn ARM state. + * + * A DPD-enabled transceiver is required for DPD to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->tx->dpdConfig + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param tx1Enable 0=disable DPD Tx1 tracking, 1= enable DPD Tx1 tracking + * \param tx2Enable 0=disable DPD Tx2 tracking, 1= enable DPD Tx2 tracking + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff() + */ +static mykonosErr_t enableDpdTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable) +{ + uint32_t radioStatus = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t enableBit[4] = {0}; + uint8_t byteOffset = 20; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableDpdTracking()\n"); +#endif + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* throw error if not in radioOff/IDLE state */ + if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR, + getMykonosErrorMessage(MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR)); + return MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR; + } + + enableBit[0] = (tx1Enable > 0) ? 1 : 0; + enableBit[1] = 0; + enableBit[2] = (tx2Enable > 0) ? 1 : 0; + enableBit[3] = 0; + + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &enableBit[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function will allow loading of the DPD model file. + * + * This function writes a copy of the user's DPD model to ARM memory and instructs the ARM to install that DPD model + * into hardware. Note that initializing the device will over write DPD model data. Note that the DPD model being + * restored must match the PA for which it is configured. Restoring a DPD model to a different PA than for which it + * is configured will not yield the desired performance. The user is responsible to insure the DPD model matches the + * PA configuration. + * + * \param device Structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired transmit channel to which to write the DPD model file (Valid ENUM type mykonosTxChannels_t: TX1 or TX2 or TX1_TX2) + * \param modelDataBuffer Pointer to the user buffer containing the history/model data to be loaded to a txChannel + * Valid sizes: 182 bytes for a single model load to either TX1 or TX2. + * 364 bytes for a dual model load to both TX1_TX2, where the TX1 model data will occupy the first 182 bytes + * and TX2 model data will occupy the second 182 bytes. + * \param modelNumberBytes Total buffer size of the user history/model data buffer. Allowed sizes are 182 bytes for TX1 or TX2 and + * 364 bytes for TX1_TX2. + * + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE User suppled modelNumberBytes size is incorrect. TX1 or TX2 = 182, TX1_TX2 = 364 + * \retval MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL User supplied txChannel does not match TX1 or TX2 or TX1_TX2 + * \retval MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG ARM returned error for Set ARM Command + */ +mykonosErr_t MYKONOS_restoreDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes) +{ + uint32_t radioStatus = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[4] = {0}; + uint32_t armBufferAddr = 0; + uint8_t *bufferPtr = 0; + uint8_t extendedData[4] = {0}; + uint8_t cmdStatusByte = 0; + + const uint8_t RESTORE = 0x08; + const uint32_t timeoutMs = 1000; + const uint32_t MODEL_SIZE = 182; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_restoreDpdModel()\n"); +#endif + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if (txChannel == TX1) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != MODEL_SIZE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE; + } + + /* retrieve the arm TX1 model buffer address */ + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* write the TX1 model */ + bufferPtr = modelDataBuffer; + retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX1 model */ + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + }/*end TX1 */ + + else if (txChannel == TX2) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != MODEL_SIZE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE; + } + + /* retrieve the arm TX2 model buffer address */ + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* write the TX2 model */ + bufferPtr = modelDataBuffer; + retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + }/* end TX2 */ + + /* check for dual txChannel type */ + else if (txChannel == TX1_TX2) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != (2 * MODEL_SIZE)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE; + } + + /* retrieve the arm TX1 model buffer address */ + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* write the TX1 model */ + bufferPtr = modelDataBuffer; + retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX1 model */ + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + bufferPtr += MODEL_SIZE; + + /* retrieve the arm TX2 model buffer address */ + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* write the TX2 model */ + retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX2 model */ + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + }/*end two txChannel model data load */ + + /* invalid txChannel for this API command */ + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL)); + return MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL; + }/* end invalid txChannel check */ + + /* instruct ARM to load DPD Model */ + extendedData[0] = MYKONOS_ARM_OBJECTID_GS_TRACKCALS; + extendedData[1] = MYKONOS_ARM_DPD_RESET; + extendedData[2] = (uint8_t)txChannel + RESTORE; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extendedData[0], sizeof(extendedData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* wait max of 1sec for command to complete */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG)); + return MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG; + } + return retVal; + } + + return MYKONOS_ERR_OK; +} + + +/** + * \brief This function called during RadioOff, will allow retrieval of the DPD model file. + * + * This function reads a copy of the DPD model from ARM memory to user memory specified by the modelDataBuffer pointer. + * The user must provide the correct buffer size with the modelNumberBytes argument. + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to read back DPD status for (Valid ENUM type mykonosTxChannels_t: TX1 or TX2 or TX1_TX2) + * \param modelDataBuffer a pointer to the user buffer where the model data is to be written. + * Valid sizes: 182 bytes for a single model load to either TX1 or TX2. + * 364 bytes for a dual model load to both TX1_TX2, where the TX1 model data will occupy the first 182 bytes + * and TX2 model data will occupy the second 182 bytes. + * \param modelNumberBytes is the total buffer size of the user model data buffer. Allowed sizes are 182 bytes for TX1 or TX2 and + * 364 bytes for TX1_TX2. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SAVEDPDMODEL_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff() + * \retval MYKONOS_ERR_SAVEDPDMODEL_BUFFERSIZE_ERROR suppled modelNumberBytes size is incorrect. TX1 or TX2 = 182, TX1_TX2 = 364 + * \retval MYKONOS_ERR_SAVEDPDMODEL_INVALID_TXCHANNEL_ERROR supplied txChannel does not match TX1 or TX2 or TX1_TX2 + */ +mykonosErr_t MYKONOS_saveDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes) +{ + uint32_t radioStatus = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t modelSize = 0; + uint8_t armData[4] = {0}; + uint32_t armBufferAddr = 0; + + const uint32_t MODEL_SIZE = 182; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_saveDpdModel()\n"); +#endif + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* throw error if not in radioOff/IDLE state */ + if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_ARMSTATE, getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_ARMSTATE)); /* radio not off or initialized */ + return MYKONOS_ERR_SAVDPDMOD_ARMSTATE; + } + + if (txChannel == TX1) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != MODEL_SIZE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */ + } + + /* retrieve the arm TX1 model buffer address */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* read the TX1 model */ + retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + modelDataBuffer += modelSize; + }/*end TX1 */ + + else if (txChannel == TX2) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != MODEL_SIZE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */ + } + + /* retrieve the arm TX2 model buffer address */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* read the TX2 model */ + retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + }/*end TX2 */ + + /* check for dual txChannel type */ + else if (txChannel == TX1_TX2) + { + /* check for single valid provided buffer size */ + if (modelNumberBytes != (2 * MODEL_SIZE)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE, + getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE)); + return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */ + } + + /* retrieve the arm TX1 model buffer address */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* read the TX1 model */ + retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + modelDataBuffer += MODEL_SIZE; + + /* retrieve the arm TX2 model buffer address */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24)); + + /* read the TX2 model */ + retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + }/* end TX1_TX2 txChannel */ + + /* invalid txChannel for this API command */ + else + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL)); + return MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL; /* invalid txChannel */ + }/* end invalid txChannel check */ + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function sets the state of the DPD actuator. + * + * This function can be called in either Radio On or Off state. + * + * \pre A DPD-enabled transceiver is required for DPD to be enabled. DPD init cal has been run and DPD tracking enable. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to set the Actuator State (Valid ENUM values: TX1, TX2 or TX1_TX2) + * \param actState Desired actuator state for the DPD, valid states are 0-disable and 1-enable + * + * \retval MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL ERROR: Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2) + * \retval MYKONOS_ERR_SETDPDACT_INV_STATE ERROR: Invalid Actuator state, valid states are 0-disable and 1-enable. + * \retval MYKONOS_ERR_SETDPDACT_ARMERRFLAG ERROR: ARM command flag error set + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setDpdActState(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t actState) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; + uint8_t extData[3] = {0}; + uint8_t actuatorSet = 0x00; + uint8_t cmdStatusByte = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdActState()\n"); +#endif + + switch (txChannel) + { + case TX1: + break; + case TX2: + break; + case TX1_TX2: + break; + + default: + /* this function allow single channel gain only */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL)); + return MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL; + } + switch (actState) + { + case 0: + actuatorSet = DISABLE_DPD_ACTUATOR; + break; + case 1: + actuatorSet = ENABLE_DPD_ACTUATOR; + break; + + default: + /* this function allow single channel gain only */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_STATE, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_STATE)); + return MYKONOS_ERR_SETDPDACT_INV_STATE; + } + + extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL; + extData[1] = actuatorSet; + extData[2] = (uint8_t)txChannel; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_ARMERRFLAG)); + return MYKONOS_ERR_SETDPDACT_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_ARMERRFLAG)); + return MYKONOS_ERR_SETDPDACT_ARMERRFLAG; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function resets the DPD model. + * + * This function allows the user to reset the DPD actuator and prior model in radioOn or radioOff mode. + * The reset can restore prior model if the parameter passed is set to 2: this resets DPD first and then restores the previously loaded + * model into ARM memory for use with subsequent iterations of DPD. + * + * If reset is 1 then the reset function just reset the DPD actuator and not use any model. + * + * \pre A DPD-enabled transceiver is required for DPD to be enabled. DPD init cal has been run and DPD tracking enable. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to be reseted (Valid ENUM values: TX1, TX2 or TX1_TX2) + * \param reset is the required reset condition that is needed, the available options are given by the enum + * ::mykonosDpdResetMode_t + * + * \retval MYKONOS_ERR_RESETDPD_INV_TXCHANNEL: Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2) + * \retval MYKONOS_ERR_RESETDPD_WRONG_PARAM ERROR: reset parameter is not valid (Valid values: MYK_DPD_RESET_FULL, MYK_DPD_RESET_PRIOR or MYK_DPD_RESET_CORRELATOR) + * \retval MYKONOS_ERR_RESETDPD_ARMERRFLAG ERROR: ARM command flag error set + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_resetDpd(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdResetMode_t reset) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; + uint8_t extData[3] = {0}; + uint8_t cmdStatusByte = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDpd()\n"); +#endif + + switch (txChannel) + { + case TX1: + break; + case TX2: + break; + case TX1_TX2: + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_INV_TXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_INV_TXCHANNEL)); + return MYKONOS_ERR_RESETDPD_INV_TXCHANNEL; + } + + if ((reset >= MYK_DPD_RESET_END) || (reset == MYK_DPD_NO_ACTION)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_WRONG_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_WRONG_PARAM)); + return MYKONOS_ERR_RESETDPD_WRONG_PARAM; + } + + /* instruct ARM to reset DPD Model */ + extData[0] = MYKONOS_ARM_OBJECTID_GS_TRACKCALS; + extData[1] = MYKONOS_ARM_DPD_RESET; + extData[2] = (uint8_t)(reset << 2) + (uint8_t)txChannel; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* wait max of 1sec for command to complete */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_ARMERRFLAG)); + return MYKONOS_ERR_RESETDPD_ARMERRFLAG; + } + return retVal; + } + + return MYKONOS_ERR_OK; +} +/** + * \brief This function will configure CLGC settings + * + * A DPD-enabled transceiver is required for CLGC to be enabled. The CLGC has several user + * adjustable settings that can be configured before running the runInitCals + * with the calMask set for the CLGC init cal. Call this function with desired + * settings set before running the CLGC init cal or enabling CLGC tracking. + * + * This function can be called in either Radio On or Off state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->clgcConfig (All members) + * + * \retval MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV ERROR: Tx and ObsRx profiles must be valid to use the CLGC feature + * \retval MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT ERROR: CLGC config structure pointer is null in device->tx->clgcConfig + * \retval MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN ERROR: CLGC tx1DesiredGain or tx2DesiredGain parameter is out of range + * \retval MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT ERROR: CLGC tx1AttenLimit or tx2AttenLimit parameter is out of range + * \retval MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO ERROR: clgcControlRatio parameter is out of range + * \retval MYKONOS_ERR_CFGCLGC_INV_THRESHOLD Error: tx1RelThreshold or tx2RelThreshold parameter is out of range + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_configClgc(mykonosDevice_t *device) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[4] = {0}; + uint8_t byteOffset = 0; + uint16_t negPnLevel = 0; + uint32_t radioStatus = 0x00; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configClgc()\n"); +#endif + + /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV)); + return MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV; + } + + if (device->tx->clgcConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT)); + return MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT; + } + + /* set CLGC desired gain parameter */ + if ((device->tx->clgcConfig->tx1DesiredGain < -10000) || (device->tx->clgcConfig->tx1DesiredGain > 10000) || (device->tx->clgcConfig->tx2DesiredGain < -10000) + || (device->tx->clgcConfig->tx2DesiredGain > 10000)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN)); + return MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN; + } + + armFieldValue[0] = (device->tx->clgcConfig->tx1DesiredGain & 0xFF); + armFieldValue[1] = (((uint16_t)device->tx->clgcConfig->tx1DesiredGain >> 8) & 0xFF); + armFieldValue[2] = (device->tx->clgcConfig->tx2DesiredGain & 0xFF); + armFieldValue[3] = (((uint16_t)device->tx->clgcConfig->tx2DesiredGain >> 8) & 0xFF); + + byteOffset = 0; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set CLGC Tx Atten limit parameter */ + if ((device->tx->clgcConfig->tx1AttenLimit > 40) || (device->tx->clgcConfig->tx2AttenLimit > 40)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT)); + return MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT; + } + + armFieldValue[0] = (device->tx->clgcConfig->tx1AttenLimit & 0xFF); + armFieldValue[1] = ((device->tx->clgcConfig->tx1AttenLimit >> 8) & 0xFF); + armFieldValue[2] = (device->tx->clgcConfig->tx2AttenLimit & 0xFF); + armFieldValue[3] = ((device->tx->clgcConfig->tx2AttenLimit >> 8) & 0xFF); + + byteOffset = 8; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set CLGC Control Ratio parameter */ + if ((device->tx->clgcConfig->tx1ControlRatio < 1) || (device->tx->clgcConfig->tx1ControlRatio > 100) || (device->tx->clgcConfig->tx2ControlRatio < 1) + || (device->tx->clgcConfig->tx2ControlRatio > 100)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO)); + return MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO; + } + + armFieldValue[0] = (device->tx->clgcConfig->tx1ControlRatio & 0xFF); + armFieldValue[1] = ((device->tx->clgcConfig->tx1ControlRatio >> 8) & 0xFF); + armFieldValue[2] = (device->tx->clgcConfig->tx2ControlRatio & 0xFF); + armFieldValue[3] = ((device->tx->clgcConfig->tx2ControlRatio >> 8) & 0xFF); + + byteOffset = 12; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set enable threshold for channel 1 */ + armFieldValue[0] = (device->tx->clgcConfig->tx1RelThresholdEn > 0) ? 1 : 0; + byteOffset = 0x24; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set enable threshold for channel 2 */ + armFieldValue[0] = (device->tx->clgcConfig->tx2RelThresholdEn > 0) ? 1 : 0; + byteOffset = 0x26; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set thresholds */ + if ((device->tx->clgcConfig->tx1RelThreshold > 10000) || (device->tx->clgcConfig->tx2RelThreshold > 10000)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_THRESHOLD, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_THRESHOLD)); + return MYKONOS_ERR_CFGCLGC_INV_THRESHOLD; + } + + /* set threshold for channel 1 */ + armFieldValue[0] = (device->tx->clgcConfig->tx1RelThreshold & 0xFF); + armFieldValue[1] = ((device->tx->clgcConfig->tx1RelThreshold >> 8) & 0xFF); + byteOffset = 0x28; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set threshold for channel 2 */ + armFieldValue[0] = (device->tx->clgcConfig->tx2RelThreshold & 0xFF); + armFieldValue[1] = ((device->tx->clgcConfig->tx2RelThreshold >> 8) & 0xFF); + byteOffset = 0x2A; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if ((device->tx->clgcConfig->pathDelayPnSeqLevel < 1) || (device->tx->clgcConfig->pathDelayPnSeqLevel > 8191)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL)); + return MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL; + } + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Radio state check */ + if (((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_IDLE) || ((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_READY)) + { + /* set CLGC additional delay offset parameter (init cal)*/ + if ((device->tx->clgcConfig->additionalDelayOffset < -64) || (device->tx->clgcConfig->additionalDelayOffset > 64)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY)); + return MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY; + } + + armFieldValue[0] = (device->tx->clgcConfig->additionalDelayOffset & 0xFF); + armFieldValue[1] = (((uint16_t)device->tx->clgcConfig->additionalDelayOffset >> 8) & 0xFF); + byteOffset = 2; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if ((device->tx->clgcConfig->pathDelayPnSeqLevel < 1) || (device->tx->clgcConfig->pathDelayPnSeqLevel > 8191)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL)); + return MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL; + } + + /* Can not be changed in radio on */ + /* Set Path Delay PN sequence amplitude - positive and negative (init cal)*/ + armFieldValue[0] = (device->tx->clgcConfig->pathDelayPnSeqLevel & 0xFF); + armFieldValue[1] = ((device->tx->clgcConfig->pathDelayPnSeqLevel >> 8) & 0xFF); + + negPnLevel = ((~device->tx->clgcConfig->pathDelayPnSeqLevel) + 1); /* times -1 */ + armFieldValue[2] = (negPnLevel & 0xFF); + armFieldValue[3] = (((negPnLevel) >> 8) & 0xFF); + byteOffset = 10; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = enableClgcTracking(device, ((device->tx->clgcConfig->allowTx1AttenUpdates > 0) ? 1 : 0), ((device->tx->clgcConfig->allowTx2AttenUpdates > 0) ? 1 : 0)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + } + else + { + /* record warning about not updated members */ + CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE, + getMykonosErrorMessage(MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE)); + } + + return MYKONOS_ERR_OK; +} + +/* \brief Reads the CLGC config structure from ARM memory + * + * This function reads the Closed Loop Gain Control structure + * from ARM memory and returns in the device->tx->clgcConfig structure. + * + * A DPD-enabled transceiver is required for CLGC to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->clgcConfig (All members) + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for CLGC functions + * \retval MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT Error: NULL pointer to device->tx->clgcConfig structure + */ +mykonosErr_t MYKONOS_getClgcConfig(mykonosDevice_t *device) +{ + uint16_t byteOffset = 0; + uint8_t armMem[16] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcConfig()\n"); +#endif + + /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV)); + return MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV; + } + + if (device->tx->clgcConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT)); + return MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT; + } + + byteOffset = 0; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], sizeof(armMem)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->tx1DesiredGain = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + device->tx->clgcConfig->tx2DesiredGain = (int16_t)(((uint16_t)(armMem[3]) << 8) | (uint16_t)(armMem[2])); + device->tx->clgcConfig->tx1AttenLimit = (((uint16_t)(armMem[9]) << 8) | (uint16_t)(armMem[8])); + device->tx->clgcConfig->tx2AttenLimit = (((uint16_t)(armMem[11]) << 8) | (uint16_t)(armMem[10])); + device->tx->clgcConfig->tx1ControlRatio = (((uint16_t)(armMem[13]) << 8) | (uint16_t)(armMem[12])); + device->tx->clgcConfig->tx2ControlRatio = (((uint16_t)(armMem[15]) << 8) | (uint16_t)(armMem[14])); + + byteOffset = 2; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + byteOffset = 10; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + /* need to figure out if this are the right addresses */ + byteOffset = 0x24; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->tx1RelThresholdEn = (uint8_t)armMem[0]; + + byteOffset = 0x26; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->tx2RelThresholdEn = (uint8_t)armMem[0]; + + byteOffset = 0x28; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->tx1RelThreshold = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + byteOffset = 0x2A; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->clgcConfig->tx2RelThreshold = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function reads the CLGC calibration status from the Mykonos ARM processor. + * + * The Closed Loop Gain Control Status is read back from the ARM processor and + * returned in the function parameter clgcStatus. + * + * A DPD-enabled transceiver is required for this feature to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to read back CLGC status for (Valid ENUM values: TX1 or TX2 only) + * \param clgcStatus Pointer to a structure to return the status information to + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM clgcStatus function parameter is a NULL pointer + * \retval MYKONOS_ERR_GETCLGCSTATUS_INV_CH txChannel parameter is a non supported value. + * \retval MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command + */ +mykonosErr_t MYKONOS_getClgcStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosClgcStatus_t *clgcStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_CLGCCONFIG, 0}; + uint8_t armData[52] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t channelSelect = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcStatus()\n"); +#endif + + if (clgcStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + channelSelect = 0; + break; + case TX2: + channelSelect = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_INV_CH)); + return MYKONOS_ERR_GETCLGCSTATUS_INV_CH; + } + } + + extData[2] = channelSelect; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + clgcStatus->errorStatus = ((uint32_t)(armData[3]) << 24) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]); + clgcStatus->desiredGain = (int32_t)(((uint32_t)(armData[23]) << 24) | ((uint32_t)(armData[22]) << 16) | ((uint32_t)(armData[21]) << 8) | (uint32_t)(armData[20])); + clgcStatus->currentGain = (int32_t)(((uint32_t)(armData[27]) << 24) | ((uint32_t)(armData[26]) << 16) | ((uint32_t)(armData[25]) << 8) | (uint32_t)(armData[24])); + clgcStatus->txGain = ((uint32_t)(armData[39]) << 24) | ((uint32_t)(armData[38]) << 16) | ((uint32_t)(armData[37]) << 8) | (uint32_t)(armData[36]); + clgcStatus->txRms = (int32_t)(((uint32_t)(armData[43]) << 24) | ((uint32_t)(armData[42]) << 16) | ((uint32_t)(armData[41]) << 8) | (uint32_t)(armData[40])); + clgcStatus->orxRms = (int32_t)(((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44])); + clgcStatus->trackCount = ((uint32_t)(armData[51]) << 24) | ((uint32_t)(armData[50]) << 16) | ((uint32_t)(armData[49]) << 8) | (uint32_t)(armData[48]); + + return retVal; +} + +/** + * \brief This private helper function called during RadioOff, will allow CLGC tracking to be scheduled + * by the ARM when back in the RadioOn state. + * + * This function sets a flag in the ARM memory that if the enableDpd tracking cal mask + * and this setting are both set, then the ARM will schedule closed loop gain control + * tracking to occur in the radioOn ARM state. + * + * A DPD-enabled transceiver is required for this feature to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->tx->dpdConfig + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param tx1Enable 0=disable CLGC Tx1 tracking, 1= enable CLGC Tx1 tracking + * \param tx2Enable 0=disable CLGC Tx2 tracking, 1= enable CLGC Tx2 tracking + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff() + */ +static mykonosErr_t enableClgcTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable) +{ + uint32_t radioStatus = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t enableBit[4] = {0}; + uint8_t byteOffset = 4; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableClgcTracking()\n"); +#endif + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* throw error if not in radioOff/IDLE state */ + if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR, + getMykonosErrorMessage(MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR)); + return MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR; + } + + enableBit[0] = (tx1Enable > 0) ? 1 : 0; + enableBit[1] = 0; + enableBit[2] = (tx2Enable > 0) ? 1 : 0; + enableBit[3] = 0; + + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &enableBit[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function updates the CLGC desired gain parameter. + * + * This function can be called in either Radio On or Off state. + * + * \pre A DPD-enabled transceiver is required for CLGC to be enabled. CLGC init cal has been run and CLGC tracking enable. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to set the (Valid ENUM values: TX1 or TX2 only) + * \param gain Total gain and attenuation (dB * 100) for the selected channel txChannel + * + * \retval MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL ERROR: Tx channel is not valid (Valid ENUM values: TX1 or TX2 only) + * \retval MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG ERROR: ARM command flag error set + * \retval MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN ERROR: CLGC gain parameter is out of range, valid range is from -10000 to 10000. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setClgcGain(mykonosDevice_t *device, mykonosTxChannels_t txChannel, int16_t gain) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; + uint8_t extData[4] = {0}; + uint8_t clcgChannel = 0x00; + uint8_t cmdStatusByte = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setClgcGain()\n"); +#endif + + /* Range check for desired gain parameter */ + if ((gain < -10000) || (gain > 10000)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN, + getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN)); + return MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN; + } + + switch (txChannel) + { + case TX1: + clcgChannel = SET_CLGC_DESIRED_GAIN_1; + break; + case TX2: + clcgChannel = SET_CLGC_DESIRED_GAIN_2; + break; + + default: + /* this function allow single channel gain only */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL, + getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL)); + return MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL; + } + + extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL; + extData[1] = clcgChannel; + extData[2] = (gain & 0xFF); + extData[3] = (((uint16_t)gain >> 8) & 0xFF); + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* check for completion */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG)); + return MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function, when called during RadioOff, will configure VSWR settings + * + * A DPD-enabled transceiver is required for VSWR to be enabled. The VSWR has several user + * adjustable settings that can be configured before running the runInitCals + * with the calMask set for the VSWR init cal. Call this function with desired + * settings set before running the VSWR init cal or enabling VSWR tracking. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->vswrConfig (All members) + * + * \retval MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV ERROR: Tx and ObsRx profiles must be valid to use the VSWR feature + * \retval MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT ERROR: CLGC config structure pointer is null in device->tx->clgcConfig + * \retval MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR ERROR: ARM is not in the IDLE(radioOff) or Ready state. + */ +mykonosErr_t MYKONOS_configVswr(mykonosDevice_t *device) +{ + uint32_t radioStatus = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[16] = {0}; + uint8_t byteOffset = 0; + uint16_t negPnLevel = 0; + + const uint8_t ENABLE_VSWR = 1; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configVswr()\n"); +#endif + + /* VSWR requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV)); + return MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV; + } + + if (device->tx->vswrConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT)); + return MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT; + } + + /* read radio state to make sure ARM is in radioOff /IDLE */ + retVal = MYKONOS_getRadioState(device, &radioStatus); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* throw error if not in radioOff/IDLE state */ + if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR)); + return MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR; + } + + /* range check valid 3p3 GPIO pin */ + if ((device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin > 11) || (device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin > 11)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN)); + return MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN; + } + + armFieldValue[0] = ENABLE_VSWR; + armFieldValue[1] = 0; + armFieldValue[2] = ENABLE_VSWR; + armFieldValue[3] = 0; + armFieldValue[4] = (device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin & 0xFF); + armFieldValue[5] = 0; + armFieldValue[6] = (device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin & 0xFF); + armFieldValue[7] = 0; + armFieldValue[8] = (device->tx->vswrConfig->tx1VswrSwitchPolarity > 0) ? 1 : 0; + armFieldValue[9] = 0; + armFieldValue[10] = (device->tx->vswrConfig->tx2VswrSwitchPolarity > 0) ? 1 : 0; + armFieldValue[11] = 0; + armFieldValue[12] = device->tx->vswrConfig->tx1VswrSwitchDelay_us; /* support full 0 to 255 us range */ + armFieldValue[13] = 0; + armFieldValue[14] = device->tx->vswrConfig->tx2VswrSwitchDelay_us; /* support full 0 to 255 us range */ + armFieldValue[15] = 0; + byteOffset = 0; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRCONFIG, byteOffset, &armFieldValue[0], 16); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* set VSWR additional delay offset parameter (init cal)*/ + if ((device->tx->vswrConfig->additionalDelayOffset < -64) || (device->tx->vswrConfig->additionalDelayOffset > 64)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY)); + return MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY; + } + + armFieldValue[0] = (device->tx->vswrConfig->additionalDelayOffset & 0xFF); + armFieldValue[1] = (((uint16_t)device->tx->vswrConfig->additionalDelayOffset >> 8) & 0xFF); + byteOffset = 2; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + if ((device->tx->vswrConfig->pathDelayPnSeqLevel < 1) || (device->tx->vswrConfig->pathDelayPnSeqLevel > 8191)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL, + getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL)); + return MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL; + } + + /* Set Path Delay PN sequence amplitude - positive and negative (init cal)*/ + armFieldValue[0] = (device->tx->vswrConfig->pathDelayPnSeqLevel & 0xFF); + armFieldValue[1] = ((device->tx->vswrConfig->pathDelayPnSeqLevel >> 8) & 0xFF); + + negPnLevel = ((~device->tx->vswrConfig->pathDelayPnSeqLevel) + 1); /* times -1 */ + armFieldValue[2] = (negPnLevel & 0xFF); + armFieldValue[3] = (((negPnLevel) >> 8) & 0xFF); + byteOffset = 10; + + /* Set for Tx1 channel */ + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Set for Tx2 channel */ + byteOffset = 30; + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 4); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/* \brief Reads the VSWR config structure from ARM memory + * + * This function reads the VSWR structure + * from ARM memory and returns in the device->tx->vswrConfig structure. + * + * A DPD-enabled transceiver is required for VSWR to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * - device->tx->vswrConfig (All members) + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for VSWR functions + * \retval MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT Error: NULL pointer to device->tx->vswrConfig structure + */ +mykonosErr_t MYKONOS_getVswrConfig(mykonosDevice_t *device) +{ + uint16_t byteOffset = 0; + uint8_t armMem[12] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getVswrConfig()\n"); +#endif + + /* VSWR requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV)); + return MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV; + } + + if (device->tx->vswrConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT)); + return MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT; + } + + byteOffset = 4; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRCONFIG, byteOffset, &armMem[0], sizeof(armMem)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin = armMem[0]; + device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin = armMem[2]; + device->tx->vswrConfig->tx1VswrSwitchPolarity = armMem[4]; + device->tx->vswrConfig->tx2VswrSwitchPolarity = armMem[6]; + device->tx->vswrConfig->tx1VswrSwitchDelay_us = armMem[8]; + device->tx->vswrConfig->tx2VswrSwitchDelay_us = armMem[10]; + + byteOffset = 2; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->vswrConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + byteOffset = 10; + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armMem[0], 2); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + device->tx->vswrConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0])); + + return MYKONOS_ERR_OK; +} + +/** + * \brief This function reads the VSWR calibration status from the Mykonos ARM processor. + * + * The VSWR Status is read back from the ARM processor and + * returned in the function parameter vswrStatus. + * + * A DPD-enabled transceiver is required for this feature to be enabled. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param txChannel Desired Transmit channel to read back VSWR status for (Valid ENUM values: TX1 or TX2 only) + * \param vswrStatus Pointer to a structure to return the status information to + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM vswrStatus function parameter is a NULL pointer + * \retval MYKONOS_ERR_GETVSWRSTATUS_INV_CH txChannel parameter is a non supported value. + * \retval MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command + */ +mykonosErr_t MYKONOS_getVswrStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosVswrStatus_t *vswrStatus) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_VSWRCONFIG, 0}; + uint8_t armData[64] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint32_t offset = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t channelSelect = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getVswrStatus()\n"); +#endif + + if (vswrStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM)); + return MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + channelSelect = 0; + break; + case TX2: + channelSelect = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_INV_CH)); + return MYKONOS_ERR_GETVSWRSTATUS_INV_CH; + } + } + + extData[2] = channelSelect; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + /* throw more specific error message instead of returning error code from waitArmCmdStatus */ + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG)); + return MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG; + } + + /* read status from ARM memory */ + offset = 0; + retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + vswrStatus->errorStatus = ((uint32_t)(armData[3]) << 24) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]); + vswrStatus->forwardGainRms_dB = (int32_t)(((uint32_t)(armData[23]) << 24) | ((uint32_t)(armData[22]) << 16) | ((uint32_t)(armData[21]) << 8) | (uint32_t)(armData[20])); + vswrStatus->forwardGainReal = (int32_t)(((uint32_t)(armData[27]) << 24) | ((uint32_t)(armData[26]) << 16) | ((uint32_t)(armData[25]) << 8) | (uint32_t)(armData[24])); + vswrStatus->forwardGainImag = (int32_t)(((uint32_t)(armData[31]) << 24) | ((uint32_t)(armData[30]) << 16) | ((uint32_t)(armData[29]) << 8) | (uint32_t)(armData[28])); + vswrStatus->reflectedGainRms_dB = (int32_t)(((uint32_t)(armData[35]) << 24) | ((uint32_t)(armData[34]) << 16) | ((uint32_t)(armData[33]) << 8) | (uint32_t)(armData[32])); + vswrStatus->reflectedGainReal = (int32_t)(((uint32_t)(armData[39]) << 24) | ((uint32_t)(armData[38]) << 16) | ((uint32_t)(armData[37]) << 8) | (uint32_t)(armData[36])); + vswrStatus->reflectedGainImag = (int32_t)(((uint32_t)(armData[43]) << 24) | ((uint32_t)(armData[42]) << 16) | ((uint32_t)(armData[41]) << 8) | (uint32_t)(armData[40])); + vswrStatus->trackCount = ((uint32_t)(armData[63]) << 24) | ((uint32_t)(armData[62]) << 16) | ((uint32_t)(armData[61]) << 8) | (uint32_t)(armData[60]); + vswrStatus->vswr_forward_tx_rms = (int32_t)(((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44])); + vswrStatus->vswr_forward_orx_rms = (int32_t)(((uint32_t)(armData[51]) << 24) | ((uint32_t)(armData[50]) << 16) | ((uint32_t)(armData[49]) << 8) | (uint32_t)(armData[48])); + vswrStatus->vswr_reflection_tx_rms = (int32_t)(((uint32_t)(armData[55]) << 24) | ((uint32_t)(armData[54]) << 16) | ((uint32_t)(armData[53]) << 8) | (uint32_t)(armData[52])); + vswrStatus->vswr_reflection_orx_rms = (int32_t)(((uint32_t)(armData[59]) << 24) | ((uint32_t)(armData[58]) << 16) | ((uint32_t)(armData[57]) << 8) | (uint32_t)(armData[56])); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Read from the Mykonos ARM program or data memory + * + * Valid memory addresses are: Program Memory (0x01000000 - 0x01017FFF), + * Data Memory (0x20000000 - 0x2000FFFF) + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param address The 32bit ARM address to read from. + * \param returnData Byte(uint8_t) array containing the data read from the ARM memory. + * \param bytesToRead Number of bytes in the returnData array. + * \param autoIncrement is boolean flag to enable or disable autoincrement of ARM register address + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READARMMEM_INV_ADDR_PARM ARM memory address is out of range + * + */ +mykonosErr_t MYKONOS_readArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *returnData, uint32_t bytesToRead, uint8_t autoIncrement) +{ + uint8_t dataMem; + uint32_t i; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmMem()\n"); +#endif + + /* check that start and stop address are in valid range */ + if ((!(address >= MYKONOS_ADDR_ARM_START_PROG_ADDR && address <= MYKONOS_ADDR_ARM_END_PROG_ADDR)) + && !(address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMMEM_INV_ADDR_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READARMMEM_INV_ADDR_PARM)); + return MYKONOS_ERR_READARMMEM_INV_ADDR_PARM; + } + + if ((!(((address + bytesToRead - 1) >= MYKONOS_ADDR_ARM_START_PROG_ADDR) && (address + bytesToRead - 1) <= MYKONOS_ADDR_ARM_END_PROG_ADDR)) + && (!(((address + bytesToRead - 1) >= MYKONOS_ADDR_ARM_START_DATA_ADDR) && (address + bytesToRead - 1) <= MYKONOS_ADDR_ARM_END_DATA_ADDR))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMMEM_INV_ADDR_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READARMMEM_INV_ADDR_PARM)); + return MYKONOS_ERR_READARMMEM_INV_ADDR_PARM; + } + + if (address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR) + { + dataMem = 1; + } + else + { + dataMem = 0; + } + + /* NOT assuming auto increment bit is already set from MYKONOS_initARM function call */ + /* setting auto increment address bit if autoIncrement evaluates true */ + if (autoIncrement) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x04, 2); + } + else + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x00, 0x04, 2); + } + + /* setting up for ARM read */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x20, 5); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2)); /* write address[9:2] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10) | (uint8_t)(dataMem << 7)); /* write address[15:10] */ + + /* start read-back at correct byte offset */ + /* read data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24]. */ + /* with address auto increment set, after xD07 is read, the address will automatically increment */ + /* without address auto increment set, 0x4 must be added to the address for correct indexing */ + if (autoIncrement) + { + for (i = 0; i < bytesToRead; i++) + { + CMB_SPIReadByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), &returnData[i]); + } + } + else + { + for (i = 0; i < bytesToRead; i++) + { + CMB_SPIReadByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), &returnData[i]); + + if ((MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)) == MYKONOS_ADDR_ARM_DATA_BYTE_3) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)(((address + 0x4) & 0x3FF) >> 2)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, ((address + 0x4) & 0x1FC00U) >> 10 | (uint8_t)(dataMem << 7)); + } + } + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Write to the Mykonos ARM program or data memory + * + * Valid memory addresses are: Program Memory (0x01000000 - 0x01017FFF), + * Data Memory (0x20000000 - 0x2000FFFF) + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param address The 32bit ARM address to write to. + * \param data Byte(uint8_t) array containing the data to write to the ARM memory. + * \param byteCount Number of bytes in the data array. + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_WRITEARMMEM_NULL_PARM Function parameter data has NULL pointer when byteCount is >0 + * \retval MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM ARM memory address is out of range of valid ARM memory + */ +mykonosErr_t MYKONOS_writeArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *data, uint32_t byteCount) +{ + /* write address, then data with auto increment enabled. */ + uint8_t dataMem; + uint32_t i; + +#if MYK_ENABLE_SPIWRITEARRAY == 1 + uint32_t addrIndex = 0; + uint32_t dataIndex = 0; + uint32_t spiBufferSize = MYK_SPIWRITEARRAY_BUFFERSIZE; + uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0}; +#endif + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_writeArmMem()\n"); +#endif + + if ((data == NULL) && (byteCount > 0)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_NULL_PARM)); + return MYKONOS_ERR_WRITEARMMEM_NULL_PARM; + } + + if ((!(address >= MYKONOS_ADDR_ARM_START_PROG_ADDR && address <= MYKONOS_ADDR_ARM_END_PROG_ADDR)) + && !(address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM, + getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM)); + return MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM; + } + + if ((!(((address + byteCount - 1) >= MYKONOS_ADDR_ARM_START_PROG_ADDR) && ((address + byteCount - 1) <= MYKONOS_ADDR_ARM_END_PROG_ADDR))) + && (!(((address + byteCount - 1) >= MYKONOS_ADDR_ARM_START_DATA_ADDR) && ((address + byteCount - 1) <= MYKONOS_ADDR_ARM_END_DATA_ADDR)))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM, + getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM)); + return MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM; + } + + if (address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR) + { + dataMem = 1; + } + else + { + dataMem = 0; + } + + /* set auto increment address bit */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x04, 2); + + /* writing the address */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x00, 0x20, 5); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10) | (uint8_t)(dataMem << 7)); + + /* start write at correct byte offset */ + /* write data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24] */ + /* with address auto increment set, after x407 is written, the address will automatically increment */ + +#if (MYK_ENABLE_SPIWRITEARRAY == 0) + + for (i = 0; i < byteCount; i++) + { + CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), data[i]); + } + +#elif (MYK_ENABLE_SPIWRITEARRAY == 1) + + addrIndex = 0; + dataIndex = 0; + for (i = 0; i < byteCount; i++) + { + addrArray[addrIndex++] = (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)); + + if (addrIndex == spiBufferSize) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &data[dataIndex], addrIndex); + dataIndex = dataIndex + addrIndex; + addrIndex = 0; + } + } + + if (addrIndex > 0) + { + CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &data[dataIndex], addrIndex); + } + +#endif + + return MYKONOS_ERR_OK; +} + +/** + * \brief Low level helper function used by Mykonos API to write the ARM memory config structures + * + * Normally this function should not be required to be used directly by the BBIC. This is a helper + * function used by other Mykonos API commands to write settings into the ARM memory. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param objectId ARM id of a particular structure or setting in ARM memory + * \param offset Byte offset from the start of the objectId's memory location in ARM memory + * \param data A byte array containing data to write to the ARM memory buffer. + * \param byteCount Number of bytes in the data array (Valid size = 1-255 bytes) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG ARM write config command failed with a nonzero error code + */ +mykonosErr_t MYKONOS_writeArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extendedData[4] = {0}; /* ARM Object id, byte offset LSB, offset MSB = 0, copy 2 bytes */ + uint32_t timeoutMs = 1000; + uint8_t cmdStatusByte = 0; + + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &data[0], byteCount); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + extendedData[0] = objectId; + extendedData[1] = (offset & 0xFF); + extendedData[2] = ((offset >> 8) & 0xFF); + extendedData[3] = byteCount; + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extendedData[0], sizeof(extendedData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG)); + return MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG)); + return MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Low level helper function used by Mykonos API to read the ARM memory config structures + * + * Normally this function should not be required to be used directly by the BBIC. This is a helper + * function used by other Mykonos API commands to read settings from the ARM memory. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param objectId ARM id of a particular structure or setting in ARM memory + * \param offset Byte offset from the start of the objectId's memory location in ARM memory + * \param data A byte array containing data to write to the ARM memory buffer. + * \param byteCount Number of bytes in the data array (Valid size = 1-255 bytes) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READARMCFG_ARMERRFLAG ARM read config command failed with a nonzero error code + */ +mykonosErr_t MYKONOS_readArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extendedData[4] = {0}; /* ARM Object id, byte offset LSB, offset MSB = 0, copy 2 bytes */ + uint32_t timeoutMs = 1000; + uint8_t cmdStatusByte = 0; + const uint8_t AUTO_INCREMENT = 1; + extendedData[0] = objectId; + extendedData[1] = (offset & 0xFF); + extendedData[2] = ((offset >> 8) & 0xFF); + extendedData[3] = byteCount; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_READCFG_OPCODE, &extendedData[0], sizeof(extendedData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_READCFG_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCFG_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_READARMCFG_ARMERRFLAG)); + return MYKONOS_ERR_READARMCFG_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCFG_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_READARMCFG_ARMERRFLAG)); + return MYKONOS_ERR_READARMCFG_ARMERRFLAG; + } + + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &data[0], byteCount, AUTO_INCREMENT); + + return retVal; +} + +/** + * \brief Sends a command to the Mykonos ARM processor + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param opCode Value (0-30, even only) indicating the desired function to run in the ARM. + * \param extendedData A byte array containing extended data to write to the ARM command interface. + * \param extendedDataNumBytes Number of bytes in the extendedData array (Valid size = 0-4 bytes) + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ARMCMD_NULL_PARM Function parameter extendedData is NULL and extendedDataNumBytes is positive + * \retval MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM ARM opcode is out of range (valid 0-30, even only) + * \retval MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM Number of extended bytes parameter is out of range (valid 0-4) + * \retval MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY ARM control interface is busy, command could not be executed by ARM + */ +mykonosErr_t MYKONOS_sendArmCommand(mykonosDevice_t *device, uint8_t opCode, uint8_t *extendedData, uint8_t extendedDataNumBytes) +{ + uint8_t armCommandBusy = 0; + uint8_t i = 0; + uint16_t extCmdByteStartAddr = MYKONOS_ADDR_ARM_EXT_CMD_BYTE_1; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_sendArmCommand()\n"); +#endif + + if ((extendedData == NULL) && (extendedDataNumBytes > 0)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_NULL_PARM)); + return MYKONOS_ERR_ARMCMD_NULL_PARM; + } + + /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */ + if ((opCode != 0) && ((opCode % 2) || (opCode > 30))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM)); + return MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM; + } + + /* the number of valid extended data bytes is from 0-4 */ + if (extendedDataNumBytes > 4) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM)); + return MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM; + } + + /* setting a 2 sec timeout for mailbox busy bit to be clear (can't send an arm mailbox command until mailbox is ready) */ + CMB_setTimeout_ms(2000); + + do + { + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_ARM_CMD, &armCommandBusy, 0x80, 7); + + if (CMB_hasTimeoutExpired()) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY, + getMykonosErrorMessage(MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY)); + return MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY; + } + } while (armCommandBusy); + + if (extendedDataNumBytes) + { + for (i = 0; i < extendedDataNumBytes; i++) + { + CMB_SPIWriteByte(device->spiSettings, extCmdByteStartAddr + i, extendedData[i]); + } + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD, opCode); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Reads the Mykonos ARM 64-bit command status register + * + * A 64-bit status register consisting of a pending bit and three-bit error type is read one byte at + * a time for opcodes 0-30. The function parses the pending bits and error bits into + * two (2) separate 16-bit words containing pending bits, and error bits if the error type > 0 + * The words are weighted according to each even-numbered opcode from 0-30, + * where, 0x0001 = opcode '0', 0x0002 = opcode '2', 0x0004 = opcode '4', 0x0008 = opcode '6' and so on. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param errorWord 16-bit error word comprised of weighted bits according to each opcode number + * The weighted bit = '1' if error type > 0, '0' if OK + * \param statusWord 16-bit pending bits word comprised of weighted bits according to each opcode number + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM Function parameters errorWord or statusWord have a NULL pointer + */ +mykonosErr_t MYKONOS_readArmCmdStatus(mykonosDevice_t *device, uint16_t *errorWord, uint16_t *statusWord) +{ + uint8_t i = 0; + uint8_t bytes[8] = {0}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmCmdStatus()\n"); +#endif + + if (errorWord == NULL || statusWord == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM)); + return MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM; + } + + /* making sure the errorWord and statusWord are clear */ + *errorWord = 0; + *statusWord = 0; + + /* read in the entire 64-bit status register into a byte array for parsing */ + for (i = 0; i < 8; i++) + { + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD_STATUS_0 + i, &bytes[i]); + } + + /* parse the byte array for pending bits and error types and generate statusWord and errorWord bits */ + for (i = 0; i < 8; i++) + { + *statusWord |= (uint16_t)((uint16_t)(((bytes[i] & 0x10) >> 3) | (bytes[i] & 0x01)) << (i * 2)); + + if (bytes[i] & 0x0E) + { + *errorWord |= (uint16_t)(0x0001 << (i * 2)); + } + else if (bytes[i] & 0xE0) + { + *errorWord |= (uint16_t)(0x0002 << (i * 2)); + } + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Isolated byte read of the Mykonos ARM 64-bit command status register based on the opcode + * + * A single byte read is performed on the 64-bit command status register according to + * the opcode of interest. The pending bit and the error type are extracted from the status + * register and returned as a single byte in the lower nibble. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param opCode Valid values are even increments from 0-30. The ARM opCode is used to determine which status register byte to read + * \param cmdStatByte returns cmdStatByte[3:1] = error type, cmdStatByte[0] = pending flag for selected opCode + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM Function parameter cmdStatByte has NULL pointer + * \retval MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM ARM opcode is out of range (valid 0-30, even only) + */ +mykonosErr_t MYKONOS_readArmCmdStatusByte(mykonosDevice_t *device, uint8_t opCode, uint8_t *cmdStatByte) +{ + uint8_t cmdByteIndex = 0; + uint8_t cmdByte = 0; + +#if 0 +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmCmdStatByte()\n"); +#endif +#endif + + if (cmdStatByte == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM)); + return MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM; + } + + /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */ + if ((opCode != 0) && ((opCode % 2) || (opCode > 30))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM)); + return MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM; + } + else + { + cmdByteIndex = (opCode / 4); + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD_STATUS_0 + cmdByteIndex, &cmdByte); + + if ((opCode / 2) % 2) + { + *cmdStatByte = ((cmdByte >> 4) & 0x0F); + } + else + { + *cmdStatByte = (cmdByte & 0x0F); + } + + return MYKONOS_ERR_OK; + } +} + +/** + * \brief Mykonos ARM command status wait function polls command status until opcode completes + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param opCode Valid values are even increments from 0-30. The ARM opCode is used to determine which pending bit to wait for + * \param timeoutMs conveys the time-out period in milliseconds + * \param cmdStatByte returns cmdStatByte[3:1] = error type, cmdStatByte[0] = pending flag for selected opCode + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM Function parameter cmdStatByte has NULL pointer + * \retval MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM Invalid ARM opcode (valid 0-30, even numbers only) + * \retval MYKONOS_ERR_ARMCMDSTATUS_ARMERROR ARM Mailbox error flag for requested opcode returned a nonzero error flag + * \retval MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT Timeout occurred before ARM command completed + */ +mykonosErr_t MYKONOS_waitArmCmdStatus(mykonosDevice_t *device, uint8_t opCode, uint32_t timeoutMs, uint8_t *cmdStatByte) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitArmCmdStatus()\n"); +#endif + + if (cmdStatByte == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM)); + return MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM; + } + + /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */ + if ((opCode != 0) && ((opCode % 2) || (opCode > 30))) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM, + getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM)); + return MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM; + } + + /* start wait */ + CMB_setTimeout_ms(timeoutMs); + + do + { + retVal = MYKONOS_readArmCmdStatusByte(device, opCode, cmdStatByte); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* If error flag is non zero in [3:1], - return error */ + if ((*cmdStatByte & 0x0E) > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_ARMERROR)); + return MYKONOS_ERR_ARMCMDSTATUS_ARMERROR; + } + + if (CMB_hasTimeoutExpired()) + { + return MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT; + } + } while (*cmdStatByte & 0x01); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Mykonos ARM configuration write + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_writeArmProfile(mykonosDevice_t *device) +{ + const uint8_t length = 100; + + int32_t i = 0; + uint8_t vcoDiv = 0; + uint8_t hsDiv = 0; + uint16_t channelsEnabled = 0; + uint8_t cfgData[100] = {0}; + + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_writeArmConfig()\n"); +#endif + + /* reading in required mykonosDevice_t structure data into array - not pretty but it works */ + for (i = 0; i < 4; i++) + { + cfgData[i] = (uint8_t)(((device->clocks->deviceClock_kHz * 1000) >> (i * 8)) & 0x000000FF); + } + + for (i = 4; i < 8; i++) + { + cfgData[i] = (uint8_t)(((device->clocks->clkPllVcoFreq_kHz) >> ((i - 4) * 8)) & 0x000000FF); + } + + vcoDiv = (uint8_t)(device->clocks->clkPllVcoDiv); + hsDiv = device->clocks->clkPllHsDiv; + + cfgData[8] = vcoDiv; /* uint8_t vco_div */ + cfgData[9] = hsDiv; /* uint8_t hs_div */ + + channelsEnabled |= ((uint16_t)device->tx->txChannels & 0x03); + channelsEnabled |= ((uint16_t)device->rx->rxChannels & 0x03) << 2; + if (device->profilesValid & ORX_PROFILE_VALID) + { + channelsEnabled |= (((uint16_t)device->obsRx->obsRxChannelsEnable & 3) << 4); + } + + if (device->profilesValid & SNIFF_PROFILE_VALID) + { + channelsEnabled |= ((((uint16_t)device->obsRx->obsRxChannelsEnable >> 2) & 7) << 6); + } + + for (i = 10; i < 12; i++) + { + cfgData[i] = (uint8_t)((channelsEnabled >> ((i - 10) * 8)) & 0xFF); + } + + cfgData[12] = ((device->rx->rxPllUseExternalLo & 0x01) << 1) | (device->tx->txPllUseExternalLo & 0x01); + cfgData[13] = 0x00; /* Not used...padding */ + cfgData[14] = 0x00; /* Not used...padding */ + cfgData[15] = 0x00; /* Not used...padding */ + + if (device->profilesValid & TX_PROFILE_VALID) + { + /* start of Tx profile data */ + cfgData[16] = (uint8_t)device->tx->txProfile->dacDiv; + cfgData[17] = device->tx->txProfile->txFirInterpolation; + cfgData[18] = device->tx->txProfile->thb1Interpolation; + cfgData[19] = device->tx->txProfile->thb2Interpolation; + + for (i = 20; i < 24; i++) + { + cfgData[i] = (uint8_t)(((device->tx->txProfile->iqRate_kHz * 1000) >> ((i - 20) * 8)) & 0x000000FF); + } + + for (i = 24; i < 28; i++) + { + cfgData[i] = (uint8_t)(((device->tx->txProfile->primarySigBandwidth_Hz) >> ((i - 24) * 8)) & 0x000000FF); + } + + for (i = 28; i < 32; i++) + { + cfgData[i] = (uint8_t)(((device->tx->txProfile->rfBandwidth_Hz) >> ((i - 28) * 8)) & 0x000000FF); + } + + for (i = 32; i < 36; i++) + { + cfgData[i] = (uint8_t)(((device->tx->txProfile->txDac3dBCorner_kHz) >> ((i - 32) * 8)) & 0x000000FF); + } + + for (i = 36; i < 40; i++) + { + cfgData[i] = (uint8_t)(((device->tx->txProfile->txBbf3dBCorner_kHz * 1000) >> ((i - 36) * 8)) & 0x000000FF); + } + } + else + { + cfgData[16] = 0; + cfgData[17] = 0; + cfgData[18] = 0; + cfgData[19] = 0; + cfgData[20] = 0; + cfgData[21] = 0; + cfgData[22] = 0; + cfgData[23] = 0; + cfgData[24] = 0; + cfgData[25] = 0; + cfgData[26] = 0; + cfgData[27] = 0; + cfgData[28] = 0; + cfgData[29] = 0; + cfgData[30] = 0; + cfgData[31] = 0; + cfgData[32] = 0; + cfgData[33] = 0; + cfgData[34] = 0; + cfgData[35] = 0; + cfgData[36] = 0; + cfgData[37] = 0; + cfgData[38] = 0; + cfgData[39] = 0; + } + + if (device->profilesValid & RX_PROFILE_VALID) + { + /* start of Rx profile data */ + cfgData[40] = device->rx->rxProfile->adcDiv; + cfgData[41] = device->rx->rxProfile->rxFirDecimation; + cfgData[42] = device->rx->rxProfile->rxDec5Decimation; + cfgData[43] = device->rx->rxProfile->rhb1Decimation; + + for (i = 44; i < 48; i++) + { + cfgData[i] = (uint8_t)(((device->rx->rxProfile->iqRate_kHz * 1000) >> ((i - 44) * 8)) & 0x000000FF); + } + + for (i = 48; i < 52; i++) + { + /* sig bw placeholder */ + cfgData[i] = (uint8_t)(((device->rx->rxProfile->rfBandwidth_Hz) >> ((i - 48) * 8)) & 0x000000FF); + } + + for (i = 52; i < 56; i++) + { + cfgData[i] = (uint8_t)(((device->rx->rxProfile->rfBandwidth_Hz) >> ((i - 52) * 8)) & 0x000000FF); + } + + for (i = 56; i < 60; i++) + { + cfgData[i] = (uint8_t)(((device->rx->rxProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 56) * 8)) & 0x000000FF); + } + } + else + { + cfgData[40] = 0; + cfgData[41] = 0; + cfgData[42] = 0; + cfgData[43] = 0; + cfgData[44] = 0; + cfgData[45] = 0; + cfgData[46] = 0; + cfgData[47] = 0; + cfgData[48] = 0; + cfgData[49] = 0; + cfgData[50] = 0; + cfgData[51] = 0; + cfgData[52] = 0; + cfgData[53] = 0; + cfgData[54] = 0; + cfgData[55] = 0; + cfgData[56] = 0; + cfgData[57] = 0; + cfgData[58] = 0; + cfgData[59] = 0; + } + + if (device->profilesValid & ORX_PROFILE_VALID) + { + /* start of ObsRx profile data */ + cfgData[60] = device->obsRx->orxProfile->adcDiv; + cfgData[61] = device->obsRx->orxProfile->rxFirDecimation; + cfgData[62] = device->obsRx->orxProfile->rxDec5Decimation; + cfgData[63] = device->obsRx->orxProfile->rhb1Decimation; + + for (i = 64; i < 68; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->iqRate_kHz * 1000) >> ((i - 64) * 8)) & 0x000000FF); + } + + for (i = 68; i < 72; i++) + { + /* sig bw placeholder */ + cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rfBandwidth_Hz) >> ((i - 68) * 8)) & 0x000000FF); + } + + for (i = 72; i < 76; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rfBandwidth_Hz) >> ((i - 72) * 8)) & 0x000000FF); + } + + for (i = 76; i < 80; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 76) * 8)) & 0x000000FF); + } + } + else + { + cfgData[60] = 0; + cfgData[61] = 0; + cfgData[62] = 0; + cfgData[63] = 0; + cfgData[64] = 0; + cfgData[65] = 0; + cfgData[66] = 0; + cfgData[67] = 0; + cfgData[68] = 0; + cfgData[69] = 0; + cfgData[70] = 0; + cfgData[71] = 0; + cfgData[72] = 0; + cfgData[73] = 0; + cfgData[74] = 0; + cfgData[75] = 0; + cfgData[76] = 0; + cfgData[77] = 0; + cfgData[78] = 0; + cfgData[79] = 0; + } + + if (device->profilesValid & SNIFF_PROFILE_VALID) + { + /* start of SnRx profile data */ + cfgData[80] = device->obsRx->snifferProfile->adcDiv; + cfgData[81] = device->obsRx->snifferProfile->rxFirDecimation; + cfgData[82] = device->obsRx->snifferProfile->rxDec5Decimation; + cfgData[83] = device->obsRx->snifferProfile->rhb1Decimation; + + for (i = 84; i < 88; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->iqRate_kHz * 1000) >> ((i - 84) * 8)) & 0x000000FF); + } + + for (i = 88; i < 92; i++) + { + /* sig bw placeholder */ + cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rfBandwidth_Hz) >> ((i - 88) * 8)) & 0x000000FF); + } + + for (i = 92; i < 96; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rfBandwidth_Hz) >> ((i - 92) * 8)) & 0x000000FF); + } + + for (i = 96; i < 100; i++) + { + cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 96) * 8)) & 0x000000FF); + } + } + else + { + cfgData[80] = 0; + cfgData[81] = 0; + cfgData[82] = 0; + cfgData[83] = 0; + cfgData[84] = 0; + cfgData[85] = 0; + cfgData[86] = 0; + cfgData[87] = 0; + cfgData[88] = 0; + cfgData[89] = 0; + cfgData[90] = 0; + cfgData[91] = 0; + cfgData[92] = 0; + cfgData[93] = 0; + cfgData[94] = 0; + cfgData[95] = 0; + cfgData[96] = 0; + cfgData[97] = 0; + cfgData[98] = 0; + cfgData[99] = 0; + } + + /* writing to the ARM memory with the array data */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &cfgData[0], length); + + return retVal; +} + +/** + * \brief Function called automatically that loads the ADC profiles into the ARM + * + * User should not need to call this function normally. It is called automatically + * during MYKONOS_initArm() to load the ADC profiles (tunes the ADC performance). + * + * Rx ADC profile is only loaded if the Rx Profile is valid, ORx ADC profile is + * only loaded if the ORx Profile is valid. Sniffer ADC profile is only loaded + * if the Sniffer profile is valid. The Loopback ADC profile is always + * loaded. If Tx profile is valid, the loopback ADC profile is chosen based + * on the Tx Primary Signal bandwidth. If no valid Tx Profile, the Rx profile + * is used to set the Loopback ADC profile. Else, ORx, then sniffer profiles + * are used to set the loopback ADC profile. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV Mykonos CLKPLL has invalid VCO divider in the clocks structure + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE When Tx Profile used, a matching ORx Profile must be provided with a valid ADC divider. + * The ORx digital filters and clock dividers are used with the Loopback Rx path for Tx calibrations. + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED ADC Profile Lookup table does not have a match + * for current Rx Profile settings. Custom ADC profile required + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED ADC Profile Lookup table does not have a match + * for current ORx Profile settings. Custom ADC profile required + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED ADC Profile Lookup table does not have a match + * for current Sniffer Rx Profile settings. Custom ADC profile required + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED ADC Profile Lookup table does not have a match + * for Loopback passband BW and ADC Clock frequency settings. Custom ADC profile required + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO Rx Profile has invalid ADC divider = 0, causing a divide by zero error + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO ORx profile has invalid ADC divider = 0, causing a divide by zero error + * \retval MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO Sniffer profile has invalid ADC divider = 0, causing a divide by zero error + * \retval MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED Error returned while trying to write Rx ADC profile to ARM memory + * \retval MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED Error returned while trying to write ORx ADC profile to ARM memory + * \retval MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED Error returned while trying to write Sniffer ADC profile into ARM memory + * \retval MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED Error returned while trying to write Loopback ADC profile into ARM memory + */ +mykonosErr_t MYKONOS_loadAdcProfiles(mykonosDevice_t *device) +{ + uint8_t adcProfile[32] = {0}; + uint8_t i = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint32_t hsDigClk_MHz = 0; + uint32_t adcClk_MHz = 0; + uint32_t vcoDiv = 0; + uint32_t vcoDivTimes10 = 10; + uint8_t profileIndex = 0; + const uint8_t ARM_CONFIG_OFFSET = 100; /* number of bytes written in MYKONOS_writeArmProfile() to ARM memory */ + + const uint8_t NUM_ADCPROFILE_COEFS = 16; + const uint8_t NUM_ADC_PROFILES = 20; + static const uint16_t adcProfileLut[20][18] = { + /* Max RFBW, ADCCLK_MHz, adcProfile[16] */ + { 20, 491, 1494, 564, 201, 98, 1280, 134, 945, 40, 529, 10, 326, 39, 30, 16, 9, 201}, + { 60, 983, 712, 462, 201, 98, 1280, 291, 1541, 149, 1054, 46, 645, 34, 48, 32, 18, 193}, + { 75, 983, 680, 477, 201, 98, 1280, 438, 1577, 242, 1046, 73, 636, 30, 48, 31, 18, 192}, + {100, 983, 655, 446, 201, 98, 1280, 336, 1631, 334, 1152, 207, 733, 33, 48, 32, 21, 212}, + { 75, 1228, 569, 369, 201, 98, 1280, 291, 1541, 149, 1320, 58, 807, 34, 48, 40, 23, 189}, + {100, 1228, 534, 386, 201, 98, 1280, 491, 1591, 279, 1306, 104, 792, 28, 48, 39, 23, 187}, + {160, 1228, 491, 375, 201, 98, 1280, 514, 1728, 570, 1455, 443, 882, 27, 48, 39, 25, 205}, + {200, 1228, 450, 349, 201, 98, 1280, 730, 1626, 818, 1476, 732, 834, 20, 41, 36, 24, 200}, + { 80, 1250, 555, 365, 201, 98, 1280, 317, 1547, 165, 1341, 65, 819, 33, 48, 40, 24, 188}, + {102, 1250, 524, 379, 201, 98, 1280, 494, 1592, 281, 1328, 107, 805, 28, 48, 40, 23, 187}, + { 80, 1333, 526, 339, 201, 98, 1280, 281, 1539, 143, 1433, 60, 877, 35, 48, 43, 25, 188}, + {217, 1333, 414, 321, 201, 98, 1280, 730, 1626, 818, 1603, 794, 905, 20, 41, 40, 26, 199}, + { 75, 1474, 486, 302, 199, 98, 1280, 206, 1523, 101, 1578, 47, 977, 37, 48, 48, 28, 186}, + {100, 1474, 465, 311, 201, 98, 1280, 353, 1556, 187, 1581, 86, 964, 32, 48, 47, 28, 185}, + {150, 1474, 436, 296, 190, 98, 1280, 336, 1631, 334, 1638, 293, 1102, 33, 48, 46, 31, 205}, + { 40, 1536, 479, 285, 190, 98, 1280, 112, 1505, 53, 1574, 25, 1026, 40, 48, 48, 29, 186}, + {100, 1536, 450, 297, 193, 98, 1280, 328, 1550, 171, 1586, 79, 1006, 33, 48, 48, 29, 184}, + {150, 1536, 421, 283, 182, 98, 1280, 313, 1620, 306, 1638, 269, 1153, 34, 48, 46, 33, 204}, + {200, 1536, 392, 299, 180, 98, 1280, 514, 1728, 570, 1638, 498, 1104, 27, 48, 44, 32, 200}, + {240, 1536, 366, 301, 178, 98, 1280, 686, 1755, 818, 1638, 742, 1056, 22, 45, 41, 31, 196}}; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadAdcProfiles\n"); +#endif + + vcoDiv = (uint32_t)device->clocks->clkPllVcoDiv; + switch (vcoDiv) + { + case VCODIV_1: + vcoDivTimes10 = 10; + break; + case VCODIV_1p5: + vcoDivTimes10 = 15; + break; + case VCODIV_2: + vcoDivTimes10 = 20; + break; + case VCODIV_3: + vcoDivTimes10 = 30; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV)); + return MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV; + } + } + + hsDigClk_MHz = device->clocks->clkPllVcoFreq_kHz / vcoDivTimes10 / 100 / device->clocks->clkPllHsDiv; + + /* If Tx Profile is valid, set loopback ADC profile based on Tx primary signal BW */ + if ((device->profilesValid & TX_PROFILE_VALID) > 0) + { + /* If custom profile, load it */ + if (device->obsRx->customLoopbackAdcProfile != NULL) + { + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = device->obsRx->customLoopbackAdcProfile[i] & 0xFF; + adcProfile[i * 2 + 1] = (device->obsRx->customLoopbackAdcProfile[i] >> 8) & 0xFF; + } + } + else + { + /* Tx requires ORx profile is configured */ + if (((device->profilesValid & TX_PROFILE_VALID) > 0) && ((device->profilesValid & ORX_PROFILE_VALID) == 0)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE)); + return MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE; + } + + if (device->obsRx->orxProfile->adcDiv == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO)); + return MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO; + } + + adcClk_MHz = hsDigClk_MHz / device->obsRx->orxProfile->adcDiv; + + /* find correct ADC profile in the LUT */ + profileIndex = NUM_ADC_PROFILES; + for (i = 0; i < NUM_ADC_PROFILES; i++) + { + /* Find a row in the LUT that matches the ADC clock frequency */ + if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->tx->txProfile->primarySigBandwidth_Hz / 1000000))) + { + profileIndex = i; + break; + } + } + + /* Verify that a profile was found in the LUT, if not return error */ + /* In this case a custom profile would need to be passed in */ + if (profileIndex >= NUM_ADC_PROFILES) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED)); + return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED; + } + + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF; + adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF; + } + } + + /* writing to the ARM memory: Set Loopback ADC Profile based on Tx Primary signal Bandwidth */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED; + } + } + + if ((device->profilesValid & RX_PROFILE_VALID) > 0) + { + /* If custom profile, load it */ + if (device->rx->rxProfile->customAdcProfile != NULL) + { + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = device->rx->rxProfile->customAdcProfile[i] & 0xFF; + adcProfile[i * 2 + 1] = (device->rx->rxProfile->customAdcProfile[i] >> 8) & 0xFF; + } + } + else + { + if (device->rx->rxProfile->adcDiv == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO)); + return MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO; + } + + adcClk_MHz = hsDigClk_MHz / device->rx->rxProfile->adcDiv; + + /* find correct ADC profile in the LUT */ + profileIndex = NUM_ADC_PROFILES; + for (i = 0; i < NUM_ADC_PROFILES; i++) + { + /* Find a row in the LUT that matches the ADC clock frequency */ + if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->rx->rxProfile->rfBandwidth_Hz / 1000000))) + { + profileIndex = i; + break; + } + } + + /* Verify that a profile was found in the LUT, if not return error */ + /* In this case a custom profile would need to be passed in */ + if (profileIndex >= NUM_ADC_PROFILES) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED)); + return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED; + } + + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF; + adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF; + } + } + + /* writing to the ARM memory with ADC Profile for Rx path */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED; + } + + /* writing to the ARM memory: Set Loopback ADC Profile = Rx ADC Profile ONLY if Tx profile is not valid */ + if ((device->profilesValid & TX_PROFILE_VALID) == 0) + { + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED; + } + } + } + + if ((device->profilesValid & ORX_PROFILE_VALID) > 0) + { + /* If custom profile, load it */ + if (device->obsRx->orxProfile->customAdcProfile != NULL) + { + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = device->obsRx->orxProfile->customAdcProfile[i] & 0xFF; + adcProfile[i * 2 + 1] = (device->obsRx->orxProfile->customAdcProfile[i] >> 8) & 0xFF; + } + } + else + { + if (device->obsRx->orxProfile->adcDiv == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO)); + return MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO; + } + + adcClk_MHz = hsDigClk_MHz / device->obsRx->orxProfile->adcDiv; + + /* find correct ADC profile in the LUT */ + profileIndex = NUM_ADC_PROFILES; + for (i = 0; i < NUM_ADC_PROFILES; i++) + { + /* Find a row in the LUT that matches the ADC clock frequency */ + if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->obsRx->orxProfile->rfBandwidth_Hz / 1000000))) + { + profileIndex = i; + break; + } + } + + /* Verify that a profile was found in the LUT, if not return error */ + /* In this case a custom profile would need to be passed in */ + if (profileIndex >= NUM_ADC_PROFILES) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED)); + return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED; + } + + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF; + adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF; + } + } + + /* writing to the ARM memory with ADC Profile for ORx path */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 32, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED; + } + + /* If Rx and Tx Profiles are not valid, set Loopback ADC profile to ORx ADC Profile */ + if (((device->profilesValid & TX_PROFILE_VALID) == 0) && ((device->profilesValid & RX_PROFILE_VALID) == 0)) + { + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED; + } + } + } + + if ((device->profilesValid & SNIFF_PROFILE_VALID) > 0) + { + /* If custom profile, load it */ + if (device->obsRx->snifferProfile->customAdcProfile != NULL) + { + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = device->obsRx->snifferProfile->customAdcProfile[i] & 0xFF; + adcProfile[i * 2 + 1] = (device->obsRx->snifferProfile->customAdcProfile[i] >> 8) & 0xFF; + } + } + else + { + + if (device->obsRx->snifferProfile->adcDiv == 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO)); + return MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO; + } + + adcClk_MHz = hsDigClk_MHz / device->obsRx->snifferProfile->adcDiv; + + /* find correct ADC profile in the LUT */ + profileIndex = NUM_ADC_PROFILES; + for (i = 0; i < NUM_ADC_PROFILES; i++) + { + /* Find a row in the LUT that matches the ADC clock frequency */ + if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->obsRx->snifferProfile->rfBandwidth_Hz / 1000000))) + { + profileIndex = i; + break; + } + } + + /* Verify that a profile was found in the LUT, if not return error */ + /* In this case a custom profile would need to be passed in */ + if (profileIndex >= NUM_ADC_PROFILES) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED)); + return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED; + } + + for (i = 0; i < NUM_ADCPROFILE_COEFS; i++) + { + adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF; + adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF; + } + } + + /* writing to the ARM memory with ADC Profile for sniffer Rx path */ + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 64, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED; + } + + /* If Tx, Rx, and ORx Profiles are not valid, set Loopback ADC profile to Sniffer Rx ADC Profile */ + if (((device->profilesValid & TX_PROFILE_VALID) == 0) && ((device->profilesValid & RX_PROFILE_VALID) == 0) && ((device->profilesValid & ORX_PROFILE_VALID) == 0)) + { + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile)); + if (retVal) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED, + getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED)); + return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED; + } + } + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Helper function to calculate commonly used digital clock frequencies in the device + * + * User should not need to call this function normally. It is called automatically + * within other API functions to calculate the main digital clock. If the pointers + * to the return parameters are NULL, that calculation will be skipped and not + * returned. + * + * + * Dependencies + * -device->clocks->clkPllVcoFreq_kHz; + * -device->clocks->clkPllVcoDiv; + * -device->clocks->clkPllHsDiv; + * + * \param device Pointer to the device settings structure + * \param hsDigClk_kHz Return value for the calculated Mykonos high speed Digital clock at the output of the CLKPLL in kHz + * \param hsDigClkDiv4or5_kHz Return value for the Mykonos high speed digital clock divided by 4 or 5 in kHz + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM device parameter is a NULL pointer + * \retval MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT device->clocks structure is a NULL pointer + * \retval MYKONOS_ERR_CLKPLL_INV_VCODIV Invalid CLKPLL VCO divider in device->clocks->clkPllVcoDiv + * \retval MYKONOS_ERR_CLKPLL_INV_HSDIV Invalid CLKPLL High speed divider in device->clocks->clkPllHsDiv + */ +static mykonosErr_t MYKONOS_calculateDigitalClocks(mykonosDevice_t *device, uint32_t *hsDigClk_kHz, uint32_t *hsDigClkDiv4or5_kHz) +{ + uint32_t hsclkRate_kHz = 0; + uint32_t clkPllVcoFrequency_kHz = 0; + mykonosVcoDiv_t vcoDiv = VCODIV_1; + uint8_t hsDiv = 4; + + if (device == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM, getMykonosErrorMessage(MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM)); + return MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM; + } + + if ((device->clocks == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT)); + return MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT; + } + + clkPllVcoFrequency_kHz = device->clocks->clkPllVcoFreq_kHz; + vcoDiv = device->clocks->clkPllVcoDiv; + hsDiv = device->clocks->clkPllHsDiv; + + switch (vcoDiv) + { + case VCODIV_1: + hsclkRate_kHz = clkPllVcoFrequency_kHz; + break; + case VCODIV_1p5: + hsclkRate_kHz = (clkPllVcoFrequency_kHz / 15) * 10; + break; + case VCODIV_2: + hsclkRate_kHz = clkPllVcoFrequency_kHz >> 1; + break; + case VCODIV_3: + hsclkRate_kHz = (clkPllVcoFrequency_kHz / 30) * 10; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_VCODIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_VCODIV)); + return MYKONOS_ERR_CLKPLL_INV_VCODIV; + } + } + + switch (hsDiv) + { + case 4: + hsDiv = 4; + break; + case 5: + hsDiv = 5; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_HSDIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_HSDIV)); + return MYKONOS_ERR_CLKPLL_INV_HSDIV; + } + } + + if (hsDigClk_kHz != NULL) + { + *hsDigClk_kHz = hsclkRate_kHz / hsDiv; + } + + if (hsDigClkDiv4or5_kHz != NULL) + { + /* This digital div 4 or 5 is always mutually exclusive with the HS Divider (4 or 5) to always + * create a /20 from the hsclk. + */ + *hsDigClkDiv4or5_kHz = hsclkRate_kHz / 20; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Performs reset to the External Tx LO Leakage tracking calibration channel estimate + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param channelSel Enum selects the channel to reset + * + * \retval MYKONOS_ERR_RESET_TXLOL_INV_PARAM Selected channel is not valid + * \retval MYKONOS_ERR_RESET_TXLOL_ARMERROR ARM error + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_resetExtTxLolChannel(mykonosDevice_t *device, mykonosTxChannels_t channelSel) +{ + const uint8_t TXLOL_RESET_CHANNEL_ESTIMATE = 0x01; + const uint32_t GETTXLOLSTATUS_TIMEOUT_MS = 1000; + + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_GS_TRACKCALS, TXLOL_RESET_CHANNEL_ESTIMATE, 0}; + uint8_t cmdStatusByte = 0; + uint8_t armErrorFlag = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetExtTxLolChannel()\n"); +#endif + + /* Check Channel */ + switch (channelSel) + { + case TX1: + extData[2] = 0x01; + break; + case TX2: + extData[2] = 0x02; + break; + case TX1_TX2: + extData[2] = 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESET_TXLOL_INV_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_RESET_TXLOL_INV_PARAM)); + return MYKONOS_ERR_RESET_TXLOL_INV_PARAM; + } + + /* throw error if not in the right state */ + retVal = MYKONOS_checkArmState(device, (MYK_ARM_IDLE | MYK_ARM_RADIO_ON)); + if (retVal) + { + return retVal; + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + if (retVal) + { + return retVal; + } + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, GETTXLOLSTATUS_TIMEOUT_MS, &cmdStatusByte); + + /* Error check WaitArmCmdStatus return */ + armErrorFlag = (cmdStatusByte >> 1); + if (armErrorFlag > 0) + { + return MYKONOS_ERR_RESET_TXLOL_ARMERROR; + } + + return retVal; +} + +/** + * \brief Configures the Radio power up/down control for Rx and Tx paths to be controlled by pins + * (TX1/2_ENABLE, RX1/2_ENABLE, and GPIO pins) or an API function call. + * + * The BBP should not have to call this as it will automatically be setup at the end of the + * MYKONOS_loadArmFromBinary() function call. If the BBP wishes to change the radio power up/down + * control method this function can be called again to change the configuration while + * the ARM is in the radioOff state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->armGpio->useRx2EnablePin + * - device->auxIo->armGpio->useTx2EnablePin + * - device->auxIo->armGpio->txRxPinMode + * - device->auxIo->armGpio->orxPinMode + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR ARM returned an error and did not accept the command. + */ +mykonosErr_t MYKONOS_setRadioControlPinMode(mykonosDevice_t *device) +{ + uint8_t extData[4] = {0x81, 0, 0, 4}; /*Object ID 0x81 (radio control structure), offset lsb, offset msb, length*/ + uint8_t armRadioControlStruct[4] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + mykonosErr_t retval = MYKONOS_ERR_OK; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRadioControlPinMode()\n"); +#endif + + /* write ARM radio control structure to enable pin mode/command mode */ + if (device->auxIo->armGpio->useRx2EnablePin > 0) + { + armRadioControlStruct[0] = 0x01; + } + + if (device->auxIo->armGpio->useTx2EnablePin > 0) + { + armRadioControlStruct[1] = 0x01; + } + + if (device->auxIo->armGpio->txRxPinMode > 0) + { + armRadioControlStruct[2] = 0x01; + } + + if (device->auxIo->armGpio->orxPinMode > 0) + { + armRadioControlStruct[3] = 0x01; + } + + retval = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armRadioControlStruct[0], sizeof(armRadioControlStruct)); + if (retval != MYKONOS_ERR_OK) + { + return retval; + } + + retval = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extData[0], sizeof(extData)); + if (retval != MYKONOS_ERR_OK) + { + return retval; + } + + timeoutMs = 1000; + retval = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte); + if (retval != MYKONOS_ERR_OK) + { + return retval; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR)); + return MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Sets the measure count which is the number of samples taken before DC offset correction is applied for the given RF channel. + * This value should be changed after ARM initialization. + * channel can be one of the following ( ::mykonosDcOffsetChannels_t ). + * + * Channel | Channel description + * ------------------------|-------------------------------- + * MYK_DC_OFFSET_RX_CHN | Selects Rx channel + * MYK_DC_OFFSET_ORX_CHN | Selects ORx channel + * MYK_DC_OFFSET_SNF_CHN | Selects Sniffer channel + * + * The total duration 'tCount' is calculated as, + * [tCount = (measureCount * 1024) / IQ data rate of the channel]. + * There is a minimum limit for the value of measureCount, the value passed should satisfy the condition 'tCount > 800us'. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param channel Receive channel to be selected. + * \param measureCount Value to be configured for the selected channel which is the number of samples taken before DC offset correction is applied. + * + * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels. + * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT measurement count value passed is invalid + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT The measureCount value passed is less than the minimum limit allowed. + */ +mykonosErr_t MYKONOS_setRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t measureCount) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS_H = 0; /* Address for Higher byte */ + uint16_t REG_ADDRESS_L = 0; /* Address for Lower byte */ + uint16_t MEASURE_CNT_RANGE = 0xFFFF; /* Mask for measure count range checking */ + + const uint8_t MEASURE_CNT_H = (measureCount & 0xFF00) >> 8; /* Higher byte of the measure count */ + const uint8_t MEASURE_CNT_L = measureCount & 0x00FF; /* Lower byte of the measure count */ + + /* Calculation of Total Duration [ tCount = (measureCount * 0x400) / IQ data rate cycles ] */ + const uint8_t FACTOR = 10; + uint32_t tCount = (measureCount << FACTOR); /* precalculations for Total duration in us */ + uint32_t IQ_RATE = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRfDcOffsetCnt()\n"); +#endif + + /* check for channel and update the appropriate register address */ + switch (channel) + { + case MYK_DC_OFFSET_RX_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_MEASURE_COUNT_1; + IQ_RATE = device->rx->rxProfile->iqRate_kHz / 1000; /* IQ Rate to calculate total duration */ + break; + case MYK_DC_OFFSET_ORX_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_1; + IQ_RATE = device->obsRx->orxProfile->iqRate_kHz / 1000; /* IQ Rate to calculate total duration */ + break; + case MYK_DC_OFFSET_SNF_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_1; + /* measureCount for Sniffer should be 10 bit */ + MEASURE_CNT_RANGE= 0x03FF; + IQ_RATE = device->obsRx->snifferProfile->iqRate_kHz / 1000; /* IQ Rate to calculate total duration */ + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN, + getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN)); + return MYKONOS_ERR_DC_OFFSET_INV_CHAN; + } + + tCount = (tCount / IQ_RATE); /* Calculating total duration in us */ + if (tCount < 800) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT, + getMykonosErrorMessage(MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT)); + return MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT ; + } + + if ((measureCount < 0x11) || (measureCount & ~MEASURE_CNT_RANGE)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT, + getMykonosErrorMessage(MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT)); + return MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT ; + } + + CMB_SPIWriteField(device->spiSettings, REG_ADDRESS_H, MEASURE_CNT_H, ((MEASURE_CNT_RANGE >>8) & 0xFF),0); + CMB_SPIWriteByte(device->spiSettings, REG_ADDRESS_L, MEASURE_CNT_L); + + return retVal; +} + +/** + * \brief retrieves the measure count which is the number of samples taken before DC offset correction is applied for the given Rf channel. + * channel can be one of the following ( ::mykonosDcOffsetChannels_t ). + * + * Channel | Channel description + * ------------------------|-------------------------------- + * MYK_DC_OFFSET_RX_CHN | Selects Rx channel + * MYK_DC_OFFSET_ORX_CHN | Selects ORx channel + * MYK_DC_OFFSET_SNF_CHN | Selects Sniffer channel + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param channel receive channel to be selected. + * \param measureCount pointer to the variable to store the read value. + * + * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels. + * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_NULL_MEASURECNT passed pointer of measureCount is NULL + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t *measureCount) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS_H = 0; /* Address for Higher byte */ + uint16_t REG_ADDRESS_L = 0; /* Address for Lower byte */ + uint16_t MEASURE_CNT_RANGE = 0xFFFF; /* Mask for measure count range checking */ + uint16_t mCount = 0; /* Temporary variable to store readback from register. */ + uint8_t readbackData = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRfDcOffsetCnt()\n"); +#endif + + switch (channel) + { + case MYK_DC_OFFSET_RX_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_MEASURE_COUNT_1; + break; + case MYK_DC_OFFSET_ORX_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_1; + break; + case MYK_DC_OFFSET_SNF_CHN: + REG_ADDRESS_H = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_2; + REG_ADDRESS_L = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_1; + /* measureCount for Sniffer should be 10 bit */ + MEASURE_CNT_RANGE= 0x03FF; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN, + getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN)); + return MYKONOS_ERR_DC_OFFSET_INV_CHAN; + } + + if (measureCount == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT, + getMykonosErrorMessage(MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT)); + return MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT; + } + + /* Store Higher byte of measureCount */ + CMB_SPIReadField(device->spiSettings, REG_ADDRESS_H, &readbackData, ((MEASURE_CNT_RANGE >>8) & 0xFF),0); + mCount = readbackData; + mCount = mCount << 8; + + /* Store Lower byte of measureCount */ + readbackData = 0; + CMB_SPIReadByte(device->spiSettings, REG_ADDRESS_L, &readbackData); + mCount = mCount | readbackData; + + *measureCount = mCount; + + return retVal; +} + +/** + * \brief Sets M-Shift value which is the Corner frequency of Rx notch filter for the given channel. + * channel can be one of the following ( ::mykonosDcOffsetChannels_t ). + * + * Channel | Channel description + * ------------------------|-------------------------------- + * MYK_DC_OFFSET_RX_CHN | Selects Rx channel + * MYK_DC_OFFSET_ORX_CHN | Selects ORx channel + * MYK_DC_OFFSET_SNF_CHN | Selects Sniffer channel + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param channel receive channel to be selected. + * \param mShift value to be configured for the given channel + * + * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels. + * \retval MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT mShift value passed is invalid. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t mShift) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS = 0; + + const uint8_t MSHIFT_MIN_RANGE= 0x08; + const uint8_t MSHIFT_MAX_RANGE= 0x14; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDigDcOffsetMShift()\n"); +#endif + + if ((mShift < MSHIFT_MIN_RANGE) || (mShift > MSHIFT_MAX_RANGE)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT, + getMykonosErrorMessage(MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT)); + return MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT; + } + + /* check channel and set the address */ + switch (channel) + { + case MYK_DC_OFFSET_RX_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT; + break; + case MYK_DC_OFFSET_ORX_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT; + break; + case MYK_DC_OFFSET_SNF_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SNF; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN, + getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN)); + return MYKONOS_ERR_DC_OFFSET_INV_CHAN; + } + + CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, mShift, 0x1F, 0); + + return retVal; +} + +/** + * \brief retrieves the M-Shift value which is the Corner frequency of Rx notch filter for the given channel. + * channel can be one of the following ( ::mykonosDcOffsetChannels_t ). + * + * Channel | Channel description + * ------------------------|-------------------------------- + * MYK_DC_OFFSET_RX_CHN | Selects Rx channel + * MYK_DC_OFFSET_ORX_CHN | Selects ORx channel + * MYK_DC_OFFSET_SNF_CHN | Selects Sniffer channel + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param channel receive channel to be selected. + * \param mShift Pointer to the variable to store mshift value of the given channel + * + * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels. + * \retval MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT mShift pointer is NULL + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t *mShift) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS = 0x0; + uint8_t readbackData = 0x0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDigDcOffsetMShift()\n"); +#endif + + if (mShift == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT, + getMykonosErrorMessage(MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT)); + return MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT; + } + + /* check for the channel and set the address */ + switch (channel) + { + case MYK_DC_OFFSET_RX_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT; + break; + case MYK_DC_OFFSET_ORX_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT; + break; + case MYK_DC_OFFSET_SNF_CHN: + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SNF; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN, + getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN)); + return MYKONOS_ERR_DC_OFFSET_INV_CHAN; + } + + CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x1F,0); + + *mShift = readbackData; + + return retVal; +} + +/** + * \brief Sets the RF PLL loop filter bandwith. + * + * \pre Command should be called in Radio Off state. ARM must be initialized. + * + * \post Loop filter should lock successfully + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * + * \param device is structure pointer to the MYKONOS data structure containing settings + * \param pllName Name of the PLL to configure.RX_PLL and TX_PLL can be configured.SNIFFER_PLL can not be configured. + * \param loopBandwidth_kHz Desired RF pll bandwith to be set. The valid values range of loopBandwidth_kHz for Rx and Tx is 50 to 750.For SRX valid values lies from 500 to 750. + * \param stability PLL Loop stability to be set.The valid values range of stability is from 3 to 15. + * + * \return MYKONOS_ERR_OK Function completed successfully + * \return MYKONOS_ERR_SETRFPLL_LF_ARMERROR ARM Command to set RF PLL loop filter bandwidth failed + * \return MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH Invalid Tx/Rx value bandwith + * \return MYKONOS_ERR_SETRFPLL_LF_PLLNAME Invalid pllName requested + * \return MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY Invalid stability range, valid range is 3-15 + */ +mykonosErr_t MYKONOS_setRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t loopBandwidth_kHz, uint8_t stability) +{ + const uint8_t SETCMD_OPCODE = 0x0A; + const uint8_t SET_PLL_BANDWIDTH = 0x6D; + const uint16_t LOOP_BW_HIGH = 750; + + uint16_t LOOP_BW_LOW = 50; + uint8_t extData[4] = {0}; + uint8_t cmdStatusByte = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + mykonosErr_t errLoopBw = MYKONOS_ERR_OK; + uint32_t timeoutMs = 1000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRfPllLoopFilter()\n"); +#endif + + switch (pllName) + { + case RX_PLL: + extData[1] = 0x00; + LOOP_BW_LOW = 50; + errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH; + break; + case TX_PLL: + extData[1] = 0x10; + LOOP_BW_LOW = 50; + errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH; + break; + case SNIFFER_PLL: +#if 0 /* Set for Sniffer PLL loop bandwidth is not supported */ + extData[1] = 0x20; + LOOP_BW_LOW = 500; + errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_SNF_LOOPBANDWIDTH; + break; +#endif + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_PLLNAME, + getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_PLLNAME)); + return MYKONOS_ERR_SETRFPLL_LF_PLLNAME; + } + } + + /* Range check for loopBandwidth - Should be between 50kHz and 750kHz for TX/RX and between 500kHz and 750 for SRX*/ + if ((loopBandwidth_kHz< LOOP_BW_LOW) || (loopBandwidth_kHz >LOOP_BW_HIGH)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, errLoopBw, + getMykonosErrorMessage(errLoopBw)); + return errLoopBw; + } + + /* Range check for stability - Should be between 3 and 15 */ + if ((stability < 3) || (stability > 15)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY, + getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY)); + return MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY; + } + + /* Generate payload for SET command */ + extData[0] = SET_PLL_BANDWIDTH; + /*left shift and truncate left side*/ + extData[1] |= stability; + extData[2] = (uint8_t)(loopBandwidth_kHz & 0xFF); //full first byte + extData[3] = (uint8_t)(loopBandwidth_kHz >> 8); //two extra bits + + /* executing the SET command */ + retVal = MYKONOS_sendArmCommand(device, SETCMD_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* waiting for command to complete */ + retVal = MYKONOS_waitArmCmdStatus(device, SETCMD_OPCODE, timeoutMs, &cmdStatusByte); + + /* performing command status check */ + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_ARMERROR)); + return MYKONOS_ERR_SETRFPLL_LF_ARMERROR; + } + + return retVal; + } + + return retVal; +} + +/** + * \brief Gets the RF PLL loop filter bandwidth and stability. + * + * This function is used to get the RF PLL loop bandwidth. It can get the RX PLL, TX PLL + * Sniffer PLL. + * + * \pre Command can be called in Radio Off state or On state. ARM must be initialized. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->spiSettings + * - device->clocks->deviceClock_kHz + * + * \param device is structure pointer to the MYKONOS data structure containing settings + * \param pllName Name of the PLL for which to read the frequency + * \param loopBandwidth_kHz RF PLL loop bandwidth for the PLL specified + * \param stability RF PLL loop stability + * + * \retval MYKONOS_ERR_OK Function completed successfully + * \retval MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME Invalid PLL name, can not get PLL frequency. Use PLL name ENUM. + * \retval MYKONOS_ERR_GETRFPLL_LF_ARMERROR ARM Command to get RF PLL frequency failed + * \retval MYKONOS_ERR_GETRFPLL_LF_NULLPARAM input parameter is NULL + */ +mykonosErr_t MYKONOS_getRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t *loopBandwidth_kHz, uint8_t *stability) +{ + const uint8_t GET_PLL_BANDWIDTH = 0x6D; + + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armData[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t extData[2] = {GET_PLL_BANDWIDTH, 0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRfPllLoopFilter()\n"); +#endif + + /* Check for NULL */ + if ((loopBandwidth_kHz == NULL)|| (stability == NULL)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_NULLPARAM)); + return MYKONOS_ERR_GETRFPLL_LF_NULLPARAM; + } + + switch(pllName) + { + case RX_PLL: extData[1] = 0x00; break; + case TX_PLL: extData[1] = 0x10; break; + case SNIFFER_PLL: extData[1] = 0x20; break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME)); + return MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME; + } + } + /* executing the GET command */ + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + + /* waiting for command to complete */ + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + + /* performing command status check */ + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_ARMERROR, + getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_ARMERROR)); + return MYKONOS_ERR_GETRFPLL_LF_ARMERROR; + } + + return retVal; + } + + /* Read from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8, 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + /* Assign to variables */ + *stability = armData[3]; + *loopBandwidth_kHz = (((uint16_t)armData[1]) << 8) | ((uint16_t)armData[0]); + + return MYKONOS_ERR_OK; +} + +/** + * \brief Enable/ Disable Digital DC Offset channels using the channel mask. + * The mask can be a combination of the following channel values ( ::mykonosRxDcOffsettEn_t ). + * + * Channel | Value | Channel description + * -------------------------|---------|-------------------------- + * MYK_DC_OFFSET_ALL_OFF | 0x00 | Disable all the channels + * MYK_DC_OFFSET_RX1 | 0x01 | Enables Rx1 + * MYK_DC_OFFSET_RX2 | 0x02 | Enables Rx1 + * MYK_DC_OFFSET_SNF | 0x04 | Enables Sniffer + * MYK_DC_OFFSET_ORX | 0x08 | Enables ORx + * MYK_DC_OFFSET_AVAILABLE | 0x0F | Enables all the channels + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param enableMask with bits of channels to be enabled. + * + * \retval MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK enable mask passed to the function is invalid, refer mykonosRxDcOffsettEn_t enum. + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setDigDcOffsetEn(mykonosDevice_t *device, uint8_t enableMask) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS = 0x00; + uint8_t dataToWrite = 0x00; + + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDigDcOffsetEn()\n"); +#endif + + if (enableMask & ~((uint8_t)MYK_DC_OFFSET_AVAILABLE)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK, + getMykonosErrorMessage(MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK)); + return MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK; + } + + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CONFIG; /* Address for Rx Digital tracking Enable bits register */ + if (enableMask & ((uint8_t)MYK_DC_OFFSET_RX1 | (uint8_t)MYK_DC_OFFSET_RX2)) /* Enable / Disable Rx1 and/or Rx2 */ + { + dataToWrite |= ((enableMask & ((uint8_t)MYK_DC_OFFSET_RX1 |(uint8_t) MYK_DC_OFFSET_RX2)) << 1 ); + } + CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, dataToWrite, 0x06,0); /* Write RX enable bits to the register */ + + dataToWrite = 0x0; /* Reset dataToWrite */ + REG_ADDRESS = MYKONOS_DIGITAL_DC_OFFSET_CH3_TRACKING; /* Address for ORx and Sniffer Digital trackingEnable bits register */ + if (enableMask & ((uint8_t)MYK_DC_OFFSET_SNF | (uint8_t)MYK_DC_OFFSET_ORX)) /* Check for channel ORx and/or Sniffer */ + { + dataToWrite |= ((enableMask & ((uint8_t)MYK_DC_OFFSET_SNF | (uint8_t)MYK_DC_OFFSET_ORX))>>2); + } + CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, dataToWrite, 0x03,0); /* Write Loopback, ORx and Sniffer enable bits to the register */ + + return retVal; +} + +/** + * \brief reads Enable/ Disable channels Digital DC Offset and returns a mask of it. + * The mask returned will be a combination of the following channel values ( ::mykonosRxDcOffsettEn_t ). + * + * Channel | Value | Channel description + * -------------------------|---------|-------------------------- + * MYK_DC_OFFSET_ALL_OFF | 0x00 | All channels are disabled + * MYK_DC_OFFSET_RX1 | 0x01 | Rx1 is enabled + * MYK_DC_OFFSET_RX2 | 0x02 | Rx2 is enabled + * MYK_DC_OFFSET_SNF | 0x04 | Sniffer is enabled + * MYK_DC_OFFSET_ORX | 0x08 | ORx is enabled + * MYK_DC_OFFSET_AVAILABLE | 0x0F | All channels are enabled + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param enableMask pointer to the variable to store Enable mask of channels + * + * \retval MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK enableMask is NULL + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDigDcOffsetEn(mykonosDevice_t *device,uint8_t *enableMask) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint16_t REG_ADDRESS = 0; + uint8_t readbackData = 0; + uint8_t enableMaskData = 0; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDigDcOffsetEn()\n"); +#endif + + if (enableMask == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK, + getMykonosErrorMessage(MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK)); + return MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK; + } + + REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CONFIG; /* register address of Rx1 and Rx2 enable bits*/ + CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x06,0); + enableMaskData |= (readbackData>>1); /* adjust bits to match channel :refer enum mykonosRfDcOffsettEn_t. */ + + readbackData = 0x00; + REG_ADDRESS = MYKONOS_DIGITAL_DC_OFFSET_CH3_TRACKING; /* register address of Orx and sniffer enable bits*/ + CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x03,0); + enableMaskData |= (uint8_t)(readbackData<<2); /* adjust bits to match channel :refer enum mykonosRfDcOffsettEn_t. */ + + *enableMask = enableMaskData; + + return retVal; +} + +/** + * \brief This function will configure the path delay settings for all the features: + * DPD, VSWR and CLGC. + * + * A DPD device is required. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param pathDelay pointer to structure of type ::mykonosPathdelay_t to be programmed + * + * \retval MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM pathDelay is null + * \retval MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE path delay valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setPathDelay(mykonosDevice_t *device, mykonosPathdelay_t *pathDelay) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[16] = {0}; + uint8_t extData[3] = {(uint8_t)MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL, (uint8_t)SET_PATH_DELAY, 0}; + uint8_t writeSize = 0; + uint8_t fifoDel[4] = {0}; + uint8_t interpIndex[4] = {0}; + uint32_t *delPointer = &pathDelay->forwardPathDelayCh1; + uint8_t i = 0; + + const uint32_t RANGE_PATH_DELAY = 4095; + const uint8_t PATH_DELAY_SIZE = 4; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setPathDelay()\n"); +#endif + + if (pathDelay == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM)); + return MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM; + } + + /* Loop to set the ARM memory data */ + for (i = 0; i < PATH_DELAY_SIZE ; i++) + { + /* Verify all the data in the structure is in range */ + if (*delPointer > RANGE_PATH_DELAY) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE)); + return MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE; + } + + fifoDel[i] = (uint8_t)(*delPointer >> 4); + interpIndex[i] = (uint8_t)(*delPointer - (fifoDel[i] * 16)); + + delPointer++; + } + + if ((device->tx->vswrConfig == NULL) || ((pathDelay->reversePathDelayCh1 == 0) && (pathDelay->reversePathDelayCh2 == 0))) + { + armFieldValue[0] = interpIndex[0]; + armFieldValue[1] = 0; + armFieldValue[2] = fifoDel[0]; + armFieldValue[3] = 0; + armFieldValue[4] = interpIndex[2]; + armFieldValue[5] = 0; + armFieldValue[6] = fifoDel[2]; + armFieldValue[7] = 0; + extData[2] = 0; + writeSize = 8; + } + else + { + armFieldValue[0] = interpIndex[0]; + armFieldValue[1] = 0; + armFieldValue[2] = fifoDel[0]; + armFieldValue[3] = 0; + armFieldValue[4] = interpIndex[2]; + armFieldValue[5] = 0; + armFieldValue[6] = fifoDel[2]; + armFieldValue[7] = 0; + armFieldValue[8] = interpIndex[1]; + armFieldValue[9] = 0; + armFieldValue[10] = fifoDel[1]; + armFieldValue[11] = 0; + armFieldValue[12] = interpIndex[3]; + armFieldValue[13] = 0; + armFieldValue[14] = fifoDel[3]; + armFieldValue[15] = 0; + extData[2] = 1; + writeSize = 16; + } + + retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armFieldValue[0], writeSize); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData)); + + return retVal; +} + +/** + * \brief This function will read the current path delay settings for the selected calibration. + * + * A DPD-enabled transceiver is required + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param select path delay status selection from ::mykonosPathDelaySel_t + * \param pathDelay pointer to structure of type ::mykonosPathdelay_t to store the read back path delay + * + * \retval MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM pathDelay is null + * \retval MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION invalid selection for getting the path delay, valid selections are given by mykonosPathDelaySel_t + * \retval MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG Arm error while reading path delay for the selected calibration status + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getPathDelay(mykonosDevice_t *device, mykonosPathDelaySel_t select, mykonosPathdelay_t *pathDelay) +{ + uint8_t extData[3] = {(uint8_t)MYKONOS_ARM_OBJECTID_CAL_STATUS, (uint8_t)MYKONOS_ARM_OBJECTID_VSWRCONFIG, 0}; + uint8_t armData[80] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint32_t *delPointer = &pathDelay->forwardPathDelayCh1; + uint8_t channel = 0; + uint8_t addr[4] = {0}; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPathDelay()\n"); +#endif + + if (pathDelay == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM, + getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM)); + return MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM; + } + + switch (select) + { + case MYK_DPD_PATH_DELAY: + extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG; + addr[0] = 24; + addr[1] = 26; + addr[2] = 0; + addr[3] = 0; + break; + case MYK_CLGC_PATH_DELAY: + extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG; + addr[0] = 60; + addr[1] = 62; + addr[2] = 0; + addr[3] = 0; + break; + case MYK_VSWR_PATH_DELAY: + extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG; + addr[0] = 72; + addr[1] = 74; + addr[2] = 76; + addr[3] = 78; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION, + getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION)); + return MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION; + } + + /* reading 2 channels, channel being the channel selector */ + for (channel = 0; channel < 2; channel++) + { + if (channel) + { + delPointer++; + } + + extData[2] = channel; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + /* throw more specific error message instead of returning error code from waitArmCmdStatus */ + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG)); + return MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG)); + return MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG; + } + + /* read status from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + *delPointer = ((uint32_t)(armData[addr[1]]) * 16) + (uint32_t)(armData[addr[0]]); + delPointer++; + if ((addr[2] != 0) && (addr[3] != 0)) + { + /* reverse path delay only applies to VSWR */ + *delPointer = ((uint32_t)(armData[addr[3]]) * 16) + (uint32_t)(armData[addr[2]]); + } + else + { + /* the rest of path delays will not have a reverse delay value */ + *delPointer = 0; + } + } + + return retVal; +} + +/** + * \brief This function reads the current error counters for all the DPD error codes from ::mykonosDpdErrors_t. + * + * A DPD-enabled transceiver is required + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param txChannel Tx channel selection from ::mykonosTxChannels_t + * \param dpdErrCnt pointer to structure of type ::mykonosDpdErrorCounters_t to store the read back error counters + * + * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM dpdErrCnt is null + * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH invalid selection for getting the error counters tx channel, only valid values are Tx1 and Tx2 + * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG Arm error while reading the error counters for the DPD status + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDpdErrorCounters(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdErrorCounters_t *dpdErrCnt) +{ + uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_DPDCONFIG, 0}; + uint8_t armData[200] = {0}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint8_t loop = 0; + uint8_t index = 0; + uint8_t channelSelect = 0; + mykonosErr_t retVal = MYKONOS_ERR_OK; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdErrorCounters()\n"); +#endif + + if (dpdErrCnt == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM, + getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM)); + return MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM; + } + + switch (txChannel) + { + case TX1: + channelSelect = 0; + break; + case TX2: + channelSelect = 1; + break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH, + getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH)); + return MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH; + } + } + + extData[2] = channelSelect; + + retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + timeoutMs = 1000; + retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte); + if (retVal != MYKONOS_ERR_OK) + { + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG)); + return MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG; + } + + return retVal; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG, + getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG)); + return MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG; + } + + /* read status from ARM memory */ + retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + dpdErrCnt->dpdErrorCount = ((uint32_t)(armData[67]) << 24) | ((uint32_t)(armData[66]) << 16) | ((uint32_t)(armData[65]) << 8) | (uint32_t)(armData[64]); + index = 68; + for (loop = 1; loop < (uint8_t)MYK_DPD_ERROR_END; loop++) + { + dpdErrCnt->errorCounter[loop] = ((uint32_t)(armData[index + 3]) << 24) | ((uint32_t)(armData[index + 2]) << 16) | ((uint32_t)(armData[index + 1]) << 8) | (uint32_t)(armData[index]); + index +=4; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief DPD feature to set the bypassing actuator when Tx signal power is below a programmable threshold given in + * ::mykonosDpdBypassConfig_t lowPowerActuatorBypassLevel. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param actConfig Pointer to actuator structure of type ::mykonosDpdBypassConfig_t which contains the settings to be programmed + * + * \retval MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT passed structure is null + * \retval MYKONOS_ERR_SETDPDACT_INV_ACTMODE invalid mode in actConfig->lowPowerActuatorBypassMode for valid modes ::mykonosDpdResetMode_t + * \retval MYKONOS_ERR_SETDPDACT_INV_LEVEL actConfig->lowPowerActuatorBypassLevel outside the range, valid range is 0 to 6000 (0 to 60dB) + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[4] = {0}; + uint8_t byteOffset = 62; + + const uint16_t LEVEL_RANGE_CHECK = 6000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdBypassConfig()\n"); +#endif + + if (actConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT)); + return MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT; + } + + if (actConfig->bypassActuatorMode >= MYK_DPD_RESET_END) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_ACTMODE, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_ACTMODE)); + return MYKONOS_ERR_SETDPDACT_INV_ACTMODE; + } + + if (actConfig->bypassActuatorLevel > LEVEL_RANGE_CHECK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_LEVEL, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_LEVEL)); + return MYKONOS_ERR_SETDPDACT_INV_LEVEL; + } + + armFieldValue[0] = (actConfig->bypassActuatorEn > 0) ? 1 : 0; + armFieldValue[1] = (uint8_t)(actConfig->bypassActuatorMode); + armFieldValue[2] = (uint8_t)(actConfig->bypassActuatorLevel & 0xFF); + armFieldValue[3] = (uint8_t)((actConfig->bypassActuatorLevel >> 8) & 0xFF); + + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + +/** + * \brief Get configuration for bypassing DPD actuator + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param actConfig actuator structure of type ::mykonosDpdBypassConfig_t + * + * \retval MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT passed structure is null + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[4] = {0}; + uint8_t byteOffset = 62; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdBypassConfig()\n"); +#endif + + if (actConfig == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT)); + return MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT; + } + + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + actConfig->bypassActuatorEn = armFieldValue[0]; + actConfig->bypassActuatorMode = (mykonosDpdResetMode_t)armFieldValue[1]; + actConfig->bypassActuatorLevel = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2])); + + return MYKONOS_ERR_OK; +} + +/** + * \brief DPD feature to set the actuator gain difference check. + * If the gain before and after the actuator exceeds the value actCheck->actuatorGainCheckLevel an error will be issued + * and the actuator will reset depending on the actCheck->actuatorGainCheckMode. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param actCheck Pointer to structure of type mykonosDpdActuatorCheck_t which contains the settings to be programmed + * + * \retval MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT passed structure is null + * \retval MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE invalid mode in actCheck->actuatorGainCheckMode for valid modes ::mykonosDpdResetMode_t + * \retval MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL actCheck->actuatorGainCheckLevel outside the range, valid range is from 0 to 3000 (0 to 30dB) + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[4] = {0}; + uint8_t byteOffset = 58; + + const uint16_t LEVEL_RANGE_CHECK = 3000; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdActuatorCheck()\n"); +#endif + + if (actCheck == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT)); + return MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT; + } + + if (actCheck->actuatorGainCheckMode >= MYK_DPD_RESET_END) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE)); + return MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE; + } + + if (actCheck->actuatorGainCheckLevel > LEVEL_RANGE_CHECK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL, + getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL)); + return MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL; + } + + armFieldValue[0] = (actCheck->actuatorGainCheckEn > 0) ? 1 : 0; + armFieldValue[1] = (uint8_t)(actCheck->actuatorGainCheckMode); + armFieldValue[2] = (uint8_t)(actCheck->actuatorGainCheckLevel & 0xFF); + armFieldValue[3] = (uint8_t)((actCheck->actuatorGainCheckLevel >> 8) & 0xFF); + + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + + +/** + * \brief Get configuration for DPD actuator check + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param actCheck Pointer to structure of type mykonosDpdActuatorCheck_t which will contain the programmed settings + * + * \retval MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT passed structure is null + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[4] = {0}; + uint8_t byteOffset = 58; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdActuatorCheck()\n"); +#endif + + if (actCheck == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT)); + return MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT; + } + + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + actCheck->actuatorGainCheckEn = armFieldValue[0]; + actCheck->actuatorGainCheckMode = (mykonosDpdResetMode_t)armFieldValue[1]; + actCheck->actuatorGainCheckLevel = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2])); + + return MYKONOS_ERR_OK; +} + + +/** + * \brief CLGC feature to set the TX attenuation tuning range to a relative range around a nominal value + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param attRangeCfg Pointer to structure of type mykonosClgcAttenTuningConfig_t which contains the settings to be programmed + * + * \retval MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV Tx and ObsRx profiles must be valid to use the CLGC feature + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT Passed structure is null + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE Invalid mode in attRangeCfg member, for valid modes ::mykonosClgcAttenTuningMode_t + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET Invalid AttenTuningPreset in attRangeCfg member, valid range is from 0 to 839 (0 to 41.95dB) + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE Invalid AttenTuningRange in attRangeCfg member, valid range is from 0 to 420 (0 to 21dB) + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS Invalid Tx1 AttenTuningRange and AttenTuningPreset combination + * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS Invalid Tx2 AttenTuningRange and AttenTuningPreset combination + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_setClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[10] = {0}; + uint8_t byteOffset = 0x2C; + + const uint16_t PRESET_CHECK = 840; + const uint16_t RANGE_CHECK = 420; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setClgcAttenTuningConfig()\n"); +#endif + + /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */ + if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV, + getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV)); + return MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV; + } + + if (attRangeCfg == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT)); + return MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT; + } + + /* Range checks */ + if ((attRangeCfg->tx1AttenTuningLimitMode >= MYK_CLGC_ATTEN_END) || (attRangeCfg->tx2AttenTuningLimitMode >= MYK_CLGC_ATTEN_END)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE)); + return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE; + } + + if ((attRangeCfg->tx1AttenTuningPreset >= PRESET_CHECK) || (attRangeCfg->tx2AttenTuningPreset >= PRESET_CHECK)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET)); + return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET; + } + + if ((attRangeCfg->tx1AttenTuningRange > RANGE_CHECK) || (attRangeCfg->tx2AttenTuningRange > RANGE_CHECK)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE)); + return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE; + } + + if (((attRangeCfg->tx1AttenTuningPreset - attRangeCfg->tx1AttenTuningRange) < 0) || + ((attRangeCfg->tx1AttenTuningPreset + attRangeCfg->tx1AttenTuningRange) > PRESET_CHECK)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS)); + return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS; + } + + if (((attRangeCfg->tx2AttenTuningPreset - attRangeCfg->tx2AttenTuningRange) < 0) || + ((attRangeCfg->tx2AttenTuningPreset + attRangeCfg->tx2AttenTuningRange) > PRESET_CHECK)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS)); + return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS; + } + + armFieldValue[0] = (uint8_t)(attRangeCfg->tx1AttenTuningLimitMode & 0xFF); + armFieldValue[1] = (uint8_t)(attRangeCfg->tx2AttenTuningLimitMode & 0xFF); + armFieldValue[2] = (uint8_t)(attRangeCfg->tx1AttenTuningPreset & 0xFF); + armFieldValue[3] = (uint8_t)((attRangeCfg->tx1AttenTuningPreset >> 8) & 0xFF); + armFieldValue[4] = (uint8_t)(attRangeCfg->tx2AttenTuningPreset & 0xFF); + armFieldValue[5] = (uint8_t)((attRangeCfg->tx2AttenTuningPreset >> 8) & 0xFF); + armFieldValue[6] = (uint8_t)(attRangeCfg->tx1AttenTuningRange & 0xFF); + armFieldValue[7] = (uint8_t)((attRangeCfg->tx1AttenTuningRange >> 8) & 0xFF); + armFieldValue[8] = (uint8_t)(attRangeCfg->tx2AttenTuningRange & 0xFF); + armFieldValue[9] = (uint8_t)((attRangeCfg->tx2AttenTuningRange >> 8) & 0xFF); + + retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + return MYKONOS_ERR_OK; +} + + +/** + * \brief Get configuration for CLGC Tx attenuation tuning range. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->profilesValid + * + * \param device Pointer to the Mykonos device data structure containing settings + * \param attRangeCfg Pointer to structure of type mykonosClgcAttenTuningConfig_t which will contain the programmed settings + * + * \retval MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT passed structure is null + * \retval MYKONOS_ERR_OK Function completed successfully + */ +mykonosErr_t MYKONOS_getClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg) +{ + mykonosErr_t retVal = MYKONOS_ERR_OK; + uint8_t armFieldValue[10] = {0}; + uint8_t byteOffset = 0x2C; + +#if (MYKONOS_VERBOSE == 1) + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcAttenTuningConfig()\n"); +#endif + + if (attRangeCfg == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT, + getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT)); + return MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT; + } + + retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue)); + if (retVal != MYKONOS_ERR_OK) + { + return retVal; + } + + attRangeCfg->tx1AttenTuningLimitMode = (mykonosClgcAttenTuningMode_t)armFieldValue[0]; + attRangeCfg->tx2AttenTuningLimitMode = (mykonosClgcAttenTuningMode_t)armFieldValue[1]; + attRangeCfg->tx1AttenTuningPreset = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2])); + attRangeCfg->tx2AttenTuningPreset = (uint16_t)(((uint16_t)(armFieldValue[5]) << 8) | (uint16_t)(armFieldValue[4])); + attRangeCfg->tx1AttenTuningRange = (uint16_t)(((uint16_t)(armFieldValue[7]) << 8) | (uint16_t)(armFieldValue[6])); + attRangeCfg->tx2AttenTuningRange = (uint16_t)(((uint16_t)(armFieldValue[9]) << 8) | (uint16_t)(armFieldValue[8])); + + return MYKONOS_ERR_OK; +} diff --git a/src/hardware/mykonos/mykonos.h b/src/hardware/mykonos/mykonos.h new file mode 100644 index 0000000..b852b58 --- /dev/null +++ b/src/hardware/mykonos/mykonos.h @@ -0,0 +1,277 @@ +/*! + * \file mykonos.h + * \brief Contains macro definitions and function prototypes for mykonos.c + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _MYKONOS_LIB_H_ +#define _MYKONOS_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "t_mykonos.h" +#include "mykonos_version.h" + +#define TX_PROFILE_VALID 0x01 +#define RX_PROFILE_VALID 0x02 +#define ORX_PROFILE_VALID 0x04 +#define SNIFF_PROFILE_VALID 0x08 + +/* + **************************************************************************** + * General Initialization functions + **************************************************************************** + */ +mykonosErr_t MYKONOS_resetDevice(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getDeviceRev(mykonosDevice_t *device, uint8_t *revision); +mykonosErr_t MYKONOS_getProductId(mykonosDevice_t *device, uint8_t *productId); +mykonosErr_t MYKONOS_setSpiSettings(mykonosDevice_t *device); +mykonosErr_t MYKONOS_verifyDeviceDataStructure(mykonosDevice_t *device); +mykonosErr_t MYKONOS_verifyProfiles(mykonosDevice_t *device); +mykonosErr_t MYKONOS_initialize(mykonosDevice_t *device); +mykonosErr_t MYKONOS_waitForEvent(mykonosDevice_t *device, waitEvent_t waitEvent, uint32_t timeout_us); +mykonosErr_t MYKONOS_readEventStatus(mykonosDevice_t *device, waitEvent_t waitEvent, uint8_t *eventDone); +mykonosErr_t MYKONOS_getApiVersion (mykonosDevice_t *device, uint32_t *siVer, uint32_t *majorVer, uint32_t *minorVer, uint32_t *buildVer); + +/* + ***************************************************************************** + * PLL / Synthesizer functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_initDigitalClocks(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t rfPllLoFrequency_Hz); +mykonosErr_t MYKONOS_getRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t *rfPllLoFrequency_Hz); +mykonosErr_t MYKONOS_checkPllsLockStatus(mykonosDevice_t *device, uint8_t *pllLockStatus); +mykonosErr_t MYKONOS_setRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t loopBandwidth_kHz, uint8_t stability); +mykonosErr_t MYKONOS_getRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t *loopBandwidth_kHz, uint8_t *stability); +/* + ***************************************************************************** + * ARM Processor Control Functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_initArm(mykonosDevice_t *device); +mykonosErr_t MYKONOS_loadArmFromBinary(mykonosDevice_t *device, uint8_t *binary, uint32_t count); +mykonosErr_t MYKONOS_loadArmConcurrent(mykonosDevice_t *device, uint8_t *binary, uint32_t count); +mykonosErr_t MYKONOS_verifyArmChecksum(mykonosDevice_t *device); +mykonosErr_t MYKONOS_checkArmState(mykonosDevice_t *device, mykonosArmState_t armStateCheck); +mykonosErr_t MYKONOS_getArmVersion(mykonosDevice_t *device, uint8_t *majorVer, uint8_t *minorVer, uint8_t *rcVer, mykonosBuild_t *buildType); + +mykonosErr_t MYKONOS_configDpd(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getDpdConfig(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getDpdStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdStatus_t *dpdStatus); +mykonosErr_t MYKONOS_restoreDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes); +mykonosErr_t MYKONOS_saveDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes); +mykonosErr_t MYKONOS_setDpdActState(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t actState); +mykonosErr_t MYKONOS_resetDpd(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdResetMode_t reset); +mykonosErr_t MYKONOS_setDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig); +mykonosErr_t MYKONOS_getDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig); +mykonosErr_t MYKONOS_setDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck); +mykonosErr_t MYKONOS_getDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck); + +mykonosErr_t MYKONOS_setClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg); +mykonosErr_t MYKONOS_getClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg); + +mykonosErr_t MYKONOS_configClgc(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getClgcConfig(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getClgcStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosClgcStatus_t *clgcStatus); +mykonosErr_t MYKONOS_setClgcGain(mykonosDevice_t *device, mykonosTxChannels_t txChannel, int16_t gain); + +mykonosErr_t MYKONOS_configVswr(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getVswrConfig(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getVswrStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosVswrStatus_t *vswrStatus); + +mykonosErr_t MYKONOS_runInitCals(mykonosDevice_t *device, uint32_t calMask); +mykonosErr_t MYKONOS_waitInitCals(mykonosDevice_t *device, uint32_t timeoutMs, uint8_t *errorFlag, uint8_t *errorCode); +mykonosErr_t MYKONOS_abortInitCals(mykonosDevice_t *device, uint32_t *calsCompleted); +mykonosErr_t MYKONOS_getInitCalStatus(mykonosDevice_t *device, mykonosInitCalStatus_t *initCalStatus); + +mykonosErr_t MYKONOS_resetExtTxLolChannel(mykonosDevice_t *device, mykonosTxChannels_t channelSel); + +mykonosErr_t MYKONOS_radioOn(mykonosDevice_t *device); +mykonosErr_t MYKONOS_radioOff(mykonosDevice_t *device); +mykonosErr_t MYKONOS_getRadioState(mykonosDevice_t *device, uint32_t *radioStatus); +mykonosErr_t MYKONOS_enableTrackingCals(mykonosDevice_t *device, uint32_t enableMask); +mykonosErr_t MYKONOS_rescheduleTrackingCal(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal); +mykonosErr_t MYKONOS_setAllTrackCalState(mykonosDevice_t *device, uint32_t trackingCalMask); +mykonosErr_t MYKONOS_getAllTrackCalState(mykonosDevice_t *device, uint32_t *trackCals); +mykonosErr_t MYKONOS_setTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t trackCalState); +mykonosErr_t MYKONOS_getTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t *trackCalState); +mykonosErr_t MYKONOS_getEnabledTrackingCals(mykonosDevice_t *device, uint32_t *enableMask); +mykonosErr_t MYKONOS_getPendingTrackingCals(mykonosDevice_t *device, uint32_t *pendingCalMask); +mykonosErr_t MYKONOS_getTxLolStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxLolStatus_t *txLolStatus); +mykonosErr_t MYKONOS_getTxQecStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxQecStatus_t *txQecStatus); + +mykonosErr_t MYKONOS_getRxQecStatus(mykonosDevice_t *device, mykonosRxChannels_t rxChannel, mykonosRxQecStatus_t *rxQecStatus); +mykonosErr_t MYKONOS_getOrxQecStatus(mykonosDevice_t *device, mykonosObsRxChannels_t orxChannel, mykonosOrxQecStatus_t *orxQecStatus); + +mykonosErr_t MYKONOS_setSnifferChannel(mykonosDevice_t *device, mykonosSnifferChannel_t snifferChannel); +mykonosErr_t MYKONOS_setRadioControlPinMode(mykonosDevice_t *device); + +mykonosErr_t MYKONOS_setPathDelay(mykonosDevice_t *device, mykonosPathdelay_t *pathDelay); +mykonosErr_t MYKONOS_getPathDelay(mykonosDevice_t *device, mykonosPathDelaySel_t select, mykonosPathdelay_t *pathDelay); + +mykonosErr_t MYKONOS_getDpdErrorCounters(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdErrorCounters_t *dpdErrCnt); + +/* Low level ARM functions */ +mykonosErr_t MYKONOS_readArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *returnData, uint32_t bytesToRead, uint8_t autoIncrement); +mykonosErr_t MYKONOS_writeArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *data, uint32_t byteCount); +mykonosErr_t MYKONOS_writeArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount); +mykonosErr_t MYKONOS_readArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount); +mykonosErr_t MYKONOS_sendArmCommand(mykonosDevice_t *device, uint8_t opCode, uint8_t *extendedData, uint8_t extendedDataNumBytes); +mykonosErr_t MYKONOS_readArmCmdStatus(mykonosDevice_t *device, uint16_t *errorWord, uint16_t *statusWord); +mykonosErr_t MYKONOS_readArmCmdStatusByte(mykonosDevice_t *device, uint8_t opCode, uint8_t *cmdStatByte); +mykonosErr_t MYKONOS_waitArmCmdStatus(mykonosDevice_t *device, uint8_t opCode, uint32_t timeoutMs, uint8_t *cmdStatByte); +mykonosErr_t MYKONOS_writeArmProfile(mykonosDevice_t *device); +mykonosErr_t MYKONOS_loadAdcProfiles(mykonosDevice_t *device); + + +/* + ***************************************************************************** + * JESD204B Datapath Functions + ***************************************************************************** + */ +/* Functions to setup the JESD204B IP */ +mykonosErr_t MYKONOS_resetDeframer(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setupSerializers(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setupDeserializers(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setupJesd204bFramer(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setupJesd204bObsRxFramer(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setupJesd204bDeframer(mykonosDevice_t *device); +mykonosErr_t MYKONOS_enableRxFramerLink(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_enableObsRxFramerLink(mykonosDevice_t *device, uint8_t enable); + +/* Functions to initialize the JESD204B link */ +mykonosErr_t MYKONOS_enableMultichipSync(mykonosDevice_t *device, uint8_t enableMcs, uint8_t *mcsStatus); +mykonosErr_t MYKONOS_enableSysrefToRxFramer(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_enableSysrefToObsRxFramer(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_enableSysrefToDeframer(mykonosDevice_t *device, uint8_t enable); + +/* Functions to help debug the JESD204B link */ +mykonosErr_t MYKONOS_readRxFramerStatus(mykonosDevice_t *device, uint8_t *framerStatus); +mykonosErr_t MYKONOS_readOrxFramerStatus(mykonosDevice_t *device, uint8_t *obsFramerStatus); +mykonosErr_t MYKONOS_readDeframerStatus(mykonosDevice_t *device, uint8_t *deframerStatus); +mykonosErr_t MYKONOS_getDeframerFifoDepth(mykonosDevice_t *device, uint8_t *fifoDepth, uint8_t *readEnLmfcCount); + +/* PRBS debug functions */ +mykonosErr_t MYKONOS_enableRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable); +mykonosErr_t MYKONOS_enableObsRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable); +mykonosErr_t MYKONOS_rxInjectPrbsError(mykonosDevice_t *device); +mykonosErr_t MYKONOS_obsRxInjectPrbsError(mykonosDevice_t *device); +mykonosErr_t MYKONOS_enableDeframerPrbsChecker(mykonosDevice_t *device, uint8_t lanes, mykonosPrbsOrder_t polyOrder, uint8_t enable); +mykonosErr_t MYKONOS_clearDeframerPrbsCounters(mykonosDevice_t *device); +mykonosErr_t MYKONOS_readDeframerPrbsCounters(mykonosDevice_t *device, uint8_t counterSelect, uint32_t *prbsErrorCount); + +/* Miscellaneous debug functions */ +mykonosErr_t MYKONOS_jesd204bIlasCheck(mykonosDevice_t *device, uint16_t *mismatch); +mykonosErr_t MYKONOS_setRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource); +mykonosErr_t MYKONOS_setObsRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource); + +/* + ***************************************************************************** + * Shared Data path functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_programFir(mykonosDevice_t *device, mykonosfirName_t filterToProgram, mykonosFir_t *firFilter); +mykonosErr_t MYKONOS_readFir(mykonosDevice_t *device, mykonosfirName_t filterToRead, mykonosFir_t *firFilter); + +/* + ***************************************************************************** + * Rx Data path functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_programRxGainTable(mykonosDevice_t *device, uint8_t *gainTablePtr, uint8_t numGainIndexesInTable, mykonosGainTable_t rxChannel); +mykonosErr_t MYKONOS_setRx1ManualGain(mykonosDevice_t *device, uint8_t gainIndex); +mykonosErr_t MYKONOS_setRx2ManualGain(mykonosDevice_t *device, uint8_t gainIndex); +mykonosErr_t MYKONOS_getRx1Gain(mykonosDevice_t *device, uint8_t *rx1GainIndex); +mykonosErr_t MYKONOS_getRx2Gain(mykonosDevice_t *device, uint8_t *rx2GainIndex); +mykonosErr_t MYKONOS_setupRxAgc(mykonosDevice_t *device); +mykonosErr_t MYKONOS_resetRxAgc(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosRxChannels_t rxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex); +mykonosErr_t MYKONOS_setObsRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex); +mykonosErr_t MYKONOS_setRx1TempGainComp(mykonosDevice_t *device, int16_t rx1TempCompGain_mdB); +mykonosErr_t MYKONOS_getRx1TempGainComp(mykonosDevice_t *device, int16_t *rx1TempCompGain_mdB); +mykonosErr_t MYKONOS_setRx2TempGainComp(mykonosDevice_t *device, int16_t rx2TempCompGain_mdB); +mykonosErr_t MYKONOS_getRx2TempGainComp(mykonosDevice_t *device, int16_t *rx2TempCompGain_mdB); +mykonosErr_t MYKONOS_setObsRxTempGainComp(mykonosDevice_t *device, int16_t obsRxTempCompGain_mdB); +mykonosErr_t MYKONOS_getObsRxTempGainComp(mykonosDevice_t *device, int16_t *obsRxTempCompGain_mdB); +mykonosErr_t MYKONOS_enableRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_setRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode); +mykonosErr_t MYKONOS_getRx1DecPower(mykonosDevice_t *device, uint16_t *rx1DecPower_mdBFS); +mykonosErr_t MYKONOS_getRx2DecPower(mykonosDevice_t *device, uint16_t *rx2DecPower_mdBFS); + +/* + ***************************************************************************** + * Observation Rx Data path functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_setDefaultObsRxPath(mykonosDevice_t *device, mykonosObsRxChannels_t defaultObsRxCh); +mykonosErr_t MYKONOS_setObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh); +mykonosErr_t MYKONOS_getObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t *obsRxCh); +mykonosErr_t MYKONOS_setObsRxManualGain(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh, uint8_t gainIndex); +mykonosErr_t MYKONOS_getObsRxGain(mykonosDevice_t *device, uint8_t *gainIndex); +mykonosErr_t MYKONOS_setupObsRxAgc(mykonosDevice_t *device); +mykonosErr_t MYKONOS_enableObsRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_setObsRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode); +mykonosErr_t MYKONOS_getObsRxDecPower(mykonosDevice_t *device, uint16_t *obsRxDecPower_mdBFS); + +/* + ***************************************************************************** + * Tx Data path functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_setTx1Attenuation(mykonosDevice_t *device, uint16_t tx1Attenuation_mdB); +mykonosErr_t MYKONOS_setTx2Attenuation(mykonosDevice_t *device, uint16_t tx2Attenuation_mdB); +mykonosErr_t MYKONOS_getTx1Attenuation(mykonosDevice_t *device, uint16_t *tx1Attenuation_mdB); +mykonosErr_t MYKONOS_getTx2Attenuation(mykonosDevice_t *device, uint16_t *tx2Attenuation_mdB); +mykonosErr_t MYKONOS_getTxFilterOverRangeStatus(mykonosDevice_t *device, uint8_t *txFilterStatus); +mykonosErr_t MYKONOS_enableTxNco(mykonosDevice_t *device, uint8_t enable, int32_t tx1ToneFreq_kHz, int32_t tx2ToneFreq_kHz); + +/* + ***************************************************************************** + * PA Protection Functions + ***************************************************************************** + */ +mykonosErr_t MYKONOS_setupPaProtection(mykonosDevice_t *device, uint16_t powerThreshold, uint8_t attenStepSize, uint8_t avgDuration, uint8_t stickyFlagEnable, uint8_t txAttenControlEnable); +mykonosErr_t MYKONOS_enablePaProtection(mykonosDevice_t *device, uint8_t enable); +mykonosErr_t MYKONOS_getDacPower(mykonosDevice_t *device, mykonosTxChannels_t channel, uint16_t *channelPower); +mykonosErr_t MYKONOS_getPaProtectErrorFlagStatus(mykonosDevice_t *device, uint8_t *errorFlagStatus); +mykonosErr_t MYKONOS_clearPaErrorFlag(mykonosDevice_t *device); + +/* + ***************************************************************************** + * Low level functions and helper functions. BBP should not need to call + ***************************************************************************** + */ +const char* getMykonosErrorMessage(mykonosErr_t errorCode); + +mykonosErr_t MYKONOS_initSubRegisterTables(mykonosDevice_t *device); +mykonosErr_t MYKONOS_setTxPfirSyncClk(mykonosDevice_t *device); /* Helper function */ +mykonosErr_t MYKONOS_setRxPfirSyncClk(mykonosDevice_t *device); /* Helper function */ + +/* + ***************************************************************************** + * Functions to configure DC offsets + ***************************************************************************** + */ +mykonosErr_t MYKONOS_setRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t measureCount); +mykonosErr_t MYKONOS_getRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t *measureCount); +mykonosErr_t MYKONOS_setDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t mShift); +mykonosErr_t MYKONOS_getDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t *mShift); +mykonosErr_t MYKONOS_setDigDcOffsetEn(mykonosDevice_t *device, uint8_t enableMask); +mykonosErr_t MYKONOS_getDigDcOffsetEn(mykonosDevice_t *device, uint8_t *enableMask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/mykonosMmap.c b/src/hardware/mykonos/mykonosMmap.c new file mode 100644 index 0000000..076be0c --- /dev/null +++ b/src/hardware/mykonos/mykonosMmap.c @@ -0,0 +1,136 @@ +/** + * \file mykonosMmap.c + * \brief Contains the Mykonos memory mapping + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +uint8_t mykonosMmap [] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x13,0x03,0x03,0x13,0x13,0x00,0x00,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,0xE4,0xE4,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA5,0xA5,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0xE4,0xE4,0x00,0x00,0x00,0x1F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9F,0xE0,0x20,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xF5,0x8F,0x0F,0x00, + 0x00,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,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; +/*!< Mykonos memory map */ diff --git a/src/hardware/mykonos/mykonos_gpio.c b/src/hardware/mykonos/mykonos_gpio.c new file mode 100644 index 0000000..caf1e04 --- /dev/null +++ b/src/hardware/mykonos/mykonos_gpio.c @@ -0,0 +1,5357 @@ +/** + *\file mykonos_gpio.c + * + *\brief Contains Mykonos APIs for transceiver GPIO configuration and control. + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +#include +#include "../common.h" +#include "mykonos.h" +#include "mykonos_gpio.h" +#include "mykonos_macros.h" +#include "mykonos_user.h" + + +/** + * \brief Helper function for return of character string based on 32-bit mykonosGpioErr_t enum value + * + * To save codespace, these error strings are ifdef'd out unless the user + * adds a define MYKONOS_VERBOSE to their workspace. This function can be + * useful for debug. Each function also returns unique error codes to + * make it easier to determine where the code broke. + * + * \param errorCode is enumerated error code value + * + * \return Returns character string based on enumerated value + */ +const char* getGpioMykonosErrorMessage(mykonosGpioErr_t errorCode) +{ +#if MYKONOS_VERBOSE == 0 + return ""; + + #else + + switch (errorCode) + { + case MYKONOS_ERR_GPIO_OK: + return ""; + + case MYKONOS_ERR_EN_MONITOR_OUT_NOT_ENABLED: + return "MYKONOS_setGpioMonitorOut() Mykonos monitor output not enable, please run GPIO setup with the correct setup for enabling the monitor output functionality\n"; + + case MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE: + return "MYKONOS_setGpioMonitorOut()The index specified is incorrect, index available are from 0x01 to 0x42\n"; + + case MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM: + return "MYKONOS_getGpioMonitorOut() if the monitorIndex is null.\n"; + + case MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM: + return "MYKONOS_getGpioMonitorOut() if the monitorMask is null.\n"; + + case MYKONOS_ERR_MGCRX1_STEP_INV_PARAM: + return "MYKONOS_setRx1GainCtrlPin() An invalid step size has been passed, valid step sizes for increment/decrement is 0-7\n"; + + case MYKONOS_ERR_MGCRX1_GPIO_DECPIN_INV_PARAM: + return "MYKONOS_setRx1GainCtrlPin() An invalid decrement pin has been passed \n"; + + case MYKONOS_ERR_MGCRX1_GPIO_INCPIN_INV_PARAM: + return "MYKONOS_setRx1GainCtrlPin() An invalid increment pin has been passed, \n"; + + case MYKONOS_ERR_MGCRX2_STEP_INV_PARAM: + return "MYKONOS_setRx2GainCtrlPin() An invalid step size has been passed, valid step sizes for increment/decrement is 0-7\n"; + + case MYKONOS_ERR_MGCRX2_GPIO_DECPIN_INV_PARAM: + return "MYKONOS_setRx2GainCtrlPin() An invalid decrement pin has been passed\n"; + + case MYKONOS_ERR_MGCRX2_GPIO_INCPIN_INV_PARAM: + return "MYKONOS_setRx2GainCtrlPin() An invalid increment pin has been passed\n"; + + case MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM: + return "MYKONOS_getRx1GainCtrlPin() if a null value has been passed to incStep.\n"; + + case MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM: + return "MYKONOS_getRx1GainCtrlPin() if a null value has been passed to decStep.\n"; + + case MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM: + return "MYKONOS_getRx1GainCtrlPin() if a null value has been passed to rx1GainIncPin.\n"; + + case MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM: + return "MYKONOS_getRx1GainCtrlPin() if a null value has been passed to rx1GainDecPin.\n"; + + case MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM: + return "MYKONOS_getRx1GainCtrlPin() if a null value has been passed to enable.\n"; + + case MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM: + return "MYKONOS_getRx2GainCtrlPin() if a null value has been passed to incStep.\n"; + + case MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM: + return "MYKONOS_getRx2GainCtrlPin() if a null value has been passed to decStep.\n"; + + case MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM: + return "MYKONOS_getRx2GainCtrlPin() if a null value has been passed to rx1GainIncPin.\n"; + + case MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM: + return "MYKONOS_getRx2GainCtrlPin() if a null value has been passed to rx1GainDecPin.\n"; + + case MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM: + return "MYKONOS_getRx2GainCtrlPin() if a null value has been passed to enable.\n"; + + case MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM: + return "MYKONOS_setTx1AttenCtrlPin() An invalid step size has been passed, valid step sizes for att are 0x00-0x1F\n"; + + case MYKONOS_ERR_TPCTX1_GPIO_INCPIN_INV_PARAM: + return "MYKONOS_setTx1AttenCtrlPin() An invalid decrement pin has been passed\n"; + + case MYKONOS_ERR_TPCTX1_GPIO_DECPIN_INV_PARAM: + return "MYKONOS_setTx1AttenCtrlPin() An invalid decrement pin has been passed\n"; + + case MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM: + return "MYKONOS_setTx2AttenCtrlPin() An invalid step size has been passed, valid step sizes for att are 0x00-0x1F\n"; + + case MYKONOS_ERR_TPCTX2_GPIO_INCPIN_INV_PARAM: + return "MYKONOS_setTx2AttenCtrlPin() An invalid decrement pin has been passed\n"; + + case MYKONOS_ERR_TPCTX2_GPIO_DECPIN_INV_PARAM: + return "MYKONOS_setTx2AttenCtrlPin() An invalid decrement pin has been passed\n"; + + case MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM: + return "MYKONOS_getTx2AttenCtrlPin() if a null value has been passed to stepSize.\n"; + + case MYKONOS_ERR_GETTX2PIN_INC_NULL_PARM: + return "MYKONOS_getTx2AttenCtrlPin() if a null value has been passed to tx2AttenIncPin.\n"; + + case MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM: + return "MYKONOS_getTx2AttenCtrlPin() if a null value has been passed to tx2AttenDecPin.\n"; + + case MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM: + return "MYKONOS_getTx2AttenCtrlPin() if a null value has been passed to enable.\n"; + + case MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM: + return "MYKONOS_getTx2AttenCtrlPin() if a null value has been passed to useTx1ForTx2.\n"; + + case MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM: + return "MYKONOS_getTx1AttenCtrlPin() if a null value has been passed to stepSize.\n"; + + case MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM: + return "MYKONOS_getTx1AttenCtrlPin() if a null value has been passed to tx1AttenIncPin.\n"; + + case MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM: + return "MYKONOS_getTx1AttenCtrlPin() if a null value has been passed to tx1AttenDecPin.\n"; + + case MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM: + return "MYKONOS_getTx1AttenCtrlPin() if a null value has been passed to enable.\n"; + + case MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM: + return "MYKONOS_getTx1AttenCtrlPin() if a null value has been passed to useTx1ForTx2.\n"; + + case MYKONOS_ERR_GPIO_SRC_PARAM_INV: + return "MYKONOS_setGpioSourceCtrl() An invalid source control parameter has been passed\n"; + + case MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM: + return "MYKONOS_getGpioSetLevel() gpioPinSetLevel pointer is NULL in function parameter\n"; + + case MYKONOS_ERR_READGPIOSPI_NULL_PARM: + return "MYKONOS_readGpioPinLevel() has a null *gpioPinLevel parameter\n"; + + case MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM: + return "MYKONOS_getGpio3v3PinLevel() has a null *gpio3v3PinLevel parameter\n"; + + case MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM: + return "MYKONOS_setupAuxDac() has a null device->auxIo pointer\n"; + + case MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM: + return "MYKONOS_getGpio3v3Oe() has NULL pointer for function parameter gpio3v3OutEn\n;"; + + case MYKONOS_ERR_INV_GP_INT_MASK_PARM: + return "General Purpose Interrupt source mask parameter is invalid\n"; + + case MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM: + return "MYKONOS_readGpInterruptStatus() has NULL status parameter\n"; + + case MYKONOS_ERR_SET_GPIO_3V3_INV_MODE: + return "Invalid GPIO3v3 source control mode\n"; + + case MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL: + return "gpio3v3 members have invalid value for the GPIO3v3 source control mode.\n"; + + case MYKONOS_ERR_SET_GPIO_1V8_INV_MODE: + return "The GPIO mode enum is not a valid value in MYKONOS_setupGpio\n"; + + case MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM: + return "MYKONOS_getGpio3v3SetLevel() has NULL pointer for function parameter gpio3v3SetLevel\n"; + + case MYKONOS_ERR_GPIO_OE_INV_PARAM: + return "MYKONOS_setGpioOe() had invalid parameter gpioOutEn (valid range 0 - 0x07FFFF)\n"; + + case MYKONOS_ERR_GETGPIO_OE_NULL_PARM: + return "MYKONOS_getGpioOe() has NULL function parameter\n"; + + case MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO: + return "device->auxIo structure has NULL pointer in MYKONOS_writeAuxDac()\n"; + + case MYKONOS_ERR_READAUXADC_NULL_PARAM: + return "MYKONOS_readAuxAdc() has NULL function parameter\n"; + + case MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER: + return "Invalid pointer detected in MYKONOS_setupGpio3v3()\n"; + + case MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER: + return "Invalid pointer detected in MYKONOS_setupGpio()\n"; + + case MYKONOS_ERR_SET_ARMGPIO_INV_POINTER: + return "Invalid pointer detected at device->auxIo->armGpio in MYKONOS_setArmGpioPins() \n"; + + case MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR: + return "ARM Command Error in MYKONOS_setArmGpioPins()\n"; + + case MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID: + return "Invalid Signal ID detected in device->auxIo->armGpio \n"; + + case MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN: + return "Out of range GPIO pin detected \n"; + + case MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE: + return "device->auxIo->auxDacValue, AUXDAC value out of range in MYKONOS_setupAuxDacs()\n"; + + case MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE: + return "auxDacCode value out of range in MYKONOS_writeAuxDac()\n"; + + case MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX: + return "auxDacIndex value out of range in MYKONOS_writeAuxDac()\n"; + + case MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM: + return "auxAdcChannel value out of range in MYKONOS_setAuxAdcChannel()\n"; + + case MYKONOS_ERR_SETUPAUXADC_INV_VCODIV: + return "device->clocks->clkPllVcoDiv value not supported in MYKONOS_setupAuxAdcs()\n"; + + case MYKONOS_ERR_INV_AUX_ADC_DEC_PARM: + return "adcDecimation value out of range in MYKONOS_setupAuxAdcs()\n"; + + case MYKONOS_ERR_SLICER_INV_RX1_SEL: + return "invalid RX1 GPIO pin selection for Slicer control in MYKONOS_setRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_INV_RX2_SEL: + return "invalid RX2 GPIO pin selection for Slicer control in MYKONOS_setRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE: + return "slicer step is out of range for the SLicer control in MYKONOS_setRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_EN_INV: + return "invalid enable in MYKONOS_setRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM: + return "rx1Pins is null pointer for the passed parameter in MYKONOS_getRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM: + return "rx1Pins is null pointer for the passed parameter in MYKONOS_getRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_STEP_NULL_PARM: + return "slicerStep is null pointer for the passed parameter in MYKONOS_getRxSlicerCtrl()\n"; + + case MYKONOS_ERR_SLICER_EN_NULL_PARM: + return "enable is null pointer for the passed parameter in MYKONOS_getRxSlicerCtrl()\n"; + + case MYKONOS_ERR_GAINCOMP_NULL_STRUCT: + return "gain compensation structure gainComp is not initialised in MYKONOS_getRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_EN_NULL_PARM: + return "enable is null pointer for the passed parameter in MYKONOS_getRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT: + return "gain compensation structure gainComp is not initialised in MYKONOS_setRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET: + return "gain compensation structure gainComp->rx1Offset is invalid in MYKONOS_setRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET: + return "gain compensation structure gainComp->rx2Offset is invalid in MYKONOS_setRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_INV_STEP: + return "gain compensation structure gainComp->compStep is invalid in MYKONOS_setRxGainCompensation()\n"; + + case MYKONOS_ERR_GAINCOMP_INV_EN: + return "enable is not valid in MYKONOS_setRxGainCompensation()\n"; + + case MYKONOS_ERR_FLOATFRMT_NULL_STRUCT: + return "floating point formatter structure floatFrmt not initialised in MYKONOS_getFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT: + return "floating point formatter structure floatFrmt not initialised in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE: + return "floating point formatter structure floatFrmt.roundMode not valid parameter in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT: + return "floating point formatter structure floatFrmt.dataFormat not valid parameter in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN: + return "floating point formatter structure floatFrmt.encNan not valid parameter in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS: + return "floating point formatter structure floatFrmt.expBits not valid parameter in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_LEADING: + return "floating point formatter structure floatFrmt.leading not valid parameter in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_RX1ATT: + return "not valid rx1 attenuation parameter passed in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_INV_RX2ATT: + return "not valid rx2 attenuation parameter passed in MYKONOS_setFloatPointFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT: + return "not valid rx2 attenuation parameter passed in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT: + return "not valid rx1 attenuation parameter passed in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_SET_INV_EN: + return "not valid enable parameter passed in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT: + return "null pointer passed for rx1 attenuation in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT: + return "null pointer passed for rx2 attenuation in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_FLOATFRMT_NULL_ENABLE: + return "null pointer passed for enable in MYKONOS_setRxEnFloatPntFrmt()\n"; + + case MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM: + return "MYKONOS_setupTempSensor() has NULL function parameter\n"; + + case MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION: + return "tempDecimation value out of range in MYKONOS_setupTempSensor()\n"; + + case MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW: + return "tempWindow value out of range in MYKONOS_setupTempSensor()\n"; + + case MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET: + return "offset value out of range in MYKONOS_setupTempSensor()\n"; + + case MYKONOS_ERR_GETTEMPSENSORCFG_NULL_PARAM: + return "MYKONOS_getTempSensorConfig() has NULL function parameter\n"; + + case MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM: + return "MYKONOS_readTempSensor() has NULL function parameter\n"; + + case MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED: + return "MYKONOS_readTempSensor() temperature sensor reading is not locked\n"; + + case MYKONOS_ERR_GPIO_HYBRID_RX1_PIN: + return "MYKONOS_setRxHybridGainChangePin() not valid pin has been passed for RX1 hybrid gain control.\n"; + + case MYKONOS_ERR_GPIO_HYBRID_RX2_PIN: + return "MYKONOS_setRxHybridGainChangePin() not valid pin has been passed for RX2 hybrid gain control.\n"; + + case MYKONOS_ERR_GPIO_HYBRID_ORX_PIN: + return "MYKONOS_setObsRxHybridGainChangePin() if invalid pin has been passed for ORX hybrid gain control.\n"; + + case MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID: + return "MYKONOS_setObsRxHybridGainChangePin() if the observation gain mode is not set to Hybrid.\n"; + + case MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM: + return "MYKONOS_getRxHybridGainChangePin() null value has been passed to rx1GainChangePin.\n"; + + case MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM: + return "MYKONOS_getRxHybridGainChangePin() null value has been passed to rx1GainChangePin.\n"; + + case MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID: + return "MYKONOS_setRxHybridGainChangePin() if gain control is not hybrid.\n"; + + case MYKONOS_ERR_GAIN_CONTROL_NOT_AGC : + return "MYKONOS_setRxAgcEnSyncPin() or MYKONOS_getObsRxAgcEnSyncPin() if the observation gain control mode is not set to AGC.\n"; + + case MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC: + return "MYKONOS_getObsRxAgcEnSyncPin() if the observation gain control mode is not set to AGC.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN: + return "MYKONOS_setRxAgcEnSyncPin() if invalid pin has been passed for RX1 AGC sync gain control.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN: + return "MYKONOS_setRxAgcEnSyncPin() if invalid pin has been passed for RX2 AGC sync gain control.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM: + return "MYKONOS_getRxAgcEnSyncPin() if a null value has been passed to rx1AgcSyncPin.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM: + return "MYKONOS_getRxAgcEnSyncPin() if a null value has been passed to rx2AgcSyncPin.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN: + return "MYKONOS_setObsRxAgcEnSyncPin() if invalid pin has been passed for ORX AGC sync gain control.\n"; + + case MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM: + return "MYKONOS_getObsRxAgcEnSyncPin() if a null value has been passed to obsRxAgcSyncPin.\n"; + + case MYKONOS_ERR_SLICER_INV_OBS_RX_SEL: + return "Invalid observation channel GPIO pin selection for Slicer control passed to MYKONOS_setObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE: + return "Slicer step is out of range passed to MYKONOS_setObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_SLICER_OBS_RX_EN_INV: + return "Invalid enable passed to MYKONOS_setObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM: + return "ObsRxPins is null pointer for the passed parameter passed to MYKONOS_getObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM: + return "SlicerStep is null pointer for the passed parameter passed to MYKONOS_getObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM: + return "Enable is null pointer for the passed parameter passed to MYKONOS_getObsRxSlicerCtrl().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT: + return "Gain compensation structure gainComp is not initialised in MYKONOS_setObsRxGainCompensation().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET: + return "Gain compensation structure gainComp->obsRxOffset is invalid in MYKONOS_setObsRxGainCompensation().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP: + return "Gain compensation structure gainComp->compStep is invalid in MYKONOS_setObsRxGainCompensation().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN: + return "Enable is not valid in MYKONOS_setObsRxGainCompensation().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT: + return "Observation channel gain compensation structure gainComp is not initialised in MYKONOS_getObsRxGainCompensation().\n"; + + case MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM: + return "enabled is null pointer for the parameter passed to MYKONOS_getObsRxGainCompensation().\n"; + + case MYKONOS_ERR_GETGPIODRV_NULL_PARAM: + return "Null parameter passed to the function MYKONOS_getGpioDrv().\n"; + + case MYKONOS_ERR_GPIO_DRV_INV_PARAM: + return "GPIO out of range passed to function MYKONOS_setGpioDrv(), valid GPIOs are in the range 0x00000 to 0x7FFFF.\n"; + + case MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM: + return "GPIO out of range -valid GPIOs are in the range 0x00000 to 0x7FFFF.\n"; + + case MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM: + return "Null parameter passed to the function MYKONOS_getGpioSlewRate().\n"; + + case MYKONOS_ERR_CMOS_DRV_NULL_PARAM: + return "Null parameter passed to the function.\n"; + + case MYKONOS_ERR_CMOS_DRV_INV_PARAM: + return "Incorrect drive strength, valid settings are given by mykonosCmosPadDrvStr_t.\n"; + + case MYKONOS_ERR_SPI2_INV_GPIO: + return "if an invalid GPIO pin configuration is passed to MYKONOS_spi2GpioSetup().\n"; + + case MYKONOS_ERR_GET_GPIO_SOURCE_CONTROL_NULL_PARM: + return "Null parameter passed to the function MYKONOS_getGpioSourceCtrl().\n"; + + default: + return "Unknown error was encountered.\n"; + } + + #endif +} + +/** + * \brief This API function configures the monitor output function for the GPIOs + * + * The monitor outputs are grouped in set of nibbles, the user can set + * individual nibbles for having the monitor output function across the available GPIO. + * In order to enable the GPIO monitor function the function setupGpio has to be run and the + * structure should have the proper setup: + * - device->auxIo->gpio->gpioOe = 0xXXXFF the first D7:D0 GPIOs will have the output enable + * - device->auxIo->gpio->gpioSrcCtrl3_0 = GPIO_MONITOR_MODE + * - device->auxIo->gpio->gpioSrcCtrl4_7 = GPIO_MONITOR_MODE + + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio->gpioOe + * - device->auxIo->gpio->gpioSrcCtrl3_0 + * - device->auxIo->gpio->gpioSrcCtrl4_7 + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \param monitorIndex which will be the index at which the outputs are going to be set. see table in documentation + * + * \param monitorMask which GPIO outputs are going to active, the available GPIO + * bit 0 will represent MYKGPIO0 and bit 7 will represent MYKGPIO7. + * + * \retval MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE if GPIO Monitor output index is not in table + * \retval MYKONOS_ERR_EN_MONITOR_OUT_NOT_ENABLED if GPIO source control not set for Monitor output + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioMonitorOut(mykonosDevice_t *device, uint8_t monitorIndex, uint8_t monitorMask) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + const uint8_t INDEX_MASK = 0x42; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioMonitorOut()\n"); +#endif + + /* Error checking for correct index. */ + if (monitorIndex > INDEX_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE, + getGpioMykonosErrorMessage(MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE)); + return MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE; + } + + /* Set the GPIO monitor index and the required pin configuration. */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_MONITOR_INDEX, monitorIndex); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_MONITOR_ENABLE, monitorMask); + + return error; +} + +/** + * \brief This API function reads the GPIO monitor index from Mykonos + * + * The monitor outputs are grouped in two set of nibbles, the user can set + * individual nibbles for having the monitor output function, this nibbles + * will output the monitor output as per the index set. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * - GPIO output enable + * - GPIO source control + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param monitorIndex which will be the index at which the outputs are set to. + * \param monitorMask which will be enable the monitor function. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM if the monitorIndex is null. + * \retval MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM if the monitorMask is null. + */ +mykonosGpioErr_t MYKONOS_getGpioMonitorOut(mykonosDevice_t *device, uint8_t *monitorIndex, uint8_t *monitorMask) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + uint8_t indexRd = 0; + uint8_t monMaskRd = 0; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioMonitorOut()\n"); +#endif + + /* Checking for null passed parameters */ + if (monitorIndex == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM)); + return MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM; + } + + if (monitorMask == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM)); + return MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM; + } + + /* Get GPIO monitor out enable. */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_MONITOR_ENABLE, &monMaskRd); + + /* Get the GPIO monitor index and the required pin configuration. */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_MONITOR_INDEX, &indexRd); + + /* assigning return values to the pointers passed */ + *monitorMask = monMaskRd; + *monitorIndex = indexRd; + + return error; +} + + + + +/** + * \brief This API function configures the GPIO inputs for controlling RX gain + * + * This API function configures the GPIO input pin and step size to allow the BBP to control gain changes in Rx1 signal chain. + * A high pulse on the 'rx1GainIncPin' in pin control mode will increment the gain by the value set in incStep'. + * A high pulse on the 'rx1GainDecPin' in pin control mode will decrement the gain by the value set in 'decStep'. + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \param incStep This sets the change (increase) in gain index that is applied when the + * increment gain pin (in MGC pin control mode) is pulsed. + * + * \param decStep This configures the decrement in gain index that should be applied + * when the decrement gain pin (in MGC pin control mode) is pulsed. + * + * \param rx1GainIncPin mykonosGpioSelect_t These bits select the GPIO used as the enable for + * the Rx1 Manual Increment gain input according to the following: + * MYKGPIO0 or MYKGPIO10 + * + * \param rx1GainDecPin mykonosGpioSelect_t These bits select the GPIO used as the enable for + * the Rx1 Manual Decrement gain input according to the following: + * MYKGPIO1 or MYKGPIO11 + * + * \param enable 0 = Disable the gain pin control for Rx1 + * 1 = enable the gain pin control for Rx1 + * + * \retval MYKONOS_ERR_MGCRX1_STEP_INV_PARAM if an invalid step size has been passed + * \retval MYKONOS_ERR_MGCRX1_GPIO_INCPIN_INV_PARAM if invalid increment pin has been passed + * \retval MYKONOS_ERR_MGCRX1_GPIO_DECPIN_INV_PARAM if invalid decrement pin has been passed + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setRx1GainCtrlPin(mykonosDevice_t *device, uint8_t incStep, uint8_t decStep, mykonosGpioSelect_t rx1GainIncPin, mykonosGpioSelect_t rx1GainDecPin, uint8_t enable) +{ + uint8_t wrtPin = 0x00; + uint8_t wrtStep = 0x00; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + const uint8_t SHIFT_CH1 = 0x00; + const uint8_t SHIFT_INC = 0x05; + const uint8_t SHIFT_DEC = 0x02; + const uint8_t MAX_STEP = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRx1GainCtrlPin()\n"); +#endif + + /* If enable then check for the next otherwise go directly to disable */ + if (enable > 0) + { + /* Error checking for correct step. */ + if ((uint8_t)(incStep > MAX_STEP) || (uint8_t)(decStep > MAX_STEP)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_MGCRX1_STEP_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_MGCRX1_STEP_INV_PARAM)); + return MYKONOS_ERR_MGCRX1_STEP_INV_PARAM; + } + + /* Pin configuration assignment*/ + switch (rx1GainIncPin) + { + case MYKGPIO0: + wrtPin |= 0x00; + break; + case MYKGPIO10: + wrtPin |= 0x04; + break; + + default: + return MYKONOS_ERR_MGCRX1_GPIO_INCPIN_INV_PARAM; + } + + switch (rx1GainDecPin) + { + case MYKGPIO1: + wrtPin |= 0x00; + break; + case MYKGPIO11: + wrtPin |= 0x01; + break; + + default: + return MYKONOS_ERR_MGCRX1_GPIO_DECPIN_INV_PARAM; + } + } + + /* Setting increment step. */ + wrtStep = (uint8_t)(incStep<spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_CFG, wrtStep, 0xFD, 0); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_GPIO_SEL, wrtPin, 0x0F, 0); + + return error; +} + +/** + * \brief This API function returns the configuration RX1 gain Pin control + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param incStep will contain the step that is used for increment. + * \param decStep will contain the step that is used for decrement. + * \param rx1GainIncPin this will have the pin used for increment. + * \param rx1GainDecPin this will have the pin used for decrement. + * \param enable will contain the enable status for this channel if it is set to 1 then this + * function is enable for this channel, if it is 0 it is not enable + * + * \retval MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM if a null value has been passed to incStep + * \retval MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM if a null value has been passed to decStep + * \retval MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM if a null value has been passed to rx1GainIncPin + * \retval MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM if a null value has been passed to rx1GainDecPin + * \retval MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM if a null value has been passed to enable + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getRx1GainCtrlPin(mykonosDevice_t *device, uint8_t *incStep, uint8_t *decStep, mykonosGpioSelect_t *rx1GainIncPin, mykonosGpioSelect_t *rx1GainDecPin, uint8_t *enable) +{ + uint8_t readVal = 0x00; + + const uint8_t MASK_GPIO_CH1 = 0x0F; + const uint8_t MASK_EN_CH1 = 0x01; + const uint8_t MASK_STEP_INC = 0xE0; + const uint8_t MASK_STEP_DEC = 0x1C; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRx1GainCtrlPin()\n"); +#endif + + /* Checking for null passed parameters */ + if (incStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM)); + return MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM; + } + + if (decStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM)); + return MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM; + } + + if (rx1GainIncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM)); + return MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM; + } + + if (rx1GainDecPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM)); + return MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM; + } + + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM)); + return MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_GPIO_SEL, &readVal); + readVal = readVal & MASK_GPIO_CH1; + + if (readVal & 0x04) + { + *rx1GainIncPin = MYKGPIO10; + } + else + { + *rx1GainIncPin = MYKGPIO0; + } + + if (readVal & 0x01) + { + *rx1GainDecPin = MYKGPIO11; + } + else + { + *rx1GainDecPin = MYKGPIO1; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_CFG, &readVal); + + *enable = readVal & MASK_EN_CH1; + + *incStep = (readVal & MASK_STEP_INC) >> 5; + + *decStep = (readVal & MASK_STEP_DEC) >> 2; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function configures the GPIO inputs for controlling RX gain + * + * This API function configures the GPIO input pin and step size to allow the BBP to control gain changes in Rx2 signal chain. + * A high pulse on the 'rx2GainIncPin' in pin control mode will increment the gain by the value set in incStep'. + * A high pulse on the 'rx2GainDecPin' in pin control mode will decrement the gain by the value set in 'decStep'. + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \param incStep This sets the change (increase) in gain index that is applied when the + * increment gain pin (in MGC pin control mode) is pulsed. + * + * \param decStep This configures the decrement in gain index that should be applied + * when the decrement gain pin (in MGC pin control mode) is pulsed. + * + * \param rx2GainIncPin mykonosGpioSelect_t These bits select the GPIO used as the enable for + * the Rx2 Manual Increment gain input according to the following: + * MYKGPIO3 or MYKGPIO13 + * + * \param rx2GainDecPin mykonosGpioSelect_t These bits select the GPIO used as the enable for + * the Rx2 Manual Decrement gain input according to the following: + * MYKGPIO4 or MYKGPIO14 + * + * \param enable 0 = Disable the gain pin control for Rx2 + * 1 = enable the gain pin control for Rx2 + * + * + * \retval MYKONOS_ERR_MGCRX2_STEP_INV_PARAM if an invalid step size is passed + * \retval MYKONOS_ERR_MGCRX2_GPIO_INCPIN_INV_PARAM if invalid increment pin has been passed + * \retval MYKONOS_ERR_MGCRX2_GPIO_DECPIN_INV_PARAM if invalid decrement pin has been passed + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setRx2GainCtrlPin(mykonosDevice_t *device, uint8_t incStep, uint8_t decStep, mykonosGpioSelect_t rx2GainIncPin, mykonosGpioSelect_t rx2GainDecPin, uint8_t enable) +{ + uint8_t wrtPin = 0x00; + uint8_t wrtStep = 0x00; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + const uint8_t SHIFT_CH2 = 0x01; + const uint8_t SHIFT_INC = 0x5; + const uint8_t SHIFT_DEC = 0x2; + const uint8_t MAX_STEP = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRx2GainCtrlPin()\n"); +#endif + + /* If enable then check for the next otherwise go directly to disable */ + if (enable > 0) + { + /* Error checking for correct step. */ + if ((uint8_t)(incStep > MAX_STEP) || (uint8_t)(decStep > MAX_STEP)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_MGCRX2_STEP_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_MGCRX2_STEP_INV_PARAM)); + return MYKONOS_ERR_MGCRX2_STEP_INV_PARAM; + } + + /* Pin configuration assignment*/ + switch (rx2GainIncPin) + { + case MYKGPIO3: + wrtPin |= 0x00; + break; + case MYKGPIO13: + wrtPin |= 0x40; + break; + + default: + return MYKONOS_ERR_MGCRX2_GPIO_INCPIN_INV_PARAM; + } + + switch (rx2GainDecPin) + { + case MYKGPIO4: + wrtPin |= 0x00; + break; + case MYKGPIO14: + wrtPin |= 0x10; + break; + + default: + return MYKONOS_ERR_MGCRX2_GPIO_DECPIN_INV_PARAM; + } + } + + /* Setting increment step. */ + wrtStep = (uint8_t)(incStep<spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_CFG, wrtStep, 0xFE, 0); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_GPIO_SEL, wrtPin, 0xF0, 0); + + return error; +} + +/** + * \brief This API function returns the configuration RX2 gain Pin control + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param incStep will contain the step that is used for increment. + * \param decStep will contain the step that is used for decrement. + * \param rx2GainIncPin this will have the pin used for increment. + * \param rx2GainDecPin this will have the pin used for decrement. + * \param enable will contain the enable status for this channel if it is set to 1 then this + * function is enable for this channel, if it is 0 it is not enable + * + * \retval MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM if a null value has been passed to incStep + * \retval MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM if a null value has been passed to decStep + * \retval MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM if a null value has been passed to rx1GainIncPin + * \retval MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM if a null value has been passed to rx1GainDecPin + * \retval MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM if a null value has been passed to enable + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getRx2GainCtrlPin(mykonosDevice_t *device, uint8_t *incStep, uint8_t *decStep, mykonosGpioSelect_t *rx2GainIncPin, mykonosGpioSelect_t *rx2GainDecPin, uint8_t *enable) +{ + uint8_t readVal = 0x00; + + const uint8_t MASK_GPIO_CH2 = 0xF0; + const uint8_t MASK_EN_CH2 = 0x02; + const uint8_t MASK_STEP_INC = 0xE0; + const uint8_t MASK_STEP_DEC = 0x1C; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRx2GainCtrlPin()\n"); +#endif + + /* Checking for null passed parameters */ + if (incStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM)); + return MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM; + } + + if (decStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM)); + return MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM; + } + + if (rx2GainIncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM)); + return MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM; + } + + if (rx2GainDecPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM)); + return MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM; + } + + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM)); + return MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_GPIO_SEL, &readVal); + readVal = readVal & MASK_GPIO_CH2; + + if (readVal & 0x40) + { + *rx2GainIncPin = MYKGPIO13; + } + else + { + *rx2GainIncPin = MYKGPIO3; + } + + if (readVal & 0x10) + { + *rx2GainDecPin = MYKGPIO14; + } + else + { + *rx2GainDecPin = MYKGPIO4; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_CFG, &readVal); + + *enable = (readVal & MASK_EN_CH2) >> 1; + + *incStep = (readVal & MASK_STEP_INC) >> 5; + + *decStep = (readVal & MASK_STEP_DEC) >> 2; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function set the pins for hybrid gain control + * + * In order to call this function the gain mode should be set to Hybrid. + * The AGC gain change will be controlled with the selected GPIO pin: + * A pulse on the 'rx1GainChangePin' in hybrid pin control will enable the AGC gain change for RX1 + * A pulse on the 'rx2GainChangePin' in hybrid pin control will enable the AGC gain change for RX2 + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param rx1GainChangePin GPIO pin that will be used for hybrid gain change control, the available pins for RX1 channel + * hybrid control are: + * MYKGPIO1 + * MYKGPIO10 + * MYKGPIO11 + * MYKGPIONAN for no GPIO selected + * + * \param rx2GainChangePin GPIO pin that will be used for hybrid gain change control, the available pins for RX2 channel + * hybrid control are: + * MYKGPIO4 + * MYKGPIO10 + * MYKGPIO13 + * MYKGPIONAN for no GPIO selected + * + * \retval MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID if gain control is not hybrid + * \retval MYKONOS_ERR_GPIO_HYBRID_RX1_PIN if invalid pin has been passed for RX1 hybrid gain control. + * \retval MYKONOS_ERR_GPIO_HYBRID_RX2_PIN if invalid pin has been passed for RX2 hybrid gain control. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t rx1GainChangePin, mykonosGpioSelect_t rx2GainChangePin) +{ + uint8_t hybridPinWrite = 0x00; + uint8_t pinRx1 = 0x00; + uint8_t pinRx2 = 0x00; + + const uint8_t HYBRID_RX_PIN_MASK = 0x0F; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRxHybridGainChangePin()\n"); +#endif + + /* Check if in Hybrid Mode */ + if (device->rx->rxGainCtrl->gainMode != HYBRID) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID)); + return MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID; + } + + /* Pin configuration assignment for RX1 and RX2 */ + switch (rx1GainChangePin) + { + case MYKGPIO1: + pinRx1 |= 0x00; + break; + case MYKGPIO10: + pinRx1 |= 0x01; + break; + case MYKGPIO11: + pinRx1 |= 0x02; + break; + case MYKGPIONAN: + pinRx1 |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_RX1_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_RX1_PIN)); + return MYKONOS_ERR_GPIO_HYBRID_RX1_PIN; + } + + switch (rx2GainChangePin) + { + case MYKGPIO4: + pinRx2 |= 0x00; + break; + case MYKGPIO10: + pinRx2 |= 0x04; + break; + case MYKGPIO13: + pinRx2 |= 0x08; + break; + case MYKGPIONAN: + pinRx2 |= 0x0C; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_RX2_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_RX2_PIN)); + return MYKONOS_ERR_GPIO_HYBRID_RX2_PIN; + } + + /* Setting GPIO control for RX1 and RX2 */ + hybridPinWrite = (pinRx1 | pinRx2); + + /* Writing GPIO pin configuration for hybrid mode. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_GAIN_CHANGE_GPIO_SEL, hybridPinWrite, HYBRID_RX_PIN_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + + + +/** + * \brief This API function gets the pin configuration for hybrid gain control of RX1 and RX2 + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param rx1GainChangePin Will return the GPIO pin used for Rx1 in hybrid gain control. + * \param rx2GainChangePin Will return the GPIO pin used for Rx2 in hybrid gain control. + * + * \retval MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM if a null value has been passed to rx1GainChangePin + * \retval MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM if a null value has been passed to rx2GainChangePin + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t *rx1GainChangePin, mykonosGpioSelect_t *rx2GainChangePin) +{ + uint8_t hybridPinRead = 0x00; + uint8_t pinRx1 = 0x00; + uint8_t pinRx2 = 0x00; + mykonosGpioSelect_t rx1Pin = MYKGPIONAN; + mykonosGpioSelect_t rx2Pin = MYKGPIONAN; + + const uint8_t MASK_RX1_PIN = 0x03; + const uint8_t MASK_RX2_PIN = 0x0C; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRxHybridGainChangePin()\n"); +#endif + + /* Checking for null passed parameters */ + if (rx1GainChangePin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM; + } + + if (rx2GainChangePin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM; + } + + /* Getting Pin configuration assignment */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_GAIN_CHANGE_GPIO_SEL, &hybridPinRead); + pinRx1 = hybridPinRead & MASK_RX1_PIN; + pinRx2 = hybridPinRead & MASK_RX2_PIN; + + /* Pin configuration mapping assignment for RX1 and RX2 */ + switch (pinRx1) + { + case 0x00: + rx1Pin = MYKGPIO1; + break; + case 0x01: + rx1Pin = MYKGPIO10; + break; + case 0x02: + rx1Pin = MYKGPIO11; + break; + default: + rx1Pin = MYKGPIONAN; + break; + } + + switch (pinRx2) + { + case 0x00: + rx2Pin = MYKGPIO4; + break; + case 0x04: + rx2Pin = MYKGPIO10; + break; + case 0x08: + rx2Pin = MYKGPIO13; + break; + default: + rx2Pin = MYKGPIONAN; + break; + } + + /* Setting pins to passed pointers */ + *rx1GainChangePin = rx1Pin; + *rx2GainChangePin = rx2Pin; + + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief This API function set the pins for hybrid gain control + * + * In order to call this function the gain mode should be set to Hybrid. + * The AGC gain change will be controlled with the selected GPIO pin: + * A pulse on the 'obsRxGainChangePin' in hybrid pin control will enable the AGC gain change for observation channel + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxGainChangePin GPIO pin that will be used for hybrid gain change control, the available pins for observation channel + * hybrid control are: + * MYKGPIO6 + * MYKGPIO10 + * MYKGPIO17 + * MYKGPIONAN for none selected + * + * \retval MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID if the observation gain mode is not set to Hybrid + * \retval MYKONOS_ERR_GPIO_HYBRID_ORX_PIN if invalid pin has been passed for ORX hybrid gain control. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setObsRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t obsRxGainChangePin) +{ + uint8_t hybridPinWrite = 0x00; + uint8_t pinOrx = 0x00; + + const uint8_t HYBRID_ORX_PIN_MASK = 0x30; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setObsRxHybridGainChangePin()\n"); +#endif + + /* Check if in Hybrid Mode */ + if (device->obsRx->orxGainCtrl->gainMode != HYBRID) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID, + getGpioMykonosErrorMessage(MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID)); + return MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID; + } + + /* Pin configuration assignment for RX1 and RX2 */ + switch (obsRxGainChangePin) + { + case MYKGPIO6: + pinOrx |= 0x00; + break; + case MYKGPIO10: + pinOrx |= 0x10; + break; + case MYKGPIO17: + pinOrx |= 0x20; + break; + case MYKGPIONAN: + pinOrx |= 0x30; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_ORX_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_ORX_PIN)); + return MYKONOS_ERR_GPIO_HYBRID_ORX_PIN; + } + + /* Setting GPIO control for observation channel */ + hybridPinWrite = pinOrx; + + /* Writing GPIO pin configuration for hybrid mode. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_GPIO_SEL, hybridPinWrite, HYBRID_ORX_PIN_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function gets the pin configuration for hybrid gain control of observation channel + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxGainChangePin Will return the GPIO pin used for observation channel in hybrid gain control. + * + * \retval MYKONOS_ERR_GPIO_HYBRID_ORX_PIN_NULL_PARM if a null value has been passed to obsRxGainChangePin + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getObsRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t *obsRxGainChangePin) +{ + uint8_t hybridPinRead = 0x00; + uint8_t pinOrx = 0x00; + mykonosGpioSelect_t orxPin = MYKGPIONAN; + + const uint8_t MASK_ORX_PIN = 0x30; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getObsRxHybridGainChangePin()\n"); +#endif + + /* Checking for null passed parameters */ + if (obsRxGainChangePin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_HYBRID_ORX_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_HYBRID_ORX_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_HYBRID_ORX_PIN_NULL_PARM; + } + + /* Getting Pin configuration assignment */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_GPIO_SEL, &hybridPinRead); + pinOrx = hybridPinRead & MASK_ORX_PIN; + + /* Pin configuration mapping assignment for RX1 and RX2 */ + switch (pinOrx) + { + case 0x00: + orxPin = MYKGPIO6; + break; + case 0x10: + orxPin = MYKGPIO10; + break; + case 0x20: + orxPin = MYKGPIO17; + break; + default: + orxPin = MYKGPIONAN; + break; + } + + /* Setting pins to passed pointer */ + *obsRxGainChangePin = orxPin; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function set the pins for sync AGC gain control + * + * In order to call this function the RX gain control should be set to AGC mode. + * The AGC gain sync will be controlled with the selected GPIO pin: + * A pulse on the 'rx1AgcSyncPin' in hybrid pin control will enable the AGC gain sync for RX1 + * A pulse on the 'rx2AgcSyncPin' in hybrid pin control will enable the AGC gain sync for RX2 + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param rx1AgcSyncPin GPIO pin that will be used for AGC sync gain control, the available pins for RX1 channel are: + * MYKGPIO1 + * MYKGPIO10 + * MYKGPIO11 + * MYKGPIONAN for no GPIO selected + * + * \param rx2AgcSyncPin GPIO pin that will be used for AGC sync gain control, the available pins for RX2 channel are: + * MYKGPIO4 + * MYKGPIO10 + * MYKGPIO13 + * MYKGPIONAN for no GPIO selected + * + * \retval MYKONOS_ERR_GAIN_CONTROL_NOT_AGC if the RX gain control mode is not set to AGC. + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN if invalid pin has been passed for RX1 AGC sync gain control. + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN if invalid pin has been passed for RX2 AGC sync gain control. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t rx1AgcSyncPin, mykonosGpioSelect_t rx2AgcSyncPin) +{ + uint8_t agcSyncPinWrite = 0x00; + uint8_t pinRx1 = 0x00; + uint8_t pinRx2 = 0x00; + + const uint8_t SYNC_RX_PIN_MASK = 0x0F; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRxAgcEnSyncPin()\n"); +#endif + + /* Check if in Hybrid Mode */ + if (device->rx->rxGainCtrl->gainMode != AGC) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAIN_CONTROL_NOT_AGC, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAIN_CONTROL_NOT_AGC)); + return MYKONOS_ERR_GAIN_CONTROL_NOT_AGC; + } + + /* Pin configuration assignment for RX1 and RX2 */ + switch (rx1AgcSyncPin) + { + case MYKGPIO1: + pinRx1 |= 0x00; + break; + case MYKGPIO10: + pinRx1 |= 0x01; + break; + case MYKGPIO11: + pinRx1 |= 0x02; + break; + case MYKGPIONAN: + pinRx1 |= 0x03; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN)); + return MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN; + } + + switch (rx2AgcSyncPin) + { + case MYKGPIO4: + pinRx2 |= 0x00; + break; + case MYKGPIO10: + pinRx2 |= 0x04; + break; + case MYKGPIO13: + pinRx2 |= 0x08; + break; + case MYKGPIONAN: + pinRx2 |= 0x0C; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN)); + return MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN; + } + + /* Setting GPIO control for RX1 and RX2 */ + agcSyncPinWrite = (pinRx1 | pinRx2); + + /* Writing GPIO pin configuration for Sync AGC. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_GAIN_CHANGE_GPIO_SEL, agcSyncPinWrite, SYNC_RX_PIN_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function gets the GPIO pin configuration for AGC gain sync control of RX1 and RX2 + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param rx1AgcSyncPin Will return the GPIO pin used for RX1 channel AGC gain sync control, + * + * \param rx2AgcSyncPin Will return the GPIO pin used for RX2 channel AGC gain sync control, + * + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM if a null value has been passed to rx1AgcSyncPin + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM if a null value has been passed to rx2AgcSyncPin + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t *rx1AgcSyncPin, mykonosGpioSelect_t *rx2AgcSyncPin) +{ + uint8_t agcSyncPinRead = 0x00; + uint8_t pinRx1 = 0x00; + uint8_t pinRx2 = 0x00; + mykonosGpioSelect_t rx1Pin = MYKGPIONAN; + mykonosGpioSelect_t rx2Pin = MYKGPIONAN; + + const uint8_t MASK_RX1_PIN = 0x03; + const uint8_t MASK_RX2_PIN = 0x0C; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRxHybridGainChangePin()\n"); +#endif + + /* Checking for null passed parameters */ + if (rx1AgcSyncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM; + } + + if (rx2AgcSyncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM; + } + + /* Getting Pin configuration assignment */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_GAIN_CHANGE_GPIO_SEL, &agcSyncPinRead); + pinRx1 = agcSyncPinRead & MASK_RX1_PIN; + pinRx2 = agcSyncPinRead & MASK_RX2_PIN; + + /* Pin configuration mapping assignment for RX1 and RX2 */ + switch (pinRx1) + { + case 0x00: + rx1Pin = MYKGPIO1; + break; + case 0x01: + rx1Pin = MYKGPIO10; + break; + case 0x02: + rx1Pin = MYKGPIO11; + break; + default: + rx1Pin = MYKGPIONAN; + break; + } + + switch (pinRx2) + { + case 0x00: + rx2Pin = MYKGPIO4; + break; + case 0x04: + rx2Pin = MYKGPIO10; + break; + case 0x08: + rx2Pin = MYKGPIO13; + break; + default: + rx2Pin = MYKGPIONAN; + break; + } + + /* Setting pins to passed pointers */ + *rx1AgcSyncPin = rx1Pin; + *rx2AgcSyncPin = rx2Pin; + + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief This API function set the pins for AGC gain Sync control + * + * In order to call this function the gain mode should be set to AGC mode. + * The AGC gain sync will be controlled with the selected GPIO pin: + * A pulse on the 'obsRxGainChangePin' in hybrid pin control will enable the AGC gain change for observation channel + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxAgcSyncPin GPIO pin that will be used for AGC sync gain control, the available pins for observation channel are: + * MYKGPIO6 + * MYKGPIO10 + * MYKGPIO17 + * MYKGPIONAN for none selected + * + * \retval MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC if the observation gain control mode is not set to AGC + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN if invalid pin has been passed for ORX AGC sync gain control. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setObsRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t obsRxAgcSyncPin) +{ + uint8_t agcSyncPinWrite = 0x00; + uint8_t pinOrx = 0x00; + + const uint8_t SYNC_ORX_PIN_MASK = 0x30; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setObsRxAgcEnSyncPin()\n"); +#endif + + /* Check if in Hybrid Mode */ + if (device->obsRx->orxGainCtrl->gainMode != AGC) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC)); + return MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC; + } + + /* Pin configuration assignment for observation channel */ + switch (obsRxAgcSyncPin) + { + case MYKGPIO6: + pinOrx |= 0x00; + break; + case MYKGPIO10: + pinOrx |= 0x10; + break; + case MYKGPIO17: + pinOrx |= 0x20; + break; + case MYKGPIONAN: + pinOrx |= 0x30; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN)); + return MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN; + } + + /* Setting GPIO control for observation channel */ + agcSyncPinWrite = pinOrx; + + /* Writing GPIO pin configuration for Sync AGC mode. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_GPIO_SEL, agcSyncPinWrite, SYNC_ORX_PIN_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function gets the pin configuration for AGC Sync gain control of observation channel + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param obsRxAgcSyncPin Will return the GPIO pin used for observation channel AGC gain sync control, + * + * \retval MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM if a null value has been passed to obsRxAgcSyncPin + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getObsRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t *obsRxAgcSyncPin) +{ + uint8_t agcSyncPinRead = 0x00; + uint8_t pinOrx = 0x00; + mykonosGpioSelect_t orxPin = MYKGPIONAN; + + const uint8_t MASK_ORX_PIN = 0x30; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getObsRxAgcEnSyncPin()\n"); +#endif + + /* Checking for null passed parameters */ + if (obsRxAgcSyncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM)); + return MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM; + } + + /* Getting Pin configuration assignment */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_GPIO_SEL, &agcSyncPinRead); + pinOrx = agcSyncPinRead & MASK_ORX_PIN; + + /* Pin configuration mapping assignment for observation channel */ + switch (pinOrx) + { + case 0x00: + orxPin = MYKGPIO6; + break; + case 0x10: + orxPin = MYKGPIO10; + break; + case 0x20: + orxPin = MYKGPIO17; + break; + default: + orxPin = MYKGPIONAN; + break; + } + + /* Setting pins to passed pointer */ + *obsRxAgcSyncPin = orxPin; + + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief This API function configures the GPIO inputs for controlling Tx attenuation settings + * + * This allows to control the TX attenuation using GPIO inputs. When a low to high transition is + * applied to the configure GPIO input the attenuation will change by the desire step. + * The stepSize parameter will set the attenuation change applied. + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \param stepSize the step that will increase or decrease the Tx1 channel attenuation. + * This parameter sets the change in Tx attenuation for each increment or decrement signal received in incr/decr mode. + * Step of 1 changes attenuation by 0.05dB. + * + * \param tx1AttenIncPin This parameter is the GPIO pin configuration that will be controlling the increment + * of Tx attenuation. Available pins are: + * Tx1 increment: MYKGPIO4 or MYKGPIO12 + * + * \param tx1AttenDecPin This parameter is the GPIO pin configuration that will be controlling the decrement + * of Tx attenuation. Available pins are: + * Tx1 decrement: MYKGPIO5 or MYKGPIO13 + * + * \param enable 0 = Disable the attenuation pin control for Tx1 + * 1 = enable the attenuation pin control for Tx1 + * + * \param useTx1ForTx2 is used to return if TX1 settings are used for TX2 channel. + * + * \retval MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM if an invalid step size is passed + * \retval MYKONOS_ERR_TPCTX1_GPIO_INCPIN_INV_PARAM if an invalid channel for TX is passed + * \retval MYKONOS_ERR_TPCTX1_GPIO_DECPIN_INV_PARAM if an invalid channel for TX is passed + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setTx1AttenCtrlPin(mykonosDevice_t *device, uint8_t stepSize, mykonosGpioSelect_t tx1AttenIncPin, mykonosGpioSelect_t tx1AttenDecPin, uint8_t enable, uint8_t useTx1ForTx2) +{ + uint8_t wrtPin = 0; + uint8_t tpcMode = 0x0; + uint8_t tpcMaskTx2 = 0x00; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + const uint8_t TX_INCDEC_MASK = 0x1F; + const uint8_t TX_PIN_MASK = 0x0F; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setTx1AttenCtrlPin()\n"); +#endif + + /* If enable then check for the next otherwise go directly to disable */ + if (enable > 0) + { + /* Error checking for correct step. */ + if (stepSize > TX_INCDEC_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM)); + return MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM; + } + + /* Pin configuration assignment for Tx1 increments */ + switch (tx1AttenIncPin) + { + case MYKGPIO4: + wrtPin |= 0x00; + break; + case MYKGPIO12: + wrtPin |= 0x01; + break; + + default: + return MYKONOS_ERR_TPCTX1_GPIO_INCPIN_INV_PARAM; + } + + /* Pin configuration assignment for Tx1 decrements */ + switch (tx1AttenDecPin) + { + case MYKGPIO5: + wrtPin |= 0x00; + break; + case MYKGPIO13: + wrtPin |= 0x04; + break; + + default: + return MYKONOS_ERR_TPCTX1_GPIO_DECPIN_INV_PARAM; + } + + /* Setting TPC mode corresponding to the enable */ + tpcMode = 0x03; + + /* Setting TPC control for Tx2 using Tx1 */ + if (useTx1ForTx2 > 0) + { + tpcMode |= 0x1C; + tpcMaskTx2 = 0x1F; + } + else + { + tpcMaskTx2 = 0x13; + } + } + else + { + /* Setting TPC mode corresponding for no Pin control */ + tpcMode = 0x05; + tpcMaskTx2 = 0x1F; + } + + /* Setting increment step. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, stepSize, TX_INCDEC_MASK, 0); + + /* Set the TPC mode for GPIO control. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, tpcMode, tpcMaskTx2, 0); + + /* Set the GPIO input pin configuration and the step size. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_GPIO_CFG, wrtPin, TX_PIN_MASK, 0); + + return error; +} + +/** + * \brief This API function returns the configuration TX1 attenuation Pin control + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param stepSize will contain the step that is used for increment and decrement. + * \param tx1AttenIncPin this will have the pin used for increment. + * \param tx1AttenDecPin this will have the pin used for decrement. + * \param enable will contain the enable status for this channel if it is set to 1 then this + * function is enable for this channel, if it is 0 it is not enable + * \param useTx1ForTx2 is used to return if TX1 settings are used for TX2 channel. + * + * \retval MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM if a null value has been passed to stepSize + * \retval MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM if a null value has been passed to tx1AttenIncPin + * \retval MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM if a null value has been passed to tx1AttenDecPin + * \retval MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM if a null value has been passed to enable + * \retval MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM if a null value has been passed to useTx1ForTx2 + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getTx1AttenCtrlPin(mykonosDevice_t *device, uint8_t *stepSize, mykonosGpioSelect_t *tx1AttenIncPin, mykonosGpioSelect_t *tx1AttenDecPin, uint8_t *enable, uint8_t *useTx1ForTx2) +{ + uint8_t readVal = 0x00; + uint8_t en = 0x00; + + const uint8_t MASK_TPC_CH1 = 0x03; + const uint8_t MASK_TPC_CH1FCH2 = 0x10; + const uint8_t MASK_TPC_STEP = 0x1F; + const uint8_t MASK_TPC_GPIO_CH1 = 0x0F; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getTx1AttenCtrlPin()\n"); +#endif + + /* Checking for null passed parameters */ + if (stepSize == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM)); + return MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM; + } + + if (tx1AttenIncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM)); + return MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM; + } + + if (tx1AttenDecPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM)); + return MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM; + } + + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM)); + return MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM; + } + + if (useTx1ForTx2 == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM)); + return MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_TPC_GPIO_CFG, &readVal); + readVal = readVal & MASK_TPC_GPIO_CH1; + + if (readVal & 0x01) + { + *tx1AttenIncPin = MYKGPIO12; + } + else + { + *tx1AttenIncPin = MYKGPIO4; + } + + if (readVal & 0x04) + { + *tx1AttenDecPin = MYKGPIO13; + } + else + { + *tx1AttenDecPin = MYKGPIO5; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, &readVal); + + en = readVal & MASK_TPC_CH1; + + *enable = (en == MASK_TPC_CH1) ? 1 : 0; + + *useTx1ForTx2 = readVal & MASK_TPC_CH1FCH2; + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, &readVal); + + *stepSize = readVal & MASK_TPC_STEP; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This API function configures the GPIO inputs for controlling Tx attenuation settings + * + * This allows to control the TX attenuation using GPIO inputs. when a low to high transition is + * applied to the configure GPIO input the attenuation will change by the desire step. + * The stepSize parameter will set the attenuation change applied. + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + * + * \param device is structure pointer to the Mykonos data structure containing settings + * + * \param stepSize the step that will increase or decrease the Tx2 channel attenuation. + * This parameter sets the change in Tx attenuation for each increment or decrement signal received in incr/decr mode. + * Step of 1 changes attenuation by 0.05dB. + * + * \param tx2AttenIncPin This parameter is the GPIO pin configuration that will be controlling the increment + * of Tx attenuation. Available pins are: + * Tx2 increment: MYKGPIO6 or MYKGPIO14 + * + * \param tx2AttenDecPin This parameter is the GPIO pin configuration that will be controlling the decrement + * of Tx attenuation. Available pins are: + * Tx2 decrement: MYKGPIO7 or MYKGPIO15 + * + * \param enable 0 = Disable the attenuation pin control for Tx2 + * 1 = enable the attenuation pin control for Tx2 + * + * \retval MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM if an invalid step size is passed + * \retval MYKONOS_ERR_TPCTX2_GPIO_INCPIN_INV_PARAM if an invalid channel for TX is passed + * \retval MYKONOS_ERR_TPCTX2_GPIO_INCPIN_INV_PARAM if an invalid channel for TX is passed + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setTx2AttenCtrlPin(mykonosDevice_t *device, uint8_t stepSize, mykonosGpioSelect_t tx2AttenIncPin, mykonosGpioSelect_t tx2AttenDecPin, uint8_t enable) +{ + uint8_t wrtPin = 0; + uint8_t tpcMode = 0x0; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + + const uint8_t TX_INCDEC_MASK = 0x1F; + const uint8_t TX2_TPC_MASK = 0x1C; + const uint8_t TX2_WRTPIN = 0xf0; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setTx2AttenCtrlPin()\n"); +#endif + + /* If enable then check for the next otherwise go directly to disable */ + if (enable > 0) + { + /* Error checking for correct step. */ + if (stepSize > TX_INCDEC_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM)); + return MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM; + } + + /* Pin configuration assignment for Tx2 increments */ + switch (tx2AttenIncPin) + { + case MYKGPIO6: + wrtPin |= 0x00; + break; + case MYKGPIO14: + wrtPin |= 0x10; + break; + + default: + return MYKONOS_ERR_TPCTX2_GPIO_INCPIN_INV_PARAM; + } + + /* Pin configuration assignment for Tx2 decrements */ + switch (tx2AttenDecPin) + { + case MYKGPIO7: + wrtPin |= 0x00; + break; + case MYKGPIO15: + wrtPin |= 0x40; + break; + + default: + return MYKONOS_ERR_TPCTX2_GPIO_DECPIN_INV_PARAM; + } + + /* Setting TPC mode corresponding to the enable */ + tpcMode = 0x0C; + } + else + { + /* Setting TPC mode corresponding for no Pin control */ + tpcMode = 0x05; + } + + /* Setting increment step. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, stepSize, TX_INCDEC_MASK, 0); + + /* Set the TPC mode for GPIO control. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, tpcMode, TX2_TPC_MASK, 0); + + /* Set the GPIO input pin configuration and the step size. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_GPIO_CFG, wrtPin, TX2_WRTPIN, 0); + + return error; +} + +/** + * \brief This API function returns the configuration TX2 attenuation Pin control + * + * + * Dependencies + * - device->spiSettings + * - device->spiSettings->chipSelectIndex + + * + * \param device is structure pointer to the Mykonos data structure containing settings + * \param stepSize will contain the step that is used for increment and decrement. + * \param tx2AttenIncPin this will have the pin used for increment. + * \param tx2AttenDecPin this will have the pin used for decrement. + * \param enable will contain the enable status for this channel if it is set to 1 then this + * function is enable for this channel, if it is 0 it is not enable + * \param useTx1ForTx2 is used to return if TX1 settings are used for TX2 channel. + * + * \retval MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM if a null value has been passed to stepSize + * \retval MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM if a null value has been passed to tx1AttenIncPin + * \retval MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM if a null value has been passed to tx1AttenDecPin + * \retval MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM if a null value has been passed to enable + * \retval MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM if a null value has been passed to useTx1ForTx2 + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getTx2AttenCtrlPin(mykonosDevice_t *device, uint8_t *stepSize, mykonosGpioSelect_t *tx2AttenIncPin, mykonosGpioSelect_t *tx2AttenDecPin, uint8_t *enable, uint8_t *useTx1ForTx2) +{ + uint8_t readVal = 0x00; + uint8_t en = 0x00; + + const uint8_t MASK_TPC_CH2 = 0x0C; + const uint8_t MASK_TPC_CH1FCH2 = 0x10; + const uint8_t MASK_TPC_STEP = 0x1F; + const uint8_t MASK_TPC_GPIO_CH2 = 0xF0; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getTx2AttenCtrlPin()\n"); +#endif + + /* Checking for null passed parameters */ + if (stepSize == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM)); + return MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM; + } + + if (tx2AttenIncPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2PIN_INC_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX2PIN_INC_NULL_PARM)); + return MYKONOS_ERR_GETTX2PIN_INC_NULL_PARM; + } + + if (tx2AttenDecPin == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM)); + return MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM; + } + + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM)); + return MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM; + } + + if (useTx1ForTx2 == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM)); + return MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_TPC_GPIO_CFG, &readVal); + readVal = readVal & MASK_TPC_GPIO_CH2; + + if (readVal & 0x10) + { + *tx2AttenIncPin = MYKGPIO14; + } + else + { + *tx2AttenIncPin = MYKGPIO6; + } + + if (readVal & 0x40) + { + *tx2AttenDecPin = MYKGPIO15; + } + else + { + *tx2AttenDecPin = MYKGPIO7; + } + + /* Getting Pin configuration assignment*/ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, &readVal); + + en = readVal & MASK_TPC_CH2; + + *enable = (en == MASK_TPC_CH2) ? 1 : 0; + + *useTx1ForTx2 = readVal & MASK_TPC_CH1FCH2; + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, &readVal); + + *stepSize = readVal & MASK_TPC_STEP; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets the Mykonos low voltage GPIO output pins level + * + * This function will only affect the GPIO pins that have their OE direction set to output and + * that have the correct source control for the nibbles in GPIO_BITBANG_MODE + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioPinLevel bit per GPIO pin, level to output for each GPIO pin. 0 = low output, 1= high output + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioPinLevel(mykonosDevice_t *device, uint32_t gpioPinLevel) +{ + + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioPinLevel()\n"); +#endif + + /* writing GPIO configuration registers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_7_0, (gpioPinLevel & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_15_8, ((gpioPinLevel >> 8) & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_18_16, ((gpioPinLevel >> 16) & 0x07)); + + /* Return */ + return error; +} + +/** + * \brief Reads the Mykonos low voltage GPIO pin levels and returns their contents in a single 32-bit word + * + * The GPIO pins that are set to be inputs in BITBANG mode will read back and be returned + * in the gpioPinLevel parameter. The return value is a bit per pin. GPIO 0 returns on bit 0 of + * the gpioPinLevel parameter. A logic low level returns a 0, a logic high level returns a 1. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioPinLevel Input Gpio pin levels read back on the pins assigned as inputs (bit per pin) + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_READGPIOSPI_NULL_PARM The pointer passed for gpioPinLevel parameter is NULL + */ +mykonosGpioErr_t MYKONOS_getGpioPinLevel(mykonosDevice_t *device, uint32_t *gpioPinLevel) +{ + uint8_t readBytes[3] = {0, 0, 0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioPinLevel()\n"); +#endif + + if (gpioPinLevel == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READGPIOSPI_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_READGPIOSPI_NULL_PARM)); + return MYKONOS_ERR_READGPIOSPI_NULL_PARM; + } + + /* reading the registers into three-byte array */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_READ_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_READ_15_8, &readBytes[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_READ_18_16, &readBytes[2]); + + /* performing concatenation and assigning value to gpio1v8SpiRead */ + *gpioPinLevel = ((uint32_t)(readBytes[2] & 0x07) << 16) | ((uint32_t)(readBytes[1]) << 8) | (uint32_t)(readBytes[0]); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos GPIO pin output levels for BITBANG mode + * + * This function allows reading the value that the GPIO output pins are + * set to drive out the pins. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioPinSetLevel is a unit32_t pointer which contains the level of each GPIO pin (bit per pin) + * + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM gpioPinSetLevel pointer is NULL in function parameter + * + */ +mykonosGpioErr_t MYKONOS_getGpioSetLevel(mykonosDevice_t *device, uint32_t *gpioPinSetLevel) +{ + uint8_t readBytes[3] = {0, 0, 0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioSetLevel()\n"); +#endif + + if (gpioPinSetLevel == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM)); + return MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM; + } + + /* reading the registers into two-byte array */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_15_8, &readBytes[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_SPI_SRC_18_16, &readBytes[2]); + + /* performing concatenation and assigning value to gpioPinSetLevel */ + *gpioPinSetLevel = ((uint32_t)(readBytes[2] & 0x07) << 16) | ((uint32_t)(readBytes[1]) << 8) | (uint32_t)(readBytes[0]); + + return MYKONOS_ERR_GPIO_OK; +} + + + +/** + * \brief Sets the General Purpose (GP) interrupt register bit mask to enable interrupt sources to assert the GP Interrupt pin + * + * Mykonos has a single output pin called General Purpose Interrupt that asserts to a logic high level + * when certain events occur. The events that cause the GP Interrupt pin to assert are user + * selectable by setting the gpMask parameter in this function. Device default is mask = x1FF = ignore + * all events. The ARM Error interrupt can not be ignored and can always assert the GP interrupt pin. + * + * gpMask | Bit description + * ------------|------------ + * [0] | TXPLL LOCK - 0 = allow PLL unlocking to assert GP Interrupt pin, 1 = ignore TXPLL LOCK + * [1] | RXPLL LOCK - 0 = allow PLL unlocking to assert GP Interrupt pin, 1 = ignore RXPLL LOCK + * [2] | SNIFFER PLL LOCK - 0 = allow PLL unlocking to assert GP Interrupt pin, 1 = ignore SNIFFER PLL LOCK + * [3] | CALIBRATION PLL LOCK - 0 = allow PLL unlocking to assert GP Interrupt pin, 1 = ignore CALIBRATION PLL LOCK + * [4] | CLKPLL LOCK - 0 = allow PLL unlocking to assert GP Interrupt pin, 1 = ignore CLKPLL LOCK + * [5] | 0 = Allow JESD204 deframer interrupt to assert GP Interrupt pin, 1 = ignore JESD204 deframer interrupt + * [6] | Tx1 PA protection - 0 = allow Tx1 PA protection event to assert GP Interrupt pin, 1 = ignore Tx1 PA protection + * [7] | Tx2 PA protection - 0 = allow Tx2 PA protection event to assert GP Interrupt pin, 1 = ignore Tx2 PA protection + * [8] | Mykonos ARM Watchdog - 0 = allow Mykonos ARM Watchdog timeout to assert GP Interrupt pin, 1 = ignore Watchdog timeout event + * [15-9] | Reserved for future use + * + * Dependencies + * - device->spiSettings + * + * \param device Pointer to the device settings structure + * \param gpMask Value is passed to enable one or more general purpose interrupt sources + * (1=ignore source, 0 = enable source interrupt to GP Interrupt pin) + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_INV_GP_INT_MASK_PARM if invalid interrupt mask is passed + */ +mykonosGpioErr_t MYKONOS_configGpInterrupt(mykonosDevice_t *device, uint16_t gpMask) +{ + const uint16_t GP_INT_VALID_MASK = 0x1FF; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_configGpInterrupt()\n"); +#endif + + /* checking for valid mask setting */ + if (gpMask & ~GP_INT_VALID_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_GP_INT_MASK_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_INV_GP_INT_MASK_PARM)); + return MYKONOS_ERR_INV_GP_INT_MASK_PARM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GP_INTERRUPT_MASK_1, (gpMask & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GP_INTERRUPT_MASK_0, ((gpMask >> 8) & 0x01)); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the General Purpose (GP) interrupt status to determine what caused the GP Interrupt pin to assert + * + * When the BBIC detects a rising edge on the General Purpose Interrupt pin, this function + * allows the BBIC to determine the source of the interrupt. The value returned in the status parameter + * will show one or more sources for the interrupt based on the following table. + * + * The PLL unlock bits are not sticky. They will follow the current status of the PLLs. If the PLL relocks, the + * status bit will clear as well. The GP Interrupt pin is the logical OR of all the sources. When all the status + * bits are low, the GP Interrupt pin will be low. The status word readback will show the current value + * for all interrupt sources, even if they are disabled by the masked. However, the GP Interrupt pin will only assert + * for the enabled sources. + * + * status | Bit description + * ------------|------------ + * [0] | 1 = TXPLL UNLOCK + * [1] | 1 = RXPLL UNLOCK + * [2] | 1 = SNIFFER PLL UNLOCK + * [3] | 1 = CALIBRATION PLL UNLOCK + * [4] | 1 = CLK PLL UNLOCK + * [5] | 1 = JESD204 deframer interrupt occurred + * [6] | 1 = Tx1 PA protection event + * [7] | 1 = Tx2 PA protection event + * [8] | 1 = Mykonos ARM Watchdog timeout + * [9] | 1 = ARM interrupt occurred + * [15-10] | Reserved for future use + * + * Dependencies + * - device->spiSettings + * + * \param device Pointer to the device settings structure + * \param status parameter to return the IRQ source(s) that caused the GP Interrpt pin to assert. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM if null *status pointer is passed + */ +mykonosGpioErr_t MYKONOS_readGpInterruptStatus(mykonosDevice_t *device, uint16_t *status) +{ + uint8_t readStatus1 = 0; + uint8_t readStatus0 = 0; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_readGpInterruptStatus()\n"); +#endif + /* checking for null pointer */ + if (status == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM)); + return MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GP_INTERRUPT_READ_1, &readStatus1); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GP_INTERRUPT_READ_0, &readStatus0); + + /* PLL Lock status bits are high when locked, invert to match up with other bits */ + *status = ((((uint16_t)(readStatus1) & 0xE0U) | ((~(uint16_t)(readStatus1)) & 0x1F)) | (((uint16_t)(readStatus0) & 0x0003) << 8)) ; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets the input and output GPIO pin selections for ARM related signals. + * + * The BBP should not have to call this as it will automatically be setup during the + * MYKONOS_loadArmFromBinary() function call. If the BBP wishes to change the GPIO + * assignments this function can be called again to change the configuration while + * the ARM is in the radioOff state. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->armGpio : all members in structure + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SET_ARMGPIO_INV_POINTER device->auxIo->armGpio pointer is null + * \retval MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID Invalid ARM GPIO pin signal ID + * \retval MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN Invalid GPIO pin selected for ARM output (valid 0-15 + output enable in bit[4]) + * \retval MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR ARM returned error setting GPIO pins + */ +mykonosGpioErr_t MYKONOS_setArmGpioPins(mykonosDevice_t *device) +{ + uint8_t i = 0; + uint8_t gpioConfig[3] = {0}; + uint8_t signalId[12] = {ORX_TRIGGER_SIGNALID, ORX_MODE_0_SIGNALID, ORX_MODE_1_SIGNALID, ORX_MODE_2_SIGNALID, RX1_ENABLE_ACK_SIGNALID, + RX2_ENABLE_ACK_SIGNALID, TX1_ENABLE_ACK_SIGNALID, TX2_ENABLE_ACK_SIGNALID, ORX1_ENABLE_ACK_SIGNALID, ORX2_ENABLE_ACK_SIGNALID, + SRX_ENABLE_ACK_SIGNALID, TX_OBS_SELECT_SIGNALID}; + uint32_t timeoutMs = 0; + uint8_t cmdStatusByte = 0; + uint32_t gpioOe = 0; + uint32_t gpioUsedMask = 0; + mykonosGpioErr_t retval = MYKONOS_ERR_GPIO_OK; + + const uint8_t GPIO_CTRL_OBJECTID = 0x60; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setArmGpioPins()\n"); +#endif + + if (device->auxIo->armGpio == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_INV_POINTER, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_INV_POINTER)); + return MYKONOS_ERR_SET_ARMGPIO_INV_POINTER; + } + + /* Write ARM set command to setup which ARM signals are using which GPIO pins */ + /* Setup input pins for ORX_MODE[2:0] and ORX_MODE_Trigger if orx is in pin mode */ + for(i = 0; i < sizeof(signalId); i++) + { + gpioConfig[0] = GPIO_CTRL_OBJECTID; + gpioConfig[1] = signalId[i]; + + switch(signalId[i]) + { + case ORX_TRIGGER_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orxTriggerPin; break; + case ORX_MODE_0_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orxMode0Pin; break; + case ORX_MODE_1_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orxMode1Pin; break; + case ORX_MODE_2_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orxMode2Pin; break; + case RX1_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->rx1EnableAck; break; + case RX2_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->rx2EnableAck; break; + case TX1_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->tx1EnableAck; break; + case TX2_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->tx2EnableAck; break; + case ORX1_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orx1EnableAck; break; + case ORX2_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->orx2EnableAck; break; + case SRX_ENABLE_ACK_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->srxEnableAck; break; + case TX_OBS_SELECT_SIGNALID: gpioConfig[2] = device->auxIo->armGpio->txObsSelect; break; + default: + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID)); + return MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID; + } + } + + if (gpioConfig[2] > 0x1F) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN)); + return MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN; + } + + /* if output signal */ + if ((signalId[i] >= RX1_ENABLE_ACK_SIGNALID) && (gpioConfig[2] != 0)) + { + gpioOe |= (uint32_t)(((gpioConfig[2] >> 4) & 0x01) << (gpioConfig[2] & 0x0F)); /* 1 = output */ + gpioUsedMask |= (uint32_t)(1 << (gpioConfig[2] & 0x0F)); + } + + /* if input signal and orx Pin mode enabled - currently only input pins are orx pin mode control */ + if ((signalId[i] < RX1_ENABLE_ACK_SIGNALID) && (device->auxIo->armGpio->orxPinMode > 0)) + { + gpioUsedMask |= (1 << (gpioConfig[2] & 0x1F)); + } + + retval = (mykonosGpioErr_t)MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &gpioConfig[0], sizeof(gpioConfig)); + if (retval != MYKONOS_ERR_GPIO_OK) + { + return retval; + } + + timeoutMs = 1000; + + if (( retval = (mykonosGpioErr_t)MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte)) != MYKONOS_ERR_GPIO_OK) + { + return retval; + } + + if (cmdStatusByte > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR)); + return MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR; + } + } + + /* Mykonos SPI regs to set GPIO OE direction only for pins used by ARM */ + if ((retval = MYKONOS_setGpioOe(device, gpioOe, gpioUsedMask)) != MYKONOS_ERR_GPIO_OK) + { + return retval; + } + + /* if any output pins enabled, write GPIO nibble source control. ARM outputs only allowed on GPIO[15:0]*/ + if (gpioOe & 0x000F) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_LOWER_BYTE, 0x09, 0x0F, 0); + } + + if (gpioOe & 0x00F0) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_LOWER_BYTE, 0x09, 0xF0, 4); + } + + if (gpioOe & 0x0F00) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_UPPER_BYTE, 0x09, 0x0F, 0); + } + + if (gpioOe & 0xF000) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_UPPER_BYTE, 0x09, 0xF0, 4); + } + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets up the auxiliary ADC + * + * This function configures the AuxADC with the requested decimation. The AuxADC clock is set as close + * as possible to 40MHz. The AuxADC conversion time = (1/40Mhz) * decimation, where the decimation ranges + * from 256 AuxADC clock cycles to 32768 AuxADc clock cycles. + * + * Note: The AuxADC is intended for relative measurements. Two back to back measurements can allow a delta + * measurement with 12bit resolution. If absolute measurements are required, an accurate + * reference should be first measured on AuxADC0 input and used to calibrate the offset/gain error of the AuxADC. + * The reference would need to be measured before each measurement to account for measurement variations caused + * by the transmitter/receiver transients as other circuits in the device are being powered up/down. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device Pointer to the device settings structure + * \param adcDecimation ADC decimation factor (0-7). Decimates by 256 * 2^(adcDecimation) ADC clock cycles. + * \param enable Stop/run ADC (0/1) + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SETUPAUXADC_INV_VCODIV CLKPLL VCO divider is invalid - Check CLKPLL setup + * \retval MYKONOS_ERR_INV_AUX_ADC_DEC_PARM AuxADC decimation out of range (valid 0-7) + */ +mykonosGpioErr_t MYKONOS_setupAuxAdcs(mykonosDevice_t *device, uint8_t adcDecimation, uint8_t enable) +{ + uint32_t hsDigClk_kHz = 0; + uint32_t auxAdcDiv = 0; + uint32_t auxAdcClk_kHz = 40000; + uint32_t vcoDiv = (uint32_t)device->clocks->clkPllVcoDiv; + uint8_t vcoDivTimes10 = 10; + + const uint8_t AUXADC_POWER_BIT_MASK = 0x80; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setupAuxAdcs()\n"); +#endif + + if (enable == 0) + { + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_0, 0xCF); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_CFG, 0x01); + + return MYKONOS_ERR_GPIO_OK; + } + else + { + switch(vcoDiv) + { + case VCODIV_1: + vcoDivTimes10 = 10; + break; + case VCODIV_1p5: + vcoDivTimes10 = 15; + break; + case VCODIV_2: + vcoDivTimes10 = 20; + break; + case VCODIV_3: + vcoDivTimes10 = 30; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPAUXADC_INV_VCODIV, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPAUXADC_INV_VCODIV)); + return MYKONOS_ERR_SETUPAUXADC_INV_VCODIV; + } + + hsDigClk_kHz = (device->clocks->clkPllVcoFreq_kHz / vcoDivTimes10 / device->clocks->clkPllHsDiv) * 10; + auxAdcDiv = ((hsDigClk_kHz / 2) / (auxAdcClk_kHz)) - 1; + + if (auxAdcDiv > 63) + { + auxAdcDiv = 63; + } + + if (adcDecimation > 0x07) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AUX_ADC_DEC_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_INV_AUX_ADC_DEC_PARM)); + return MYKONOS_ERR_INV_AUX_ADC_DEC_PARM; + } + + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADR_AUX_ADC_CLOCK_DIVIDE, (uint8_t)(auxAdcDiv)); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADDR_AUX_ADC_CFG, (uint8_t)((adcDecimation << 1))); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADDR_AUX_ADC_SEL, 0x00); /* Set AuxADC select to AuxADC0 */ + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_0, 0, AUXADC_POWER_BIT_MASK, 7); + + /* Set Clock enable bit to latch divider */ + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADR_AUX_ADC_CLOCK_DIVIDE, (uint8_t)(auxAdcDiv | 0x80)); + } + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets the selected channel of the auxiliary ADC + * + * After setting the AuxADC channel, wait at least 1 AuxADC conversion time before + * reading back the AuxADC value. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param auxAdcChannel desired Aux ADC input(0-4 and 16 = temperature sensor) + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM Invalid AuxADC channel (valid 0-4 and 16) + */ +mykonosGpioErr_t MYKONOS_setAuxAdcChannel(mykonosDevice_t *device, mykonosAuxAdcChannels_t auxAdcChannel) +{ + uint8_t currentAuxAdcChan = 0x00; + + const uint8_t CHANNEL_MASK = 0x17; + const uint8_t POWER_UP_AUXADC = 0x00; + const uint8_t POWER_DOWN_AUXADC = 0x01; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setAuxAdcChannel()\n"); +#endif + + if (((uint8_t)auxAdcChannel & ~CHANNEL_MASK) > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM)); + return MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM; + } + + /* Read current selected channel, if different power down AUXADC and change AUXADC */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_SEL, ¤tAuxAdcChan); + if (currentAuxAdcChan != (uint8_t)auxAdcChannel) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AUX_ADC_CFG, POWER_DOWN_AUXADC, 0x01, 0); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_SEL, ((auxAdcChannel & MYK_AUXADC_0_DIV2) ? 0: auxAdcChannel)); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AUX_ADC_CFG, POWER_UP_AUXADC, 0x01, 0); + } + + /* Invalid AuxADC channel, the only valid channel for external ref is channel 0 */ + if (auxAdcChannel == MYK_AUXADC_0_DIV2) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_1, 0x01, 0x04, 2); + } + else if (auxAdcChannel == MYK_AUXADC_0) + { + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_1, 0x00, 0x04, 2); + } + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads from the selected channel of the auxiliary ADC + * + * Before using this function to read back the AuxADC value of the + * currently selected AuxADC, make sure that at least 1 conversion time + * of the ADC has passed since setting the AuxADC channel. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param adcCode is a pointer for return of the 12bit ADC read value + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_READAUXADC_NULL_PARAM Function parameter adcCode is a NULL pointer + */ +mykonosGpioErr_t MYKONOS_readAuxAdc(mykonosDevice_t *device, uint16_t *adcCode) +{ + uint8_t adcNibble = 0; + + const uint8_t AUXADC_LOCK_BIT_MASK = 0x80; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_readAuxAdcs()\n"); +#endif + + if (adcCode == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READAUXADC_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_READAUXADC_NULL_PARAM)); + return MYKONOS_ERR_READAUXADC_NULL_PARAM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AUX_ADC_CFG, 1, AUXADC_LOCK_BIT_MASK, 7); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_READ_MSB, &adcNibble); + *adcCode = adcNibble << 4; + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AUX_ADC_READ_LSB, &adcNibble); + *adcCode |= (adcNibble & 0x0F); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets up the 10 AuxDACs on the Mykonos device. + * + * This function uses the configuration in the Mykonos device data structure AuxIO substructure to + * setup which of the ten AuxDACs are enabled, their slope, Vref(mid point) and their initial DAC code. + * + * This function can be called any time after MYKONOS_initialize() to reconfigure, enable, disable the + * different AuxDAC outputs. The AuxDACs are used in manual control mode. After calling this setup + * function, it is possible to change a particular AuxDAC code by calling the writeAuxDac() function. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->auxDacEnable: 1= enabled, 0 = disabled + * - device->auxIo->auxDacSlope[i]: 0 = 1.404mv/code, 1= 0.702mV/code + * - device->auxIo->auxDacVref: 0 = 1v midpoint, 1 = 1.5v midpoint, 2 = 2v midpoint, 3 = 2.5v midpoint + * - device->auxIo->auxDacValue[i]: 10bit DAC code (0-1023) + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM device->auxIo structure has a NULL pointer + * \retval MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE auxDAC code is out of range (valid 0-1023) + */ +mykonosGpioErr_t MYKONOS_setupAuxDacs(mykonosDevice_t *device) +{ + uint8_t i = 0; /* for loop index */ + uint8_t auxDacConfig = 0 ; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setupAuxDacs()\n"); +#endif + + if (device->auxIo == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM)); + return MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_CONTROL_5_0, 0x3F); /* Enable Manual AuxDAC control for all AuxDACs[5:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_CONTROL_9_6, 0x0F); /* Enable Manual AuxDAC control for all AuxDACs[9:6] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_5_0, 0x3F); /* Power down all AuxDACs[5:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_9_6, 0x0F); /* Power down all AuxDACs[9:6] */ + + for (i = 0; i < 10; i++) + { + /* If auxDac enabled, setup AuxDAC configuration */ + if ((device->auxIo->auxDacEnable >> i) & 0x01) + { + if (device->auxIo->auxDacValue[i] > 1023) + { + device->auxIo->auxDacValue[i] = 1023; /* clip value to max */ + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE)); + error = MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE; /* Complete AuxDAC configuration before returning error code */ + } + + auxDacConfig = 0x00; /* initialize config variable */ + + if (device->auxIo->auxDacSlope[i] > 0) + { + auxDacConfig = 0x40; /* bit [6] sets the slope */ + } + + auxDacConfig |= ((device->auxIo->auxDacVref[i] & 0x03) << 4); + + /* Write AuxDAC config and DAC code */ + CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_AUXDAC_0_WORD_MSB + (i * 2)), (auxDacConfig | ((device->auxIo->auxDacValue[i] >> 8) & 0x0F))); + CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_AUXDAC_0_WORD_MSB + (i * 2 ) + 1), (device->auxIo->auxDacValue[i] & 0xFF)); + } + } + + /* Write enable bit to latch DAC codes into DACs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AUX_DAC_LATCH_CONTROL, 0x01); + + /* Power up selected AuxDacs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_5_0, (~device->auxIo->auxDacEnable & 0x3F)); /* Power up enabled AuxDACs[5:0] */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_9_6, (((uint16_t)(~device->auxIo->auxDacEnable) >> 6) & 0x0F)); /* Power up enabled AuxDACs[9:6] */ + + return error; +} + +/** + * \brief Writes the current AuxDAC code for a particular AuxDAC + * + * This function updates the 10bit code that controls the AuxDAC output voltage. + * The auxDacCode is updated for the specified auxDAC. Also the auxDacCode is written + * to the device data structure for future reference. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->auxDacValue[i] + * + * \param device is a pointer to the device settings structure + * \param auxDacIndex AuxDAC to set the DAC code for (0-9) + * \param auxDacCode DAC code to update the AuxDAC to. Sets the output voltage of the DAC (valid 0-1023) + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE AuxDac code invalid (valid 0-1023) + * \retval MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX AuxDAC index out of range (valid 0-9) + * \retval MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO device->auxIo has NULL pointer + */ +mykonosGpioErr_t MYKONOS_writeAuxDac(mykonosDevice_t *device, uint8_t auxDacIndex, uint16_t auxDacCode) +{ + uint16_t auxDacAddr = 0; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_writeAuxDac()\n"); +#endif + + if (auxDacCode > 1023) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE, + getGpioMykonosErrorMessage(MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE)); + return MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE; + } + + if (auxDacIndex > 9) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX, + getGpioMykonosErrorMessage(MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX)); + return MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX; + } + + if (device->auxIo == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO, + getGpioMykonosErrorMessage(MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO)); + return MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO; + } + + device->auxIo->auxDacValue[auxDacIndex] = auxDacCode; + + auxDacAddr = MYKONOS_ADDR_AUXDAC_0_WORD_MSB + (auxDacIndex * 2); + + /* Write AuxDAC config and DAC code */ + CMB_SPIWriteField(device->spiSettings, auxDacAddr, (auxDacCode >> 8), 0x0F, 0); + CMB_SPIWriteByte(device->spiSettings, (auxDacAddr + 1), (auxDacCode & 0xFF)); + + /* Write enable bit to latch DAC codes into DACs */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AUX_DAC_LATCH_CONTROL, 0x01); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Sets the Mykonos low voltage GPIO configuration registers + * + * Sets the low voltage GPIO pin direction for each low voltage GPIO pin and + * sets the source control mode (feature) for each group of 4 GPIO pins. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio - all members + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER device->auxIo->gpio pointer is NULL + * \retval MYKONOS_ERR_SET_GPIO_1V8_INV_MODE gpio structure members have invalid enum value for the GPIO source control mode. + */ +mykonosGpioErr_t MYKONOS_setupGpio(mykonosDevice_t *device) +{ + uint32_t srcWrite = 0x000000; + uint32_t oEnMask = 0x7FFFF; + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setupGpio()\n"); +#endif + + if (device->auxIo->gpio == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER)); + return MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER; + } + + /* write GPIO pin direction registers */ + if ((error = MYKONOS_setGpioOe(device, device->auxIo->gpio->gpioOe, oEnMask)) != MYKONOS_ERR_GPIO_OK) + { + return error; + } + + /* write GPIO source control mode */ + if (((uint8_t)device->auxIo->gpio->gpioSrcCtrl3_0 > 15) || ((uint8_t)device->auxIo->gpio->gpioSrcCtrl7_4 > 15) || + ((uint8_t)device->auxIo->gpio->gpioSrcCtrl11_8 > 15) || ((uint8_t)device->auxIo->gpio->gpioSrcCtrl15_12 > 15) || + ((uint8_t)device->auxIo->gpio->gpioSrcCtrl18_16 > 15)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_GPIO_1V8_INV_MODE, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_GPIO_1V8_INV_MODE)); + return MYKONOS_ERR_SET_GPIO_1V8_INV_MODE; + } + + srcWrite = (uint32_t)device->auxIo->gpio->gpioSrcCtrl3_0 + ((uint32_t)device->auxIo->gpio->gpioSrcCtrl7_4 << 4) + + ((uint32_t)device->auxIo->gpio->gpioSrcCtrl11_8 << 8) + ((uint32_t)device->auxIo->gpio->gpioSrcCtrl15_12 << 12) + + ((uint32_t)device->auxIo->gpio->gpioSrcCtrl18_16 << 16); + + error = MYKONOS_setGpioSourceCtrl(device, srcWrite); + + return error; +} + +/** + * \brief Sets the Mykonos low voltage GPIO output pins direction + * + * This function will set the GPIO direction given by the passed parameter, + * the direction can be either output or input. The gpioUsedMask parameter + * allows the function to only affect the GPIO pins of interest. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio->gpioOe + * + * \param device is a pointer to the device settings structure + * \param gpioOutEn (valid range 0 - 0x07FFFF), bit per GPIO pin, the direction is + * + * gpioOutEn[bit] | GPIO[bit] direction + * ----------------|------------------- + * 0 | input + * 1 | output + * + * \param gpioUsedMask Mask used to control which Oe bits are set/cleared. If + * mask bit =1, that bit will be modified by gpioOutEn bit + * + * \retval MYKONOS_ERR_GPIO_OE_INV_PARAM If the Output enable parameter is invalid + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioOe(mykonosDevice_t *device, uint32_t gpioOutEn, uint32_t gpioUsedMask) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + + const uint32_t GPIO_OE_MASK = 0x7FFFF; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioOe()\n"); +#endif + + /* Error checking for correct number of GPIOs available. */ + if (gpioOutEn > GPIO_OE_MASK ) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OE_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_OE_INV_PARAM)); + return MYKONOS_ERR_GPIO_OE_INV_PARAM; + } + + /* Mykonos SPI regs to set GPIO OE direction */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_7_0, (gpioOutEn & 0xFF), (gpioUsedMask & 0xFF), 0); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_15_8, ((gpioOutEn >> 8) & 0xFF), ((gpioUsedMask >> 8) & 0xFF), 0); + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_18_16, ((gpioOutEn >> 16) & 0xFF), ((gpioUsedMask >> 16) & 0xFF), 0); + + /* Updating gpioConfig->gpioSetup->gpioOe output enable */ + if ((error = MYKONOS_getGpioOe(device, &gpioOutEn)) != MYKONOS_ERR_GPIO_OK) + { + return error; + } + + device->auxIo->gpio->gpioOe = gpioOutEn; + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Gets the Mykonos low voltage GPIO output pins direction + * + * This function will get the GPIO direction currently set in the device, + * the direction can be either output or input. The return gpioOutEn function + * parameter returns a bit per GPIO pin. 1 = output from the Mykonos Device, + * 0 = input into the Mykonos device. + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param *gpioOutEn a pointer to the data to be returned with the output enable reading + * + * gpioOutEn[bit] | GPIO[bit] direction + * ----------------|------------------- + * 0 | input + * 1 | output + * + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETGPIO_OE_NULL_PARM gpioOutEn function parameter is NULL + */ +mykonosGpioErr_t MYKONOS_getGpioOe(mykonosDevice_t *device, uint32_t *gpioOutEn) +{ + uint8_t readBytes[3] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioOe()\n"); +#endif + + if (gpioOutEn == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIO_OE_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIO_OE_NULL_PARM)); + return MYKONOS_ERR_GETGPIO_OE_NULL_PARM; + } + + /* Reading GPIO output enable registers */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_15_8, &readBytes[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_DIR_CTL_18_16, &readBytes[2]); + + /* Updating gpioConfig->gpioSetup->gpioOe output enable */ + *gpioOutEn = ((uint32_t)(readBytes[2] & 0x07) << 16) | ((uint32_t)(readBytes[1]) << 8) | (uint32_t)(readBytes[0]); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + + +/** + * \brief Sets the Mykonos GPIO source control for different GPIO functionality + * + * This function will only affect the GPIO pins that have their OE direction set to output. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioSrcCtrl nibble based source control, this is a 32 bit containing + * 5 nibbles that will be set the source control. + * + * \retval MYKONOS_ERR_GPIO_SRC_PARAM_INV If the source control parameter is invalid + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioSourceCtrl(mykonosDevice_t *device, uint32_t gpioSrcCtrl) +{ + const uint32_t GPIO_SRC_MASK = 0xFFFFF; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioSourceCtrl()\n"); +#endif + + /* writing GPIO configuration registers */ + if (gpioSrcCtrl > GPIO_SRC_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_SRC_PARAM_INV, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_SRC_PARAM_INV)); + return MYKONOS_ERR_GPIO_SRC_PARAM_INV; + } + + /* writing GPIO configuration registers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_LOWER_BYTE, (gpioSrcCtrl & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_UPPER_BYTE, ((gpioSrcCtrl >> 8) & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_EXTRA_BITS, ((gpioSrcCtrl >> 16) & 0x0F)); + + /* Updating gpioConfig->gpioSetup source control */ + device->auxIo->gpio->gpioSrcCtrl3_0 = (mykonosGpioMode_t)(gpioSrcCtrl & 0x0F); + device->auxIo->gpio->gpioSrcCtrl7_4 = (mykonosGpioMode_t)((gpioSrcCtrl >> 4) & 0x0F); + device->auxIo->gpio->gpioSrcCtrl11_8 = (mykonosGpioMode_t)((gpioSrcCtrl >> 8) & 0x0F); + device->auxIo->gpio->gpioSrcCtrl15_12 = (mykonosGpioMode_t)((gpioSrcCtrl >> 12) & 0x0F); + device->auxIo->gpio->gpioSrcCtrl18_16 = (mykonosGpioMode_t)((gpioSrcCtrl >> 16) & 0x0F); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos GPIO source control for different GPIO functionality + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioSrcCtrl nibble based source control, this is a 32 bit containing + * 5 nibbles that will be set the source control. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getGpioSourceCtrl(mykonosDevice_t *device, uint32_t *gpioSrcCtrl) +{ + uint8_t readBytes[3] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioSourceCtrl()\n"); +#endif + + if (gpioSrcCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_GPIO_SOURCE_CONTROL_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GET_GPIO_SOURCE_CONTROL_NULL_PARM)); + return MYKONOS_ERR_GET_GPIO_SOURCE_CONTROL_NULL_PARM; + } + + /* Reading GPIO output enable registers */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_LOWER_BYTE, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_UPPER_BYTE, &readBytes[1]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_SOURCE_CONTROL_EXTRA_BITS, &readBytes[2]); + + /* Updating gpioConfig->gpioSetup->gpioOe output enable */ + *gpioSrcCtrl = ((uint32_t)(readBytes[2] & 0x0F) << 16) | ((uint32_t)(readBytes[1]) << 8) | (uint32_t)(readBytes[0]); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + + +/** + * \brief Sets the Mykonos 3.3 VDC GPIO configuration registers + * + * This function sets the GPIO 3.3v pin direction (1=output, 0=input) and + * sets the mode of each nibble of GPIO 3.3v pins. See the mykonosGpio3v3Mode_t + * enum for possible modes. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio3v3 - all members + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER device->auxIo->gpio3v3 pointer is NULL + * \retval MYKONOS_ERR_SET_GPIO_3V3_INV_MODE gpio3v3 members have invalid enum value for the GPIO3v3 source control mode. + */ +mykonosGpioErr_t MYKONOS_setupGpio3v3(mykonosDevice_t *device) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setupGpio3v3()\n"); +#endif + + if (device->auxIo->gpio3v3 == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER)); + return MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER; + } + else + { + /* write GPIO pin direction registers */ + if ((error = MYKONOS_setGpio3v3Oe(device, device->auxIo->gpio3v3->gpio3v3Oe)) != MYKONOS_ERR_GPIO_OK) + + /* write GPIO3v3 mode */ + if (((uint8_t)device->auxIo->gpio3v3->gpio3v3SrcCtrl3_0 > 15) || + ((uint8_t)device->auxIo->gpio3v3->gpio3v3SrcCtrl7_4 > 15) || + ((uint8_t)device->auxIo->gpio3v3->gpio3v3SrcCtrl11_8 > 15)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_GPIO_3V3_INV_MODE, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_GPIO_3V3_INV_MODE)); + return MYKONOS_ERR_SET_GPIO_3V3_INV_MODE; + } + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_LSB_SRC_CTL, ((device->auxIo->gpio3v3->gpio3v3SrcCtrl7_4 << 4) | device->auxIo->gpio3v3->gpio3v3SrcCtrl3_0)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_MSB_SRC_CTL, (device->auxIo->gpio3v3->gpio3v3SrcCtrl11_8 & 0x0F)); + + return error; + } +} + +/** + * \brief If the GPIO3v3 pins are setup for BITBANG mode, this function sets + * the output pin levels per pin + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio3v3 - all members + * + * \param device is a pointer to the device settings structure + * \param gpio3v3PinLevel Bit per pin to set the level of each GPIO3v3 output pin + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpio3v3PinLevel(mykonosDevice_t *device, uint16_t gpio3v3PinLevel) +{ + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpio3v3PinLevel()\n"); +#endif + + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_SRC_7_0, (gpio3v3PinLevel & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_SRC_15_8, ((gpio3v3PinLevel >> 8) & 0x0F)); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos 3.3 VDC GPIO pin output levels for BITBANG mode + * + * This function allows reading the value that the 3.3v GPIO output pins are + * set to drive out the pins. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpio3v3SetLevel is a unit16_t pointer which contains the level of each GPIO3V3 pin (bit per pin) + * + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM gpio3v3SetLevel pointer is NULL in function parameter + */ +mykonosGpioErr_t MYKONOS_getGpio3v3SetLevel(mykonosDevice_t *device, uint16_t *gpio3v3SetLevel) +{ + uint8_t readBytes[2] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpio3v3SetLevel()\n"); +#endif + + if (gpio3v3SetLevel == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM)); + return MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM; + } + + /* reading the registers into two-byte array */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_SRC_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_SRC_15_8, &readBytes[1]); + + /* performing concatenation and assigning value to gpio3v3SpiRead */ + *gpio3v3SetLevel = ((uint16_t)(readBytes[1] & 0x0F) << 8) | (uint16_t)(readBytes[0]); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos 3.3 VDC GPIO pin levels for BITBANG mode + * + * Note: this function is only capable of reading back pin levels for the + * 3.3v pins set to be inputs. Any pins set to be a GPIO output will read + * back as zero. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpio3v3PinLevel is a unit16_t pointer which contains the level of each GPIO3V3 pin + * that is defined as an input + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM gpio3v3PinLevel pointer is NULL in function parameter + */ +mykonosGpioErr_t MYKONOS_getGpio3v3PinLevel(mykonosDevice_t *device, uint16_t *gpio3v3PinLevel) +{ + uint8_t readBytes[2] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpio3v3PinLevel()\n"); +#endif + + if (gpio3v3PinLevel == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM)); + return MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM; + } + + /* reading the registers for input pin levels */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_READ_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_SPI_READ_15_8, &readBytes[1]); + + *gpio3v3PinLevel = ((uint16_t)(readBytes[1] & 0x0F) << 8) | (uint16_t)(readBytes[0]); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This function sets the Pin direction control for the Mykonos 3.3 VDC GPIO. + * + * The bits in gpio3v3OutEn are used to configure each corresponding pin as an input or an output. + * If the bit is set, the pin is configured as an output, and if it is clear the pin is configured as an input. + * For example, setting gpio3v3OutEn = 0x02 will configure GPIO_3p3_2 as an output and the rest pins as inputs. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - device->auxIo->gpio3v3 - all members + * + * \param device is a pointer to the device settings structure + * \param gpio3v3OutEn Bit per pin to set the level of each GPIO3v3 output pin + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpio3v3Oe(mykonosDevice_t *device, uint16_t gpio3v3OutEn) +{ + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpio3v3Oe()\n"); +#endif + + /* write GPIO pin direction registers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_DIR_CTL_7_0, (gpio3v3OutEn & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_DIR_CTL_15_8, ((gpio3v3OutEn >> 8) & 0x0F)); + + /* update device->auxIo->gpio3v3 structure */ + device->auxIo->gpio3v3->gpio3v3Oe = gpio3v3OutEn; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos 3.3 VDC GPIO pin direction + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpio3v3OutEn is a unit16_t pointer which will contain the output enable parameter, + * this will be a bit field, if a bit is set then the corresponding GPIO pin is an output, + * if the bit is not set then the corresponding pin is an input + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM gpio3v3OutEn pointer is NULL in function parameter + */ +mykonosGpioErr_t MYKONOS_getGpio3v3Oe(mykonosDevice_t *device, uint16_t *gpio3v3OutEn) +{ + uint8_t readBytes[2] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpio3v3Oe()\n"); +#endif + + /* checking for null parameter */ + if (gpio3v3OutEn == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM)); + return MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM; + } + + /* reading the registers for input pin levels */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_DIR_CTL_7_0, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_DIR_CTL_15_8, &readBytes[1]); + + *gpio3v3OutEn = ((uint16_t)(readBytes[1] & 0x0F) << 8) | (uint16_t)(readBytes[0]); + + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Sets the Mykonos GPIO 3.3 VDC source control for different GPIO fucntionality + * + * This function will only affect the GPIO pins that have their OE direction set to output. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpio3v3SrcCtrl nibble based source control, this is a 12 bit containing + * 3 nibbles that will be set the source control. + * + * \retval MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL gpio3v3 members have invalid value for the GPIO3v3 source control mode. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpio3v3SourceCtrl(mykonosDevice_t *device, uint16_t gpio3v3SrcCtrl) +{ + const uint16_t GPIO_SRC_MASK = 0x0FFF; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpio3v3SourceCtrl()\n"); +#endif + + /* writing GPIO configuration registers */ + if (gpio3v3SrcCtrl > GPIO_SRC_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL, + getGpioMykonosErrorMessage(MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL)); + return MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL; + } + + /* writing GPIO configuration registers */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_LSB_SRC_CTL, (gpio3v3SrcCtrl & 0xFF)); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_MSB_SRC_CTL, ((gpio3v3SrcCtrl >> 8) & 0xFF)); + + /* Updating gpioConfig->gpioSetup source control */ + device->auxIo->gpio3v3->gpio3v3SrcCtrl3_0 = (mykonosGpio3v3Mode_t)(gpio3v3SrcCtrl & 0x0F); + device->auxIo->gpio3v3->gpio3v3SrcCtrl7_4 = (mykonosGpio3v3Mode_t)(gpio3v3SrcCtrl & 0xF0); + device->auxIo->gpio3v3->gpio3v3SrcCtrl11_8 = (mykonosGpio3v3Mode_t)((gpio3v3SrcCtrl >> 8) & 0x0F); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads the Mykonos 3v3 GPIO source control for different GPIO functionality + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpio3v3SrcCtrl nibble based source control, this is a 12 bit containing + * 3 nibbles that will be set the source control. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getGpio3v3SourceCtrl(mykonosDevice_t *device, uint16_t *gpio3v3SrcCtrl) +{ + uint8_t readBytes[2] = {0}; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpio3v3SourceCtrl()\n"); +#endif + + /* checking for null parameter */ + if (gpio3v3SrcCtrl == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM)); + return MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM; + } + + /* Reading GPIO output enable registers */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_LSB_SRC_CTL, &readBytes[0]); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GPIO_3V3_MSB_SRC_CTL, &readBytes[1]); + + /* Updating gpioConfig->gpioSetup->gpioOe output enable */ + *gpio3v3SrcCtrl = ((uint16_t)(readBytes[1] & 0xFF) << 8) | ((uint16_t)(readBytes[0])); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Gain compensation enable and setup function. + * + * The gain compensation block is a function that compensates for the attenuation in the internal attenuator for the Rx channels. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gainComp which is a mykonosGainComp_t structure. + * \param enable this parameter enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT gain compensation structure gainComp is not initialised + * \retval MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET gain compensation structure gainComp->rx1Offset is invalid + * \retval MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET gain compensation structure gainComp->rx2Offset is invalid + * \retval MYKONOS_ERR_GAINCOMP_INV_STEP gain compensation structure gainComp->compStep is invalid + * \retval MYKONOS_ERR_GAINCOMP_INV_EN enable is not valid + */ +mykonosGpioErr_t MYKONOS_setRxGainCompensation (mykonosDevice_t *device, mykonosGainComp_t *gainComp, uint8_t enable) +{ + uint8_t regWr2 = 0x00; + uint8_t regWr3 = 0x00; + uint8_t regWr4 = 0x00; + + /* Max parameter values for error checking */ + const uint8_t RXOFFSET_RANGE = 0x1F; + const uint8_t STEP_RANGE = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRxGainCompensation()\n"); +#endif + + /* Check for gainComp initialised */ + if (gainComp == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT)); + return MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT; + } + + /* Check for enable */ + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_INV_EN, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_INV_EN)); + return MYKONOS_ERR_GAINCOMP_INV_EN; + } + else if (enable == 1) + { + /* Check for gain compensation Rx1 offset range */ + if (gainComp->rx1Offset > RXOFFSET_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET)); + return MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET; + } + + /* Check for gain compensation Rx2 offset range */ + if (gainComp->rx2Offset > RXOFFSET_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET)); + return MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET; + } + + /* Check for gain compensation step range */ + if (gainComp->compStep > STEP_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_INV_STEP, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_INV_STEP)); + return MYKONOS_ERR_GAINCOMP_INV_STEP; + } + + /* Enabling gain compensation block */ + regWr4 = 0x88 | gainComp->compStep; + regWr3 = gainComp->rx2Offset; + regWr2 = gainComp->rx1Offset; + } + + /* Write gain compensation setup to device */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_GAIN_COMP_OFFSET, regWr2); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_GAIN_COMP_OFFSET, regWr3); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_GAIN_COMP_CFG, regWr4); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Get gain compensation setup and enabled function. + * + * The gain compensation block is a function that compensates for the attenuation in the internal attenuator for the Rx channels. + * This function will get the current setup and the enable state of the block. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gainComp pointer to a mykonosGainComp_t structure, will held the current device gain compensation settings. + * \param enabled pointer this parameter will contain the enable state of the gain compensation block. + * enabled = 1 + * disabled = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GAINCOMP_NULL_STRUCT gain compensation structure gainComp is not initialised + * \retval MYKONOS_ERR_GAINCOMP_EN_NULL_PARM enable is null pointer for the passed parameter + */ +mykonosGpioErr_t MYKONOS_getRxGainCompensation (mykonosDevice_t *device, mykonosGainComp_t *gainComp, uint8_t *enabled) +{ + uint8_t regWr2 = 0x00; + uint8_t regWr3 = 0x00; + uint8_t regWr4 = 0x00; + + /* Mask parameter values populating mykonosGainComp_t structure */ + const uint8_t ENABLED_MASK = 0x80; + const uint8_t STEP_MASK = 0x07; + + /* Shift values for writing gain values */ + const uint8_t ENABLED_SHIFT = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRxGainCompensation()\n"); +#endif + + /* Check for gainComp for Null */ + if (gainComp == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_NULL_STRUCT)); + return MYKONOS_ERR_GAINCOMP_NULL_STRUCT; + } + + if (enabled == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GAINCOMP_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GAINCOMP_EN_NULL_PARM)); + return MYKONOS_ERR_GAINCOMP_EN_NULL_PARM; + } + + /* Read gain compensation setup from device */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX1_GAIN_COMP_OFFSET, ®Wr2); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX2_GAIN_COMP_OFFSET, ®Wr3); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX_GAIN_COMP_CFG, ®Wr4); + + + /* Parsing read data to passed by reference parameters */ + *enabled = (regWr4 & ENABLED_MASK) >> ENABLED_SHIFT; + gainComp->compStep = (regWr4 & STEP_MASK); + gainComp->rx2Offset = regWr3; + gainComp->rx1Offset = regWr2; + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Gain compensation enable and setup function for the observation channel. + * + * The gain compensation block is a function that compensates for the attenuation in the internal attenuator for the observation channels. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gainComp is a pointer to the mykonosObsRxGainComp_t structure. + * \param enable enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT gain compensation structure gainComp is not initialised + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET gain compensation structure gainComp->obsRxOffset is invalid + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP gain compensation structure gainComp->compStep is invalid + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN enable is not valid + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setObsRxGainCompensation (mykonosDevice_t *device, mykonosObsRxGainComp_t *gainComp, uint8_t enable) +{ + uint8_t regWr2 = 0x00; + uint8_t regWr3 = 0x00; + + /* Max parameter values for error checking */ + const uint8_t RXOFFSET_RANGE = 0x1F; + + /* Shift values for writing gain values */ + const uint8_t STEP_RANGE = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setObsRxGainCompensation()\n"); +#endif + + /* Check for gainComp initialised */ + if (gainComp == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT; + } + + /* Check for enable */ + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN; + } + else if (enable == 1) + { + /* Check for gain compensation offset range */ + if (gainComp->obsRxOffset > RXOFFSET_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET; + } + + /* Check for gain compensation step range */ + if (gainComp->compStep > STEP_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP; + } + + /* Enabling gain compensation block */ + regWr3 = 0x88 | gainComp->compStep; + regWr2 = ((gainComp->obsRxOffset & 0x1E) >> 1) | ((gainComp->obsRxOffset & 0x01) << 4); + } + + /* Write gain compensation setup to device */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_OFFSET, regWr2); + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_CFG, regWr3); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Get gain compensation setup and enabled function for the observation channel. + * + * The gain compensation block is a function that compensates for the attenuation in the internal attenuator for the observation + * channels. + * This function will get the current setup and the enable state of the block. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gainComp pointer to a mykonosObsRxGainComp_t structure, will held the current device gain compensation settings. + * \param enabled pointer this parameter will contain the enable state of the gain compensation block. + * enabled = 1 + * disabled = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT observation channel gain compensation structure gainComp is not initialised + * \retval MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM enabled is null pointer for the parameter passed + */ +mykonosGpioErr_t MYKONOS_getObsRxGainCompensation (mykonosDevice_t *device, mykonosObsRxGainComp_t *gainComp, uint8_t *enabled) +{ + uint8_t regRd2 = 0x00; + uint8_t regRd3 = 0x00; + + /* Masks values for populating mykonosObsRxGainComp_t structure */ + const uint8_t ENABLED_MASK = 0x80; + const uint8_t STEP_MASK = 0x07; + + /* Shift values for populating mykonosObsRxGainComp_t structure */ + const uint8_t ENABLED_SHIFT = 0x07; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getObsRxGainCompensation()\n"); +#endif + + /* Check for gainComp for Null */ + if (gainComp == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT; + } + + if (enabled == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM)); + return MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM; + } + + /* Read gain compensation setup from device */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_OFFSET, ®Rd2); + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_CFG, ®Rd3); + + + /* Parsing read data to passed by reference parameters */ + *enabled = (regRd3 & ENABLED_MASK) >> ENABLED_SHIFT; + gainComp->compStep = (regRd3 & STEP_MASK); + gainComp->obsRxOffset = ((regRd2 & 0x0F) << 1) | ((regRd2 & 0x10) >> 4); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Slicer control over GPIO inputs. + * + * The user can control the slicer position via 3 GPIO inputs per channel. + * There are various configurations for the GPIO pins, this configurations are enumerated in the mykonosRxSlicer_t. + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - Gain compensation block has to be enabled in order to user the slicer control + * + * \param device is a pointer to the device settings structure + * \param slicerStep configures the step size of the slicer when external pin contol mode is enabled. + * Slicer gain in this mode is determined by multiplying the step size by the input bit code from the BBP. + * Step sizes are as follows: + * sllicerStep | step + * -------------|------------ + * 0 | 1 + * 1 | 2 + * 2 | 3 + * 3 | 4 + * + * \param rx1Pins Rx1 slicer inputs can take values from one of the following combinations that are specified in mykonosRxSlicer_t enum: + * -GPIO_2, GPIO_1, and GPIO_0 + * -GPIO_7, GPIO_6, and GPIO_5 + * -GPIO_10, GPIO_9, and GPIO_8 + * \param rx2Pins Rx2 slicer inputs can take values from one of the following combinations that are specified in mykonosRxSlicer_t enum: + * -GPIO_7, GPIO_6, and GPIO_5 + * -GPIO_13, GPIO_12, and GPIO_11 + * \param enable this parameter enables the external pin control mode so the BBP can control the slicer setting. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SLICER_INV_RX1_SEL invalid RX1 GPIO pin selection for Slicer control + * \retval MYKONOS_ERR_SLICER_INV_RX2_SEL invalid RX2 GPIO pin selection for Slicer control + * \retval MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE slicer step is out of range + * \retval MYKONOS_ERR_SLICER_EN_INV invalid enable + */ +mykonosGpioErr_t MYKONOS_setRxSlicerCtrl(mykonosDevice_t *device, uint8_t slicerStep, mykonosRxSlicer_t rx1Pins, mykonosRxSlicer_t rx2Pins, uint8_t enable) +{ + uint8_t regWr = 0x00; + + const uint8_t STEP_MASK = 0x03; + const uint8_t STEP_SHIFT = 0x05; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRxSlicerCtrl()\n"); +#endif + + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_EN_INV, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_EN_INV)); + return MYKONOS_ERR_SLICER_EN_INV; + } + else if (enable == 1) + { + /* Enabling Slicer input control */ + regWr = 0x80; + + /* Check for Rx1 Slicer input control */ + switch (rx1Pins) + { + case GPIO_0_1_2: + regWr |= 0x00; + break; + case GPIO_5_6_7: + regWr |= 0x01; + break; + case GPIO_8_9_10: + regWr |= 0x02; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_INV_RX1_SEL, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_INV_RX1_SEL)); + return MYKONOS_ERR_SLICER_INV_RX1_SEL; + } + + /* Check for Rx2 Slicer input control */ + switch (rx2Pins) + { + case GPIO_11_12_13: + regWr |= 0x00; + break; + case GPIO_5_6_7: + regWr |= 0x04; + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_INV_RX2_SEL, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_INV_RX2_SEL)); + return MYKONOS_ERR_SLICER_INV_RX2_SEL; + } + + /* Check for Slicer input step size control */ + if (slicerStep > STEP_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE)); + return MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE; + } + else + { + regWr |= (uint8_t)(slicerStep << STEP_SHIFT); + } + } + + /* Write to device the slicer configuration */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_SLCR_PIN_CFG, regWr); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This function will get the programmed Slicer control for Rx1 and Rx2 channels. + * + * The user can control the slicer position via 3 GPIO inputs per channel. + * There are various configurations for the GPIO pins, this configurations are enumerated in the mykonosRxSlicer_t. + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param slicerStep will contain the configured step size + * \param rx1Pins will contain the configured GPIO combination for Rx1 + * \param rx2Pins will contain the configured GPIO combination for Rx2 + * \param enable will contain the programmed enable setting + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM rx1Pins is null pointer for the passed parameter + * \retval MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM rx1Pins is null pointer for the passed parameter + * \retval MYKONOS_ERR_SLICER_STEP_NULL_PARM slicerStep is null pointer for the passed parameter + * \retval MYKONOS_ERR_SLICER_EN_NULL_PARM enable is null pointer for the passed parameter + */ +mykonosGpioErr_t MYKONOS_getRxSlicerCtrl(mykonosDevice_t *device, uint8_t *slicerStep, mykonosRxSlicer_t *rx1Pins, mykonosRxSlicer_t *rx2Pins, uint8_t *enable) +{ + uint8_t regRd = 0x00; + + /* Mask parameter values populating parameters */ + const uint8_t EN_MASK = 0x80; + const uint8_t STEP_MASK = 0x60; + const uint8_t RX1_MASK = 0x03; + const uint8_t RX2_MASK = 0x0C; + + /* Shift values for populating passed parameters */ + const uint8_t EN_SHIFT = 0x07; + const uint8_t STEP_SHIFT = 0x05; + const uint8_t RX1_SHIFT = 0x00; + const uint8_t RX2_SHIFT = 0x02; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRxSlicerCtrl()\n"); +#endif + + /* Check for Rx1 Slicer input control null parameter */ + if (rx1Pins == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM)); + return MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM; + } + + /* Check for Rx2 Slicer input control null parameter */ + if (rx2Pins == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM)); + return MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM; + } + + /* Check for Slicer step control null parameter */ + if (slicerStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_STEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_STEP_NULL_PARM)); + return MYKONOS_ERR_SLICER_STEP_NULL_PARM; + } + + /* Check for Slicer step control null parameter */ + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_EN_NULL_PARM)); + return MYKONOS_ERR_SLICER_EN_NULL_PARM; + } + + /* Reading SLicer control register */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX_SLCR_PIN_CFG, ®Rd); + + /* Parsing values */ + *enable = (regRd & EN_MASK) >> EN_SHIFT; + *slicerStep = (regRd & STEP_MASK) >> STEP_SHIFT; + + /* Map to enum */ + switch ((regRd & RX2_MASK) >> RX2_SHIFT) + { + case 0: + *rx2Pins = GPIO_11_12_13; + break; + case 1: + *rx2Pins = GPIO_5_6_7; + break; + + default: + *rx2Pins = GPIO_11_12_13; + break; + } + + *rx1Pins = (mykonosRxSlicer_t)((regRd & RX1_MASK) >> RX1_SHIFT); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Slicer control over GPIO inputs for the observation channel. + * + * The user can control the slicer position via 3 GPIO inputs for the observation channel. + * There are various configurations for the GPIO pins, this configurations are enumerated in the mykonosObsRxSlicer_t. + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - Gain compensation block has to be enabled in order to user the slicer control + * + * \param device is a pointer to the device settings structure + * \param slicerStep configures the step size of the slicer when external pin contol mode is enabled. + * Slicer gain in this mode is determined by multiplying the step size by the input bit code from the BBP. + * Step sizes are as follows: + * sllicerStep | step + * -------------|------------ + * 0 | 1 + * 1 | 2 + * 2 | 3 + * 3 | 4 + * + * \param obsRxPins observation slicer inputs can take values from one of the following combinations that are specified in mykonosObsRxSlicer_t enum: + * -GPIO_18, GPIO_17 and GPIO_16 + * -GPIO_16, GPIO_15 and GPIO_14 + * \param enable enables the external pin control mode so the BBP can control the slicer setting. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_SLICER_INV_OBS_RX_SEL invalid observation channel GPIO pin selection for Slicer control + * \retval MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE slicer step is out of range + * \retval MYKONOS_ERR_SLICER_OBS_RX_EN_INV invalid enable + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setObsRxSlicerCtrl(mykonosDevice_t *device, uint8_t slicerStep, mykonosObsRxSlicer_t obsRxPins, uint8_t enable) +{ + uint8_t regWr = 0x00; + + const uint8_t STEP_MASK = 0x03; + const uint8_t STEP_SHIFT = 0x05; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setObsRxSlicerCtrl()\n"); +#endif + + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_OBS_RX_EN_INV, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_OBS_RX_EN_INV)); + return MYKONOS_ERR_SLICER_OBS_RX_EN_INV; + } + else if (enable == 1) + { + /* Enabling Slicer input control */ + regWr = 0x80; + + /* Check for Rx1 Slicer input control */ + switch (obsRxPins) + { + case GPIO_18_17_16: + regWr |= 0x00; + break; + case GPIO_16_15_14: + regWr |= 0x01; + break; + + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_INV_OBS_RX_SEL, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_INV_OBS_RX_SEL)); + return MYKONOS_ERR_SLICER_INV_OBS_RX_SEL; + } + + /* Check for Slicer input step size control */ + if (slicerStep & ~STEP_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE)); + return MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE; + } + else + { + regWr |= (uint8_t)((slicerStep << STEP_SHIFT)); + } + } + + /* Write to device the slicer configuration */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_SLCR_PIN_CFG, regWr); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This function will get the programmed Slicer control for observation channel. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param slicerStep will contain the configured step size + * \param obsRxPins will contain the configured GPIO combination + * \param enable will contain the programmed enable setting + * + * \retval MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM obsRxPins is null pointer for the passed parameter + * \retval MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM slicerStep is null pointer for the passed parameter + * \retval MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM, enable is null pointer for the passed parameter + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getObsRxSlicerCtrl(mykonosDevice_t *device, uint8_t *slicerStep, mykonosObsRxSlicer_t *obsRxPins, uint8_t *enable) +{ + uint8_t regRd = 0x00; + + /* Mask parameter values populating slicer parameters */ + const uint8_t EN_MASK = 0x80; + const uint8_t STEP_MASK = 0x60; + const uint8_t OBS_RX_MASK = 0x03; + + /* Shift values for writing slicer parameters */ + const uint8_t EN_SHIFT = 0x07; + const uint8_t STEP_SHIFT = 0x05; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getObsRxSlicerCtrl()\n"); +#endif + + /* Check for Rx1 Slicer input control null parameter */ + if (obsRxPins == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM)); + return MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM; + } + + /* Check for Slicer step control null parameter */ + if (slicerStep == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM)); + return MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM; + } + + /* Check for Slicer step control null parameter */ + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM)); + return MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM; + } + + /* Reading Slicer control register */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DPD_SNF_RX_SLCR_PIN_CFG, ®Rd); + + /* Parsing values */ + *enable = (regRd & EN_MASK) >> EN_SHIFT; + *slicerStep = (regRd & STEP_MASK) >> STEP_SHIFT; + + /* Map to enum */ + switch (regRd & OBS_RX_MASK) + { + case 0: + *obsRxPins = GPIO_18_17_16; + break; + case 1: + *obsRxPins = GPIO_16_15_14; + break; + + default: + *obsRxPins = (mykonosObsRxSlicer_t)0; + break; + } + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Floating point formatter enable and setup function. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range (total gain range on AD9371 is 42dB) + * which increases the bitwidth in the digital datapath. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - Gain compensation block has to be enabled in order to user floating point formatter + * + * \param device is a pointer to the device settings structure + * \param floatFrmt which is a mykonosFloatPntFrmt_t structure. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT floating point formatter structure floatFrmt not initialized + * \retval MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE floating point formatter structure floatFrmt.roundMode not valid parameter + * \retval MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT floating point formatter structure floatFrmt.dataFormat not valid parameter + * \retval MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN floating point formatter structure floatFrmt.encNan not valid parameter + * \retval MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS floating point formatter structure floatFrmt.expBits not valid parameter + * \retval MYKONOS_ERR_FLOATFRMT_INV_LEADING floating point formatter structure floatFrmt.leading not valid parameter + */ +mykonosGpioErr_t MYKONOS_setFloatPointFrmt (mykonosDevice_t *device, mykonosFloatPntFrmt_t *floatFrmt) +{ + uint8_t regWr1 = 0x00; + + /* Max parameter values for error checking */ + const uint8_t ROUND_RANGE = 0x04; + const uint8_t DATA_FRMT_RANGE = 0x01; + const uint8_t ENCODE_RANGE = 0x01; + const uint8_t EXPBITS_RANGE = 0x03; + const uint8_t LEADING_RANGE = 0x01; + + /* Shift values for writing mykonosFloatPntFrmt_t values */ + const uint8_t ROUND_SHIFT = 0x05; + const uint8_t DATA_FRMT_SHIFT = 0x04; + const uint8_t ENCODE_SHIFT = 0x03; + const uint8_t EXPBITS_SHIFT = 0x01; + const uint8_t LEADING_SHIFT = 0x00; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setFloatPointFrmt()\n"); +#endif + + /* Check for gainComp initialised */ + if (floatFrmt == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT)); + return MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT; + } + + /* Check for floating point round mode */ + if (floatFrmt->roundMode > ROUND_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE)); + return MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE; + } + + /* Check for floating point data format */ + if (floatFrmt->dataFormat > DATA_FRMT_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT)); + return MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT; + } + + /* Check for floating point encode NaN */ + if (floatFrmt->encNan > ENCODE_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN)); + return MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN; + } + + /* Check for floating point exponent bits range */ + if (floatFrmt->expBits > EXPBITS_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS)); + return MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS; + } + + /* Check for floating point hide leading ones */ + if (floatFrmt->leading > LEADING_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_LEADING, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_LEADING)); + return MYKONOS_ERR_FLOATFRMT_INV_LEADING; + } + + regWr1 = (uint8_t)((floatFrmt->roundMode << ROUND_SHIFT) | (floatFrmt->dataFormat << DATA_FRMT_SHIFT) | + (floatFrmt->encNan << ENCODE_SHIFT) | (floatFrmt->expBits << EXPBITS_SHIFT) | + (floatFrmt->leading << LEADING_SHIFT)); + + + /* Write gain compensation setup to device */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_CFG, regWr1); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Floating point formatter setup function. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range + * which increases the bit-width in the digital data-path. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - Gain compensation block has to be enabled in order to user floating point formatter + * + * \param device is a pointer to the device settings structure + * \param floatFrmt which is a mykonosFloatPntFrmt_t structure. + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_NULL_STRUCT floating point formatter structure floatFrmt not initialized + * + */ +mykonosGpioErr_t MYKONOS_getFloatPointFrmt (mykonosDevice_t *device, mykonosFloatPntFrmt_t *floatFrmt) +{ + uint8_t regRd1 = 0x00; + + /* Mask parameter values populating mykonosGainComp_t structure */ + const uint8_t ROUND_MASK = 0xE0; + const uint8_t DATA_FRMT_MASK = 0x10; + const uint8_t ENCODE_MASK = 0x08; + const uint8_t EXPBITS_MASK = 0x06; + const uint8_t LEADING_MASK = 0x01; + + /* Shift values for writing gain values */ + const uint8_t ROUND_SHIFT = 0x05; + const uint8_t DATA_FRMT_SHIFT = 0x04; + const uint8_t ENCODE_SHIFT = 0x03; + const uint8_t EXPBITS_SHIFT = 0x01; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getFloatPointFrmt()\n"); +#endif + + /* Check floatFrmt for Null */ + if (floatFrmt == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_STRUCT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_STRUCT)); + return MYKONOS_ERR_FLOATFRMT_NULL_STRUCT; + } + + /* Read gain compensation setup from device */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_CFG, ®Rd1); + + /* Parsing read data to passed by reference parameters */ + floatFrmt->roundMode = (regRd1 & ROUND_MASK) >> ROUND_SHIFT; + floatFrmt->dataFormat = (regRd1 & DATA_FRMT_MASK) >> DATA_FRMT_SHIFT; + floatFrmt->encNan = (regRd1 & ENCODE_MASK) >> ENCODE_SHIFT; + floatFrmt->expBits = (regRd1 & EXPBITS_MASK) >> EXPBITS_SHIFT; + floatFrmt->leading = regRd1 & LEADING_MASK; + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Floating point formatter enable/disable Rx1 and Rx2 function. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range + * which increases the bit-width in the digital data-path. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * - Gain compensation block has to be enabled in order to user floating point formatter + * + * \param device is a pointer to the device settings structure + * \param rx1Att this parameter sets the integer data attenuation for the Rx1 channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * \param rx2Att this parameter sets the integer data attenuation for the Rx2 channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * \param enable this parameter enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT not valid rx1 attenuation parameter passed in MYKONOS_setRxEnFloatPntFrmt() + * \retval MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT not valid rx2 attenuation parameter passed in MYKONOS_setRxEnFloatPntFrmt() + * \retval MYKONOS_ERR_FLOATFRMT_SET_INV_EN not valid enable parameter passed in MYKONOS_setRxEnFloatPntFrmt() + */ +mykonosGpioErr_t MYKONOS_setRxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t rx1Att, uint8_t rx2Att, uint8_t enable) +{ + uint8_t regWr = 0x00; + + const uint8_t RXATT_RANGE = 0x07; + const uint8_t RX1ATT_SHIFT = 0x01; + const uint8_t RX2ATT_SHIFT = 0x05; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setRxEnFloatPntFrmt()\n"); +#endif + + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_SET_INV_EN, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_SET_INV_EN)); + return MYKONOS_ERR_FLOATFRMT_SET_INV_EN; + } + else if (enable == 1) + { + /* Check for rx1Att range */ + if (rx1Att > RXATT_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT)); + return MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT; + } + + /* Check for rx2Att range */ + if (rx2Att > RXATT_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT)); + return MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT; + } + + /* Enabling floating point formatter for Rx1 and Rx2 */ + regWr = 0x11; + regWr |= (uint8_t)((rx1Att << RX1ATT_SHIFT) | (rx2Att << RX2ATT_SHIFT)); + } + + /* Writing floating point formatter enables for Rx1 and Rx2 */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_RX_CTRL, regWr); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Floating point formatter setup function. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range (total gain range on AD9371 is 42dB) + * which increases the bitwidth in the digital datapath. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param rx1Att this parameter sets the integer data attenuation for the Rx1 channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * \param rx2Att this parameter sets the integer data attenuation for the Rx2 channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * \param enable this parameter enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT null pointer passed for rx1 attenuation in MYKONOS_setRxEnFloatPntFrmt() + * \retval MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT null pointer passed for rx2 attenuation in MYKONOS_setRxEnFloatPntFrmt() + * \retval MYKONOS_ERR_FLOATFRMT_NULL_ENABLE null pointer passed for enable in MYKONOS_setRxEnFloatPntFrmt() + */ +mykonosGpioErr_t MYKONOS_getRxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t *rx1Att, uint8_t *rx2Att, uint8_t *enable) +{ + uint8_t regRd = 0x00; + + const uint8_t EN_MASK = 0x11; + const uint8_t RX1ATT_MASK = 0x0E; + const uint8_t RX1ATT_SHIFT = 0x01; + const uint8_t RX2ATT_MASK = 0xE0; + const uint8_t RX2ATT_SHIFT = 0x05; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getRxEnFloatPntFrmt()\n"); +#endif + + /* Check for rx1Att NULL parameter */ + if (rx1Att == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT)); + return MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT; + } + + /* Check for rx2Att NULL parameter */ + if (rx2Att == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT)); + return MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT; + } + + /* Check for enable NULL parameter */ + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_ENABLE, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_ENABLE)); + return MYKONOS_ERR_FLOATFRMT_NULL_ENABLE; + } + + /* Read Rx1 and Rx2 floating point enables */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_RX_CTRL, ®Rd); + + *rx1Att = (regRd & RX1ATT_MASK) >> RX1ATT_SHIFT; + *rx2Att = (regRd & RX2ATT_MASK) >> RX2ATT_SHIFT ; + *enable = (regRd & EN_MASK) ? 1 : 0; + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + + +/** + * \brief Floating point formatter enable function for ORx channel. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range + * which increases the bit-width in the digital data-path. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param orxAtt this parameter sets the integer data attenuation for the ORx channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * * \param enable this parameter enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_INV_ORXATT not valid Orx attenuation parameter passed in MYKONOS_setOrxEnFloatPntFrmt() + * \retval MYKONOS_ERR_FLOATFRMT_INV_ORXEN not valid enable parameter passed in MYKONOS_setOrxEnFloatPntFrmt() + */ +mykonosGpioErr_t MYKONOS_setOrxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t orxAtt, uint8_t enable) +{ + uint8_t regWr = 0x00; + + const uint8_t ORXATT_RANGE = 0x07; + const uint8_t ORXATT_SHIFT = 0x01; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setOrxEnFloatPntFrmt()\n"); +#endif + + /* Check for enable */ + if (enable > 1) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_ORXEN, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_ORXEN)); + return MYKONOS_ERR_FLOATFRMT_INV_ORXEN; + } + else if (enable == 1) + { + /* Check for rx1Att range */ + if (orxAtt > ORXATT_RANGE) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_INV_ORXATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_INV_ORXATT)); + return MYKONOS_ERR_FLOATFRMT_INV_ORXATT; + } + + /* Enabling floating point formatter for Rx1 and Rx2 */ + regWr = 0x01; + regWr |= (uint8_t)(orxAtt << ORXATT_SHIFT); + } + + /* Writing floating point formatter enable for ORX channel */ + CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_ORX_CTRL, regWr); + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Floating point formatter enable and setup function. + * + * The floating point formatter block is a function that works in conjunction with the gain + * compensating block, as the gain compensation requires increased dynamic range (total gain range on AD9371 is 42dB) + * which increases the bitwidth in the digital datapath. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param orxAtt this parameter sets the integer data attenuation for the ORx channel in 6dB steps + * to enable the entire data range to be represented in the selected floating point format. + * \param enable this parameter enables or disables the gain compensation block. + * enable = 1 + * disable = 0 + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_FLOATFRMT_NULL_ORXATT null pointer passed for orxAtt + * \retval MYKONOS_ERR_FLOATFRMT_NULL_ORXENABLE null pointer passed for enable + */ +mykonosGpioErr_t MYKONOS_getOrxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t *orxAtt, uint8_t *enable) +{ + uint8_t regRd = 0x00; + + const uint8_t EN_MASK = 0x01; + const uint8_t ORXATT_MASK = 0x0E; + const uint8_t ORXATT_SHIFT = 0x01; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getOrxEnFloatPntFrmt()\n"); +#endif + + /* Check for orxAtt NULL parameter */ + if (orxAtt == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_ORXATT, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_ORXATT)); + return MYKONOS_ERR_FLOATFRMT_NULL_ORXATT; + } + + /* Check for enable NULL parameter */ + if (enable == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FLOATFRMT_NULL_ORXENABLE, + getGpioMykonosErrorMessage(MYKONOS_ERR_FLOATFRMT_NULL_ORXENABLE)); + return MYKONOS_ERR_FLOATFRMT_NULL_ORXENABLE; + } + + /* Read Rx1 and Rx2 floating point enables */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FLOATING_POINT_ORX_CTRL, ®Rd); + + *orxAtt = (regRd & ORXATT_MASK) >> ORXATT_SHIFT; + *enable = (regRd & EN_MASK) ? 1 : 0; + + /* Return */ + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief Sets up the Temperature Sensor + * + * Before using this function to set up the temp sensor, + * make sure that you call the MYKONOS_setupAuxADC() function + * to ensure that the AuxADC clock is setup and running correctly at 40 MHz, + * and that the structure mykonosTempSensorConfig_t tempSensor is populated. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param tempSensor is a pointer to the mykonosTempSensorConfig_t which holds + * the configuration settings for the temperature sensor + * + * \retval MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM Function parameter tempSensor is a NULL pointer + * \retval MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION tempDecimation value out of range (0-7) + * \retval MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET offset value out of range (0-255) + * \retval MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW tempWindow out of range (0-15) + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setupTempSensor(mykonosDevice_t *device, mykonosTempSensorConfig_t *tempSensor) +{ + uint8_t offsetFromDevice = 0; + + const uint8_t OFFSET_API = 0x43; +/* const uint8_t TEMP_OFFSET_MASK = 0xFF;*/ + const uint8_t TEMP_WINDOW_MASK = 0xF0; + const uint8_t TEMP_WINDOW_CHECK = 0x0F; + const uint8_t TEMP_DEC_MASK = 0x07; + const uint8_t OFFSET_OVERRIDE_MASK = 0x10; + +#ifdef MYKONOS_VERBOSE + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setupTempSensor()\n"); +#endif + + /* Check for structure initialisation mykonosTempSensorConfig_t */ + if (tempSensor == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM)); + return MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM; + } + + /* Check Temperature sensor decimation range */ + if ((tempSensor->tempDecimation & ~TEMP_DEC_MASK) > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION)); + return MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION; + } + + /* Override fused offset */ + if (tempSensor->overrideFusedOffset > 0) + { + /* Check Temperature sensor offset range */ +/* if (tempSensor->offset & ~TEMP_OFFSET_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET)); + return MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET; + }*/ + + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONFIG, 1, OFFSET_OVERRIDE_MASK, 4); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_OFFSET, tempSensor->offset); + } + else + { + /* If manual override was not requested, read back device offset value. + * If factory fused it is non-zero; else API adds a typical offset value */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_OFFSET, &(offsetFromDevice)); + if (offsetFromDevice == 0) + { + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_OFFSET, OFFSET_API); + } + } + + /* Check Temperature sensor window range */ + if ((tempSensor->tempWindow & ~TEMP_WINDOW_CHECK) > 0) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW, + getGpioMykonosErrorMessage(MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW)); + return MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW; + } + else + { + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB, tempSensor->tempWindow, TEMP_WINDOW_MASK, 4); + } + + /* Single shot setup */ + CMB_SPIWriteByte (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_MSB, 0x00); + + /* Write decimation factor for the Temperature sensor */ + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONFIG, tempSensor->tempDecimation, TEMP_DEC_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads from the Temperature Sensor registers and populates device data structure + * + * After this function is executed, the tempSensor parameter holds updated values + * from the device registers. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param tempSensor is a pointer to the mykonosTempSensorConfig_t which holds + * the configuration settings for the tempSensor + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_GETTEMPSENSORCONFIG_NULL_PARAM Function parameter tempSensor is a NULL pointer + */ +mykonosGpioErr_t MYKONOS_getTempSensorConfig(mykonosDevice_t *device, mykonosTempSensorConfig_t *tempSensor) +{ + uint8_t tempConfig = 0; + + const uint8_t TEMP_WINDOW_MASK = 0xF0; + const uint8_t TEMP_FUSE_MASK = 0x10; + const uint8_t TEMP_DECIMATION_MASK = 0x07; + const uint8_t TEMP_FUSE_SHIFT = 0x04; + +#ifdef MYKONOS_VERBOSE + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getTempSensorConfig()\n"); +#endif + + /* Check tempSensor null parameter passed */ + if (tempSensor == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTEMPSENSORCFG_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETTEMPSENSORCFG_NULL_PARAM)); + return MYKONOS_ERR_GETTEMPSENSORCFG_NULL_PARAM; + } + + /* Read back factory offset, if fused; else manual offset value */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_OFFSET, &(tempSensor->offset)); + + /* Read back Decimation and override Offset Temperature sensor parameters */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONFIG, &tempConfig); + tempSensor->overrideFusedOffset = (tempConfig & TEMP_FUSE_MASK) >> TEMP_FUSE_SHIFT; + tempSensor->tempDecimation = (tempConfig & TEMP_DECIMATION_MASK); + + /* Read back tempWindow */ + CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB, &tempConfig, TEMP_WINDOW_MASK, 4); + tempSensor->tempWindow = tempConfig; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Initiates temperature measurement + * + * This function will initiate the Temperature sensor measurement. + * + * \pre + * MYKONOS_setupTempSensor() function to set the temperature sensor. + * MYKONOS_setAuxAdcChannel() function with the AuxADC setting for Temperature sensor channel MYK_TEMPSENSOR + * from the enum type mykonosAuxAdcChannels_t. + * + * \post + * Internal temperature sensor will perform measurement and updated register values, + * read back using MYKONOS_readTempSensor() function. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_startTempMeasurement(mykonosDevice_t *device) +{ + const uint8_t TEMP_LOCK_MASK = 0x80; + const uint8_t TEMP_LOCK_BIT = 0x01; + const uint8_t MEASUREMENT_MASK = 0x01; + +#ifdef MYKONOS_VERBOSE + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_startTempMeasurement()\n"); +#endif + + /* Write the lock bit to ensure that a valid measurement is achieved */ + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONFIG, TEMP_LOCK_BIT, TEMP_LOCK_MASK, 7); + + /* Initiate Temperature measurement */ + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB, 1, MEASUREMENT_MASK, 0); + CMB_SPIWriteField (device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB, 0, MEASUREMENT_MASK, 0); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief Reads temperature code and statuses from the Temperature Sensor registers + * + * This function reads the temperature sensor's statuses and temperature code. + * Allow at least one computation period to elapse. + * The temperature sensor computation period is as 6 times the AuxADC conversion time. + * AuxADC conversion time = (1/40Mhz) * (256 * 2^(tempDecimation)) + * + * Before using this function to read back the temperature, make sure that temperature sensor + * is setup using the MYKONOS_setupTempSensor() function. + * + * \pre Before using this function to read back the sensor value: + * MYKONOS_setupTempSensor() function is needed in order to set up the Temperature sensor. + * MYKONOS_setAuxAdcChannel() function has to be called in order to set the proper AuxADC + * channel. AuxADC channel MYK_TEMPSENSOR is used for the Temperature sensor. + * MYKONOS_startTempMeasurement() this function will start the Temperature sensor, this + * function is needed to be called for every reading that needs to be performed. + * + * \post "tempStatus" structure will contain the status information and the temperature + * code. + * If a valid measurement is achieved then tempStatus->tempValid will be set and + * tempStatus->tempCode will contain the actual reading. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param tempStatus is a pointer to the mykonosTempSensorStatus_t structure which will be updated + * with the temp sensor readings + * + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + * \retval MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM Function parameter tempSensor is a NULL pointer + * \retval MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED temperature sensor reading is not locked + */ +mykonosGpioErr_t MYKONOS_readTempSensor(mykonosDevice_t *device, mykonosTempSensorStatus_t *tempStatus) +{ + int16_t temperature = 0; + uint8_t statusWord = 0; + uint8_t rgRd = 0x00; + + const uint8_t CODE_TO_DEGREE_CELSIUS = 0x67; + const uint8_t TEMP_VALID_MASK = 0x02; + const uint8_t WINDOW_EXCEED_MASK = 0x08; + const uint8_t WINDOW_HI_LO_MASK = 0x04; + const uint8_t TEMP_LOCK = 0x80; + +#ifdef MYKONOS_VERBOSE + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_readTempSensor()\n"); +#endif + + if (tempStatus == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM)); + return MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM; + } + + /* Check for temperature sensor value lock */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONFIG, &rgRd); + if ((rgRd & TEMP_LOCK) == TEMP_LOCK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED, + getGpioMykonosErrorMessage(MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED)); + return MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED; + } + + /* Perform temperature status reading */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB, &statusWord); + tempStatus->windowExceeded = (statusWord & WINDOW_EXCEED_MASK) >> 3; + tempStatus->windowHiLo = (statusWord & WINDOW_HI_LO_MASK) >> 2; + tempStatus->tempValid = (0x01 & ~((statusWord & TEMP_VALID_MASK) >> 1)); + + /* Perform temperature reading */ + CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TEMP_SENSOR_READ, &rgRd); + temperature = rgRd - CODE_TO_DEGREE_CELSIUS; + tempStatus->tempCode = temperature; + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This function sets the drive strength for the required GPIOs. + * + * This function will set the required drive strength, the settings for GPIO drive strength are normal drive and double drive. + * + * GPIO pins that can be assigned independent drive strength are: + * -MYKGPIO0 to MYKGPIO7 and MYKGPIO18 + * + * The rest of GPIOs are paired as: + * -MYKGPIO17 and MYKGPIO16 + * -MYKGPIO8 and MYKGPIO15 + * -MYKGPIO14 and MYKGPIO13 + * -MYKGPIO10 and MYKGPIO9 + * -MYKGPIO12 and MYKGPIO11 + * + * This means that if it is required to double the drive strength for MYKGPIO17 then the drive strength will also be doubled for MYKGPIO16. + * + * If the particular bitfield for gpioDrv is set then the drive strength will be doubled. Note that multiple GPIOs can be set at a time. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioDrv GPIO drive strength setup, valid range is from 0x00000 to 0x7FFFF. + * + * \retval MYKONOS_ERR_GPIO_DRV_INV_PARAM GPIO out of range- valid GPIOs are in the range 0x00000 to 0x7FFFF. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioDrv(mykonosDevice_t *device, uint32_t gpioDrv) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + uint8_t reg0 = 0x00; + uint8_t reg1 = 0x00; + + const uint32_t GPIO_MASK = 0x7FFFF; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioDrv()\n"); +#endif + + /* Error checking for correct number of GPIOs. */ + if (gpioDrv > GPIO_MASK ) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_DRV_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_DRV_INV_PARAM)); + return MYKONOS_ERR_GPIO_DRV_INV_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_DRV_CTL_0, ®0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_DRV_CTL_1, ®1); + + reg1 = reg1 & 0xC0; + + if (gpioDrv & 0xFF) + { + reg0 = (uint8_t)(gpioDrv & 0xFF); + } + else + { + reg0 = 0x00; + } + + if (gpioDrv & (uint32_t)MYKGPIO18) + { + reg1 |= 0x01; + } + + if ((gpioDrv & (uint32_t)MYKGPIO17) || (gpioDrv & (uint32_t)MYKGPIO16)) + { + reg1 |= 0x02; + } + + if ((gpioDrv & (uint32_t)MYKGPIO15) || (gpioDrv & (uint32_t)MYKGPIO8)) + { + reg1 |= 0x04; + } + + if ((gpioDrv & (uint32_t)MYKGPIO14) || (gpioDrv & (uint32_t)MYKGPIO13)) + { + reg1 |= 0x08; + } + + if ((gpioDrv & (uint32_t)MYKGPIO10) || (gpioDrv & (uint32_t)MYKGPIO9)) + { + reg1 |= 0x10; + } + + if ((gpioDrv & (uint32_t)MYKGPIO12) || (gpioDrv & (uint32_t)MYKGPIO11)) + { + reg1 |= 0x20; + } + + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_DRV_CTL_0, reg0); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_DRV_CTL_1, reg1); + + return error; +} + + +/** + * \brief This function gets the GPIOs drive strength. + * + * This function will get the programmed drive strength for all the GPIOs + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure. + * \param gpioDrv will contain the current GPIOs drive strength setting. + * + * \retval MYKONOS_ERR_GETGPIODRV_NULL_PARAM null parameter passed to the function. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getGpioDrv(mykonosDevice_t *device, uint32_t *gpioDrv) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + uint8_t reg0 = 0x00; + uint8_t reg1 = 0x00; + uint32_t gpioDrvRd = 0x00; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioDrv()\n"); +#endif + + /* Error checking for correct number of GPIOs. */ + if (gpioDrv == NULL ) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETGPIODRV_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GETGPIODRV_NULL_PARAM)); + return MYKONOS_ERR_GETGPIODRV_NULL_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_DRV_CTL_0, ®0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_DRV_CTL_1, ®1); + + gpioDrvRd = (uint32_t)reg0 & 0xFF; + + if (reg1 & 0x01) + { + gpioDrvRd |= (uint32_t)MYKGPIO18; + } + + if (reg1 & 0x02) + { + gpioDrvRd |= (uint32_t)MYKGPIO17 | (uint32_t)MYKGPIO16; + } + + if (reg1 & 0x04) + { + gpioDrvRd |= (uint32_t)MYKGPIO8 | (uint32_t)MYKGPIO15; + } + + if (reg1 & 0x08) + { + gpioDrvRd |= (uint32_t)MYKGPIO14 | (uint32_t)MYKGPIO13; + } + + if (reg1 & 0x10) + { + gpioDrvRd |= (uint32_t)MYKGPIO10 | (uint32_t)MYKGPIO9; + } + + if (reg1 & 0x20) + { + gpioDrvRd |= (uint32_t)MYKGPIO12 | (uint32_t)MYKGPIO11; + } + + *gpioDrv = (mykonosGpioSelect_t)gpioDrvRd; + + return error; +} + +/** + * \brief This function sets the slew rate for the required GPIOs. + * + * This function will set the required slew rate, the settings for GPIO slew rate are given by the enumeration type mykonosGpioSlewRate_t. + * + * GPIO pins that can be assigned independent slew rate are: + * -MYKGPIO0 to MYKGPIO7 and MYKGPIO18 + * + * The rest of GPIOs are paired as: + * -MYKGPIO17 and MYKGPIO16 + * -MYKGPIO8 and MYKGPIO15 + * -MYKGPIO14 and MYKGPIO13 + * -MYKGPIO10 and MYKGPIO9 + * -MYKGPIO12 and MYKGPIO11 + * + * This means that if it is required to set the slew rate for MYKGPIO17 then the same slew rate will be applied for MYKGPIO16. + * + * If the particular bitfield for gpioSelect is set then slewRate will be set for that GPIO. Note that multiple GPIOs can be set at a time. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param gpioSelect GPIO for which the slew rate will be changed, valid range 0x00000 to 0x7FFFF. + * \param slewRate slew rate setting, valid slew rate settings are given by the enumeration type mykonosGpioSlewRate_t + * + * \retval MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM GPIO out of range- valid GPIOs are in the range 0x00000 to 0x7FFFF. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setGpioSlewRate(mykonosDevice_t *device, mykonosGpioSelect_t gpioSelect, mykonosGpioSlewRate_t slewRate) +{ + mykonosGpioErr_t error = MYKONOS_ERR_GPIO_OK; + uint8_t reg0 = 0x00; + uint8_t reg1 = 0x00; + uint8_t reg2 = 0x00; + uint8_t reg3 = 0x00; + + const uint32_t GPIO_MASK = 0x7FFFF; + const uint8_t SLEWRATE_MASK = 0x03; + const uint32_t SHIFT4NIBLE = 0x06; + const uint32_t SHIFT3NIBLE = 0x04; + const uint32_t SHIFT2NIBLE = 0x02; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setGpioSlewRate()\n"); +#endif + + /* Error checking for correct number of GPIOs. */ + if (((uint32_t)gpioSelect > GPIO_MASK) || ((uint8_t)slewRate > SLEWRATE_MASK)) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM)); + return MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_0, ®0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_1, ®1); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_2, ®2); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_3, ®3); + + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO18) + { + reg0 = (reg0 & ~(SLEWRATE_MASK << SHIFT4NIBLE)) | ((uint8_t)slewRate << SHIFT4NIBLE); + } + if (((uint32_t)gpioSelect & (uint32_t)MYKGPIO17) || ((uint32_t)gpioSelect & (uint32_t)MYKGPIO16)) + { + reg0 = (reg0 & ~(SLEWRATE_MASK << SHIFT3NIBLE)) | ((uint8_t)slewRate << SHIFT3NIBLE); + } + if (((uint32_t)gpioSelect & (uint32_t)MYKGPIO15) || ((uint32_t)gpioSelect & (uint32_t)MYKGPIO8)) + { + reg0 = (reg0 & ~(SLEWRATE_MASK << SHIFT2NIBLE)) | ((uint8_t)slewRate << SHIFT2NIBLE); + } + if (((uint32_t)gpioSelect & (uint32_t)MYKGPIO14) || ((uint32_t)gpioSelect & (uint32_t)MYKGPIO13)) + { + reg0 = (reg0 & ~(SLEWRATE_MASK)) | (uint8_t)slewRate; + } + if (((uint32_t)gpioSelect & (uint32_t)MYKGPIO11) || ((uint32_t)gpioSelect & (uint32_t)MYKGPIO12)) + { + reg1 = (reg1 & ~(SLEWRATE_MASK << SHIFT4NIBLE)) | ((uint8_t)slewRate << SHIFT4NIBLE); + } + if (((uint32_t)gpioSelect & (uint32_t)MYKGPIO9) || ((uint32_t)gpioSelect & (uint32_t)MYKGPIO10)) + { + reg1 = (reg1 & ~(SLEWRATE_MASK << SHIFT3NIBLE)) | ((uint8_t)slewRate << SHIFT3NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO7) + { + reg1 = (reg1 & ~(SLEWRATE_MASK << SHIFT2NIBLE)) | ((uint8_t)slewRate << SHIFT2NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO6) + { + reg1 = (reg1 & ~(SLEWRATE_MASK)) | (uint8_t)slewRate; + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO5) + { + reg2 = (reg2 & ~(SLEWRATE_MASK << SHIFT4NIBLE)) | ((uint8_t)slewRate << SHIFT4NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO4) + { + reg2 = (reg2 & ~(SLEWRATE_MASK << SHIFT3NIBLE)) | ((uint8_t)slewRate << SHIFT3NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO3) + { + reg2 = (reg2 & ~(SLEWRATE_MASK << SHIFT2NIBLE)) | ((uint8_t)slewRate << SHIFT2NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO2) + { + reg2 = (reg2 & ~(SLEWRATE_MASK)) | (uint8_t)slewRate; + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO1) + { + reg3 = (reg3 & ~(SLEWRATE_MASK << SHIFT2NIBLE)) | ((uint8_t)slewRate << SHIFT2NIBLE); + } + if ((uint32_t)gpioSelect & (uint32_t)MYKGPIO0) + { + reg3 = (reg3 & ~(SLEWRATE_MASK)) | (uint8_t)slewRate; + } + + /* Prepare registers */ + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_SLEW_CTL_0, reg0); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_SLEW_CTL_1, reg1); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_SLEW_CTL_2, reg2); + CMB_SPIWriteByte (device->spiSettings, MYKONOS_GPIO_SLEW_CTL_3, reg3); + + return error; +} + + +/** + * \brief This function gets the GPIO slew rate setting. + * + * This function will get the programmed slew rate for the GPIO given by slewRateGpio. + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure. + * \param gpioSelect GPIO selection for getting the slew rate setting. + * \param slewRate will contain the GPIO slew rate setting. + * + * \retval MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM null parameter passed to the function. + * \retval MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM GPIO out of range- valid GPIOs are in the range 0x00000 to 0x7FFFF. + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getGpioSlewRate(mykonosDevice_t *device, mykonosGpioSelect_t gpioSelect, mykonosGpioSlewRate_t *slewRate) +{ + uint8_t reg0 = 0x00; + uint8_t reg1 = 0x00; + uint8_t reg2 = 0x00; + uint8_t reg3 = 0x00; + mykonosGpioSlewRate_t slewSetting = MYK_SLEWRATE_NONE; + + const uint32_t SLEWRATE_MASK = 0x03; + const uint32_t SHIFT4NIBLE = 0x06; + const uint32_t SHIFT3NIBLE = 0x04; + const uint32_t SHIFT2NIBLE = 0x02; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getGpioSlewRate()\n"); +#endif + + /* Error checking for NULL parameter. */ + if (slewRate == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM)); + return MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_0, ®0); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_1, ®1); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_2, ®2); + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_3, ®3); + + switch (gpioSelect) + { + case MYKGPIO18: + slewSetting = (mykonosGpioSlewRate_t)((reg0 & (SLEWRATE_MASK << SHIFT4NIBLE)) >> SHIFT4NIBLE); + break; + case MYKGPIO17: + case MYKGPIO16: + slewSetting = (mykonosGpioSlewRate_t)((reg0 & (SLEWRATE_MASK << SHIFT3NIBLE)) >> SHIFT3NIBLE); + break; + case MYKGPIO15: + case MYKGPIO8: + slewSetting = (mykonosGpioSlewRate_t)((reg0 & (SLEWRATE_MASK << SHIFT2NIBLE)) >> SHIFT2NIBLE); + break; + case MYKGPIO14: + case MYKGPIO13: + slewSetting = (mykonosGpioSlewRate_t)(reg0 & (SLEWRATE_MASK)); + break; + case MYKGPIO11: + case MYKGPIO12: + slewSetting = (mykonosGpioSlewRate_t)((reg1 & (SLEWRATE_MASK << SHIFT4NIBLE)) >> SHIFT4NIBLE); + break; + case MYKGPIO9: + case MYKGPIO10: + slewSetting = (mykonosGpioSlewRate_t)((reg1 & (SLEWRATE_MASK << SHIFT3NIBLE)) >> SHIFT3NIBLE); + break; + case MYKGPIO7: + slewSetting = (mykonosGpioSlewRate_t)((reg1 & (SLEWRATE_MASK << SHIFT2NIBLE)) >> SHIFT2NIBLE); + break; + case MYKGPIO6: + slewSetting = (mykonosGpioSlewRate_t)(reg1 & (SLEWRATE_MASK)); + break; + case MYKGPIO5: + slewSetting = (mykonosGpioSlewRate_t)((reg2 & (SLEWRATE_MASK << SHIFT4NIBLE)) >> SHIFT4NIBLE); + break; + case MYKGPIO4: + slewSetting = (mykonosGpioSlewRate_t)((reg2 & (SLEWRATE_MASK << SHIFT3NIBLE)) >> SHIFT3NIBLE); + break; + case MYKGPIO3: + slewSetting = (mykonosGpioSlewRate_t)((reg2 & (SLEWRATE_MASK << SHIFT2NIBLE)) >> SHIFT2NIBLE); + break; + case MYKGPIO2: + slewSetting = (mykonosGpioSlewRate_t)(reg2 & (SLEWRATE_MASK)); + break; + case MYKGPIO1: + slewSetting = (mykonosGpioSlewRate_t)((reg3 & (SLEWRATE_MASK << SHIFT2NIBLE)) >> SHIFT2NIBLE); + break; + case MYKGPIO0: + slewSetting = (mykonosGpioSlewRate_t)(reg3 & (SLEWRATE_MASK)); + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM)); + return MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM; + } + + *slewRate = slewSetting; + + return MYKONOS_ERR_GPIO_OK; +} + + +/** + * \brief This function sets the CMOS output driver. + * + * This function sets the CMOS output driver to increase pad drive strength for the SPI_DIO and GP_INTERRUPT pads + * according to the following settings of the enumeration type mykonosCmosPadDrvStr_t + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param cmosDrv drive for the CMOS output driver + * + * \retval MYKONOS_ERR_CMOS_DRV_INV_PARAM invalid drive strength, valid settings are given by mykonosCmosPadDrvStr_t + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_setCmosDrv(mykonosDevice_t *device, mykonosCmosPadDrvStr_t cmosDrv) +{ + const uint8_t CMOS_DRV_MASK = 0x0F; + const uint8_t CMOS_DRV_SHIFT = 0x04; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_setCmosDrv()\n"); +#endif + + /* Error checking for correct drive */ + switch (cmosDrv) + { /* fall through since this is only checking */ + case MYK_CMOSPAD_DRV_1X: + case MYK_CMOSPAD_DRV_2X: + case MYK_CMOSPAD_DRV_3X: + case MYK_CMOSPAD_DRV_4X: + case MYK_CMOSPAD_DRV_5X: + break; + default: + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CMOS_DRV_INV_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_CMOS_DRV_INV_PARAM)); + return MYKONOS_ERR_CMOS_DRV_INV_PARAM; + } + + CMB_SPIWriteField(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_3, cmosDrv, (~CMOS_DRV_MASK), CMOS_DRV_SHIFT); + + return MYKONOS_ERR_GPIO_OK; +} + +/** + * \brief This function gets the programmed CMOS output driver + * + * + * Dependencies + * - device->spiSettings->chipSelectIndex + * + * \param device is a pointer to the device settings structure + * \param cmosDrv will be the programmed drive for the CMOS output driver + * + * \retval MYKONOS_ERR_CMOS_DRV_NULL_PARAM Null parameter passed to the function + * \retval MYKONOS_ERR_GPIO_OK Function completed successfully + */ +mykonosGpioErr_t MYKONOS_getCmosDrv(mykonosDevice_t *device, mykonosCmosPadDrvStr_t *cmosDrv) +{ + uint8_t regRd = 0x00; + + const uint8_t CMOS_DRV_MASK = 0xF0; + const uint8_t CMOS_DRV_SHIFT = 0x04; + +#if MYKONOS_VERBOSE == 1 + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_getCmosDrv()\n"); +#endif + + if (cmosDrv == NULL) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CMOS_DRV_NULL_PARAM, + getGpioMykonosErrorMessage(MYKONOS_ERR_CMOS_DRV_NULL_PARAM)); + return MYKONOS_ERR_CMOS_DRV_NULL_PARAM; + } + + CMB_SPIReadByte(device->spiSettings, MYKONOS_GPIO_SLEW_CTL_3, ®Rd); + + *cmosDrv = (mykonosCmosPadDrvStr_t)((regRd & CMOS_DRV_MASK) >> CMOS_DRV_SHIFT); + + return MYKONOS_ERR_GPIO_OK; +} + +/** +* \brief This API function configures and enables the secondary SPI port. +* +* This port allows control compatibility with BBPs that employ dual SPI ports. +* The GPIO mapping for the SPI2 is fixed: +* SPI signal | GPIO +* -------------|------------------- +* CSB_2 | GPIO 3 +* SCLK_2 | GPIO 2 +* SDO_2 | GPIO 1 +* SDO_2/SDI2 | GPIO 0 +* +* The secondary SPI port only has a small subset of registers that affect the +* attenuation of the TX channels. It uses a fifth GPIO pin in order to decide +* which TxAttenuation word is active. The Tx Attenuation words in the 2nd SPI +* port are different than the first SPI port. On the 2nd SPI port, each +* transmitter has two Tx Attenuation words (an active word and an inactive +* word). The BBIC should write to the inactive TxAttenuation word. Then the +* fifth GPIO pin should be asserted to make the inactive TxAttenuation word +* active. This allows the BBIC to tightly control in real time when the +* TxAttenuation updates. +* +* Dependencies +* - device->spiSettings +* - device->spiSettings->chipSelectIndex +* +* \param device is a pointer to the device settings structure +* \param enable This is parameter will enable the secondary SPI port: 1 = enable, 0 = disable +* \param updateTxAttenPinSelect This parameter set the GPIO pin to be toggle for using the inactive attenuation words for both channels +* tx update | GPIO +* ------------|------------------- +* 0x00 | GPIO 4 +* 0x01 | GPIO 8 +* 0x02 | GPIO 14 +* 0x03 | none selected +* +* \retval MYKONOS_ERR_SPI2_INV_GPIO if an invalid GPIO pin configuration is passed +* \retval MYKONOS_ERR_HAL_LAYER if HAL function error is passed +* \retval MYKONOS_ERR_OK Function completed successfully +*/ +mykonosGpioErr_t MYKONOS_spi2GpioSetup(mykonosDevice_t *device, uint8_t enable, uint8_t updateTxAttenPinSelect) +{ + uint8_t regWrite = 0; + uint8_t enableBit = 0; + + const uint32_t SPI2_PIN_MASK = 0x03; + +#ifdef MYKONOS_VERBOSE + CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GPIO_OK, "MYKONOS_spi2GpioSetup()\n"); +#endif + + /* Error checking for correctness of GPIO to control attenuation word. */ + if (updateTxAttenPinSelect & ~SPI2_PIN_MASK) + { + CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SPI2_INV_GPIO, + getGpioMykonosErrorMessage(MYKONOS_ERR_SPI2_INV_GPIO)); + return MYKONOS_ERR_SPI2_INV_GPIO; + } + + /* masking the enable bit and the required pin */ + enableBit = (enable > 0) ? 1 : 0; + regWrite = (uint8_t)((updateTxAttenPinSelect << 4) | (enableBit << 3)); + + /* Set the SPI2 enable and the GPIO pin associated. */ + CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_1, regWrite, 0x38, 0); + + return MYKONOS_ERR_GPIO_OK; +} + diff --git a/src/hardware/mykonos/mykonos_gpio.h b/src/hardware/mykonos/mykonos_gpio.h new file mode 100644 index 0000000..f69ec74 --- /dev/null +++ b/src/hardware/mykonos/mykonos_gpio.h @@ -0,0 +1,172 @@ +/*! + * \file mykonos_gpio.h + * \brief Contains macro definitions and function prototypes for mykonos_gpio.c + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef MYKONOSGPIO_H_ +#define MYKONOSGPIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "t_mykonos.h" +#include "t_mykonos_gpio.h" + +/* + ***************************************************************************** + * GPIO functions + ***************************************************************************** + */ + +/* GPIO CMOS and SPI setting Functions */ +mykonosGpioErr_t MYKONOS_setGpioDrv(mykonosDevice_t *device, uint32_t gpioDrv); +mykonosGpioErr_t MYKONOS_getGpioDrv(mykonosDevice_t *device, uint32_t *gpioDrv); + +mykonosGpioErr_t MYKONOS_setGpioSlewRate(mykonosDevice_t *device, mykonosGpioSelect_t gpioSelect, mykonosGpioSlewRate_t slewRate); +mykonosGpioErr_t MYKONOS_getGpioSlewRate(mykonosDevice_t *device, mykonosGpioSelect_t gpioSelect, mykonosGpioSlewRate_t *slewRate); + +mykonosGpioErr_t MYKONOS_setCmosDrv(mykonosDevice_t *device, mykonosCmosPadDrvStr_t spiDrv); +mykonosGpioErr_t MYKONOS_getCmosDrv(mykonosDevice_t *device, mykonosCmosPadDrvStr_t *spiDrv); + + +/* Monitor output Functions */ +mykonosGpioErr_t MYKONOS_setGpioMonitorOut(mykonosDevice_t *device, uint8_t monitorIndex, uint8_t monitorMask); +mykonosGpioErr_t MYKONOS_getGpioMonitorOut(mykonosDevice_t *device, uint8_t *monitorIndex, uint8_t *monitorMask); + +/* RX GPIO Functions */ +mykonosGpioErr_t MYKONOS_setRx1GainCtrlPin(mykonosDevice_t *device, uint8_t incStep, uint8_t decStep, mykonosGpioSelect_t rx1GainIncPin, mykonosGpioSelect_t rx1GainDecPin, uint8_t enable); +mykonosGpioErr_t MYKONOS_setRx2GainCtrlPin(mykonosDevice_t *device, uint8_t incStep, uint8_t decStep, mykonosGpioSelect_t rx2GainIncPin, mykonosGpioSelect_t rx2GainDecPin, uint8_t enable); +mykonosGpioErr_t MYKONOS_getRx1GainCtrlPin(mykonosDevice_t *device, uint8_t *incStep, uint8_t *decStep, mykonosGpioSelect_t *rx1GainIncPin, mykonosGpioSelect_t *rx1GainDecPin, uint8_t *enable); +mykonosGpioErr_t MYKONOS_getRx2GainCtrlPin(mykonosDevice_t *device, uint8_t *incStep, uint8_t *decStep, mykonosGpioSelect_t *rx2GainIncPin, mykonosGpioSelect_t *rx2GainDecPin, uint8_t *enable); + +mykonosGpioErr_t MYKONOS_setRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t rx1GainChangePin, mykonosGpioSelect_t rx2GainChangePin); +mykonosGpioErr_t MYKONOS_getRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t *rx1GainChangePin, mykonosGpioSelect_t *rx2GainChangePin); +mykonosGpioErr_t MYKONOS_setObsRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t obsRxGainChangePin); +mykonosGpioErr_t MYKONOS_getObsRxHybridGainChangePin(mykonosDevice_t *device, mykonosGpioSelect_t *obsRxGainChangePin); + +mykonosGpioErr_t MYKONOS_setRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t rx1AgcSyncPin, mykonosGpioSelect_t rx2AgcSyncPin); +mykonosGpioErr_t MYKONOS_getRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t *rx1AgcSyncPin, mykonosGpioSelect_t *rx2AgcSyncPin); +mykonosGpioErr_t MYKONOS_setObsRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t obsRxAgcSyncPin); +mykonosGpioErr_t MYKONOS_getObsRxAgcEnSyncPin(mykonosDevice_t *device, mykonosGpioSelect_t *obsRxAgcSyncPin); + +/* TX GPIO Functions */ +mykonosGpioErr_t MYKONOS_setTx1AttenCtrlPin(mykonosDevice_t *device, uint8_t stepSize, mykonosGpioSelect_t tx1AttenIncPin, mykonosGpioSelect_t tx1AttenDecPin, uint8_t enable, uint8_t useTx1ForTx2); +mykonosGpioErr_t MYKONOS_setTx2AttenCtrlPin(mykonosDevice_t *device, uint8_t stepSize, mykonosGpioSelect_t tx2AttenIncPin, mykonosGpioSelect_t tx2AttenDecPin, uint8_t enable); +mykonosGpioErr_t MYKONOS_getTx1AttenCtrlPin(mykonosDevice_t *device, uint8_t *stepSize, mykonosGpioSelect_t *tx1AttenIncPin, mykonosGpioSelect_t *tx1AttenDecPin, uint8_t *enable, uint8_t *useTx1ForTx2); +mykonosGpioErr_t MYKONOS_getTx2AttenCtrlPin(mykonosDevice_t *device, uint8_t *stepSize, mykonosGpioSelect_t *tx2AttenIncPin, mykonosGpioSelect_t *tx2AttenDecPin, uint8_t *enable, uint8_t *useTx1ForTx2); + +mykonosGpioErr_t MYKONOS_spi2GpioSetup(mykonosDevice_t *device, uint8_t enable, uint8_t updateTxAttenPinSelect); + +/* GPIO memory source Functions */ +mykonosGpioErr_t MYKONOS_setGpioPinLevel(mykonosDevice_t *device, uint32_t gpioPinLevel); +mykonosGpioErr_t MYKONOS_getGpioPinLevel(mykonosDevice_t *device, uint32_t *gpioPinLevel); +mykonosGpioErr_t MYKONOS_getGpioSetLevel(mykonosDevice_t *device, uint32_t *gpioPinSetLevel); + +/* Gain Compensation Functions */ +mykonosGpioErr_t MYKONOS_setRxGainCompensation (mykonosDevice_t *device, mykonosGainComp_t *gainComp, uint8_t enable); +mykonosGpioErr_t MYKONOS_getRxGainCompensation (mykonosDevice_t *device, mykonosGainComp_t *gainComp, uint8_t *enabled); + +mykonosGpioErr_t MYKONOS_setObsRxGainCompensation (mykonosDevice_t *device, mykonosObsRxGainComp_t *gainComp, uint8_t enable); +mykonosGpioErr_t MYKONOS_getObsRxGainCompensation (mykonosDevice_t *device, mykonosObsRxGainComp_t *gainComp, uint8_t *enabled); + +/* SLICER Functions */ +mykonosGpioErr_t MYKONOS_setRxSlicerCtrl(mykonosDevice_t *device, uint8_t slicerStep, mykonosRxSlicer_t rx1Pins, mykonosRxSlicer_t rx2Pins, uint8_t enable); +mykonosGpioErr_t MYKONOS_getRxSlicerCtrl(mykonosDevice_t *device, uint8_t *slicerStep, mykonosRxSlicer_t *rx1Pins, mykonosRxSlicer_t *rx2Pins, uint8_t *enable); + +mykonosGpioErr_t MYKONOS_setObsRxSlicerCtrl(mykonosDevice_t *device, uint8_t slicerStep, mykonosObsRxSlicer_t obsRxPins, uint8_t enable); +mykonosGpioErr_t MYKONOS_getObsRxSlicerCtrl(mykonosDevice_t *device, uint8_t *slicerStep, mykonosObsRxSlicer_t *obsRxPins, uint8_t *enable); + +/* Floating Point Formatter Functions */ +mykonosGpioErr_t MYKONOS_setFloatPointFrmt (mykonosDevice_t *device, mykonosFloatPntFrmt_t *floatFrmt); +mykonosGpioErr_t MYKONOS_getFloatPointFrmt (mykonosDevice_t *device, mykonosFloatPntFrmt_t *floatFrmt); + +mykonosGpioErr_t MYKONOS_setRxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t rx1Att, uint8_t rx2Att, uint8_t enable); +mykonosGpioErr_t MYKONOS_getRxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t *rx1Att, uint8_t *rx2Att, uint8_t *enable); + +mykonosGpioErr_t MYKONOS_setOrxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t orxAtt, uint8_t enable); +mykonosGpioErr_t MYKONOS_getOrxEnFloatPntFrmt (mykonosDevice_t *device, uint8_t *orxAtt, uint8_t *enable); + +/* + ***************************************************************************** + * General Purpose Interrupt functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_configGpInterrupt(mykonosDevice_t *device, uint16_t gpMask); +mykonosGpioErr_t MYKONOS_readGpInterruptStatus(mykonosDevice_t *device, uint16_t *status); + +/* + ***************************************************************************** + * ARM GPIO usage functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_setArmGpioPins(mykonosDevice_t *device); + +/* + ***************************************************************************** + * AuxADC/AuxDAC functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_setupAuxAdcs(mykonosDevice_t *device, uint8_t adcDecimation, uint8_t enable); +mykonosGpioErr_t MYKONOS_setAuxAdcChannel(mykonosDevice_t *device, mykonosAuxAdcChannels_t auxAdcChannel); +mykonosGpioErr_t MYKONOS_readAuxAdc(mykonosDevice_t *device, uint16_t *adcCode); +mykonosGpioErr_t MYKONOS_setupAuxDacs(mykonosDevice_t *device); +mykonosGpioErr_t MYKONOS_writeAuxDac(mykonosDevice_t *device, uint8_t auxDacIndex, uint16_t auxDacCode); + +/* + ***************************************************************************** + * GPIO3v3 functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_setupGpio3v3(mykonosDevice_t *device); + +mykonosGpioErr_t MYKONOS_setGpio3v3PinLevel(mykonosDevice_t *device, uint16_t gpio3v3PinLevel); +mykonosGpioErr_t MYKONOS_getGpio3v3SetLevel(mykonosDevice_t *device, uint16_t *gpio3v3SetLevel); + +mykonosGpioErr_t MYKONOS_getGpio3v3PinLevel(mykonosDevice_t *device, uint16_t *gpio3v3PinLevel); + +mykonosGpioErr_t MYKONOS_setGpio3v3Oe(mykonosDevice_t *device, uint16_t gpio3v3OutEn); +mykonosGpioErr_t MYKONOS_getGpio3v3Oe(mykonosDevice_t *device, uint16_t *gpio3v3OutEn); + +mykonosGpioErr_t MYKONOS_setGpio3v3SourceCtrl(mykonosDevice_t *device, uint16_t gpio3v3SrcCtrl); +mykonosGpioErr_t MYKONOS_getGpio3v3SourceCtrl(mykonosDevice_t *device, uint16_t *gpio3v3SrcCtrl); + +/* + ***************************************************************************** + * GPIO helper functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_setupGpio(mykonosDevice_t *device); +mykonosGpioErr_t MYKONOS_setGpioOe(mykonosDevice_t *device, uint32_t gpioOutEn, uint32_t gpioUsedMask); +mykonosGpioErr_t MYKONOS_getGpioOe(mykonosDevice_t *device, uint32_t *gpioOutEn); + +mykonosGpioErr_t MYKONOS_setGpioSourceCtrl(mykonosDevice_t *device, uint32_t gpioSrcCtrl); +mykonosGpioErr_t MYKONOS_getGpioSourceCtrl(mykonosDevice_t *device, uint32_t *gpioSrcCtrl); + +/* + ***************************************************************************** + * Temperature Sensor functions + ***************************************************************************** + */ +mykonosGpioErr_t MYKONOS_setupTempSensor(mykonosDevice_t *device, mykonosTempSensorConfig_t *tempSensor); +mykonosGpioErr_t MYKONOS_getTempSensorConfig(mykonosDevice_t *device, mykonosTempSensorConfig_t *tempSensor); + +mykonosGpioErr_t MYKONOS_startTempMeasurement(mykonosDevice_t *device); +mykonosGpioErr_t MYKONOS_readTempSensor(mykonosDevice_t *device, mykonosTempSensorStatus_t *tempStatus); + +const char* getGpioMykonosErrorMessage(mykonosGpioErr_t errorCode); + +#ifdef __cplusplus +} +#endif + +#endif /* MYKONOSGPIO_H_ */ diff --git a/src/hardware/mykonos/mykonos_macros.h b/src/hardware/mykonos/mykonos_macros.h new file mode 100644 index 0000000..354f561 --- /dev/null +++ b/src/hardware/mykonos/mykonos_macros.h @@ -0,0 +1,707 @@ +/** + * \file mykonos_macros.h + * \brief Contains address and miscellaneous macro definitions for Mykonos API + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef CLEMENTE_TDD_MACROS_H +#define CLEMENTE_TDD_MACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MYKONOS_ADDR_CONFIGURATION_CONTROL_0 0x000 +#define MYKONOS_ADDR_SPI_CONFIGURATION_CONTROL_1 0x001 +#define MYKONOS_ADDR_PRODUCT_ID 0x004 +#define MYKONOS_GPIO_DRV_CTL_0 0x020 +#define MYKONOS_GPIO_DRV_CTL_1 0x021 +#define MYKONOS_GPIO_SLEW_CTL_0 0x022 +#define MYKONOS_GPIO_SLEW_CTL_1 0x023 +#define MYKONOS_GPIO_SLEW_CTL_2 0x024 +#define MYKONOS_GPIO_SLEW_CTL_3 0x025 + +#define MYKONOS_ADDR_DIGITAL_IO_CONTROL 0x028 + +#define MYKONOS_ADDR_SYSREF_PAD_CONFIG 0x040 +#define MYKONOS_ADDR_TX1_SYNC_PAD_CONFIG 0x041 +#define MYKONOS_ADDR_TX2_SYNC_PAD_CONFIG 0x042 +#define MYKONOS_ADDR_RX1_SYNC_CONFIG 0x043 +#define MYKONOS_ADDR_RX2_SYNC_CONFIG 0x044 + +/* Mykonos Framer Registers */ +#define MYKONOS_ADDR_FRAMER_RESET 0x059 +#define MYKONOS_ADDR_FRAMER_CLK_EN 0x05A +#define MYKONOS_ADDR_FRAMER_ADDR 0x05B +#define MYKONOS_ADDR_FRAMER_DATA 0x05C +#define MYKONOS_ADDR_FRAMER_WRITE_EN 0x05D +#define MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN 0x05E +#define MYKONOS_ADDR_FRAMER_CONFIG_F 0x05F +#define MYKONOS_ADDR_FRAMER_LANE_CTL 0x060 +#define MYKONOS_ADDR_FRAMER_ADC_XBAR_SEL 0x061 +#define MYKONOS_ADDR_FRAMER_LANE_XBAR_SEL 0x062 +#define MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV 0x063 +#define MYKONOS_ADDR_FRAMER_SYNCN_FILT 0x064 +#define MYKONOS_ADDR_FRAMER_LMFC_F_OFFSET 0x065 +#define MYKONOS_ADDR_FRAMER_LMFC_K_OFFSET 0x066 +#define MYKONOS_ADDR_FRAMER_TEST_CNTR_CTL 0x067 +#define MYKONOS_ADDR_FRAMER_STATUS_STRB 0x068 +#define MYKONOS_ADDR_FRAMER_STATUS 0x069 +#define MYKONOS_ADDR_FRAMER_SYSREF_TO_LMFC_CNTR_STAT 0x06A +#define MYKONOS_ADDR_FRAMER_SYSREF_TO_LMFC_ERR_MARGIN 0x06B +#define MYKONOS_ADDR_FRAMER_LANE_FIFO_STRB 0x06C +#define MYKONOS_ADDR_FRAMER_LANE0_FIFO_RDWR_ADDR 0x06D +#define MYKONOS_ADDR_FRAMER_LANE1_FIFO_RDWR_ADDR 0x06E +#define MYKONOS_ADDR_FRAMER_LANE2_FIFO_RDWR_ADDR 0x06F +#define MYKONOS_ADDR_FRAMER_LANE3_FIFO_RDWR_ADDR 0x070 +#define MYKONOS_ADDR_FRAMER_PRBS10_CTL 0x071 +#define MYKONOS_ADDR_FRAMER_PRBS20_CTL 0x072 +#define MYKONOS_ADDR_FRAMER_PATTERN_GEN_EN 0x073 +#define MYKONOS_ADDR_FRAMER_PATTERN_GEN_7_TO_0 0x074 +#define MYKONOS_ADDR_FRAMER_PATTERN_GEN_15_TO_8 0x075 +#define MYKONOS_ADDR_FRAMER_PATTERN_GEN_19_TO_16 0x076 +#define MYKONOS_ADDR_FRAMER_CONFIG_JTX_GEN 0x077 +#define MYKONOS_ADDR_FRAMER_LANE_DATA_CTL 0x078 +#define MYKONOS_ADDR_FRAMER_DATA_SAMPLE_CTL 0x079 + +/* Mykonos Deframer Sub Address Map */ +#define MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_RECVD 0x00 +#define MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_CFG 0x50 + +/* Mykonos Deframer Registers */ +#define MYKONOS_ADDR_DEFRAMER_RESET 0x07A +#define MYKONOS_ADDR_DEFRAMER_CLK_EN 0x07B +#define MYKONOS_ADDR_DEFRAMER_ADDR 0x07C +#define MYKONOS_ADDR_DEFRAMER_DATA 0x07D +#define MYKONOS_ADDR_DEFRAMER_WR_EN 0x07E +#define MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN 0x07F +#define MYKONOS_ADDR_DEFRAMER_CONFIG_F 0x080 +#define MYKONOS_ADDR_DEFRAMER_LANE_FIFO_CTL 0x081 +#define MYKONOS_ADDR_DEFRAMER_DAC_XBAR_SEL 0x082 +#define MYKONOS_ADDR_DEFRAMER_LANE_XBAR_SEL 0x083 +#define MYKONOS_ADDR_DEFRAMER_LMFC_F_OFFSET 0x084 +#define MYKONOS_ADDR_DEFRAMER_LMFC_K_OFFSET 0x085 +#define MYKONOS_ADDR_DEFRAMER_CONFIG_SYNC_USER_DATA_CTL 0x086 +#define MYKONOS_ADDR_DEFRAMER_SYNC_REQ_RETIME 0x087 +#define MYKONOS_ADDR_DEFRAMER_TEST 0x088 +#define MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_STRT_DAC_XBAR_REV 0x089 +#define MYKONOS_ADDR_DEFRAMER_STAT_STRB 0x08A +#define MYKONOS_ADDR_DEFRAMER_STAT 0x08B +#define MYKONOS_ADDR_DEFRAMER_TEST_ERR_CNT_STAT 0x08C +#define MYKONOS_ADDR_DEFRAMER_DET_FIFO_RD_ADDR 0x08D +#define MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_ADDR 0x08E +#define MYKONOS_ADDR_DEFRAMER_QBLMFC_VS_EXTLMFC_CNTR_STAT 0x08F +#define MYKONOS_ADDR_DEFRAMER_DET_FIFO_STAT 0x090 +#define MYKONOS_ADDR_DEFRAMER_STRT_RD_DEL_STOP_WR 0x091 +#define MYKONOS_ADDR_DEFRAMER_FIFO_SAMPLE_SPI_ADDR_RD 0x092 +#define MYKONOS_ADDR_DEFRAMER_FIFO_BYTE_SPI_ADDR_RD 0x093 +#define MYKONOS_ADDR_DEFRAMER_FIFO_BYTE_SPI_DATA_RD 0x094 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE0_7_TO_0 0x095 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE0_15_TO_8 0x096 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE1_7_TO_0 0x097 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE1_15_TO_8 0x098 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE2_7_TO_0 0x099 +#define MYKONOS_ADDR_DEFRAMER_SAMPLE2_15_TO_8 0x09A +#define MYKONOS_ADDR_DEFRAMER_SAMPLE3_7_TO_0 0x09B +#define MYKONOS_ADDR_DEFRAMER_SAMPLE3_15_TO_8 0x09C +#define MYKONOS_ADDR_DEFRAMER_LANE_FIFO_STRB 0x09D +#define MYKONOS_ADDR_DEFRAMER_LANE0_FIFO_RDWR_ADDR 0x09E +#define MYKONOS_ADDR_DEFRAMER_LANE1_FIFO_RDWR_ADDR 0x09F +#define MYKONOS_ADDR_DEFRAMER_LANE2_FIFO_RDWR_ADDR 0x0A0 +#define MYKONOS_ADDR_DEFRAMER_LANE3_FIFO_RDWR_ADDR 0x0A1 +#define MYKONOS_ADDR_DEFRAMER_SYSREF_TO_LMFC_CNTR_STAT 0x0A2 +#define MYKONOS_ADDR_DEFRAMER_SYSREF_TO_LMFC_ERR_MARGIN 0x0A3 +#define MYKONOS_ADDR_DEFRAMER_PRBS10_CTL 0x0A4 +#define MYKONOS_ADDR_DEFRAMER_PRBS20_CTL 0x0A5 +#define MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE 0x0A6 +#define MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_7_TO_0 0x0A7 +#define MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_15_TO_8 0x0A8 +#define MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_23_TO_16 0x0A9 +#define MYKONOS_ADDR_DEFRAMER_LANE_DATA_CTL 0x0AA +#define MYKONOS_ADDR_DEFRAMER_STATUS_2 0x0AB +#define MYKONOS_ADDR_DEFRAMER_DET_FIFO_PHASE 0x0AC + +/* Mykonos Serializer Registers */ +#define MYKONOS_ADDR_SERIALIZER_CTL_0 0x0B0 +#define MYKONOS_ADDR_SERIALIZER_CTL_1 0x0B1 +#define MYKONOS_ADDR_SERIALIZER_CTL_2 0x0B2 +#define MYKONOS_ADDR_SERIALIZER_CTL_3 0x0B3 +#define MYKONOS_ADDR_SERIALIZER_HS_DIV_TXSER_CLK_EN 0x0B4 +#define MYKONOS_ADDR_SERIALIZER_SPECIAL 0x0B5 + +/* Mykonos Deserializer Registers */ +#define MYKONOS_ADDR_DESERIALIZER_PDET_CTL 0x0BC +#define MYKONOS_ADDR_DESERIALIZER_CTL_0 0x0BD +#define MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_0 0x0BE +#define MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_1 0x0BF +#define MYKONOS_ADDR_DESERIALIZER_EQ_CTL_0 0x0C1 +#define MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1 0x0C2 +#define MYKONOS_ADDR_DESERIALIZER_MISC_CTL 0x0C3 +#define MYKONOS_ADDR_DESERIALIZER_EQ_HP_EN 0x0C4 +#define MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1_TO_0 0x0C5 +#define MYKONOS_ADDR_DESERIALIZER_EQ_CTL_3_TO_2 0x0C6 +#define MYKONOS_ADDR_DESERIALIZER_HS_DIV_RXCDR_CLK_EN 0x0CD +#define MYKONOS_ADDR_DESERIALIZER_SPECIAL 0x0CE +#define MYKONOS_ADDR_DESERIALIZER_CDR_CAL_CTL 0x0D0 + +#define MYKONOS_ADDR_CONFIGURATION_CONTROL_1 0x100 +#define MYKONOS_ADDR_CONFIGURATION_CONTROL_2 0x101 +#define MYKONOS_ADDR_CONFIGURATION_CONTROL_4 0x102 +#define MYKONOS_ADDR_CONFIGURATION_CONTROL_5 0x103 +#define MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_1 0x104 +#define MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_2 0x105 +#define MYKONOS_ADDR_DPD_SNIFFER_GPIO_SELECT 0x106 +#define MYKONOS_ADDR_SNIFFER_CONFIGURATION_CONTROL 0x107 +#define MYKONOS_ADDR_DPD_CONFIGURATION_CONTROL 0x108 +#define MYKONOS_ADDR_LOOPBACK_CONFIGURATION_CONTROL 0x109 + +#define MYKONOS_ADDR_CLOCK_CONTROL_0 0x117 +#define MYKONOS_ADDR_CLOCK_CONTROL_1 0x118 +#define MYKONOS_ADDR_CLOCK_CONTROL_2 0x119 +#define MYKONOS_ADDR_CLOCK_CONTROL_3 0x11A +#define MYKONOS_ADDR_CLOCK_CONTROL_4 0x11B +#define MYKONOS_ADDR_CLOCK_CONTROL_5 0x11C + +#define MYKONOS_ADDR_MCS_CONTROL 0x120 +#define MYKONOS_ADDR_MCS_STATUS 0x121 + +/* CLK PLL Registers */ +#define MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0 0x141 +#define MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1 0x142 +#define MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0 0x143 +#define MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1 0x144 +#define MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2 0x145 +#define MYKONOS_ADDR_CLK_SYNTH_F_VCOTN_BYTE1 0x148 +#define MYKONOS_ADDR_CLK_SYNTH_BYTE1 0x149 +#define MYKONOS_ADDR_CLK_SYNTH_BYTE2 0x14A +#define MYKONOS_ADDR_CLK_SYNTH_BYTE3 0x14B +#define MYKONOS_ADDR_CLK_SYNTH_BYTE5 0x14D +#define MYKONOS_ADDR_CLK_SYNTH_BYTE6 0x14E +#define MYKONOS_ADDR_CLK_SYNTH_BYTE7 0x14F +#define MYKONOS_ADDR_CLK_SYNTH_LF_R3 0x150 +#define MYKONOS_ADDR_CLK_SYNTH_BYTE9 0x152 +#define MYKONOS_ADDR_CLK_SYNTH_CAL_STAT 0x154 +#define MYKONOS_ADDR_CLK_SYNTH_VCO_CAL_REF 0x155 +#define MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1 0x157 +#define MYKONOS_ADDR_CLK_SYNTH_CAL_CONTROL 0x159 +#define MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL1 0x15E +#define MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL2 0x15F + +/* DPD Registers */ +#define MYKONOS_ADDR_TX1_DPD_MODEL_INDIRECT_PTR 0x178 +#define MYKONOS_ADDR_TX2_DPD_MODEL_INDIRECT_PTR 0x17C +#define MYKONOS_ADDR_DPD_RMS_BUF_SIZE 0x180 +#define MYKONOS_ADDR_TX1_DPD_MODEL_WORKING_PTR 0x188 +#define MYKONOS_ADDR_TX2_DPD_MODEL_WORKING_PTR 0x18C + +/* Rx NCO Control registers */ +#define MYKONOS_ADDR_CALPLL_SDM_CONTROL 0x17F +#define MYKONOS_ADDR_RX_NCO_CONTROL 0x190 +#define MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_3 0x191 +#define MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_2 0x192 +#define MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_1 0x193 +#define MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_3 0x194 +#define MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_2 0x195 +#define MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_1 0x196 +#define MYKONOS_ADDR_RX_NCO_DPD_SNIFFER_FTW_BYTE_3 0x197 +#define MYKONOS_ADDR_RX_NCO_DPD_SNIFFER_FTW_BYTE_2 0x198 +#define MYKONOS_ADDR_RX_NCO_DPD_SNIFFER_FTW_BYTE_1 0x199 + +#define MYKONOS_ADDR_ENSM_CONFIG_7_0 0x1B0 +#define MYKONOS_ADDR_CALIBRATION_CONTROL 0x1B2 +#define MYKONOS_ADDR_ENSM_MANUAL_GAIN_LOCK_GPIO_SELECT 0x1B5 +#define MYKONOS_ADDR_REFERENCE_CLOCK_CYCLES 0x1C0 +#define MYKONOS_ADDR_TX_PD_OVERIDE_7_0 0x209 +#define MYKONOS_ADDR_RCAL_CONTROL 0x224 +#define MYKONOS_ADDR_REF_PAD_CONFIG1 0x230 +#define MYKONOS_ADDR_REF_PAD_CONFIG2 0x231 + +#define MYKONOS_ADDR_RXSYNTH_CP_CAL_STAT 0x254 +#define MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1 0x257 +#define MYKONOS_ADDR_TXSYNTH_CP_CAL_STAT 0x2C4 +#define MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1 0x2C7 +#define MYKONOS_ADDR_SNIFF_RXSYNTH_CP_CAL_STAT 0x354 +#define MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1 0x357 +#define MYKONOS_ADDR_SNIFF_RXLOGEN_BYTE1 0x380 + +#define MYKONOS_ADDR_RX_FILTER_CONFIGURATION 0x410 +#define MYKONOS_ADDR_RX_FILTER_GAIN 0x411 +#define MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN 0x412 + +/* Mykonos Temperature Gain Compensation Registers */ +#define MYKONOS_ADDR_RX1_TEMP_GAIN_COMP 0x420 +#define MYKONOS_ADDR_RX2_TEMP_GAIN_COMP 0x421 +#define MYKONOS_ADDR_OBS_TEMP_GAIN_COMP 0x422 + +/* Mykonos AGC General Registers */ +#define MYKONOS_ADDR_AGC_CFG_1 0x42E +#define MYKONOS_ADDR_AGC_CFG_2 0x42F +#define MYKONOS_ADDR_AGC_GAIN_CHANGE_GPIO_SEL 0x430 +#define MYKONOS_ADDR_AGC_RX1_MAX_GAIN_INDEX 0x431 +#define MYKONOS_ADDR_AGC_RX1_MIN_GAIN_INDEX 0x432 +#define MYKONOS_ADDR_AGC_MANUAL_GAIN_CFG 0x433 +#define MYKONOS_ADDR_AGC_MANUAL_GAIN_GPIO_SEL 0x434 +#define MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_1 0x435 +#define MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_2 0x436 +#define MYKONOS_ADDR_AGC_LOCK_LEVEL 0x437 +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_1 0x438 +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_2 0x439 +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_3 0x43A +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_4 0x43B +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_5 0x43C +#define MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_6 0x43D +#define MYKONOS_ADDR_AGC_RX1_GAIN_LOCK_DELAY 0x43E +#define MYKONOS_ADDR_AGC_RX2_GAIN_LOCK_DELAY 0x43F +#define MYKONOS_ADDR_AGC_RX1_ATTACK_DELAY 0x440 +#define MYKONOS_ADDR_AGC_RX2_ATTACK_DELAY 0x441 +#define MYKONOS_ADDR_AGC_ULB_THRSH 0x442 +#define MYKONOS_ADDR_AGC_LLB_THRSH 0x443 +#define MYKONOS_ADDR_AGC_RX_BLOCK_DET_DECAY 0x444 +#define MYKONOS_ADDR_AGC_RESET_PD_HIGH_CNT 0x445 +#define MYKONOS_ADDR_AGC_RX2_MAX_GAIN_INDEX 0x446 +#define MYKONOS_ADDR_AGC_RX2_MIN_GAIN_INDEX 0x447 +#define MYKONOS_ADDR_AGC_ORX_SNRX_CFG_1 0x448 +#define MYKONOS_ADDR_AGC_ORX_SNRX_CFG_2 0x449 +#define MYKONOS_ADDR_AGC_ORX_SNRX_MAX_GAIN_INDEX 0x44A +#define MYKONOS_ADDR_AGC_ORX_SNRX_MIN_GAIN_INDEX 0x44B +#define MYKONOS_ADDR_AGC_ORX_SNRX_MANUAL_GAIN_CFG 0x44C +#define MYKONOS_ADDR_AGC_ORX_SNRX_GPIO_SEL 0x44D +#define MYKONOS_ADDR_AGC_ORX_SNRX_LOCK_LEVEL 0x44E +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_1 0x44F +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_2 0x450 +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_3 0x451 +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_4 0x452 +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_5 0x453 +#define MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_6 0x454 +#define MYKONOS_ADDR_AGC_ORX_SNRX_GAIN_LOCK_DELAY 0x455 +#define MYKONOS_ADDR_AGC_ORX_SNRX_ATTACK_DELAY 0x456 +#define MYKONOS_ADDR_AGC_ORX_SNRX_ULB_THRSH 0x457 +#define MYKONOS_ADDR_AGC_ORX_SNRX_LLB_THRSH 0x458 +#define MYKONOS_ADDR_AGC_ORX_SNRX_BLOCK_DET_DECAY 0x459 +#define MYKONOS_ADDR_AGC_ORX_SNRX_RESET_PD_HIGH_CNT 0x45A +#define MYKONOS_ADDR_AGC_ORX1_MANUAL_GAIN_INDEX 0x45B +#define MYKONOS_ADDR_AGC_ORX2_MANUAL_GAIN_INDEX 0x45C +#define MYKONOS_ADDR_AGC_SNRX_MANUAL_GAIN_INDEX 0x45D +#define MYKONOS_ADDR_AGC_LOOPBACK1_MANUAL_GAIN_INDEX 0x45E +#define MYKONOS_ADDR_AGC_LOOPBACK2_MANUAL_GAIN_INDEX 0x45F +#define MYKONOS_ADDR_AGC_ORX_SNRX_ACTIVE 0x460 + +/* Mykonos Fast Attack AGC Registers */ +#define MYKONOS_ADDR_AGC_FAST_CFG_1 0x468 +#define MYKONOS_ADDR_AGC_FAST_CFG_2 0x469 +#define MYKONOS_ADDR_AGC_FAST_ENRGY_LOST_THRSH 0x46A +#define MYKONOS_ADDR_AGC_FAST_STRONG_SIG_THRSH 0x46B +#define MYKONOS_ADDR_AGC_FAST_SETTING_DELAY 0x46C +#define MYKONOS_ADDR_AGC_FAST_OPT_MAX_GAIN 0x46D +#define MYKONOS_ADDR_AGC_FAST_ENRGY_DET_CNT 0x46E +#define MYKONOS_ADDR_AGC_FAST_AGCLL_UPPER_LIMIT 0x46F +#define MYKONOS_ADDR_AGC_FAST_GAIN_LOCK_EXIT_CNT 0x470 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_CFG_1 0x471 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_CFG_2 0x472 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_ENRGY_LOST_THRSH 0x473 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_STRONG_SIG_THRSH 0x474 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_SET_DELAY 0x475 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_OPT_MAX_GAIN 0x476 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_ENRGY_DET_CNT 0x477 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_AGCLL_UPPER_LIMIT 0x478 +#define MYKONOS_ADDR_AGC_FAST_ORX_SNRX_GAIN_LOCK_EXIT_CNT 0x479 + +/* Mykonos Slow Loop - Hybrid AGC Registers */ +#define MYKONOS_ADDR_AGC_SLOW_LOCK_LEV_THRSH 0x480 +#define MYKONOS_ADDR_AGC_SLOW_ULB_CNT_THRSH 0x481 +#define MYKONOS_ADDR_AGC_SLOW_LLB_CNT_THRSH 0x482 +#define MYKONOS_ADDR_AGC_SLOW_HIGH_OVRG_CNT_THRSH 0x483 +#define MYKONOS_ADDR_AGC_SLOW_LOW_OVRG_CNT_THRSH 0x484 +#define MYKONOS_ADDR_AGC_SLOW_VERYLOW_OVRG_CNT_THRSH 0x485 +#define MYKONOS_ADDR_AGC_SLOW_DIG_SAT_CNT_THRSH 0x486 +#define MYKONOS_ADDR_AGC_SLOW_UPPER0_THRSH_GAIN_STEP 0x487 +#define MYKONOS_ADDR_AGC_SLOW_LOWER0_THRSH_GAIN_STEP 0x488 +#define MYKONOS_ADDR_AGC_SLOW_UPPER1_THRSH_GAIN_STEP 0x489 +#define MYKONOS_ADDR_AGC_SLOW_LOWER1_THRSH_GAIN_STEP 0x48A +#define MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_1 0x48B +#define MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_2 0x48C +#define MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_3 0x48D +#define MYKONOS_ADDR_AGC_SLOW_LOOP_CFG 0x48E +#define MYKONOS_ADDR_AGC_SLOW_POWER_THRSH 0x48F +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOCK_LEV_THRSH 0x490 + +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ULB_CNT_THRSH 0x491 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LLB_CNT_THRSH 0x492 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_HIGH_OVRG_CNT_THRSH 0x493 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_LOW_OVRG_CNT_THRSH 0x494 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_VERYLOW_OVRG_CNT_THRSH 0x495 + +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_DIG_SAT_CNT_THRSH 0x496 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER0_THRSH_GAIN_STEP 0x497 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER0_THRSH_GAIN_STEP 0x498 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER1_THRSH_GAIN_STEP 0x499 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER1_THRSH_GAIN_STEP 0x49A +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_1 0x49B +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_2 0x49C +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_3 0x49D +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG 0x49E +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_POWER_THRSH 0x49F +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UL_SIG_POW_MEAS_DEL_1 0x4A0 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UL_SIG_POW_MEAS_DEL_2 0x4A1 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UL_SIG_POW_MEAS_DUR_1 0x4A2 +#define MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UL_SIG_POW_MEAS_DUR_2 0x4A3 + +/* Mykonos Gain Control Read Registers */ +#define MYKONOS_ADDR_GAIN_CTL_CHANNEL_1 0x4B0 +#define MYKONOS_ADDR_GAIN_CTL_FAST_ATTK_STATE 0x4B1 +#define MYKONOS_ADDR_GAIN_CTL_SLOW_LOOP_STATE 0x4B2 +#define MYKONOS_ADDR_GAIN_CTL_CHANNEL_2 0x4B3 +#define MYKONOS_ADDR_GAIN_CTL_OVRG_SIGS_CHANNEL_1 0x4B4 +#define MYKONOS_ADDR_GAIN_CTL_OVRG_SIGS_CHANNEL_2 0x4B5 +#define MYKONOS_ADDR_GAIN_CTL_ORX_SNRX_GAIN 0x4B6 +#define MYKONOS_ADDR_GAIN_CTL_ORX_SNRX_LOOP_STATE 0x4B7 +#define MYKONOS_ADDR_GAIN_CTL_ORX_SNRX_OVRG_SIGS 0x4B8 + +/* Mykonos Rx Data Path Overrange Registers */ +#define MYKONOS_ADDR_RX_OVRG_DATAPATH_OVRFLW 0x4B9 +#define MYKONOS_ADDR_RX_OVRG_ORX_SNRX_DATAPATH_OVRFLW 0x4BA + +/* Mykonos RSSI Measurement Registers and Dec Power Measurement Registers*/ +#define MYKONOS_ADDR_RSSI_MEAS_DURATION_0_1 0x4C0 +#define MYKONOS_ADDR_RSSI_MEAS_DURATION_2_3 0x4C1 +#define MYKONOS_ADDR_RSSI_CFG 0x4C6 +#define MYKONOS_DEC_POWER_CONFIG_1 0x4C7 +#define MYKONOS_DEC_POWER_CONFIG_2 0x4C8 +#define MYKONOS_ADDR_DPD_SNF_RSSI_CFG 0x4CF +#define MYKONOS_ADDR_DPD_RSSI_CFG 0x4D6 +#define MYKONOS_SNIFFER_DEC_POWER_CONFIG_1 0x4D7 +#define MYKONOS_SNIFFER_DEC_POWER_CONFIG_2 0x4D8 +#define MYKONOS_CH1_DECIMATED_PWR 0x4DE +#define MYKONOS_CH2_DECIMATED_PWR 0x4DF +#define MYKONOS_SNIFFER_DECIMATED_PWR 0x4E6 + +#define MYKONOS_ADDR_DIGITAL_GAIN_CONFIG 0x4F0 +#define MYKONOS_ADDR_DPD_SNIFFER_DIGITAL_GAIN_CONFIG 0x4F1 +#define MYKONOS_ADDR_GAIN_TABLE_ADDR 0x500 +#define MYKONOS_ADDR_GAIN_TABLE_RX1_FE_GAIN 0x501 +#define MYKONOS_ADDR_GAIN_TABLE_RX1_EXT_CTL 0x502 +#define MYKONOS_ADDR_GAIN_TABLE_RX1_DIG_GAIN 0x503 +#define MYKONOS_ADDR_GAIN_TABLE_RX2_FE_GAIN 0x504 +#define MYKONOS_ADDR_GAIN_TABLE_RX2_EXT_CTL 0x505 +#define MYKONOS_ADDR_GAIN_TABLE_RX2_DIG_GAIN 0x506 +#define MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN 0x507 +#define MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB 0x508 +#define MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN 0x509 +#define MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION 0x516 +#define MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION 0x517 +#define MYKONOS_ADDR_RXFE1_LOCM 0x520 +#define MYKONOS_ADDR_RXFE2_LOCM 0x521 +#define MYKONOS_ADDR_RXLOOPBACK1_CNTRL_1 0x540 +#define MYKONOS_ADDR_RXLOOPBACK2_CNTRL_1 0x541 +#define MYKONOS_ADDR_RX_LOOPBACK1_CNTRL_4 0x546 +#define MYKONOS_ADDR_RX_LOOPBACK2_CNTRL_4 0x547 + +/* Mykonos Overload/Peak Detection Registers */ +#define MYKONOS_ADDR_OVRLD_ADC_OVRLD_CFG 0x580 +#define MYKONOS_ADDR_OVRLD_ADC_OVRLD_UPPER_THRSH 0x581 +#define MYKONOS_ADDR_OVRLD_ADC_OVRLD_LOWER_THRSH 0x582 + +#define MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_CFG 0x583 +#define MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_UPPER_THRSH 0x584 +#define MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_LOWER_THRSH 0x585 +#define MYKONOS_ADDR_OVRLD_PD_DEC_VERYLOW_THRSH 0x586 +#define MYKONOS_ADDR_ORX_SNRX_OVRLD_ADC_OVRLD_CFG 0x587 +#define MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_CFG 0x58A +#define MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_UPPER_THRSH 0x58B +#define MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_LOWER_THRSH 0x58C +#define MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_VERYLOW_THRSH 0x58D + +#define MYKONOS_ADDR_RX_ADC_FLASH_DELAY 0x5B6 +#define MYKONOS_ADDR_RX_ADC_FLASH_CTRL 0x5B7 +#define MYKONOS_ADDR_RX_ADC1_PRFL 0x5DD +#define MYKONOS_ADDR_RX_ADC2_PRFL 0x5DE +#define MYKONOS_ADDR_ORX_ADC_PRFL 0x5DF + +#define MYKONOS_ADDR_RFDC_MEASURE_COUNT_1 0x631 +#define MYKONOS_ADDR_RFDC_MEASURE_COUNT_2 0x632 +#define MYKONOS_ADDR_RFDC_PROGRAM_SHIFT 0x635 +#define MYKONOS_ADDR_RFDC_CONFIG2 0x636 +#define MYKONOS_DPD_Sniffer_RFDC_CAL_TRACK_EN 0x642 +#define MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_1 0x644 +#define MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_2 0x645 +#define MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_1 0x650 +#define MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_2 0x651 +#define MYKONOS_ADDR_DIGITAL_DC_MIN_CAL_IDX 0x63A +#define MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT 0x674 +#define MYKONOS_ADDR_DIGITAL_DC_OFFSET_CONFIG 0x676 +#define MYKONOS_DIGITAL_DC_OFFSET_CH3_TRACKING 0x67A +#define MYKONOS_ADDR_DIGITAL_DC_OFFSET_SNF 0x67C +#define MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT 0x67D + +#define MYKONOS_ADDR_RX_GAIN_COMP_DELAY 0x710 +#define MYKONOS_ADDR_RX1_GAIN_COMP_OFFSET 0x711 +#define MYKONOS_ADDR_RX2_GAIN_COMP_OFFSET 0x712 +#define MYKONOS_ADDR_RX_GAIN_COMP_CFG 0x713 +#define MYKONOS_ADDR_RX_SLCR_PIN_CFG 0x714 +#define MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_DELAY 0x715 +#define MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_OFFSET 0x716 +#define MYKONOS_ADDR_DPD_SNF_RX_GAIN_COMP_CFG 0x717 +#define MYKONOS_ADDR_DPD_SNF_RX_SLCR_PIN_CFG 0x718 + +#define MYKONOS_ADDR_FLOATING_POINT_CFG 0x750 +#define MYKONOS_ADDR_FLOATING_POINT_RX_CTRL 0x751 +#define MYKONOS_ADDR_FLOATING_POINT_ORX_CTRL 0x752 + + +#define MYKONOS_ADDR_SNRX_LNA_BIAS_C 0x81B + + +#define MYKONOS_ADDR_ORX_ADC_FLASH_DELAY 0x846 +#define MYKONOS_ADDR_ORX_ADC_FLASH_CTRL 0x847 + +#define MYKONOS_ADDR_TX_FILTER_CONFIGURATION 0x910 +#define MYKONOS_ADDR_TX1_ATTENUATION_0_READBACK 0x940 +#define MYKONOS_ADDR_TX1_ATTENUATION_1_READBACK 0x941 +#define MYKONOS_ADDR_TX2_ATTENUATION_0_READBACK 0x942 +#define MYKONOS_ADDR_TX2_ATTENUATION_1_READBACK 0x943 +#define MYKONOS_ADDR_TX_FILTER_OVERFLOW 0x950 + +/* Mykonos PA Protection Block Registers */ +#define MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION 0x955 +#define MYKONOS_ADDR_PA_PROTECTION_ATTEN_CONTROL 0x956 +#define MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_LSB 0x957 +#define MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_MSB 0x958 +#define MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB 0x959 +#define MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_MSB 0x95A +#define MYKONOS_ADDR_TX1_ATTENUATION_0 0x960 +#define MYKONOS_ADDR_TX1_ATTENUATION_1 0x961 +#define MYKONOS_ADDR_TX2_ATTENUATION_0 0x962 +#define MYKONOS_ADDR_TX2_ATTENUATION_1 0x963 +#define MYKONOS_ADDR_TX1_GAIN_0 0x967 +#define MYKONOS_ADDR_TX1_GAIN_1 0x968 +#define MYKONOS_ADDR_TX1_GAIN_2 0x969 +#define MYKONOS_ADDR_TX2_GAIN_0 0x96A +#define MYKONOS_ADDR_TX2_GAIN_1 0x96B +#define MYKONOS_ADDR_TX2_GAIN_2 0x96C +#define MYKONOS_ADDR_TX_INCR_DECR_WORD 0x96D +#define MYKONOS_ADDR_TX_TPC_CONFIG 0x96E +#define MYKONOS_ADDR_TX_TPC_GPIO_CFG 0x96F + +#define MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_MSB 0x9CB +#define MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_LSB 0x9CC +#define MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_MSB 0x9CD +#define MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_LSB 0x9CE + +/* Mykonos GPIO Registers */ +#define MYKONOS_ADDR_GPIO_3V3_DIR_CTL_7_0 0xB00 +#define MYKONOS_ADDR_GPIO_3V3_DIR_CTL_15_8 0xB01 +#define MYKONOS_ADDR_GPIO_3V3_SPI_SRC_7_0 0xB02 +#define MYKONOS_ADDR_GPIO_3V3_SPI_SRC_15_8 0xB03 +#define MYKONOS_ADDR_GPIO_3V3_SPI_READ_7_0 0xB04 +#define MYKONOS_ADDR_GPIO_3V3_SPI_READ_15_8 0xB05 +#define MYKONOS_ADDR_GPIO_3V3_LSB_SRC_CTL 0xB06 +#define MYKONOS_ADDR_GPIO_3V3_MSB_SRC_CTL 0xB07 + +#define MYKONOS_ADDR_GPIO_DIR_CTL_7_0 0xB20 +#define MYKONOS_ADDR_GPIO_DIR_CTL_15_8 0xB21 +#define MYKONOS_ADDR_GPIO_DIR_CTL_18_16 0xB22 +#define MYKONOS_ADDR_GPIO_SPI_SRC_7_0 0xB23 +#define MYKONOS_ADDR_GPIO_SPI_SRC_15_8 0xB24 +#define MYKONOS_ADDR_GPIO_SPI_SRC_18_16 0xB25 +#define MYKONOS_ADDR_GPIO_SPI_READ_7_0 0xB26 +#define MYKONOS_ADDR_GPIO_SPI_READ_15_8 0xB27 +#define MYKONOS_ADDR_GPIO_SPI_READ_18_16 0xB28 +#define MYKONOS_ADDR_SOURCE_CONTROL_LOWER_BYTE 0xB29 +#define MYKONOS_ADDR_SOURCE_CONTROL_UPPER_BYTE 0xB2A +#define MYKONOS_ADDR_SOURCE_CONTROL_EXTRA_BITS 0xB2B + +#define MYKONOS_ADDR_GPIO_MONITOR_INDEX 0xB40 +#define MYKONOS_ADDR_GPIO_MONITOR_ENABLE 0xB41 + +#define MYKONOS_ADDR_GP_INTERRUPT_MASK_1 0xB42 +#define MYKONOS_ADDR_GP_INTERRUPT_MASK_0 0xB43 +#define MYKONOS_ADDR_GP_INTERRUPT_READ_1 0xB44 +#define MYKONOS_ADDR_GP_INTERRUPT_READ_0 0xB45 + +#define MYKONOS_ADDR_PDAUXDAC_MANUAL_CONTROL_5_0 0xB73 +#define MYKONOS_ADDR_PDAUXDAC_MANUAL_CONTROL_9_6 0xB74 +#define MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_5_0 0xB75 +#define MYKONOS_ADDR_PDAUXDAC_MANUAL_IN_9_6 0xB76 +#define MYKONOS_ADDR_AUX_DAC_LATCH_CONTROL 0xB9F +#define MYKONOS_ADDR_AUXDAC_0_WORD_MSB 0xBA0 + +#define MYKONOS_ADR_AUX_ADC_CLOCK_DIVIDE 0xBC0 +#define MYKONOS_ADDR_AUX_ADC_CFG 0xBC1 +#define MYKONOS_ADDR_AUX_ADC_READ_MSB 0xBC2 +#define MYKONOS_ADDR_AUX_ADC_READ_LSB 0xBC3 +#define MYKONOS_ADDR_AUX_ADC_SEL 0xBC4 +#define MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_0 0xBC5 +#define MYKONOS_ADDR_AUX_ADC_BUFFER_CONFIG_1 0xBC6 + +#define MYKONOS_ADDR_TEMP_SENSOR_OFFSET 0xBE0 +#define MYKONOS_ADDR_TEMP_SENSOR_CONTROL_LSB 0xBE1 +#define MYKONOS_ADDR_TEMP_SENSOR_CONTROL_MSB 0xBE2 +#define MYKONOS_ADDR_TEMP_SENSOR_READ 0xBE3 +#define MYKONOS_ADDR_TEMP_SENSOR_CONFIG 0xBE4 + +#define MYKONOS_ADDR_DIGITAL_TEST_BYTE_0 0xC40 + +/* ARM subsystem registers */ +#define MYKONOS_ADDR_ARM_CTL_1 0xD00 +#define MYKONOS_ADDR_ARM_CTL_2 0xD01 +#define MYKONOS_ADDR_ARM_ADDR_BYTE_0 0xD02 +#define MYKONOS_ADDR_ARM_ADDR_BYTE_1 0xD03 +#define MYKONOS_ADDR_ARM_DATA_BYTE_0 0xD04 +#define MYKONOS_ADDR_ARM_DATA_BYTE_1 0xD05 +#define MYKONOS_ADDR_ARM_DATA_BYTE_2 0xD06 +#define MYKONOS_ADDR_ARM_DATA_BYTE_3 0xD07 +#define MYKONOS_ADDR_ARM_CLK_CTL 0xD08 +#define MYKONOS_ADDR_AHB_SPI_BRIDGE 0xD09 +#define MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_0 0xD0A +#define MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_1 0xD0B +#define MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_2 0xD0C +#define MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_3 0xD0D +#define MYKONOS_ADDR_ARM_STACK_PTR_BYTE_0 0xD0E +#define MYKONOS_ADDR_ARM_STACK_PTR_BYTE_1 0xD0F +#define MYKONOS_ADDR_ARM_STACK_PTR_BYTE_2 0xD10 +#define MYKONOS_ADDR_ARM_STACK_PTR_BYTE_3 0xD11 +#define MYKONOS_ADDR_ARM_BRIDGE_CLK_CTL 0xD14 + +/* ARM mailbox registers */ +#define MYKONOS_ADDR_ARM_CMD 0xD30 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_1 0xD31 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_2 0xD32 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_3 0xD33 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_4 0xD34 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_5 0xD35 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_6 0xD36 +#define MYKONOS_ADDR_ARM_EXT_CMD_BYTE_7 0xD37 +#define MYKONOS_ADDR_ARM_CMD_STATUS_0 0xD38 +#define MYKONOS_ADDR_ARM_CMD_STATUS_1 0xD39 +#define MYKONOS_ADDR_ARM_CMD_STATUS_2 0xD3A +#define MYKONOS_ADDR_ARM_CMD_STATUS_3 0xD3B +#define MYKONOS_ADDR_ARM_CMD_STATUS_4 0xD3C +#define MYKONOS_ADDR_ARM_CMD_STATUS_5 0xD3D +#define MYKONOS_ADDR_ARM_CMD_STATUS_6 0xD3E +#define MYKONOS_ADDR_ARM_CMD_STATUS_7 0xD3F + +#define MYKONOS_ADDR_ARM_OPCODE_STATE_0 0xD40 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_1 0xD41 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_2 0xD42 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_3 0xD43 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_4 0xD44 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_5 0xD45 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_6 0xD46 +#define MYKONOS_ADDR_ARM_OPCODE_STATE_7 0xD47 + +/* Mykonos Power-Down Override Control Registers */ +#define MYKONOS_ADDR_TX_PD_OVERRIDE_CONTROL_7_0 0xD89 + +/* Mykonos Observation Framer Registers */ +#define MYKONOS_ADDR_OBS_FRAMER_RESET 0xDC0 +#define MYKONOS_ADDR_OBS_FRAMER_CLK_EN 0xDC1 +#define MYKONOS_ADDR_OBS_FRAMER_ADDR 0xDC2 +#define MYKONOS_ADDR_OBS_FRAMER_DATA 0xDC3 +#define MYKONOS_ADDR_OBS_FRAMER_WRITE_EN 0xDC4 +#define MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN 0xDC5 +#define MYKONOS_ADDR_OBS_FRAMER_CONFIG_F 0xDC6 +#define MYKONOS_ADDR_OBS_FRAMER_LANE_CTL 0xDC7 +#define MYKONOS_ADDR_OBS_FRAMER_ADC_XBAR_SEL 0xDC8 +#define MYKONOS_ADDR_OBS_FRAMER_LANE_XBAR_SEL 0xDC9 +#define MYKONOS_ADDR_OBS_FRAMER_CONFIG_LOOPBACK_XBAR_REV 0xDCA +#define MYKONOS_ADDR_OBS_FRAMER_SYNCN_FILT 0xDCB +#define MYKONOS_ADDR_OBS_FRAMER_LMFC_F_OFFSET 0xDCC +#define MYKONOS_ADDR_OBS_FRAMER_LMFC_K_OFFSET 0xDCD +#define MYKONOS_ADDR_OBS_FRAMER_TEST_CNTR_CTL 0xDCE +#define MYKONOS_ADDR_OBS_FRAMER_STATUS_STRB 0xDCF +#define MYKONOS_ADDR_OBS_FRAMER_STATUS 0xDD0 +#define MYKONOS_ADDR_OBS_FRAMER_SYSREF_TO_LMFC_CNTR_STAT 0xDD1 +#define MYKONOS_ADDR_OBS_FRAMER_SYSREF_TO_LMFC_ERR_MARGIN 0xDD2 +#define MYKONOS_ADDR_OBS_FRAMER_LANE_FIFO_STRB 0xDD3 +#define MYKONOS_ADDR_OBS_FRAMER_LANE0_FIFO_RDWR_ADDR 0xDD4 +#define MYKONOS_ADDR_OBS_FRAMER_LANE1_FIFO_RDWR_ADDR 0xDD5 +#define MYKONOS_ADDR_OBS_FRAMER_LANE2_FIFO_RDWR_ADDR 0xDD6 +#define MYKONOS_ADDR_OBS_FRAMER_LANE3_FIFO_RDWR_ADDR 0xDD7 +#define MYKONOS_ADDR_OBS_FRAMER_PRBS10_CTL 0xDD8 +#define MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL 0xDD9 +#define MYKONOS_ADDR_OBS_FRAMER_PATTERN_GEN_EN 0xDDA +#define MYKONOS_ADDR_OBS_FRAMER_PATTERN_GEN_7_TO_0 0xDDB +#define MYKONOS_ADDR_OBS_FRAMER_PATTERN_GEN_15_TO_8 0xDDC +#define MYKONOS_ADDR_OBS_FRAMER_PATTERN_GEN_19_TO_16 0xDDD +#define MYKONOS_ADDR_OBS_FRAMER_CONFIG_JTX_GEN 0xDDE +#define MYKONOS_ADDR_OBS_FRAMER_LANE_DATA_CTL 0xDDF +#define MYKONOS_ADDR_OBS_FRAMER_DATA_SAMPLE_CTL 0xDE0 + +#define MYKONOS_ADDR_PFIR_COEFF_CTL 0xDFF +#define MYKONOS_ADDR_PFIR_COEFF_DATA 0xE00 +#define MYKONOS_ADDR_PFIR_COEFF_ADDR 0xE01 + +/* ARM memory */ +#define MYKONOS_ADDR_ARM_START_PROG_ADDR 0x01000000 +#define MYKONOS_ADDR_ARM_END_PROG_ADDR 0x01017FFF +#define MYKONOS_ADDR_ARM_START_DATA_ADDR 0x20000000 +#define MYKONOS_ADDR_ARM_END_DATA_ADDR 0x2000FFFF +#define MYKONOS_ADDR_ARM_BUILD_CHKSUM_ADDR 0x01017FE0 +#define MYKONOS_ADDR_ARM_CALC_CHKSUM_ADDR 0x01017FE4 +#define MYKONOS_ADDR_ARM_VERSION 0x01000128 +#define MYKONOS_ARM_ABORT_OPCODE 0x00 +#define MYKONOS_ARM_RUNINIT_OPCODE 0x02 +#define MYKONOS_ARM_RADIOON_OPCODE 0x04 +#define MYKONOS_ARM_WRITECFG_OPCODE 0x06 +#define MYKONOS_ARM_READCFG_OPCODE 0x08 +#define MYKONOS_ARM_SET_OPCODE 0x0A +#define MYKONOS_ARM_GET_OPCODE 0x0C + +#define MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG 0x0F +#define MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG 0x10 +#define MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG 0x11 +#define MYKONOS_ARM_OBJECTID_DPDCONFIG 0x24 +#define MYKONOS_ARM_DPD_RESET 0x02 +#define MYKONOS_ARM_OBJECTID_GS_TRACKCALS 0x66 +#define MYKONOS_ARM_OBJECTID_RXQEC_TRACKING 0x20 +#define MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING 0x21 +#define MYKONOS_ARM_OBJECTID_TXLOL_TRACKING 0x22 +#define MYKONOS_ARM_OBJECTID_TXQEC_TRACKING 0x23 +#define MYKONOS_ARM_OBJECTID_CLGCCONFIG 0x25 +#define MYKONOS_ARM_OBJECTID_VSWRCONFIG 0x26 +#define MYKONOS_ARM_OBJECTID_CAL_STATUS 0x42 +#define MYKONOS_ARM_OBJECTID_INIT_CAL_DONE 0x43 +#define MYKONOS_ARM_OBJECTID_ORX_MODE 0x61 +#define MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME 0x65 +#define MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL 0x66 +#define MYKONOS_ARM_OBJECTID_TRACKING_CAL_PENDING 0x67 +#define MYKONOS_ARM_OBJECTID_RADIO_CONTROL 0x81 +#define MYKONOS_ARM_OBJECTID_CALSCHEDULER 0x83 + +#define MYKONOS_ARM_SYSTEMSTATE_POWERUP 0x00 +#define MYKONOS_ARM_SYSTEMSTATE_READY 0x01 +#define MYKONOS_ARM_SYSTEMSTATE_IDLE 0x02 +#define MYKONOS_ARM_SYSTEMSTATE_RADIO_ON 0x03 + +#define ORX_TRIGGER_SIGNALID 0x00 +#define ORX_MODE_0_SIGNALID 0x01 +#define ORX_MODE_1_SIGNALID 0x02 +#define ORX_MODE_2_SIGNALID 0x03 +#define RX1_ENABLE_ACK_SIGNALID 0x04 +#define RX2_ENABLE_ACK_SIGNALID 0x05 +#define TX1_ENABLE_ACK_SIGNALID 0x06 +#define TX2_ENABLE_ACK_SIGNALID 0x07 +#define ORX1_ENABLE_ACK_SIGNALID 0x08 +#define ORX2_ENABLE_ACK_SIGNALID 0x09 +#define SRX_ENABLE_ACK_SIGNALID 0x0A +#define TX_OBS_SELECT_SIGNALID 0x0B + +#define DISABLE_DPD_ACTUATOR 0x03 +#define ENABLE_DPD_ACTUATOR 0x04 +#define SET_CLGC_DESIRED_GAIN_1 0x05 +#define SET_CLGC_DESIRED_GAIN_2 0x06 +#define SET_PATH_DELAY 0x08 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/mykonos_user.c b/src/hardware/mykonos/mykonos_user.c new file mode 100644 index 0000000..5cedb57 --- /dev/null +++ b/src/hardware/mykonos/mykonos_user.c @@ -0,0 +1,176 @@ +/** + * \file mykonos_user.c + * \brief Contains Mykonos default gain table values for Rx, ObsRx, and SnRx + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#include +#include "t_mykonos.h" +#include "mykonos_user.h" + +/** + * \brief Default Rx gain table settings + */ +uint8_t RxGainTable [61][4] = +{ + /* Order: {FE table, External Ctl, Digital Gain/Atten, Enable Atten} */ + {0, 0, 0, 0}, /* Gain index 255 */ + {3, 0, 2, 1}, /* Gain index 254 */ + {6, 0, 3, 1}, /* Gain index 253 */ + {10, 0, 0, 0}, /* Gain index 252 */ + {13, 0, 1, 1}, /* Gain index 251 */ + {16, 0, 0, 0}, /* Gain index 250 */ + {18, 0, 3, 1}, /* Gain index 249 */ + {21, 0, 1, 1}, /* Gain index 248 */ + {23, 0, 3, 1}, /* Gain index 247 */ + {25, 0, 4, 1}, /* Gain index 246 */ + {28, 0, 0, 0}, /* Gain index 245 */ + {30, 0, 0, 0}, /* Gain index 244 */ + {31, 0, 5, 1}, /* Gain index 243 */ + {33, 0, 4, 1}, /* Gain index 242 */ + {35, 0, 2, 1}, /* Gain index 241 */ + {37, 0, 0, 0}, /* Gain index 240 */ + {38, 0, 4, 1}, /* Gain index 239 */ + {39, 0, 7, 1}, /* Gain index 238 */ + {41, 0, 2, 1}, /* Gain index 237 */ + {42, 0, 4, 1}, /* Gain index 236 */ + {43, 0, 6, 1}, /* Gain index 235 */ + {44, 0, 8, 1}, /* Gain index 234 */ + {45, 0, 9, 1}, /* Gain index 233 */ + {46, 0, 10, 1}, /* Gain index 232 */ + {47, 0, 10, 1}, /* Gain index 231 */ + {48, 0, 9, 1}, /* Gain index 230 */ + {49, 0, 8, 1}, /* Gain index 229 */ + {50, 0, 6, 1}, /* Gain index 228 */ + {51, 0, 3, 1}, /* Gain index 227 */ + {51, 0, 13, 1}, /* Gain index 226 */ + {52, 0, 9, 1}, /* Gain index 225 */ + {53, 0, 5, 1}, /* Gain index 224 */ + {53, 0, 15, 1}, /* Gain index 223 */ + {54, 0, 9, 1}, /* Gain index 222 */ + {54, 0, 19, 1}, /* Gain index 221 */ + {55, 0, 11, 1}, /* Gain index 220 */ + {55, 0, 21, 1}, /* Gain index 219 */ + {56, 0, 11, 1}, /* Gain index 218 */ + {56, 0, 21, 1}, /* Gain index 217 */ + {57, 0, 9, 1}, /* Gain index 216 */ + {57, 0, 19, 1}, /* Gain index 215 */ + {57, 0, 29, 1}, /* Gain index 214 */ + {58, 0, 12, 1}, /* Gain index 213 */ + {58, 0, 22, 1}, /* Gain index 212 */ + {58, 0, 32, 1}, /* Gain index 211 */ + {59, 0, 11, 1}, /* Gain index 210 */ + {59, 0, 21, 1}, /* Gain index 209 */ + {59, 0, 31, 1}, /* Gain index 208 */ + {59, 0, 41, 1}, /* Gain index 207 */ + {60, 0, 13, 1}, /* Gain index 206 */ + {60, 0, 23, 1}, /* Gain index 205 */ + {60, 0, 33, 1}, /* Gain index 204 */ + {60, 0, 43, 1}, /* Gain index 203 */ + {60, 0, 53, 1}, /* Gain index 202 */ + {61, 0, 14, 1}, /* Gain index 201 */ + {61, 0, 24, 1}, /* Gain index 200 */ + {61, 0, 34, 1}, /* Gain index 199 */ + {61, 0, 44, 1}, /* Gain index 198 */ + {61, 0, 54, 1}, /* Gain index 197 */ + {61, 0, 64, 1}, /* Gain index 196 */ + {61, 0, 74, 1}, /* Gain index 195 */ +}; + +/** + * \brief Default ORx gain table settings + */ +uint8_t ORxGainTable [19][4] = +{ + /* Order: {FE table, External Ctl, Digital Gain/Atten, Enable Atten} */ + {0, 0, 0, 0}, /* Gain index 255 */ + {7, 0, 0, 0}, /* Gain index 254 */ + {13, 0, 1, 1}, /* Gain index 253 */ + {18, 0, 3, 1}, /* Gain index 252 */ + {23, 0, 3, 1}, /* Gain index 251 */ + {28, 0, 0, 0}, /* Gain index 250 */ + {32, 0, 0, 0}, /* Gain index 249 */ + {35, 0, 2, 1}, /* Gain index 248 */ + {38, 0, 4, 1}, /* Gain index 247 */ + {41, 0, 2, 1}, /* Gain index 246 */ + {43, 0, 6, 1}, /* Gain index 245 */ + {46, 0, 0, 0}, /* Gain index 244 */ + {47, 0, 10, 1}, /* Gain index 243 */ + {49, 0, 8, 1}, /* Gain index 242 */ + {51, 0, 3, 1}, /* Gain index 241 */ + {52, 0, 9, 1}, /* Gain index 240 */ + {53, 0, 14, 1}, /* Gain index 239 */ + {54, 0, 18, 1}, /* Gain index 238 */ + {56, 0, 0, 0} /* Gain index 237 */ + +}; + +/** + * \brief Default SnRx gain table settings + */ +uint8_t SnRxGainTable [53][4] = +{ + /* Order: {FE table, LNA Bypass, Digital Gain/Atten, Enable Atten} */ + {0, 0, 0, 0}, /* Gain index 255 */ + {1, 0, 7, 1}, /* Gain index 254 */ + {3, 0, 1, 0}, /* Gain index 253 */ + {3, 0, 15, 1}, /* Gain index 252 */ + {5, 0, 0, 0}, /* Gain index 251 */ + {6, 0, 2, 1}, /* Gain index 250 */ + {7, 0, 2, 1}, /* Gain index 249 */ + {8, 0, 12, 1}, /* Gain index 248 */ + {9, 0, 7, 1}, /* Gain index 247 */ + {11, 0, 1, 0}, /* Gain index 246 */ + {11, 0, 15, 1},/* Gain index 245 */ + {13, 0, 1, 0}, /* Gain index 244 */ + {14, 0, 2, 0}, /* Gain index 243 */ + {14, 0, 10, 1},/* Gain index 242 */ + {15, 0, 0, 0}, /* Gain index 241 */ + {15, 0, 20, 1},/* Gain index 240 */ + {16, 0, 2, 1}, /* Gain index 239 */ + {16, 0, 22, 1},/* Gain index 238 */ + {17, 0, 1, 0}, /* Gain index 237 */ + {17, 0, 15, 1},/* Gain index 236 */ + {17, 0, 35, 1},/* Gain index 235 */ + {17, 0, 55, 1},/* Gain index 234 */ + {18, 0, 7, 1}, /* Gain index 233 */ + {18, 0, 27, 1},/* Gain index 232 */ + { 6, 1, 7, 1}, /* Gain index 231 */ + { 7, 1, 7, 1}, /* Gain index 230 */ + { 8, 1, 17, 1}, /* Gain index 229 */ + { 9, 1, 12, 1}, /* Gain index 228 */ + {11, 1, 0, 0}, /* Gain index 227 */ + {12, 1, 3, 1}, /* Gain index 226 */ + {13, 1, 0, 0}, /* Gain index 225 */ + {14, 1, 1, 0}, /* Gain index 224 */ + {14, 1, 15, 1},/* Gain index 223 */ + {15, 1, 5, 1}, /* Gain index 222 */ + {15, 1, 25, 1},/* Gain index 221 */ + {16, 1, 7, 1}, /* Gain index 220 */ + {16, 1, 27, 1},/* Gain index 219 */ + {17, 1, 0, 0}, /* Gain index 218 */ + {17, 1, 20, 1},/* Gain index 217 */ + {17, 1, 40, 1},/* Gain index 216 */ + {17, 1, 60, 1},/* Gain index 215 */ + {18, 1, 12, 1},/* Gain index 214 */ + {18, 1, 32, 1},/* Gain index 213 */ + {18, 1, 52, 1},/* Gain index 212 */ + {18, 1, 72, 1},/* Gain index 211 */ + {18, 1, 92, 1},/* Gain index 210 */ + {19, 1, 1, 0}, /* Gain index 209 */ + {19, 1, 15, 1},/* Gain index 208 */ + {19, 1, 35, 1},/* Gain index 207 */ + {19, 1, 55, 1},/* Gain index 206 */ + {19, 1, 75, 1},/* Gain index 205 */ + {19, 1, 95, 1},/* Gain index 204 */ + {19, 1, 115, 1}/* Gain index 203 */ +}; + diff --git a/src/hardware/mykonos/mykonos_user.h b/src/hardware/mykonos/mykonos_user.h new file mode 100644 index 0000000..2875837 --- /dev/null +++ b/src/hardware/mykonos/mykonos_user.h @@ -0,0 +1,85 @@ +/** + * \file mykonos_user.h + * + * \brief Contains macro definitions and global structure declarations for mykonos_user.c + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _MYKONOSPROFILES_H_ +#define _MYKONOSPROFILES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* turns verbose messaging on */ +#define MYKONOS_VERBOSE 1 +#define MYK_ENABLE_SPIWRITEARRAY 1 + +/* 3 Bytes per SPI transaction * 341 transactions = ~1024 byte buffer size */ +/* Minimum MYK_SPIWRITEARRAY_BUFFERSIZE = 27 */ +#define MYK_SPIWRITEARRAY_BUFFERSIZE 341 +/* + ***************************************** + * Rx, ObsRx, and Sniffer gain tables + ****************************************** + */ +#define MAX_GAIN_TABLE_INDEX 255 + +#define START_RX_GAIN_INDEX 255 +#define MAX_RX_GAIN_TABLE_NUMINDEXES (START_RX_GAIN_INDEX + 1) +#define MIN_RX_GAIN_TABLE_INDEX 0 + +#define START_ORX_GAIN_INDEX 47 +#define MAX_ORX_GAIN_TABLE_NUMINDEXES (START_ORX_GAIN_INDEX + 1) +#define MIN_ORX_GAIN_TABLE_INDEX (MAX_GAIN_TABLE_INDEX - START_ORX_GAIN_INDEX) + +#define START_SNRX_GAIN_INDEX 127 +#define MAX_SNRX_GAIN_TABLE_NUMINDEXES (START_SNRX_GAIN_INDEX + 1) +#define MIN_SNRX_GAIN_TABLE_INDEX (MAX_GAIN_TABLE_INDEX - START_SNRX_GAIN_INDEX) + +#define START_LOOPBACK_GAIN_INDEX 47 +#define MAX_LOOPBACK_GAIN_TABLE_NUMINDEXES (START_LOOPBACK_GAIN_INDEX + 1) +#define MIN_LOOPBACK_GAIN_TABLE_INDEX (MAX_GAIN_TABLE_INDEX - START_SNRX_GAIN_INDEX) + +extern uint8_t RxGainTable [61][4]; +extern uint8_t ORxGainTable [19][4]; +extern uint8_t SnRxGainTable [53][4]; + + +/* + ******************************************** + * Rx, Sniffer, ObsRx and Tx Profiles limits + ******************************************** + */ +#define MIN_RX_IQRATE_KHZ 15000 /*!< Mykonos minimum IQ rate for the Rx channel, expressed in KHz */ +#define MAX_RX_IQRATE_KHZ 320000 /*!< Mykonos maximum IQ rate for the Rx channel, expressed in KHz */ + +#define MIN_TX_IQRATE_KHZ 15000 /*!< Mykonos minimum IQ rate for the Tx channel, expressed in KHz */ +#define MAX_TX_IQRATE_KHZ 492000 /*!< Mykonos maximum IQ rate for the Tx channel, expressed in KHz */ + +#define MIN_SNIFFER_RFBW_HZ 5000000 /*!< Mykonos minimum Sniffer channel bandwidth expressed in Hz */ +#define MAX_SNIFFER_RFBW_HZ 20000000 /*!< Mykonos maximum Sniffer channel bandwidth expressed in Hz */ + +#define MIN_ORX_RFBW_HZ 5000000 /*!< Mykonos minimum Observation channel bandwidth expressed in Hz */ +#define MAX_ORX_RFBW_HZ 250000000 /*!< Mykonos maximum Observation channel bandwidth expressed in Hz */ + +#define MIN_RX_RFBW_HZ 5000000 /*!< Mykonos minimum Rx channel bandwidth expressed in Hz */ +#define MAX_RX_RFBW_HZ 100000000 /*!< Mykonos maximum Rx channel bandwidth expressed in Hz */ + +#define MIN_TX_RFBW_HZ 20000000 /*!< Mykonos minimum Tx channel bandwidth expressed in Hz */ +#define MAX_TX_RFBW_HZ 250000000 /*!< Mykonos maximum Tx channel bandwidth expressed in Hz */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/mykonos_version.h b/src/hardware/mykonos/mykonos_version.h new file mode 100644 index 0000000..c7f58d2 --- /dev/null +++ b/src/hardware/mykonos/mykonos_version.h @@ -0,0 +1,31 @@ +/** + * \file mykonos_version.h + * \brief Contains the version number for the Mykonos API + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in * this zip file. +* +*/ + +#ifndef MYKONOS_VERSION_H_ +#define MYKONOS_VERSION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MYKONOS_CURRENT_SI_VERSION 1 /*!< Mykonos current silicon version */ +#define MYKONOS_CURRENT_MAJOR_VERSION 5 /*!< Mykonos current ARM major version */ +#define MYKONOS_CURRENT_MINOR_VERSION 2 /*!< Mykonos current ARM minor version */ +#define MYKONOS_CURRENT_BUILD_VERSION 3566 /*!< Mykonos current API build version */ + +#ifdef __cplusplus +} +#endif + +#endif /* MYKONOS_VERSION_H_ */ diff --git a/src/hardware/mykonos/t_ad9528.h b/src/hardware/mykonos/t_ad9528.h new file mode 100644 index 0000000..02cd278 --- /dev/null +++ b/src/hardware/mykonos/t_ad9528.h @@ -0,0 +1,194 @@ +/** + * \file t_ad9528.h + * \brief Contains enum and structure data types for all AD9528 function calls + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _AD9528_TYPES_H_ +#define _AD9528_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../common.h" + +/* AD9528 SPI Address defines */ +#define AD9528_ADDR_ADI_SPI_CONFIG_A 0x000 +#define AD9528_ADDR_ADI_SPI_CONFIG_B 0x001 +#define AD9528_ADDR_IO_UPDATE 0x00F + +#define AD9528_ADDR_REF_A_DIVIDER_LSB 0x100 +#define AD9528_ADDR_REF_A_DIVIDER_MSB 0x101 +#define AD9528_ADDR_REF_B_DIVIDER_LSB 0x102 +#define AD9528_ADDR_REF_B_DIVIDER_MSB 0x103 +#define AD9528_ADDR_PLL1_N_DIV_LSB 0x104 +#define AD9528_ADDR_PLL1_N_DIV_MSB 0x105 +#define AD9528_ADDR_PLL1_CHARGEPUMP 0x106 +#define AD9528_ADDR_PLL1_CP_CTRL2 0x107 +#define AD9528_ADDR_INPUT_RECEIVERS1 0x108 +#define AD9528_ADDR_INPUT_RECEIVERS2 0x109 +#define AD9528_ADDR_INPUT_RECEIVERS3 0x10A +#define AD9528_ADDR_PLL1_FASTLOCK 0x10B + +#define AD9528_ADDR_PLL2_CHARGEPUMP 0x200 +#define AD9528_ADDR_PLL2_N_DIV 0x201 +#define AD9528_ADDR_PLL2_CTRL 0x202 +#define AD9528_ADDR_PLL2_VCO_CTRL 0x203 +#define AD9528_ADDR_PLL2_VCO_DIV 0x204 +#define AD9528_ADDR_PLL2_LF_CTRL1 0x205 +#define AD9528_ADDR_PLL2_LF_CTRL2 0x206 +#define AD9528_ADDR_PLL2_RDIV 0x207 +#define AD9528_ADDR_PLL2_REPLICA_CHDIV 0x208 +#define AD9528_ADDR_PLL2_REPLICA_DIV_PHASE 0x209 + +#define AD9528_ADDR_CH_OUT0_CTRL1 0x300 +#define AD9528_ADDR_CH_OUT0_CTRL2 0x301 +#define AD9528_ADDR_CH_OUT0_CHDIV 0x302 +#define AD9528_ADDR_OUTPUT_SYNC 0x32A +#define AD9528_ADDR_MASK_SYNC1 0x32B +#define AD9528_ADDR_MASK_SYNC2 0x32C +#define AD9528_ADDR_EN_OUTPUT_PATH_SEL1 0x32D +#define AD9528_ADDR_EN_OUTPUT_PATH_SEL2 0x32E + +#define AD9528_ADDR_SYSERF_DIV_LSB 0x400 +#define AD9528_ADDR_SYSERF_DIV_MSB 0x401 +#define AD9528_ADDR_SYSREF_CTRL3 0x402 +#define AD9528_ADDR_SYSREF_CTRL4 0x403 +#define AD9528_ADDR_SYSREF_CTRL5 0x404 + +#define AD9528_ADDR_POWERDOWN_CTRL 0x500 +#define AD9528_ADDR_CH_POWERDOWN1 0x501 +#define AD9528_ADDR_CH_POWERDOWN2 0x502 +#define AD9528_ADDR_LDO_ENABLES1 0x503 +#define AD9528_ADDR_LDO_ENABLES2 0x504 +#define AD9528_ADDR_STATUS0_CTRL 0x505 +#define AD9528_ADDR_STATUS1_CTRL 0x506 +#define AD9528_ADDR_STATUS_OE 0x507 +#define AD9528_ADDR_STATUS_READBACK0 0x508 +#define AD9528_ADDR_STATUS_READBACK1 0x509 + + + +///Enum to select what source outputs from each AD9528 output channel +typedef enum +{ + CHANNEL_DIV = 0, PLL1_OUTPUT = 1, //VCXO frequency + SYSREF = 2, + INV_PLL1_OUTPUT = 5 //VCXO inverted +} ad9528outSourceSel_t; + +///Enum to select what output buffer standard is used for the clock outputs +typedef enum +{ + LVDS = 0, LVDS_BOOST = 1, HSTL = 2 +} ad9528outBufferControl_t; + +///Enum to select the clock input buffer mode. +typedef enum +{ + DISABLED = 0, SINGLE_ENDED, NEG_SINGLE_ENDED, DIFFERENTIAL +} ad9528RefBuffer_t; + +/// Structure to hold AD9528 PLL1 settings +typedef struct +{ + uint32_t refA_Frequency_Hz; + uint16_t refA_Divider; + ad9528RefBuffer_t refA_bufferCtrl; + + uint32_t refB_Frequency_Hz; + uint16_t refB_Divider; + ad9528RefBuffer_t refB_bufferCtrl; + + uint32_t vcxo_Frequency_Hz; + ad9528RefBuffer_t vcxoBufferCtrl; + + uint16_t nDivider; + uint8_t bypassPll1; +} ad9528pll1Settings_t; + +/// Structure to hold AD9528 PLL2 settings +typedef struct +{ + uint8_t rfDivider; //VCO divider: Valid range (3,4,5) + uint8_t n2Divider; //PLL2 N2 Divider + uint8_t totalNdiv; //NDiv = 4*Bdiv + Adiv //Bdiv valid range (3 to 63), Adiv valid range (0-3) +} ad9528pll2Settings_t; + +/// Structure to hold AD9528 Output Clock settings +typedef struct +{ + uint16_t outPowerDown; //bit per output, if 1 power down that output. + ad9528outSourceSel_t outSource[14]; //CHANNEL_DIV, PLL1_OUTPUT, SYSREF, INV_PLL1_OUTPUT + ad9528outBufferControl_t outBufferCtrl[14]; //LVDS, LVDS_BOOST, HSTL + uint8_t outAnalogDelay[14]; //5 bits + uint8_t outDigitalDelay[14]; //6 bits, 1/2 clock resolution @ channel div input frequency + uint8_t outChannelDiv[14]; //8 bit channel divider + uint32_t outFrequency_Hz[14]; //output clock frequency per clock output +} ad9528outputSettings_t; + +///Enum to select the SYSREF output source +typedef enum +{ + EXTERNAL = 0, EXT_RESAMPLED = 1, INTERNAL = 2 +} sysrefSourceSelection_t; + +///Enum to choose the SYSREF pattern mode. +typedef enum +{ + NSHOT = 0, CONTINUOUS = 1, PRBS = 2, STOP = 3 +} sysrefPatternMode_t; + +///Enum to select the SYSREF input pin mode. +typedef enum +{ + LEVEL_ACTIVE_HIGH = 0, LEVEL_ACTIVE_LOW = 1, RISING_EDGE = 2, FALLING_EDGE = 3 +} sysrefPinEdgeMode_t; + +///Enum to select the SYSREF output # of pulses for NSHOT mode. +typedef enum +{ + ONE_PULSE = 0, TWO_PULSES = 2, FOUR_PULSES = 3, SIX_PULSES = 4, EIGHT_PULSES = 5 +} sysrefNshotMode_t; + +//Enum to select how a SYSREF is requested. +typedef enum +{ + SPI = 0, PIN = 1 +} sysrefRequestMethod_t; + +/// Structure to hold AD9528 SYSREF output settings +typedef struct +{ + sysrefRequestMethod_t sysrefRequestMethod; + sysrefSourceSelection_t sysrefSource; + sysrefPinEdgeMode_t sysrefPinEdgeMode; + ad9528RefBuffer_t sysrefPinBufferMode; + sysrefPatternMode_t sysrefPatternMode; + sysrefNshotMode_t sysrefNshotMode; + uint16_t sysrefDivide; + +} ad9528sysrefSettings_t; + +/// Structure to hold AD9528 settings +typedef struct +{ + spiSettings_t *spiSettings; + ad9528pll1Settings_t *pll1Settings; + ad9528pll2Settings_t *pll2Settings; + ad9528outputSettings_t *outputSettings; + ad9528sysrefSettings_t *sysrefSettings; +} ad9528Device_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/t_mykonos.h b/src/hardware/mykonos/t_mykonos.h new file mode 100644 index 0000000..66db0d7 --- /dev/null +++ b/src/hardware/mykonos/t_mykonos.h @@ -0,0 +1,1710 @@ +/*! + * \file t_mykonos.h + * \brief Contains type definitions for Mykonos API + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef _T_MYKONOS_LIB_H_ +#define _T_MYKONOS_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../common.h" + + +/** + * \brief Enum of unique error codes from the Mykonos API functions. + * Each error condition in the library should get its own enum value to allow + * easy debug of errors. + */ +typedef enum +{ + MYKONOS_ERR_OK=0, + MYKONOS_ERR_HAL_LAYER, + MYKONOS_ERR_INV_PARM, + MYKONOS_ERR_FAILED, + MYKONOS_ERR_WAITFOREVENT_INV_PARM, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT, + MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_WAIT, + MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_ALERT, + MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_TXRX, + MYKONOS_ERR_SETENSM_INVALIDSTATE, + MYKONOS_ERR_PU_RXPATH_INV_PARAM, + MYKONOS_ERR_PU_TXPATH_INV_PARAM, + MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM, + MYKONOS_ERR_INIT_INV_ORXCHAN, + MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE, + MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION, + MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION, + MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION, + MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION, + MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION, + MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION, + MYKONOS_ERR_INIT_INV_SNIFFER_RHB1, + MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC, + MYKONOS_ERR_INIT_INV_ORX_RHB1, + MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC, + MYKONOS_ERR_INIT_INV_ADCDIV, + MYKONOS_ERR_INIT_INV_DACDIV, + MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV, + MYKONOS_ERR_CLKPLL_INV_HSDIV, + MYKONOS_ERR_CLKPLL_INV_VCODIV, + MYKONOS_ERR_CLKPLL_INV_RXTXPROFILES, + MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX, + MYKONOS_ERR_SETCLKPLL_INV_FRACWORD, + MYKONOS_ERR_SETRFPLL_INV_PLLNAME, + MYKONOS_ERR_SETRFPLL_INV_LO_PARM, + MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM, + MYKONOS_ERR_NULL_DEVICE_PARAM, + MYKONOS_ERR_CALCDEVCLK_NULLPARAM, + MYKONOS_ERR_SETRFPLL_INV_VCOINDEX, + MYKONOS_ERR_SETRFPLL_INV_REFCLK, + MYKONOS_ERR_SETORXGAIN_INV_CHANNEL, + MYKONOS_ERR_SETORXGAIN_INV_GAIN, + MYKONOS_ERR_GETORX1GAIN_INV_POINTER, + MYKONOS_ERR_GETORX2GAIN_INV_POINTER, + MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER, + MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED, + MYKONOS_ERR_SETTX1ATTEN_INV_PARM, + MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM, + MYKONOS_ERR_SETTX2ATTEN_INV_PARM, + MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM, + MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM, + MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM, + MYKONOS_ERR_RXFIR_INV_GAIN_PARM, + MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM, + MYKONOS_ERR_SRXFIR_INV_GAIN_PARM, + MYKONOS_ERR_TXFIR_INV_GAIN_PARM, + MYKONOS_ERR_READFIR_NULL_PARM, + MYKONOS_ERR_READFIR_COEFS_NULL, + MYKONOS_ERR_READFIR_INV_FIRNAME_PARM, + MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM, + MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM, + MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM, + MYKONOS_ERR_INITSER_INV_VCODIV_PARM, + MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM, + MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM, + MYKONOS_ERR_INITDES_INV_VCODIV_PARM, + MYKONOS_ERR_SER_INV_M_PARM, + MYKONOS_ERR_SER_INV_L_PARM, + MYKONOS_ERR_SER_INV_LANERATE_PARM, + MYKONOS_ERR_SER_INV_LANEEN_PARM, + MYKONOS_ERR_SER_INV_AMP_PARM, + MYKONOS_ERR_SER_INV_PREEMP_PARM, + MYKONOS_ERR_SER_INV_LANEPN_PARM, + MYKONOS_ERR_SER_LANE_CONFLICT_PARM, + MYKONOS_ERR_SER_INV_TXSER_DIV_PARM, + MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM, + MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM, + MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT, + MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT, + MYKONOS_ERR_DESER_INV_M_PARM, + MYKONOS_ERR_DESER_INV_L_PARM, + MYKONOS_ERR_DESER_INV_HSCLK_PARM, + MYKONOS_ERR_DESER_INV_LANERATE_PARM, + MYKONOS_ERR_DESER_INV_LANEEN_PARM, + MYKONOS_ERR_DESER_INV_EQ_PARM, + MYKONOS_ERR_DESER_INV_LANEPN_PARM, + MYKONOS_ERR_FRAMER_INV_M_PARM, + MYKONOS_ERR_FRAMER_INV_BANKID_PARM, + MYKONOS_ERR_FRAMER_INV_LANEID_PARM, + MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM, + MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM, + MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM, + MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM, + MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM, + MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM, + MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM, + MYKONOS_ERR_DEFRAMER_INV_M_PARM, + MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM, + MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM, + MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM, + MYKONOS_ERR_DEFRAMER_INV_K_PARAM, + MYKONOS_ERR_DEFRAMER_INV_FK_PARAM, + MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM, + MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM, + MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM, + MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM, + MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM, + MYKONOS_ERR_INITARM_INV_DATARATE_PARM, + MYKONOS_ERR_INITARM_INV_REGCLK, + MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM, + MYKONOS_ERR_LOADHEX_INV_CHARCOUNT, + MYKONOS_ERR_LOADHEX_INVALID_FIRSTCHAR, + MYKONOS_ERR_LOADHEX_INVALID_CHKSUM, + MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT, + MYKONOS_ERR_ARM_INVALID_BUILDCHKSUM, + MYKONOS_ERR_READARMMEM_INV_ADDR_PARM, + MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM, + MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM, + MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM, + MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM, + MYKONOS_ERR_CHECKDEVSTRUCT_SPI, + MYKONOS_ERR_CHECKDEVSTRUCT_RX, + MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB, + MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR, + MYKONOS_ERR_CHECKDEVSTRUCT_TX, + MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB, + MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR, + MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX, + MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXSUB, + MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR, + MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR, + MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL, + MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL, + MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER, + MYKONOS_ERR_INITSER_INV_PROFILE, + MYKONOS_ERR_INITDES_INV_TXPROFILE, + MYKONOS_ERR_JESD204B_ILAS_MISMATCH, + MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL, + MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE, + MYKONOS_ERR_WRITE_CFG_MEMORY_FAILED, + MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM, + MYKONOS_ERR_RXFRAMER_INV_FK_PARAM, + MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM, + MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM, + MYKONOS_ERR_PU_OBSRXPATH_INV_LOSOURCE_PARAM, + MYKONOS_ERR_ARM_RADIOON_FAILED, + MYKONOS_ERR_INV_RX_GAIN_MODE_PARM, + MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM, + MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_RX_APD_THRESH_DIFF_VS_ATTACK_GAIN_STEP, + MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM, + MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM, + MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM, + MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_RX_BLOCK_DET_DECAY_PARM, + MYKONOS_ERR_INV_AGC_RX_APD_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_RECOVERY_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG, + MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION, + MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER, + MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC, + MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE, + MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE, + MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY, + MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH, + MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH, + MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH, + MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH, + MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP, + MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP, + MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP, + MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP, + MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE, + MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE, + MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT, + MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT, + MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_OBSRX_APD_THRESH_DIFF_VS_ATTACK_GAIN_STEP, + MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_BLOCK_DET_DECAY_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_APD_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_RECOVERY_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX_SELECT, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION, + MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER, + MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC, + MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE, + MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT, + MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE, + MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY, + MYKONOS_ERR_INV_AGC_OBSRX1_MAX_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX1_MIN_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX2_MAX_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX2_MIN_GAIN_INDEX, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP, + MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP, + MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM, + MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT, + MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CALPLL_LOCK, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLLCP, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLL_LOCK, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLLCP, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLL_LOCK, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLLCP, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLL_LOCK, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLLCP, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLL_LOCK, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXBBFCALDONE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXBBFCALDONE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RFDCCALDONE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ADCTUNECALDONE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX1ADCPROFILE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX2ADCPROFILE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ORXADCPROFILE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RCALDONE, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ARMBUSY, + MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_INITARMDONE, + MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY, + MYKONOS_ERR_PU_OBSRXPATH_ARMERROR, + MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR, + MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR, + MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR, + MYKONOS_ERR_SETRFPLL_ARMERROR, + MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM, + MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV, + MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED, + MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED, + MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED, + MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION, + MYKONOS_ERR_SETUP_PA_PROT_INV_STICKY_ENABLE, + MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP, + MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_ENABLE, + MYKONOS_ERR_SETUP_PA_PROT_INV_POWER_THRESH, + MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL, + MYKONOS_ERR_GET_DAC_PWR_INV_POINTER, + MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER, + MYKONOS_ERR_GET_OBSRX_OVERLOADS_NULL_PARM, + MYKONOS_ERR_GET_RX1_OVERLOADS_NULL_PARM, + MYKONOS_ERR_GET_RX2_OVERLOADS_NULL_PARM, + MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM, + MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM, + MYKONOS_ERR_ARM_RADIOOFF_FAILED, + MYKONOS_ERR_WAIT_INITCALS_NULL_PARAM, + MYKONOS_ERR_WAIT_INITCALS_CALFAILED, + MYKONOS_ERR_WAIT_INITCALS_ARMERROR, + MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM, + MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM, + MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM, + MYKONOS_ERR_PROGRAMFIR_NULL_PARM, + MYKONOS_ERR_PROGRAMFIR_COEFS_NULL, + MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM, + MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM, + MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM, + MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM, + MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM, + MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM, + MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM, + MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM, + MYKONOS_ERR_ARMCMD_NULL_PARM, + MYKONOS_ERR_WRITEARMMEM_NULL_PARM, + MYKONOS_ERR_LOADBIN_NULL_PARAM, + MYKONOS_ERR_ARM_INV_ADDR_PARM, + MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT, + MYKONOS_ERR_LOADARMCON_NULL_PARAM, + MYKONOS_ERR_GETTX1ATTEN_NULL_PARM, + MYKONOS_ERR_GETTX2ATTEN_NULL_PARM, + MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM, + MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM, + MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID, + MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID, + MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID, + MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM, + MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED, + MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED, + MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO, + MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED, + MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO, + MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED, + MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO, + MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED, + MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE, + MYKONOS_ERR_GETRFPLL_INV_PLLNAME, + MYKONOS_ERR_GETRFPLL_ARMERROR, + MYKONOS_ERR_GETRFPLL_NULLPARAM, + MYKONOS_ERR_INITARM_INV_VCODIV, + MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV, + MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV, + MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV, + MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN, + MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN, + MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN, + MYKONOS_ERR_GET_RX1_DEC_POWER_NUM_SAMPLES, + MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM, + MYKONOS_ERR_GET_RX2_DEC_POWER_NUM_SAMPLES, + MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM, + MYKONOS_ERR_GET_OBSRX_DEC_POWER_NUM_SAMPLES, + MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM, + MYKONOS_ERR_GETARMVER_NULL_PARM, + MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR, + MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR, + MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE, + MYKONOS_ERR_RESTDPDMOD_ARMSTATE, + MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL, + MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG, + MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE, + MYKONOS_ERR_SAVDPDMOD_ARMSTATE, + MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL, + MYKONOS_ERR_SAVDPDMOD_ARMERRFLAG, + MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG, + MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV, + MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT, + MYKONOS_ERR_CFGDPD_INV_DPDDAMPING, + MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES, + MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH, + MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT, + MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN, + MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT, + MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO, + MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN, + MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL, + MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG, + MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY, + MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL, + MYKONOS_ERR_READARMCFG_ARMERRFLAG, + MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM, + MYKONOS_ERR_ARMCMDSTATUS_ARMERROR, + MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT, + MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR, + MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT, + MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV, + MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG, + MYKONOS_ERR_GETDPDSTATUS_NULLPARAM, + MYKONOS_ERR_SETDEFOBSRXPATH_NULL_OBSRX_STRUCT, + MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT, + MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM, + MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG, + MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER, + MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM, + MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM, + MYKONOS_ERR_GETDPDSTATUS_INV_CH, + MYKONOS_ERR_GETCLGCSTATUS_INV_CH, + MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE, + MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE, + MYKONOS_ERR_TXFIR_TAPSEXCEEDED, + MYKONOS_ERR_TXFIR_INV_NUMROWS, + MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM, + MYKONOS_ERR_RXFIR_TAPSEXCEEDED, + MYKONOS_ERR_ORXFIR_TAPSEXCEEDED, + MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED, + MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM, + MYKONOS_ERR_GETINITCALSTATUS_ARMERROR, + MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS, + MYKONOS_ERR_CFGDPD_INV_MODELVERSION, + MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL, + MYKONOS_ERR_SETDPDACT_INV_STATE, + MYKONOS_ERR_SETDPDACT_ARMERRFLAG, + MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV, + MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT, + MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV, + MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT, + MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM, + MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT, + MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY, + MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL, + MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV, + MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR, + MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN, + MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL, + MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY, + MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT, + MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT, + MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV, + MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG, + MYKONOS_ERR_GETVSWRSTATUS_INV_CH, + MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM, + MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX, + MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX, + MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL, + MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL, + MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX, + MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX, + MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL, + MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE, + MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE, + MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE, + MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP, + MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP, + MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP, + MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL, + MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL, + MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL, + MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM, + MYKONOS_ERR_GETTXLOLSTATUS_INV_CH, + MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG, + MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM, + MYKONOS_ERR_GETTXQECSTATUS_INV_CH, + MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG, + MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM, + MYKONOS_ERR_GETRXQECSTATUS_INV_CH, + MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG, + MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM, + MYKONOS_ERR_GETORXQECSTATUS_INV_CH, + MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG, + MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV, + MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG, + + MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV, + MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG, + + MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM, + MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG, + MYKONOS_ERR_GETSTATEALL_TRACK_ARMERROR, + + MYKONOS_ERR_SETSTATE_TRACK_CAL_INV, + MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG, + + MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM, + MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG, + MYKONOS_ERR_GETSTATE_TRACK_ARMERROR, + + MYKONOS_ERR_ARMSTATE_PROFILE_ERROR, + MYKONOS_ERR_ARMSTATE_CAL_ERROR, + MYKONOS_ERR_ARMSTATE_EXCEPTION, + MYKONOS_ERR_WAITARMCSTATE_TIMEOUT, + + MYKONOS_ERR_GETPRODUCTID_NULL_PARAM, + MYKONOS_ERR_GET_API_VERSION_NULL_PARAM, + + MYKONOS_ERR_PROFILES_HSDIGCLK, + MYKONOS_ERR_RXPROFILE_RXCHANNEL, + MYKONOS_ERR_RXPROFILE_IQRATE, + MYKONOS_ERR_RXPROFILE_RFBW, + MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION, + MYKONOS_ERR_RXPROFILE_FIR_COEFS, + MYKONOS_ERR_RXPROFILE_ADCDIV, + MYKONOS_ERR_TXPROFILE_IQRATE, + MYKONOS_ERR_TXPROFILE_RFBW, + MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION, + MYKONOS_ERR_TXPROFILE_FIR_COEFS, + MYKONOS_ERR_TXPROFILE_DACDIV, + MYKONOS_ERR_RESET_TXLOL_INV_PARAM, + MYKONOS_ERR_RESET_TXLOL_ARMERROR, + MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY, + MYKONOS_ERR_SETRFPLL_LF_PLLNAME, + MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH, + MYKONOS_ERR_SETRFPLL_LF_INV_SNF_LOOPBANDWIDTH, + MYKONOS_ERR_SETRFPLL_LF_ARMERROR, + MYKONOS_ERR_GETRFPLL_LF_ARMERROR, + MYKONOS_ERR_GETRFPLL_LF_NULLPARAM, + MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME, + MYKONOS_ERR_DC_OFFSET_INV_CHAN, + MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT, + MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT, + MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT, + MYKONOS_ERR_RF_DC_OFFSET_INV_ENABLE_MASK, + MYKONOS_ERR_RF_DC_OFFSET_NULL_ENABLE_MASK, + MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT, + MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT, + MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK, + MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK, + MYKONOS_ERR_CFGCLGC_INV_THRESHOLD, + MYKONOS_ERR_RESETDPD_INV_TXCHANNEL, + MYKONOS_ERR_RESETDPD_ARMERRFLAG, + MYKONOS_ERR_RESETDPD_WRONG_PARAM, + MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE, + MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM, + MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE, + MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM, + MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION, + MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG, + + + MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM, + MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH, + MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG, + + MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT, + MYKONOS_ERR_SETDPDACT_INV_ACTMODE, + MYKONOS_ERR_SETDPDACT_INV_LEVEL, + MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT, + + MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT, + MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE, + MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL, + MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT, + + MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT, + MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE, + MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET, + MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE, + MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS, + MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS, + + MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT, + + MYKONOS_ERR_END +} mykonosErr_t; + +/** + * \brief Enum for Mykonos low voltage GPIO available pins + */ +typedef enum +{ + MYKGPIONAN = 0x00, + MYKGPIO0 = 0x1, + MYKGPIO1 = 0x2, + MYKGPIO2 = 0x4, + MYKGPIO3 = 0x8, + MYKGPIO4 = 0x10, + MYKGPIO5 = 0x20, + MYKGPIO6 = 0x40, + MYKGPIO7 = 0x80, + MYKGPIO8 = 0x100, + MYKGPIO9 = 0x200, + MYKGPIO10 = 0x400, + MYKGPIO11 = 0x800, + MYKGPIO12 = 0x1000, + MYKGPIO13 = 0x2000, + MYKGPIO14 = 0x4000, + MYKGPIO15 = 0x8000, + MYKGPIO16 = 0x10000, + MYKGPIO17 = 0x20000, + MYKGPIO18 = 0x40000 +} mykonosGpioSelect_t; + + +/** + * \brief Enum of valid Mykonos Enable State Machine (ENSM) states + */ +typedef enum +{ + WAIT = 0, /*!< Mykonos ENSM state upon which a power up in the WAIT/SLEEP state occurs */ + INIT = 1, /*!< Mykonos ENSM state upon which a power up delay state ocurrs to allow clocks to stabilize */ + WAITCALS = 2, /*!< Mykonos ENSM state upon which calibrations are initializing */ + ALERTCALS = 3, /*!< Mykonos ENSM state upon which calibrations are occurring */ + ALERTLDS = 4, /*!< Mykonos ENSM state upon which a delay state is occurring when moving from WAIT to ALERT to allow internal circuits to power up */ + ALERT = 5, /*!< Mykonos ENSM state upon which the internal RF synth is powered up, and TX and RX data paths are still powered down */ + TX_RX = 6, /*!< Mykonos ENSM state upon which the ability to power up data paths depending on the TxEnable/RxEnable pins or SPI bits */ + FLUSH = 7 /*!< Mykonos ENSM state upon which the data paths are cleared when exiting the TX_RX state */ +} mykonosEnsmState_t; + + +/** + * \brief Enum of possible Tx channels + */ +typedef enum +{ + TXOFF = 0, + TX1 = 1, + TX2 = 2, + TX1_TX2 = 3 +} mykonosTxChannels_t; + +/** + * \brief Enum of possible Rx channels + */ +typedef enum +{ + RXOFF = 0, + RX1 = 1, + RX2 = 2, + RX1_RX2 = 3 +} mykonosRxChannels_t; + +/** + * \brief Enum of possible Observation Rx channels + */ +typedef enum +{ + OBS_RXOFF = 0, + OBS_RX1_TXLO = 1, + OBS_RX2_TXLO = 2, + OBS_INTERNALCALS = 3, + OBS_SNIFFER = 4, + OBS_RX1_SNIFFERLO = 5, + OBS_RX2_SNIFFERLO = 6, + OBS_SNIFFER_A = 0x14, + OBS_SNIFFER_B = 0x24, + OBS_SNIFFER_C = 0x34 +} mykonosObsRxChannels_t; + +/** + * \brief Enum of possible Sniffer Rx channels + */ +typedef enum +{ + SNIFFER_A = 1, + SNIFFER_B = 2, + SNIFFER_C = 3 +} mykonosSnifferChannel_t; + +/** + * \brief Enum of possible Observation Rx channels to enable and run calibrations for during init. + * Choose ENUM value that enables all channels that will be used in the system. During system use, + * only one channel can be used at a time. This is also used to alert the ARM processor + * which observation channels are valid for the current desired system setup. + */ +typedef enum +{ + MYK_OBS_RXOFF = 0x00, + MYK_ORX1 = 0x01, + MYK_ORX2 = 0x02, + MYK_ORX1_ORX2 = 0x03, + MYK_SNRXA = 0x04, + MYK_SNRXB = 0x08, + MYK_SNRXC = 0x10, + MYK_SNRXA_B_C = 0x1C +} mykonosObsRxChannelsEn_t; + +/** + * \brief Enum of possible DAC divider settings (2x, 2.5x, 4x) + */ +typedef enum +{ + DACDIV_2, + DACDIV_2p5, + DACDIV_4 +} mykonosDacDiv_t; + +/** + * \brief Enum of possible VCO divider settings (1x, 1.5x, 2x, 3x) + */ +typedef enum +{ + VCODIV_1 = 0, + VCODIV_1p5 = 1, + VCODIV_2 = 2, + VCODIV_3 = 3 +} mykonosVcoDiv_t; + +/** + * \brief Enum of possible PRBS pattern settings + */ +typedef enum +{ + MYK_PRBS7 = 0, + MYK_PRBS15 = 1, + MYK_PRBS31 = 2 +} mykonosPrbsOrder_t; + +/** + * \brief Enum of RF PLL names + */ +typedef enum +{ + CLK_PLL, + RX_PLL, + TX_PLL, + SNIFFER_PLL +} mykonosRfPllName_t; + +/** + * \brief Enum of Rx profile types + */ +typedef enum +{ + MYK_RX_PROFILE, + MYK_OBS_PROFILE, + MYK_SNIFFER_PROFILE +} mykonosRxProfType_t; + +/** + * \brief Enum of ORx PLL names + */ +typedef enum +{ + OBSLO_TX_PLL, + OBSLO_SNIFFER_PLL +} mykonosObsRxLoSource_t; + +/** + * \brief Enum of possible wait events to use with MYKONOS_waitForEvent() + */ +typedef enum +{ + CALPLL_LOCK, + CLKPLLCP, + CLKPLL_LOCK, + RF_RXPLLCP, + RF_RXPLL_LOCK, + RF_TXPLLCP, + RF_TXPLL_LOCK, + RF_SNIFFERPLLCP, + RF_SNIFFERPLL_LOCK, + RXBBF_CALDONE, + TXBBF_CALDONE, + RX_RFDC_CALDONE, + RX_ADCTUNER_CALDONE, + RX1_ADCPROFILE, + RX2_ADCPROFILE, + ORX_ADCPROFILE, + RCAL_CALDONE, + ARMBUSY, + INITARM_DONE +} waitEvent_t; + +/** + * \brief Enum to set the desired FIR filter type for related functions + */ +typedef enum +{ + TX1_FIR = 1, + TX2_FIR = 2, + TX1TX2_FIR = 3, + RX1_FIR = 4, + RX2_FIR = 8, + RX1RX2_FIR = 12, + OBSRX_A_FIR = 16, + OBSRX_B_FIR = 32 +} mykonosfirName_t; + +/** + * \brief Enum to set the desired Rx gain table channel + */ +typedef enum +{ + RX1_GT = 1, + RX2_GT, + RX1_RX2_GT, + ORX_GT, + SNRX_GT, + LOOPBACK_GT +}mykonosGainTable_t; + +/** + * \brief Enum to set the Rx Gain control mode + */ +typedef enum +{ + MGC = 0, /*!< Manual Gain Control */ + AGC = 2, /*!< Automatic Gain Control (AGC) */ + HYBRID = 3 /*!< Hybrid AGC Gain Control */ + +} mykonosGainMode_t; + +/** + * \brief Enum to set the Tx Atenuation step size + */ +typedef enum +{ + TXATTEN_0P05_DB = 0, /*!< Tx attenuation 0.05dB step size */ + TXATTEN_0P1_DB = 1, /*!< Tx attenuation 0.1dB step size */ + TXATTEN_0P2_DB = 2, /*!< Tx attenuation 0.2dB step size */ + TXATTEN_0P4_DB = 3 /*!< Tx attenuation 0.4dB step size */ +} mykonosTxAttenStepSize_t; + +/** + * \brief Enum to help set the init calibration mask + */ +typedef enum +{ + TX_BB_FILTER = 0x0001, + ADC_TUNER = 0x0002, + TIA_3DB_CORNER = 0x0004, + DC_OFFSET = 0x0008, + TX_ATTENUATION_DELAY = 0x0010, + RX_GAIN_DELAY = 0x0020, + FLASH_CAL = 0x0040, + PATH_DELAY = 0x0080, + TX_LO_LEAKAGE_INTERNAL = 0x0100, + TX_LO_LEAKAGE_EXTERNAL = 0x0200, + TX_QEC_INIT = 0x0400, + LOOPBACK_RX_LO_DELAY = 0x0800, + LOOPBACK_RX_RX_QEC_INIT = 0x1000, + RX_LO_DELAY = 0x2000, + RX_QEC_INIT = 0x4000, + DPD_INIT = 0x8000, + CLGC_INIT = 0x10000, + VSWR_INIT = 0x20000 +} mykonosInitCalibrations_t; + +/** + * \brief Enum to help set the tracking calibration mask + */ +typedef enum +{ + TRACK_RX1_QEC = 0x00001, + TRACK_RX2_QEC = 0x00002, + TRACK_ORX1_QEC = 0x00004, + TRACK_ORX2_QEC = 0x00008, + TRACK_TX1_LOL = 0x00010, + TRACK_TX2_LOL = 0x00020, + TRACK_TX1_QEC = 0x00040, + TRACK_TX2_QEC = 0x00080, + TRACK_TX1_DPD = 0x00100, + TRACK_TX2_DPD = 0x00200, + TRACK_TX1_CLGC = 0x00400, + TRACK_TX2_CLGC = 0x00800, + TRACK_TX1_VSWR = 0x01000, + TRACK_TX2_VSWR = 0x02000, + TRACK_ORX1_QEC_SNLO = 0x10000, + TRACK_ORX2_QEC_SNLO = 0x20000, + TRACK_SRX_QEC = 0x40000 +} mykonosTrackingCalibrations_t; + + +/** + * \brief Enum to select the desired status calibration path delay read back + */ +typedef enum +{ + MYK_DPD_PATH_DELAY = 0, + MYK_CLGC_PATH_DELAY = 1, + MYK_VSWR_PATH_DELAY = 2 +} mykonosPathDelaySel_t; + +/** + * \brief Enum to set the GPIO3v3 mode + */ +typedef enum +{ + GPIO3V3_LEVELTRANSLATE_MODE = 1, /*!< Level translate mode, signal level on low voltage GPIO output on GPIO3v3 pins */ + GPIO3V3_INVLEVELTRANSLATE_MODE = 2, /*!< Inverted Level translate mode, inverse of signal level on low voltage GPIO output on GPIO3v3 pins */ + GPIO3V3_BITBANG_MODE = 3, /*!< Manual mode, API function sets output pin levels and reads input pin levels */ + GPIO3V3_EXTATTEN_LUT_MODE = 4 /*!< GPIO3v3 output level follows Rx1/Rx2 gain table external control 6bit field. */ +} mykonosGpio3v3Mode_t; + +/** + * \brief Enum to set the low voltage GPIO mode + */ +typedef enum +{ + GPIO_MONITOR_MODE = 0, /*!< Allows a choice of debug signals to output from Mykonos to monitor the state of the device */ + GPIO_BITBANG_MODE = 3, /*!< Manual mode, API function sets output pin levels and reads input pin levels */ + GPIO_ARM_OUT_MODE = 9, /*!< Allows internal ARM processor to output on GPIO pins */ + GPIO_SLICER_OUT_MODE = 10 /*!< Allows Slicer active configuration to the GPIO output pins */ +} mykonosGpioMode_t; + +/** + * \brief Enum for ARM states + */ +typedef enum +{ + MYK_ARM_POWERUP = 0x00, /*!< ARM is powered up and ready to be programmed */ + MYK_ARM_READY = 0x01, /*!< ARM enter this state once the boot up sequence is completed */ + MYK_ARM_IDLE = 0x02, /*!< ARM enter this state after initial calibrations are completed */ + MYK_ARM_RADIO_ON = 0x04, /*!< ARM has moved from MYKONOS_ARM_IDLE state into MYKONOS_ARM_RADIO_ON after the proper command, an abort command will move back to MYKONOS_ARM_IDLE state */ + MYK_ARM_PROFILE_ERROR = 0x08, /*!< ARM has detected an illegal profile */ + MYK_ARM_CAL_ERROR = 0x40, /*!< ARM has detected an error in the tracking calibrations */ + MYK_ARM_EXCEPTION = 0x80 /*!< ARM system problem has been detected */ +} mykonosArmState_t; + +/** + * \brief Enum for channel selection for DC offset settings. + */ +typedef enum +{ + MYK_DC_OFFSET_RX_CHN = 0x01, /*!< Select Rx channel */ + MYK_DC_OFFSET_ORX_CHN = 0x02, /*!< Select ORx channel */ + MYK_DC_OFFSET_SNF_CHN = 0x04 /*!< Select Sniffer channel */ +}mykonosDcOffsetChannels_t; + +/** + * \brief Enum of Rx channels for configuring (Enable /disable) DC offsets. + */ +typedef enum +{ + MYK_DC_OFFSET_ALL_OFF = 0x00, /*!< Disable all the channels */ + MYK_DC_OFFSET_RX1 = 0x01, /*!< Enables Rx1 */ + MYK_DC_OFFSET_RX2 = 0x02, /*!< Enables Rx2 */ + MYK_DC_OFFSET_SNF = 0x04, /*!< Enables Sniffer */ + MYK_DC_OFFSET_ORX = 0x08, /*!< Enables ORx */ + MYK_DC_OFFSET_AVAILABLE = 0x0F /*!< Enables all the channels */ +}mykonosRxDcOffsettEn_t; + +/** + * \brief Enum of build type + */ +typedef enum +{ + MYK_BUILD_RELEASE = 0X00, + MYK_BUILD_DEBUG = 0x01, + MYK_BUILD_TEST_OBJECT = 0x04 +}mykonosBuild_t; + +/** + * \brief Enum for DPD error codes + */ +typedef enum +{ + MYK_NO_ERROR = 0, /*!< No Error */ + MYK_ORX_DISABLED = 1, /*!< ORX_DISABLED */ + MYK_TX_DISABLED = 2, /*!< TX_DISABLED */ + MYK_PATHDELAY_NOT_SETUP = 3, /*!< PATHDELAY_NOT_SETUP */ + MYK_DPD_INIT_NOT_RUN = 4, /*!< DPD_INIT_NOT_RUN */ + MYK_ORX_SIG_TOO_LOW = 5, /*!< ORX_SIG_TOO_LOW */ + MYK_ORX_SIG_SATURATED = 6, /*!< ORX_SIG_SATURATED */ + MYK_TX_SIG_TOO_LOW = 7, /*!< TX_SIG_TOO_LOW */ + MYK_TX_SIG_SATURATED = 8, /*!< TX_SIG_SATURATED */ + MYK_MODEL_ERROR_HIGH = 9, /*!< MODEL_ERROR_HIGH */ + MYK_AM_AM_OUTLIERS = 10, /*!< AM_AM_OUTLIERS */ + MYK_INVALID_TX_PROFILE = 11, /*!< INVALID_TX_PROFILE */ + MYK_ORX_TRACKING_DISABLED = 12, /*!< ORX_TRACKING_DISABLED ORx tracking must be enabled */ + MYK_ERR_RESERVED_13 = 13, /*!< Reserved DPD error */ + MYK_ERR_BAD_ACTUATOR_MODEL = 14, /*!< DPD actuator model is in bad state */ + MYK_ERR_LOW_POWER_ACTUATOR_BYPASS = 15, /*!< DPD actuator bypassed due to low input power */ + + MYK_DPD_ERROR_END +} mykonosDpdErrors_t; + +/** + * \brief Enum for DPD reset modes + */ +typedef enum +{ + MYK_DPD_NO_ACTION = 0, /*!< DPD no Action error */ + MYK_DPD_RESET_FULL = 1, /*!< Full DPD reset */ + MYK_DPD_RESET_PRIOR = 4, /*!< Reset only prior model */ + MYK_DPD_RESET_CORRELATOR = 8, /*!< Reset correlator only */ + + MYK_DPD_RESET_END +} mykonosDpdResetMode_t; + + +/** + * \brief Enum for CLGC Tx attenuation tuning range modes + */ +typedef enum +{ + MYK_CLGC_ATTEN_TUNING_PRESET = 0, /*!< Set attenuation to the tx[]AttenTuningPreset */ + MYK_CLGC_ATTEN_DISCARD = 1, /*!< Ignore calculated attenuation level and keep the existing one */ + MYK_CLGC_ATTEN_UPDATE = 2, /*!< Set attenuation to tx[]AttenTuningPreset + tx[]AttenTuningRange if calculated attenuation is above this level + Set attenuation to tx[]AttenTuningPreset - tx[]AttenTuningRange if calculated attenuation is below this level*/ + + MYK_CLGC_ATTEN_END +} mykonosClgcAttenTuningMode_t; + +/** + * \brief Data structure to hold 3.3 VDC GPIO settings + */ +typedef struct +{ + uint16_t gpio3v3Oe; /*!< Pin direction: bit per 3.3v GPIO, 0=Input, 1=Output from Mykonos device */ + mykonosGpio3v3Mode_t gpio3v3SrcCtrl3_0; /*!< Mode for GPIO3v3[3:0] pins */ + mykonosGpio3v3Mode_t gpio3v3SrcCtrl7_4; /*!< Mode for GPIO3v3[7:4] pins */ + mykonosGpio3v3Mode_t gpio3v3SrcCtrl11_8; /*!< Mode for GPIO3v3[11:8] pins */ +} mykonosGpio3v3_t; + +/** + * \brief Data structure to hold low voltage GPIO settings + */ +typedef struct +{ + uint32_t gpioOe; /*!< Output Enable per low voltage GPIO pin (1=output, 0=input) */ + mykonosGpioMode_t gpioSrcCtrl3_0; /*!< Mode for low voltage GPIO[3:0] pins */ + mykonosGpioMode_t gpioSrcCtrl7_4; /*!< Mode for low voltage GPIO[7:4] pins */ + mykonosGpioMode_t gpioSrcCtrl11_8; /*!< Mode for low voltage GPIO[11:8] pins */ + mykonosGpioMode_t gpioSrcCtrl15_12; /*!< Mode for low voltage GPIO[15:12] pins */ + mykonosGpioMode_t gpioSrcCtrl18_16; /*!< Mode for low voltage GPIO[18:16] pins */ +} mykonosGpioLowVoltage_t; + +/** + * \brief Structure used within the DPD config structure to hold a int8_t complex number + */ +typedef struct{ + int8_t real; /*!< real part of the complex number */ + int8_t imag; /*!< imaginary part of the complex number */ +} int8_cpx; + +/** + * \brief Structure to configure DPD (Only valid for a DPD-enabled transceiver) + * \deprecated robustModeling member of this structure is no longer in use. + * This information is loaded into the ARM memory using the + * MYKONOS_configDpd() function before running the DPD init or tracking + * calibrations. These values can only be changed when the ARM is in the + * radioOff state. + */ +typedef struct +{ + uint8_t damping; /*!< 1/2^(damping + 8) fraction of previous model 'forgotten' per adaptation (default: 5 = '1/8192' , valid 0 to 15), 0 = infinite damping */ + uint8_t numWeights; /*!< number of weights to use for int8_cpx weights weights member of this structure (default = 1) */ + uint8_t modelVersion; /*!< DPD model version: one of four different generalized polynomial models: 0 = same as R0 silicon, 1-3 are new and the best one depends on the PA (default: 2) */ + uint8_t highPowerModelUpdate; /*!< 1 = Update saved model whenever peak Tx digital RMS is within 1dB of historical peak Tx RMS */ + uint8_t modelPriorWeight; /*!< Determines how much weight the loaded prior model has on DPD modeling (Valid 0 - 32, default 20) */ + uint8_t robustModeling; /*!< This is deprecated and no longer in use */ + uint16_t samples; /*!< number of samples to capture (default: 512, valid 64 - 32768) */ + uint16_t outlierThreshold; /*!< threshold for sample in AM-AM plot outside of 1:1 line to be thrown out. (default: 50% = 8192/2, valid 8192 to 1) */ + int16_t additionalDelayOffset; /*!< 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64) */ + uint16_t pathDelayPnSeqLevel; /*!< Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191) */ + int8_cpx weights[3]; /*!< DPD model error weighting (real/imag valid from -128 to 127) */ +} mykonosDpdConfig_t; + +/** + * \brief Structure to configure the feature to bypass DPD actuator when signal power below a threshold + * + */ +typedef struct +{ + uint8_t bypassActuatorEn; /*!< Enable/Disable feature to bypass actuator when input power below a certain threshold */ + mykonosDpdResetMode_t bypassActuatorMode; /*!< Follows reset DPD enum */ + uint16_t bypassActuatorLevel; /*!< Tx RMS level below which actuator is bypassed. P_dBFS = 20*log10(bypassActuatorLevel/8192) */ +} mykonosDpdBypassConfig_t; + + + +/** + * \brief Structure to configure the DPD actuator gain check + * + */ +typedef struct +{ + uint8_t actuatorGainCheckEn; /*!< Enable Gain check for DPD actuator */ + mykonosDpdResetMode_t actuatorGainCheckMode; /*!< Follows reset DPD enum */ + uint16_t actuatorGainCheckLevel; /*!< If the gain difference before and after the actuator exceeds this value an error will be issued + and the actuator will reset depending on the actuatorGainCheckMode, in 0.01dB, where a value of 200 => 2dB*/ +} mykonosDpdActuatorCheck_t; + +/** + * \brief Structure to configure CLGC (Closed Loop Gain Control) (Only valid for a DPD-enabled transceiver) + * + * This information is loaded into the ARM memory using the + * MYKONOS_configClgc() function before running the CLGC init or tracking + * calibrations. + * These values can be changed when the ARM is in the radioOff or radioOn states. + */ +typedef struct +{ + int16_t tx1DesiredGain; /*!< (value = 100 * dB (valid range -32768 to 32767) - total gain and attenuation from Mykonos Tx1 output to ORx1 input in (dB * 100) */ + int16_t tx2DesiredGain; /*!< (value = 100 * dB (valid range -32768 to 32767) - total gain and attenuation from Mykonos Tx2 output to ORx2 input in (dB * 100) */ + uint16_t tx1AttenLimit; /*!< (valid range 0 - 40dB), no default, depends on PA, Protects PA by making sure Tx1Atten is not reduced below the limit */ + uint16_t tx2AttenLimit; /*!< (valid range 0 - 40dB), no default, depends on PA, Protects PA by making sure Tx2Atten is not reduced below the limit */ + uint16_t tx1ControlRatio; /*!< valid range 1-100, default 45 */ + uint16_t tx2ControlRatio; /*!< valid range 1-100, default 45 */ + uint8_t allowTx1AttenUpdates; /*!< 0= allow CLGC to run, but Tx1Atten will not be updated. User can still read back power measurements. 1=CLGC runs, and Tx1Atten automatically updated */ + uint8_t allowTx2AttenUpdates; /*!< 0= allow CLGC to run, but Tx2Atten will not be updated. User can still read back power measurements. 1=CLGC runs, and Tx2Atten automatically updated */ + + int16_t additionalDelayOffset; /*!< 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64) */ + uint16_t pathDelayPnSeqLevel; /*!< Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191) */ + + uint16_t tx1RelThreshold; /*!< Threshold for Tx1 in order to stop tracking, value = 100 * dB, default 6db then value = 600 */ + uint16_t tx2RelThreshold; /*!< Threshold for Tx2 in order to stop tracking, value = 100 * dB, default 6db then value = 600 */ + uint8_t tx1RelThresholdEn; /*!< Threshold feature enable for Tx1, 0 = disable, 1 = enable, default = 0 */ + uint8_t tx2RelThresholdEn; /*!< Threshold feature enable for Tx2, 0 = disable, 1 = enable, default = 0 */ +} mykonosClgcConfig_t; + +/** + * \brief Structure to configure the CLGC attenuation tuning range + */ +typedef struct +{ + mykonosClgcAttenTuningMode_t tx1AttenTuningLimitMode; /*!< Tx1 CLGC Attenuation tuning mode */ + mykonosClgcAttenTuningMode_t tx2AttenTuningLimitMode; /*!< Tx2 CLGC Attenuation tuning mode */ + uint16_t tx1AttenTuningPreset; /*!< Tx1 CLGC nominal attenuation, valid range is 0 to 839 with a 0.05dB*/ + uint16_t tx2AttenTuningPreset; /*!< Tx2 CLGC nominal attenuation, valid range is 0 to 839 with a 0.05dB*/ + uint16_t tx1AttenTuningRange; /*!< Tx1 CLGC relative attenuation range around nominal attenuation, valid range is 0 to 420 with a 0.05dB*/ + uint16_t tx2AttenTuningRange; /*!< Tx2 CLGC relative attenuation range around nominal attenuation, valid range is 0 to 420 with a 0.05dB*/ +} mykonosClgcAttenTuningConfig_t; + +/** + * \brief Structure to configure VSWR (Only valid for a DPD-enabled transceiver) + * + * This information is loaded into the ARM memory using the + * MYKONOS_configVswr() function before running the VSWR init or tracking + * calibrations. + * These values can be changed when the ARM is in the radioOff states. + */ +typedef struct +{ + /* VSWR init cal parameters */ + int16_t additionalDelayOffset; /*!< 16th of an ORx sample (16=1sample), (default 0, valid -64 to 64) */ + uint16_t pathDelayPnSeqLevel; /*!< Default 255 (-30dBFs=(20Log10(value/8192)), (valid range 1 to 8191) */ + + /* VSWR tracking cal parameters */ + uint8_t tx1VswrSwitchGpio3p3Pin; /*!< 3p3V GPIO pin to use to control VSWR switch for Tx1 (valid 0-11) (output from Mykonos) */ + uint8_t tx2VswrSwitchGpio3p3Pin; /*!< 3p3V GPIO pin to use to control VSWR switch for Tx2 (valid 0-11) (output from Mykonos) */ + uint8_t tx1VswrSwitchPolarity; /*!< 3p3v GPIO pin polarity for forward path of Tx1, opposite used for reflection path (1 = high level, 0 = low level) */ + uint8_t tx2VswrSwitchPolarity; /*!< 3p3v GPIO pin polarity for forward path of Tx2, opposite used for reflection path (1 = high level, 0 = low level) */ + uint8_t tx1VswrSwitchDelay_us; /*!< Delay for Tx1 after flipping the VSWR switch until measurement is made. In us resolution with a range from 0 to 255us */ + uint8_t tx2VswrSwitchDelay_us; /*!< Delay for Tx2 after flipping the VSWR switch until measurement is made. In us resolution with a range from 0 to 255us */ +} mykonosVswrConfig_t; + +typedef struct +{ + /** + * errorStatus(decimal) | Description + * ---------------------|----------------------- + * 0 | NO ERROR (Tracking success) + * 1 | Tx data path not enabled + * 2 | ORX data path is not enabled + * 3 | Loopback switch closed + * 4 | VSWR init cal was not run + * 5 | Path delay not setup + * 6 | Data measurement was aborted + * 7 | VSWR disabled + * 8 | If set, entered cal but not finished + * 9 | No GPIO configured in single ORx configuration + * 10 | Tx is not observable with any of the ORx Channels + * 11 | ORX_TRACKING_DISABLED ORx tracking must be enabled + * + */ + uint32_t errorStatus; + uint32_t trackCount; /*!< Number of times VSWR tracking has run since last reset */ + int32_t forwardGainRms_dB; /*!< Forward RMS gain measured from Tx to ORx path (1 = 0.01 dB Gain) */ + int32_t forwardGainReal; /*!< Real part of the forward path complex gain (1 = 0.01 linear Gain) */ + int32_t forwardGainImag; /*!< Imaginary part of the forward path complex gain (1 = 0.01 linear Gain) */ + int32_t reflectedGainRms_dB; /*!< Measured reflection path gain in RMS (1 = 0.01 dB Gain) */ + int32_t reflectedGainReal; /*!< Real part of the reflection path complex gain (1 = 0.01 linear Gain) */ + int32_t reflectedGainImag; /*!< Imaginary part of the reflection path complex gain (1 = 0.01 linear Gain) */ + int32_t vswr_forward_tx_rms; /*!< Forward RMS measured from Tx path (1 = 0.01 dBFS) */ + int32_t vswr_forward_orx_rms; /*!< Forward RMS measured from ORx path (1 = 0.01 dBFS) */ + int32_t vswr_reflection_tx_rms; /*!< Reflected RMS measured from Tx path (1 = 0.01 dBFS) */ + int32_t vswr_reflection_orx_rms; /*!< Reflected RMS measured from ORx path (1 = 0.01 dBFS) */ +} mykonosVswrStatus_t; + +/** + * \brief Data structure to hold Mykonos FIR filter settings + */ +typedef struct +{ + int8_t gain_dB; /*!< Filter gain in dB*/ + uint8_t numFirCoefs; /*!< Number of coefficients in the FIR filter */ + int16_t *coefs; /*!< A pointer to an array of filter coefficients */ +} mykonosFir_t; + +/** + * \brief Data structure to hold Mykonos JESD204b Framer configuration settings + */ +typedef struct +{ + uint8_t bankId; /*!< JESD204B Configuration Bank ID extension to Device ID. Range is 0..15 */ + uint8_t deviceId; /*!< JESD204B Configuration Device ID link identification number. Range is 0..255 */ + uint8_t lane0Id; /*!< JESD204B Configuration starting Lane ID. If more than one lane is used, each lane will increment from the Lane0 ID. Range is 0..31 */ + uint8_t M; /*!< Number of ADCs (0, 2, or 4) where 2 ADCs are required per receive chain (I and Q) */ + uint8_t K; /*!< Number of frames in a multiframe. Default = 32, F*K must be modulo 4. Where, F=2*M/numberOfLanes */ + uint8_t scramble; /*!< Scrambling off if framerScramble = 0, if framerScramble > 0 scrambling is enabled */ + uint8_t externalSysref; /*!< External SYSREF select. 0 = use internal SYSREF, 1 = use external SYSREF */ + uint8_t serializerLanesEnabled; /*!< Serializer lane select bit field. Where, [0] = Lane0 enabled, [1] = Lane1 enabled, etc */ + uint8_t serializerLaneCrossbar; /*!< Lane crossbar to map framer lane outputs to physical lanes */ + uint8_t serializerAmplitude; /*!< Serializer amplitude setting. Default = 22. Range is 0..31 */ + uint8_t preEmphasis; /*!< Serializer pre-emphasis setting. Default = 4 Range is 0..7 */ + uint8_t invertLanePolarity; /*!< Lane inversion select. Default = 0. Where, bit[0] = 0 will invert lane [0], bit[1] = 0 will invert lane 1, etc. */ + uint8_t lmfcOffset; /*!< LMFC offset value for deterministic latency setting. Range is 0..31 */ + uint8_t newSysrefOnRelink; /*!< Flag for determining if SYSREF on relink should be set. Where, if > 0 = set, 0 = not set */ + uint8_t enableAutoChanXbar; /*!< Flag for determining if auto channel select for the xbar should be set. Where, if > 0 = set, '0' = not set */ + uint8_t obsRxSyncbSelect; /*!< Selects SYNCb input source. Where, 0 = use RXSYNCB for this framer, 1 = use OBSRX_SYNCB for this framer */ + uint8_t rxSyncbMode; /*!< Flag for determining if CMOS mode for RX Sync signal is used. Where, if > 0 = CMOS, '0' = LVDS */ + uint8_t overSample; /*!< Selects framer bit repeat or oversampling mode for lane rate matching. Where, 0 = bitRepeat mode (changes effective lanerate), 1 = overSample (maintains same lane rate between ObsRx framer and Rx framer and oversamples the ADC samples) */ + uint8_t enableManualLaneXbar; /*!< Flag for determining if API will calculate the appropriate settings for framer lane outputs to physical lanes. Where, if '0' = API will set automatic lane crossbar, '1' = set to manual mode and the value in serializerLaneCrossbar will be used */ +} mykonosJesd204bFramerConfig_t; + +/* NO Doxygen content required for this data structure as this is used internally */ +/// @cond +typedef struct +{ + uint8_t DID; /*!< JESD204B Configuration Device ID for ILAS check */ + uint8_t BID; /*!< JESD204B Configuration Bank ID for ILAS check */ + uint8_t LID0; /*!< JESD204B Configuration starting Lane ID for ILAS check */ + uint8_t L; /*!< JESD204B Configuration L = lanes per data converter for ILAS check */ + uint8_t SCR; /*!< JESD204B Configuration scramble setting for ILAS check */ + uint8_t F; /*!< JESD204B Configuration F = octets per frame for ILAS check */ + uint8_t K; /*!< JESD204B Configuration K = frames per multiframe for ILAS check */ + uint8_t M; /*!< JESD204B Configuration M = number of data converters for ILAS check */ + uint8_t N; /*!< JESD204B Configuration N = data converter sample resolution for ILAS check */ + uint8_t CS; /*!< JESD204B Configuration CS = number of control bits transferred per sample per frame for ILAS check */ + uint8_t NP; /*!< JESD204B Configuration NP = JESD204B word size based on the highest resolution of the data converter for ILAS check */ + uint8_t S; /*!< JESD204B Configuration S = number of samples/data converter/frame for ILAS check */ + uint8_t CF; /*!< JESD204B Configuration CF = '0' = control bits appended to each sample, '1' = appended to end of frame for ILAS check */ + uint8_t HD; /*!< JESD204B Configuration HD = high density bit - samples are contained within lane (0) or divided over more than one lane (1) for ILAS check */ + uint8_t FCHK0; /*!< JESD204B Configuration checksum for ILAS check */ +} mykonosJesd204bLane0Config_t; +/// @endcond + +/** +* \brief Data structure to hold the settings for the deserializer and deframer configuration +* +* EQ Settings | 3GHz Loss (dB) |6GHz Loss (dB) | max FR408HR Length (in) | max FR4 Length (in) +*-------------|----------------|---------------|-------------------------|--------------------- +* 0 | 6.5 | 14 | 20 | 12 +* 1 | 11.5 | 21 | 30 | 20 +* 2 | 18 | 31 | 46 | 32 +* 3 | 21.5 | 38 | 56 | 40 +* 4 | 22 | 39 | 60 | 43 +*/ +typedef struct +{ + uint8_t bankId; /*!< Extension to Device ID. Range is 0..15 */ + uint8_t deviceId; /*!< Link identification number. Range is 0..255 */ + uint8_t lane0Id; /*!< Lane0 ID. Range is 0..31 */ + uint8_t M; /*!< Number of DACs (0, 2, or 4) - 2 DACs per transmit chain (I and Q) */ + uint8_t K; /*!< Number of frames in a multiframe. Default = 32, F*K = modulo 4. Where, F=2*M/numberOfLanes */ + uint8_t scramble; /*!< Scrambling off if scramble = 0, if framerScramble > 0 scrambling is enabled */ + uint8_t externalSysref; /*!< External SYSREF select. 0 = use internal SYSREF, 1 = external SYSREF */ + uint8_t deserializerLanesEnabled; /*!< Deserializer lane select bit field. Where, [0] = Lane0 enabled, [1] = Lane1 enabled, etc */ + uint8_t deserializerLaneCrossbar; /*!< Lane crossbar to map physical lanes to deframer lane inputs [1:0] = Deframer Input 0 Lane section, [3:2] = Deframer Input 1 lane select, etc */ + uint8_t EQSetting; /*!< Equalizer setting. Applied to all deserializer lanes. Range is 0..4 */ + uint8_t invertLanePolarity; /*!< PN inversion per each lane. bit[0] = 1 Invert PN of Lane 0, bit[1] = Invert PN of Lane 1, etc */ + uint8_t lmfcOffset; /*!< LMFC offset value to adjust deterministic latency. Range is 0..31 */ + uint8_t newSysrefOnRelink; /*!< Flag for determining if SYSREF on relink should be set. Where, if > 0 = set, '0' = not set */ + uint8_t enableAutoChanXbar; /*!< Flag for determining if auto channel select for the xbar should be set. Where, if > 0 = set, '0' = not set */ + uint8_t txSyncbMode; /*!< Flag for determining if CMOS mode for TX Sync signal is used. Where, if > 0 = CMOS, '0' = LVDS */ + uint8_t enableManualLaneXbar; /*!< Flag for determining if API will calculate the appropriate settings for deframer lane in to physical lanes. Where, if '0' = API will set automatic lane crossbar, '1' = set to manual mode and the value in deserializerLaneCrossbar will be used */ +} mykonosJesd204bDeframerConfig_t; + +/** + * \brief Data structure to hold settings for the current Rx specific use case profile + */ +typedef struct +{ + uint8_t adcDiv; /*!< The divider used to generate the ADC clock (Valid: 1,2) */ + mykonosFir_t *rxFir; /*!< Pointer to Rx FIR filter structure */ + uint8_t rxFirDecimation; /*!< Rx FIR decimation (1,2,4) */ + uint8_t rxDec5Decimation; /*!< Decimation of Dec5 or Dec4 filter (5,4) */ + uint8_t enHighRejDec5; /*!< If set, and DEC5 filter used, will use a higher rejection DEC5 FIR filter. Where, 1 = enabled, 0 = disabled */ + uint8_t rhb1Decimation; /*!< RX Halfband1 (HB1) decimation. Can be either 1 or 2 */ + uint32_t iqRate_kHz; /*!< Rx IQ data rate in kHz */ + uint32_t rfBandwidth_Hz; /*!< Rx RF passband bandwidth for the profile */ + uint32_t rxBbf3dBCorner_kHz; /*!< Rx BBF (TIA) 3dB corner in kHz */ + uint16_t *customAdcProfile; /*!< Custom ADC profile to set the bandwidth of the ADC response */ +} mykonosRxProfile_t; + +/** + * \brief Data structure to hold settings for the current Tx specific use case profile + */ +typedef struct +{ + mykonosDacDiv_t dacDiv; /*!< The divider used to generate the DAC clock (ENUM Values)*/ + mykonosFir_t *txFir; /*!< Pointer to Tx FIR filter structure */ + uint8_t txFirInterpolation; /*!< The TX digital FIR filter interpolation (1,2,4) */ + uint8_t thb1Interpolation; /*!< Tx Halfband1 (HB1) filter interpolation (1,2) */ + uint8_t thb2Interpolation; /*!< Tx Halfband2 (HB2) filter interpolation (1,2) */ + uint8_t txInputHbInterpolation; /*!< Interpolation of half band filter before the programmable FIR (valid 1,2,4) */ + uint32_t iqRate_kHz; /*!< Tx IQ data rate in kHz */ + uint32_t primarySigBandwidth_Hz; /*!< Tx primary signal BW */ + uint32_t rfBandwidth_Hz; /*!< Tx RF passband bandwidth for the profile */ + uint32_t txDac3dBCorner_kHz; /*!< DAC filter 3dB corner in kHz */ + uint32_t txBbf3dBCorner_kHz; /*!< Tx BBF 3dB corner in kHz */ + uint8_t enableDpdDataPath; /*!< Enable Tx Dynamic pre distortion - only valid for a DPD-enabled transceiver */ +} mykonosTxProfile_t; + +/** + * \brief Data structure to hold SnRx gain control settings for initialization and during use + */ +typedef struct +{ + mykonosGainMode_t gainMode; /*!< Current Sniffer gain control mode setting */ + uint8_t gainIndex; /*!< Current Sniffer gain index. Can be used differently for Manual Gain control/AGC */ + uint8_t maxGainIndex; /*!< Max gain index for the currently loaded Sniffer Gain table */ + uint8_t minGainIndex; /*!< Min gain index for the currently loaded Sniffer Gain table */ +} mykonosSnifferGainControl_t; + +/** + * \brief Data structure to hold ORx gain control settings for initialization and during use + */ +typedef struct +{ + mykonosGainMode_t gainMode; /*!< Current ORx gain control mode setting */ + uint8_t orx1GainIndex; /*!< ORx1 Gain Index, can be used in different ways for manual and AGC gain control */ + uint8_t orx2GainIndex; /*!< ORx2 Gain Index, can be used in different ways for manual and AGC gain control */ + uint8_t maxGainIndex; /*!< Max gain index for the currently loaded ORx Gain table */ + uint8_t minGainIndex; /*!< Min gain index for the currently loaded ORx Gain table */ +} mykonosORxGainControl_t; + +/** + * \brief Data structure to hold Rx gain control settings for initialization and during use + */ +typedef struct +{ + mykonosGainMode_t gainMode; /*!< Current Rx gain control mode setting */ + uint8_t rx1GainIndex; /*!< Rx1 Gain Index, can be used in different ways for manual and AGC gain control */ + uint8_t rx2GainIndex; /*!< Rx2 Gain Index, can be used in different ways for manual and AGC gain control */ + uint8_t rx1MaxGainIndex; /*!< Max gain index for the currently loaded Rx1 Gain table */ + uint8_t rx1MinGainIndex; /*!< Min gain index for the currently loaded Rx1 Gain table */ + uint8_t rx2MaxGainIndex; /*!< Max gain index for the currently loaded Rx2 Gain table */ + uint8_t rx2MinGainIndex; /*!< Min gain index for the currently loaded Rx2 Gain table */ + uint8_t rx1Rssi; /*!< Stores Rx1 RSSI value read back from the Mykonos */ + uint8_t rx2Rssi; /*!< Stores Rx2 RSSI value read back from the Mykonos */ +} mykonosRxGainControl_t; + +/** + * \brief Data structure to hold peak detector settings for the AGC + */ +typedef struct +{ + /* Threshold Settings */ + uint8_t apdHighThresh; /*!< APD high threshold. Must be greater than apdLowThresh. Min = apdLowThresh, Max = 0x3F. 6-bit field. */ + uint8_t apdLowThresh; /*!< APD low threshold. Must be less than apdHighThresh. Min = 0, Max = apdHighThresh. 6-bit field. */ + uint8_t hb2HighThresh; /*!< HB2 high threshold. Must be greater than hb2LowThresh. Min = hb2LowThresh, Max = 0xFF. 8-bit field. */ + uint8_t hb2LowThresh; /*!< HB2 low threshold. Must be less than hb2HighThresh. Min = 0, Max = hb2HighThresh. 8-bit field. */ + uint8_t hb2VeryLowThresh; /*!< HB2 very low threshold. Must be less than hb2LowThresh. Min = 0, Max = hb2LowThresh. 8-bit field. */ + + /* Threshold Counter Settings */ + uint8_t apdHighThreshExceededCnt; /*!< APD high threshold exceeded counter. Sets number of peaks to detect above apdHighThresh to cause gain decrement according to apdHighGainStepAttack. 8-bit field. */ + uint8_t apdLowThreshExceededCnt; /*!< APD low threshold exceeded counter. Sets number of peaks to detect below apdLowThresh to cause gain increment according to apdLowGainStepRecovery. 8-bit field. */ + uint8_t hb2HighThreshExceededCnt; /*!< HB2 high threshold exceeded counter. Sets number of overloads to detect above hb2HighThresh to cause gain decrement according to hb2HighGainStepAttack. 8-bit field. */ + uint8_t hb2LowThreshExceededCnt; /*!< HB2 low threshold exceeded counter. Sets number of peaks to detect below hb2LowThresh to cause gain increment according to hb2LowGainStepRecovery. 8-bit field. */ + uint8_t hb2VeryLowThreshExceededCnt; /*!< HB2 very low threshold exceeded counter. Sets number of peaks to detect below hb2VeryLowThresh to cause gain increment according to hb2VeryLowGainStepRecovery. 8-bit field. */ + + /* Gain Step Settings */ + uint8_t apdHighGainStepAttack; /*!< Number of gain indices to decrement gain when apdHighThreshExceededCnt is exceeded. 5-bit field. */ + uint8_t apdLowGainStepRecovery; /*!< Number of gain indices to increment gain when apdLowThreshExceededCnt is exceeded. 5-bit field */ + uint8_t hb2HighGainStepAttack; /*!< Number of gain indices to decrement gain when hb2HighThreshExceededCnt is exceeded. 5-bit field */ + uint8_t hb2LowGainStepRecovery; /*!< Number of gain indices to increment gain when hb2LowThreshExceededCnt is exceeded. 5-bit field*/ + uint8_t hb2VeryLowGainStepRecovery; /*!< Number of gain indices to increment gain when hb2VeryLowThreshExceededCnt is exceeded. 5-bit field */ + + /* Fast Attack Settings */ + uint8_t apdFastAttack; /*!< [1] Enables APD fast attack mode - gain decrements immediately when apdHighThreshExceededCnt is exceeded. [0] disables APD fast attack mode - gain decrements at the expiry of agcGainUpdateCounter. 1-bit field. */ + uint8_t hb2FastAttack; /*!< [1] Enables HB2 fast attack mode - gain decrements immediately when hb2HighThreshExceededCnt is exceeded. [0] disables HB2 fast attack mode - gain decrements at the expiry of agcGainUpdateCounter. 1-bit field. */ + + /* HB2 Configuration Settings */ + uint8_t hb2OverloadDetectEnable; /*!< [1] Enables the HB2 overload detector. [0] Disables the HB2 overload detector. 1-bit field. */ + uint8_t hb2OverloadDurationCnt; /*!< Sets the samples size window of the HB2 overload detector. If hb2OverloadThreshCnt number of overloads are detected, the hb2xxxThreshExceededCnt increments. 3-bit field. [001]=1, [001]=4, [010]=8, [011]=12, [100]=16, [101]=24, [110]=32, [111]=INVALID */ + uint8_t hb2OverloadThreshCnt; /*!< Sets the number of individual overloads necessary within hb2OverloadDurationCnt samples to increment the hb2xxxThreshExceededCnt */ +} mykonosPeakDetAgcCfg_t; + +/** + * \brief Data structure to hold power measurement settings for the AGC + */ +typedef struct +{ + /* Threshold Settings */ + uint8_t pmdUpperHighThresh; /*!< Power measurement upper band, high threshold . This value is a positive offset to the pmdUpperLowThresh threshold. 4-bit field */ + uint8_t pmdUpperLowThresh; /*!< Power measurement upper band, low threshold. This value sets the threshold in (negative) -dBFS. Byte value must be less than pmdLowerHighThresh. 7-bit field */ + uint8_t pmdLowerHighThresh; /*!< Power measurement lower band, high threshold. This value sets the threshold in (negative) -dBFS. Byte value must be greater than pmdUpperLowThresh. 7-bit field */ + uint8_t pmdLowerLowThresh; /*!< Power measurement lower band, low threshold. This value is a negative offset to the pmdLowerHighThresh threshold. 4-bit field */ + + /* Gain Step Settings */ + uint8_t pmdUpperHighGainStepAttack; /*!< Number of gain indices to decrement gain if pmdUpperHighThresh is exceeded by the end of the agcGainUpdateCounter. 5-bit field */ + uint8_t pmdUpperLowGainStepAttack; /*!< Number of gain indices to decrement gain if pmdUpperLowThresh is exceeded by the end of the agcGainUpdateCounter. 5-bit field */ + uint8_t pmdLowerHighGainStepRecovery; /*!< Number of gain indices to increment gain if pmdLowerHighThresh is not exceeded by the end of the agcGainUpdateCounter. 5-bit field */ + uint8_t pmdLowerLowGainStepRecovery; /*!< Number of gain indices to increment gain if pmdLowerLowThresh is not exceeded by the end of the agcGainUpdateCounter. 5-bit field */ + + /* PMD Configuration Settings */ + uint8_t pmdMeasDuration; /*!< Number of samples to measure power on. The number of samples corresponding to the 4-bit word is 8*2^(pmdMeasDuration[3:0]). This value must be less than agcGainUpdateCounter */ + uint8_t pmdMeasConfig; /*!< Power measurement configuration. 2-bit field. [00]=PMD disabled, [01]=PMD Enabled at HB2 output, [10]=Enabled at RFIR output (recommended), [11]=PMD Enabled at BBDC2 */ +} mykonosPowerMeasAgcCfg_t; + +/** + * \brief Data structure to hold general AGC settings for initialization and during use + */ +typedef struct +{ + /* Gain Table Settings */ + uint8_t agcRx1MaxGainIndex; /*!< Maximum Rx1 gain index allowed in AGC mode. Must be greater than agcRx1MinGainIndex and valid gain index. 8-bit field */ + uint8_t agcRx1MinGainIndex; /*!< Minimum Rx1 gain index allowed in AGC mode. Must be less than agcRx1MinGainIndex and valid gain index. 8-bit field */ + uint8_t agcRx2MaxGainIndex; /*!< Maximum Rx2 gain index allowed in AGC mode. Must be greater than agcRx2MinGainIndex and valid gain index. 8-bit field */ + uint8_t agcRx2MinGainIndex; /*!< Minimum Rx2 gain index allowed in AGC mode. Must be less than agcRx2MinGainIndex and valid gain index. 8-bit field */ + uint8_t agcObsRxMaxGainIndex; /*!< Maximum ObsRx gain index allowed in AGC mode. Must be greater than agcObsRxMinGainIndex and valid gain index. 8-bit field */ + uint8_t agcObsRxMinGainIndex; /*!< Minimum ObsRx gain index allowed in AGC mode. Must be less than agcObsRxMaxGainIndex and valid gain index. 8-bit field */ + uint8_t agcObsRxSelect; /*!< Sniffer or ObsRx AGC channel select. [1] = SnRx */ + + /* AGC Mode Selection */ + uint8_t agcPeakThresholdMode; /*!< [1] = Peak Threshold Mode, power based gain changes are disabled. [0] = Peak and overload detectors are ignored for gain changes */ + uint8_t agcLowThsPreventGainIncrease; /*!< [1] PMD based gain increments are ignored if apd/hb2LowThreshExceedCnt is high [0] apdLowThreshExceededCnt and hb2LowThreshExceededCnt are "Don't cares" to the AGC gain recovery */ + + /* AGC General Settings */ + uint32_t agcGainUpdateCounter; /*!< Number of samples for the AGC gain update counter. Counter operates on the IQ data rate. 22-bit field. Min = 0x000001, Max = 0x3FFFFF */ + uint8_t agcSlowLoopSettlingDelay; /*!< Number of IQ data rate clock cycles to wait after a gain change before peak/power measurements resume. 7-bit field */ + uint8_t agcPeakWaitTime; /*!< Number of IQ data rate clock cycles to wait to enable peak/overload detectors after AGC is enabled. 5-bit field. Min = 0x02. Max = 0x1F */ + uint8_t agcResetOnRxEnable; /*!< [1] = Performs a reset of the AGC slow loop state machine when Rx is disabled. [0] = AGC slow loop state machine maintains its state when Rx is disabled. */ + uint8_t agcEnableSyncPulseForGainCounter; /*!< [1] = Allows sync of agcGainUpdateCounter to the time-slot boundary. GPIO setup required. [0] = agcGainUpdateCounter functions as normal */ + + mykonosPeakDetAgcCfg_t *peakAgc; /*!< pointer to structure for Peak AGC */ + mykonosPowerMeasAgcCfg_t *powerAgc; /*!< pointer to structure for Power AGC */ +} mykonosAgcCfg_t; + +/** + * \brief Data structure to hold Tx data path settings + */ +typedef struct +{ + mykonosTxProfile_t *txProfile; /*!< Tx datapath profile, 3dB corner frequencies, and digital filter enables */ + mykonosJesd204bDeframerConfig_t *deframer; /*!< Mykonos JESD204b deframer config for the Tx data path */ + mykonosTxChannels_t txChannels; /*!< The desired Tx channels to enable during initialization */ + uint8_t txPllUseExternalLo; /*!< Internal LO=0, external LO*2 if =1 */ + uint64_t txPllLoFrequency_Hz; /*!< Tx PLL LO frequency (internal or external LO) */ + mykonosTxAttenStepSize_t txAttenStepSize; /*!< Tx Attenuation step size */ + uint16_t tx1Atten_mdB; /*!< Initial and current Tx1 Attenuation */ + uint16_t tx2Atten_mdB; /*!< Initial and current Tx2 Attenuation */ + mykonosDpdConfig_t *dpdConfig; /*!< DPD settings. Only valid for a DPD-enabled transceiver, set pointer to NULL otherwise */ + mykonosClgcConfig_t *clgcConfig; /*!< CLGC settings. Only valid for a DPD-enabled transceiver, set pointer to NULL otherwise */ + mykonosVswrConfig_t *vswrConfig; /*!< VSWR settings. Only valid for a DPD-enabled transceiver, set pointer to NULL otherwise */ +} mykonosTxSettings_t; + +/** + * \brief Data structure to hold Rx data path settings + */ +typedef struct +{ + mykonosRxProfile_t *rxProfile; /*!< Rx datapath profile, 3dB corner frequencies, and digital filter enables */ + mykonosJesd204bFramerConfig_t *framer; /*!< Rx JESD204b framer configuration structure */ + mykonosRxGainControl_t *rxGainCtrl; /*!< Rx Gain control settings structure */ + mykonosAgcCfg_t *rxAgcCtrl; /*!< Rx AGC control settings structure */ + mykonosRxChannels_t rxChannels; /*!< The desired Rx Channels to enable during initialization */ + uint8_t rxPllUseExternalLo; /*!< Internal LO = 0, external LO*2 = 1 */ + uint64_t rxPllLoFrequency_Hz; /*!< Rx PLL LO Frequency (internal or external LO) */ + uint8_t realIfData; /*!< Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where, if > 0 = real IF data, '0' = zero IF (IQ) data*/ +} mykonosRxSettings_t; + +/** + * \brief Data structure to hold ORx data path settings + */ +typedef struct +{ + mykonosRxProfile_t *orxProfile; /*!< ORx datapath profile, 3dB corner frequencies, and digital filter enables. */ + mykonosORxGainControl_t *orxGainCtrl; /*!< ObsRx gain control settings structure */ + mykonosAgcCfg_t *orxAgcCtrl; /*!< ORx AGC control settings structure */ + mykonosRxProfile_t *snifferProfile; /*!< Sniffer datapath profile, 3dB corner frequencies, and digital filter enables. */ + mykonosSnifferGainControl_t *snifferGainCtrl; /*!< SnRx gain control settings structure */ + mykonosJesd204bFramerConfig_t *framer; /*!< ObsRx JESD204b framer configuration structure */ + mykonosObsRxChannelsEn_t obsRxChannelsEnable; /*!< The desired ObsRx channels to configure/calibrate during initialization */ + mykonosObsRxLoSource_t obsRxLoSource; /*!< The sniffer/ORx mixers can use the TX_PLL or SNIFFER_PLL */ + uint64_t snifferPllLoFrequency_Hz; /*!< SnRx PLL LO frequency in Hz */ + uint8_t realIfData; /*!< Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where if > 0 = real IF data, '0' = complex data */ + uint16_t *customLoopbackAdcProfile; /*!< Custom Loopback ADC profile to set the bandwidth of the ADC response */ + mykonosObsRxChannels_t defaultObsRxChannel; /*!< Default ObsRx channel to enter when radioOn called */ +} mykonosObsRxSettings_t; + + +/** + * \brief Data structure to hold ARM GPIO pin assignments for each ARM input/output pin. + */ +typedef struct +{ + uint8_t useRx2EnablePin; /*!< 0= RX1_ENABLE controls RX1 and RX2, 1 = separate RX1_ENABLE/RX2_ENABLE pins */ + uint8_t useTx2EnablePin; /*!< 0= TX1_ENABLE controls TX1 and TX2, 1 = separate TX1_ENABLE/TX2_ENABLE pins */ + uint8_t txRxPinMode; /*!< 0= ARM command mode, 1 = Pin mode to power up Tx/Rx chains */ + uint8_t orxPinMode; /*!< 0= ARM command mode, 1 = Pin mode to power up ObsRx receiver*/ + + /* Mykonos ARM input GPIO pins -- Only valid if orxPinMode = 1 */ + uint8_t orxTriggerPin; /*!< Select desired GPIO pin (valid 4-15) */ + uint8_t orxMode2Pin; /*!< Select desired GPIO pin (valid 0-18) */ + uint8_t orxMode1Pin; /*!< Select desired GPIO pin (valid 0-18) */ + uint8_t orxMode0Pin; /*!< Select desired GPIO pin (valid 0-18) */ + + /* Mykonos ARM output GPIO pins -- always available, even when pin mode not enabled*/ + uint8_t rx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t rx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t tx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t tx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t orx1EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t orx2EnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t srxEnableAck; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + uint8_t txObsSelect; /*!< Select desired GPIO pin (0-15), [4] = Output Enable */ + /* When 2Tx are used with only 1 ORx input, this GPIO tells the BBIC which Tx channel is */ + /* active for calibrations, so BBIC can route correct RF Tx path into the single ORx input */ +} mykonosArmGpioConfig_t; + +/** + * \brief Data structure to hold auxiliary IO settings (AuxDAC, ARM GPIO, GPIO3.3v, low voltage GPIO, HSCP, etc) + */ +typedef struct +{ + uint16_t auxDacEnable; /*!< Aux DAC enable. One bit per Aux DAC. Where bit[0] = Aux DAC 0, bit[1] = Aux DAC 1, etc */ + uint16_t auxDacValue[10]; /*!< Aux DAC value */ + uint8_t auxDacSlope[10]; /*!< Aux DAC slope */ + uint8_t auxDacVref[10]; /*!< Aux DAC voltage reference value */ + + mykonosGpio3v3_t *gpio3v3; /*!< GPIO 3.3 VDC settings data structure pointer */ + mykonosGpioLowVoltage_t *gpio; /*!< Low voltage GPIO settings data structure pointer */ + mykonosArmGpioConfig_t *armGpio; /*!< Mykonos ARM GPIO settings*/ +} mykonosAuxIo_t; + +/** + * \brief Data structure to hold digital clock settings + */ +typedef struct +{ + uint32_t deviceClock_kHz; /*!< CLKPLL and device reference clock frequency in kHz */ + uint32_t clkPllVcoFreq_kHz; /*!< CLKPLL VCO frequency in kHz */ + mykonosVcoDiv_t clkPllVcoDiv; /*!< CLKPLL VCO divider */ + uint8_t clkPllHsDiv; /*!< CLKPLL high speed clock divider */ +} mykonosDigClocks_t; + + +/** + * \brief Data structure used to read back the Init Calibration Status + */ +typedef struct +{ + uint32_t calsDoneLastRun; /*!< Init cals that completed in the last call to MYKONOS_runInitCals() */ + uint32_t calsDoneLifetime; /*!< Init cals that have completed successfully since loading of the ARM processor */ + uint32_t calsMinimum; /*!< Minimum set of init cals that must complete before device can move to radioOn state */ + uint8_t initErrCal; /*!< If an init cal had an error, this represents the opcode of the init cal that reported an error */ + uint8_t initErrCode; /*!< If an init cal had an error, this represents the ARM error code describing the failure */ +} mykonosInitCalStatus_t; + +/** + * \brief Data structure used to read back DPD calibration status + */ +typedef struct +{ + /** + * dpdErrorStatus (decimal) | Description + * --------------------------|----------------------- + * 0 | No Error + * 1 | ORX_DISABLED + * 2 | TX_DISABLED + * 3 | PATHDELAY_NOT_SETUP + * 4 | DPD_INIT_NOT_RUN + * 5 | ORX_SIG_TOO_LOW + * 6 | ORX_SIG_SATURATED + * 7 | TX_SIG_TOO_LOW + * 8 | TX_SIG_SATURATED + * 9 | MODEL_ERROR_HIGH + * 10 | AM_AM_OUTLIERS + * 11 | INVALID_TX_PROFILE + * 12 | ORX_TRACKING_DISABLED ORx tracking must be enabled + * 13 | Cal suspended + * 14 | Reserved + * 15 | Reserved + * 16 | Reserved + * 17 | Reserved + * 18 | Reserved + */ + uint32_t dpdErrorStatus; + uint32_t dpdTrackCount; /*!< Number of times DPD tracking has run since last reset */ + uint32_t dpdModelErrorPercent; /*!< Percent Error of PA model * 10 to include 1 decimal place */ + uint32_t dpdExtPathDelay; /*!< External path delay from Tx output to ORx input, at 1/16 sample resolution of ORx sample rate */ + uint16_t dpdMaxAdaptationCurrent; /*!< max amplitude of current adaptation */ + uint16_t dpdMaxAdaptation; /*!< max amplitude of adaptation since DPD started*/ + uint32_t dpdIterCount; /*!< number of times DPD tracking has run since last reset*/ +} mykonosDpdStatus_t; + +/** + * \brief Data structure used to read back CLGC calibration status + */ +typedef struct +{ + /** + * clgcErrorStatus(decimal) | Description + * -------------------------|----------------------- + * 0 | NO ERROR + * 1 | TX Disabled + * 2 | ORx is disabled + * 3 | Loopback switch is clo + * 4 | Data measurement aborted during capture + * 5 | No initial calibration was done + * 6 | Path delay not setup + * 7 | No apply control is possible + * 8 | Control value is out of range + * 9 | CLGC feature is disabled + * 10 | TX attenuation is capped + * 11 | Gain measurement + * 12 | No GPIO configured in single ORx configuration + * 13 | Tx is not observable with any of the ORx Channels + * 14 | ORX_TRACKING_DISABLED ORx tracking must be enabled + * 15 | PA Protection Activated + * 16 | Relative Threshold Violated + * 17 | RESERVED + * 18 | Tx power too low + * 19 | ORx power too low + */ + uint32_t errorStatus; + uint32_t trackCount; /*!< Number of times CLGC tracking has run since last reset */ + int32_t desiredGain; /*!< Desired gain/attenuation from Tx output to ORx input of Mykonos device. 0.01 dB resolution */ + int32_t currentGain; /*!< Current measured gain in 0.01 dB resolution. */ + uint32_t txGain; /*!< Current TxAttenuation setting, same as MYKONOS_getTx1/2Attenuation(), in 0.05dB resolution */ + int32_t txRms; /*!< Tx digital sample power measured at DPD block input (0.01 dB resolution) */ + int32_t orxRms; /*!< ORx digital sample power measured at ORx port (0.01 dB resolution) */ +} mykonosClgcStatus_t; + +/** + * \brief Data structure to hold Tx LOL Status + */ +typedef struct +{ + uint32_t errorCode; /*!< error code from Tx LOL */ + uint32_t percentComplete; /*!< percent of required data collected for the current cal. Range 0 to 100 */ + uint32_t performanceMetric; /*!< Variance of the corrections, and gives an indication in dB on how much LO leakage is corrected on an average tracking pass. */ + uint32_t iterCount; /*!< running counter that increments each time the cal runs to completion */ + uint32_t updateCount; /*!< running counter that increments each time the cal updates the correction/actuator hardware */ +} mykonosTxLolStatus_t; + +/** + * \brief This structure contains the internal path delay + * + */ +typedef struct +{ + uint32_t forwardPathDelayCh1; /*!< Forward path delay for Channel 1 valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate */ + uint32_t reversePathDelayCh1; /*!< Reverse path delay for Channel 1 valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate */ + uint32_t forwardPathDelayCh2; /*!< Forward path delay for Channel 2 valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate */ + uint32_t reversePathDelayCh2; /*!< Reverse path delay for Channel 2 valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate */ +} mykonosPathdelay_t; + +/** + * \brief This structure contains the DPD error status counters for the different errors + * + */ +typedef struct +{ + uint32_t dpdErrorCount; /*!< DPD total error count */ + uint32_t errorCounter[MYK_DPD_ERROR_END]; /*!< array for individual error counters corresponding to ::mykonosDpdErrors_t */ +} mykonosDpdErrorCounters_t; + +/** + * \brief Data structure to hold Tx QEC Status + */ +typedef struct +{ + uint32_t errorCode; /*!< error code from Tx QEC */ + uint32_t percentComplete; /*!< percent of required data collected for the current cal. Range 0 to 100 */ + uint32_t performanceMetric; /*!< Number of codes adjusted which is the number of codes of correction made last time which can be converted to an IRR power metric as with Rx QEC, if desired. */ + uint32_t iterCount; /*!< running counter that increments each time the cal runs to completion */ + uint32_t updateCount; /*!< running counter that increments each time the cal updates the correction/actuator hardware */ +} mykonosTxQecStatus_t; + +/** + * \brief Data structure to hold Rx QEC Status + */ +typedef struct +{ + uint32_t errorCode; /*!< error code from Rx QEC */ + uint32_t percentComplete; /*!< percent of required data collected for the current cal. Range 0 to 100 */ + uint32_t selfcheckIrrDb; /*!< selfCheckIrrdDb - Power-weighted average Image Rejection Ratio (IRR) in dBc. */ + uint32_t iterCount; /*!< running counter that increments each time the cal runs to completion */ + uint32_t updateCount; /*!< running counter that increments each time the cal updates the correction/actuator hardware */ +} mykonosRxQecStatus_t; + +/** + * \brief Data structure to hold Orx QEC Status + */ +typedef struct +{ + uint32_t errorCode; /*!< error code from Orx QEC */ + uint32_t percentComplete; /*!< percent of required data collected for the current cal. Range 0 to 100 */ + uint32_t selfcheckIrrDb; /*!< selfCheckIrrdDb - Power-weighted average Image Rejection Ratio (IRR) in dBc. */ + uint32_t iterCount; /*!< running counter that increments each time the cal runs to completion */ + uint32_t updateCount; /*!< running counter that increments each time the cal updates the correction/actuator hardware */ +} mykonosOrxQecStatus_t; + +/** + * \brief Data structure to hold Mykonos device settings + */ +typedef struct +{ + spiSettings_t *spiSettings; /*!< SPI settings data structure pointer */ + mykonosRxSettings_t *rx; /*!< Rx settings data structure pointer */ + mykonosTxSettings_t *tx; /*!< Tx settings data structure pointer */ + mykonosObsRxSettings_t *obsRx; /*!< ObsRx settings data structure pointer */ + mykonosAuxIo_t *auxIo; /*!< Auxiliary IO settings data structure pointer */ + mykonosDigClocks_t *clocks; /*!< Holds settings for CLKPLL and reference clock */ + uint8_t profilesValid; /*!< Mykonos initialize function uses this as an output to remember which profile data structure pointers are valid */ +} mykonosDevice_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/hardware/mykonos/t_mykonos_gpio.h b/src/hardware/mykonos/t_mykonos_gpio.h new file mode 100644 index 0000000..71f2cf9 --- /dev/null +++ b/src/hardware/mykonos/t_mykonos_gpio.h @@ -0,0 +1,375 @@ +/*! + * \file t_mykonos_gpio.h + * \brief Mykonos GPIO error handling and type defines + * + * Mykonos API version: 1.5.2.3566 + */ + +/** +* \page Disclaimer Legal Disclaimer +* Copyright 2015-2017 Analog Devices Inc. +* Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file. +* +*/ + +#ifndef T_MYKONOSGPIO_H_ +#define T_MYKONOSGPIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "../common.h" + +/** + * \brief Enum of unique error codes from the Mykonos GPIO API functions. + * Each error condition in the library should get its own enum value to allow + * easy debug of errors. + */ +typedef enum +{ + MYKONOS_ERR_GPIO_OK = 0, + MYKONOS_ERR_EN_MONITOR_OUT_NOT_ENABLED, + MYKONOS_ERR_EN_MONITOR_OUT_SRC_CTRL, + MYKONOS_ERR_MONITOR_OUT_INDEX_RANGE, + MYKONOS_ERR_GETGPIOMON_INDEX_NULL_PARM, + MYKONOS_ERR_GETGPIOMON_MONITORMASK_NULL_PARM, + + MYKONOS_ERR_MGCRX2_GPIO_DECPIN_INV_PARAM, + MYKONOS_ERR_MGCRX2_GPIO_INCPIN_INV_PARAM, + MYKONOS_ERR_MGCRX2_SOURCE_CONFIG, + MYKONOS_ERR_MGCRX2_STEP_INV_PARAM, + MYKONOS_ERR_MGCRX1_GPIO_DECPIN_INV_PARAM, + MYKONOS_ERR_MGCRX1_GPIO_INCPIN_INV_PARAM, + MYKONOS_ERR_MGCRX1_STEP_INV_PARAM, + MYKONOS_ERR_GETRX2PIN_INCSTEP_NULL_PARM, + MYKONOS_ERR_GETRX2PIN_DECSTEP_NULL_PARM, + MYKONOS_ERR_GETRX2PIN_INCPIN_NULL_PARM, + MYKONOS_ERR_GETRX2PIN_DECPIN_NULL_PARM, + MYKONOS_ERR_GETRX2PIN_EN_NULL_PARM, + MYKONOS_ERR_GETRX1PIN_INCSTEP_NULL_PARM, + MYKONOS_ERR_GETRX1PIN_DECSTEP_NULL_PARM, + MYKONOS_ERR_GETRX1PIN_INCPIN_NULL_PARM, + MYKONOS_ERR_GETRX1PIN_DECPIN_NULL_PARM, + MYKONOS_ERR_GETRX1PIN_EN_NULL_PARM, + + MYKONOS_ERR_TPCTX2_GPIO_DECPIN_INV_PARAM, + MYKONOS_ERR_TPCTX2_GPIO_INCPIN_INV_PARAM, + MYKONOS_ERR_TPCTX2_GPIO_STEP_INV_PARAM, + MYKONOS_ERR_TPCTX1_GPIO_DECPIN_INV_PARAM, + MYKONOS_ERR_TPCTX1_GPIO_INCPIN_INV_PARAM, + MYKONOS_ERR_TPCTX1_GPIO_STEP_INV_PARAM, + MYKONOS_ERR_GETTX2PIN_STEP_NULL_PARM, + MYKONOS_ERR_GETTX2PIN_INC_NULL_PARM, + MYKONOS_ERR_GETTX2PIN_DEC_NULL_PARM, + MYKONOS_ERR_GETTX2PIN_EN_NULL_PARM, + MYKONOS_ERR_GETTX2PIN_TX1TX2_NULL_PARM, + MYKONOS_ERR_GETTX1PIN_STEP_NULL_PARM, + MYKONOS_ERR_GETTX1PIN_INC_NULL_PARM, + MYKONOS_ERR_GETTX1PIN_DEC_NULL_PARM, + MYKONOS_ERR_GETTX1PIN_EN_NULL_PARM, + MYKONOS_ERR_GETTX1PIN_TX1TX2_NULL_PARM, + + MYKONOS_ERR_SPI2_INV_GPIO, + MYKONOS_ERR_SPI2_INV_SETUP, + + MYKONOS_ERR_SET_GPIO_1V8_INV_POINTER, + + MYKONOS_ERR_GETGPIOSETLEVEL_NULL_PARM, + MYKONOS_ERR_READGPIOSPI_NULL_PARM, + MYKONOS_ERR_SET_GPIO_1V8_INV_MODE, + MYKONOS_ERR_GETGPIO_OE_NULL_PARM, + MYKONOS_ERR_GPIO_OE_INV_PARAM, + MYKONOS_ERR_GPIO_SRC_PARAM_INV, + MYKONOS_ERR_GET_GPIO_SOURCE_CONTROL_NULL_PARM, + + MYKONOS_ERR_INV_GP_INT_MASK_PARM, + MYKONOS_ERR_GP_INT_STATUS_NULL_PARAM, + + MYKONOS_ERR_GETGPIO3V3OUT_NULL_PARM, + MYKONOS_ERR_SET_GPIO_3V3_INV_POINTER, + MYKONOS_ERR_GETGPIO3V3SPI_NULL_PARM, + MYKONOS_ERR_GPIO3V3OUTEN_NULL_PARM, + MYKONOS_ERR_SET_GPIO_3V3_INV_MODE, + MYKONOS_ERR_SET_GPIO_3V3_INV_SRC_CTRL, + + MYKONOS_ERR_SET_ARMGPIO_INV_POINTER, + MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR, + MYKONOS_ERR_SET_ARMGPIO_PINS_INV_SIGNALID, + MYKONOS_ERR_SET_ARMGPIO_PINS_INV_GPIOPIN, + + MYKONOS_ERR_SETUPAUXDAC_NULL_PARAM, + MYKONOS_ERR_WRITEAUXDAC_NULL_AUXIO, + MYKONOS_ERR_READAUXADC_NULL_PARAM, + MYKONOS_ERR_SETUPAUXDAC_INV_AUXDACCODE, + MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACCODE, + MYKONOS_ERR_WRITEAUXDAC_INV_AUXDACINDEX, + MYKONOS_ERR_INV_AUX_ADC_CHAN_PARM, + MYKONOS_ERR_SETUPAUXADC_INV_VCODIV, + MYKONOS_ERR_INV_AUX_ADC_DEC_PARM, + + MYKONOS_ERR_GAINCOMP_NULL_STRUCT, + MYKONOS_ERR_GAINCOMP_EN_NULL_PARM, + MYKONOS_ERR_GAINCOMP_SET_NULL_STRUCT, + MYKONOS_ERR_GAINCOMP_INV_RX1_OFFSET, + MYKONOS_ERR_GAINCOMP_INV_RX2_OFFSET, + MYKONOS_ERR_GAINCOMP_INV_STEP, + MYKONOS_ERR_GAINCOMP_INV_EN, + + MYKONOS_ERR_OBS_RX_GAINCOMP_SET_NULL_STRUCT, + MYKONOS_ERR_OBS_RX_GAINCOMP_EN_NULL_PARAM, + MYKONOS_ERR_OBS_RX_GAINCOMP_INV_EN, + MYKONOS_ERR_OBS_RX_GAINCOMP_INV_OFFSET, + MYKONOS_ERR_OBS_RX_GAINCOMP_INV_STEP, + MYKONOS_ERR_OBS_RX_GAINCOMP_NULL_STRUCT, + + MYKONOS_ERR_SLICER_STEP_OUT_OF_RANGE, + MYKONOS_ERR_SLICER_INV_RX1_SEL, + MYKONOS_ERR_SLICER_INV_RX2_SEL, + MYKONOS_ERR_SLICER_EN_INV, + + MYKONOS_ERR_SLICER_RX1PIN_NULL_PARM, + MYKONOS_ERR_SLICER_RX2PIN_NULL_PARM, + MYKONOS_ERR_SLICER_STEP_NULL_PARM, + MYKONOS_ERR_SLICER_EN_NULL_PARM, + + MYKONOS_ERR_SLICER_INV_OBS_RX_SEL, + MYKONOS_ERR_SLICER_OBS_RX_STEP_OUT_OF_RANGE, + MYKONOS_ERR_SLICER_OBS_RX_EN_INV, + MYKONOS_ERR_SLICER_OBS_RX_EN_NULL_PARM, + MYKONOS_ERR_SLICER_OBS_RX_STEP_NULL_PARM, + MYKONOS_ERR_SLICER_OBS_RXPIN_NULL_PARM, + + MYKONOS_ERR_FLOATFRMT_NULL_STRUCT, + MYKONOS_ERR_FLOATFRMT_SET_NULL_STRUCT, + MYKONOS_ERR_FLOATFRMT_INV_ROUND_MODE, + MYKONOS_ERR_FLOATFRMT_INV_DATA_FORMAT, + MYKONOS_ERR_FLOATFRMT_INV_ENC_NAN, + MYKONOS_ERR_FLOATFRMT_INV_EXP_BITS, + MYKONOS_ERR_FLOATFRMT_INV_LEADING, + MYKONOS_ERR_FLOATFRMT_INV_RX1ATT, + MYKONOS_ERR_FLOATFRMT_INV_RX2ATT, + MYKONOS_ERR_FLOATFRMT_INV_EN, + MYKONOS_ERR_FLOATFRMT_NULL_RX1ATT, + MYKONOS_ERR_FLOATFRMT_NULL_RX2ATT, + MYKONOS_ERR_FLOATFRMT_NULL_ENABLE, + MYKONOS_ERR_FLOATFRMT_SET_INV_EN, + MYKONOS_ERR_FLOATFRMT_SET_INV_RX1ATT, + MYKONOS_ERR_FLOATFRMT_SET_INV_RX2ATT, + + MYKONOS_ERR_FLOATFRMT_INV_ORXATT, + MYKONOS_ERR_FLOATFRMT_INV_ORXEN, + MYKONOS_ERR_FLOATFRMT_NULL_ORXATT, + MYKONOS_ERR_FLOATFRMT_NULL_ORXENABLE, + + MYKONOS_ERR_SETUPTEMPSENSOR_NULL_PARAM, + MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPDECIMATION, + MYKONOS_ERR_SETUPTEMPSENSOR_INV_OFFSET, + MYKONOS_ERR_SETUPTEMPSENSOR_INV_TEMPWINDOW, + MYKONOS_ERR_GETTEMPSENSORCFG_NULL_PARAM, + MYKONOS_ERR_READTEMPSENSOR_NULL_PARAM, + MYKONOS_ERR_READTEMPSENSOR_NOT_LOCKED, + + MYKONOS_ERR_GAIN_CONTROL_NOT_HYBRID, + MYKONOS_ERR_GPIO_HYBRID_RX1_PIN, + MYKONOS_ERR_GPIO_HYBRID_RX2_PIN, + MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_NULL_PARM, + MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_NULL_PARM, + MYKONOS_ERR_GPIO_HYBRID_RX1_PIN_READ, + MYKONOS_ERR_GPIO_HYBRID_RX2_PIN_READ, + MYKONOS_ERR_AGC_OBS_NOT_IN_HYBRID, + MYKONOS_ERR_GPIO_HYBRID_ORX_PIN, + MYKONOS_ERR_GPIO_HYBRID_ORX_PIN_NULL_PARM, + + MYKONOS_ERR_GAIN_CONTROL_NOT_AGC, + MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN, + MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN, + MYKONOS_ERR_GPIO_AGC_SYNC_RX1_PIN_NULL_PARM, + MYKONOS_ERR_GPIO_AGC_SYNC_RX2_PIN_NULL_PARM, + MYKONOS_ERR_OBS_GAIN_CONTROL_NOT_AGC, + MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN, + MYKONOS_ERR_GPIO_AGC_SYNC_ORX_PIN_NULL_PARM, + + MYKONOS_ERR_GETGPIODRV_NULL_PARAM, + MYKONOS_ERR_GPIO_DRV_INV_PARAM, + + MYKONOS_ERR_GPIO_SLEW_RATE_INV_PARAM, + MYKONOS_ERR_GPIO_GETSLEW_NULL_PARAM, + + MYKONOS_ERR_CMOS_DRV_INV_PARAM, + MYKONOS_ERR_CMOS_DRV_NULL_PARAM +} mykonosGpioErr_t; + +/** + * \brief Enum of possible Rx Slicer pin combinations + */ +typedef enum +{ + GPIO_0_1_2 = 0, /*!< GPIO combination for RX1 */ + GPIO_5_6_7 = 1, /*!< GPIO combination for RX1 or RX2 */ + GPIO_8_9_10 = 2, /*!< GPIO combination for RX1 */ + GPIO_11_12_13 = 3 /*!< GPIO combination for RX2 */ +} mykonosRxSlicer_t; + +/** + * \brief Enum of possible observation channel Slicer pin combinations + */ +typedef enum +{ + GPIO_18_17_16 = 0, /*!< GPIO combination for observation channel */ + GPIO_16_15_14 = 1 /*!< GPIO combination for observation channel */ +} mykonosObsRxSlicer_t; + +/** + * \brief Enum of possible GPIO slew rate settings + */ +typedef enum +{ + MYK_SLEWRATE_NONE = 0, /*!< Lower slew rate for the GPIO */ + MYK_SLEWRATE_LOW = 1, /*!< Low slew rate for the GPIO */ + MYK_SLEWRATE_MEDIUM = 2, /*!< Medium slew rate for the GPIO */ + MYK_SLEWRATE_HIGH = 3 /*!< High slew rate for the GPIO */ +} mykonosGpioSlewRate_t; + +/** + * \brief Enumerated list of CMOS pads drive strength options + */ +typedef enum +{ + MYK_CMOSPAD_DRV_1X = 0x00, /*!< 2.5pF load @ 65MHz */ + MYK_CMOSPAD_DRV_2X = 0x01, /*!< 5pF load @ 65MHz */ + MYK_CMOSPAD_DRV_3X = 0x03, /*!< 7.5pF load @ 65MHz */ + MYK_CMOSPAD_DRV_4X = 0x07, /*!< 10pF load @ 65MHz */ + MYK_CMOSPAD_DRV_5X = 0x0F /*!< 12.5pF load @ 65MHz */ +} mykonosCmosPadDrvStr_t; + + +/** + * \brief Enumerated list for Aux ADCs + */ +typedef enum +{ + MYK_AUXADC_0 = 0x00, /*!< Aux ADC channel 0 */ + MYK_AUXADC_1 = 0x01, /*!< Aux ADC channel 1 */ + MYK_AUXADC_2 = 0x02, /*!< Aux ADC channel 2 */ + MYK_AUXADC_3 = 0x03, /*!< Aux ADC channel 3 */ + MYK_AUXADC_0_DIV2 = 0x04, /*!< Aux ADC channel 0 with the divider by 2 set */ + MYK_TEMPSENSOR = 0x10 /*!< Temperature sensor channel */ +} mykonosAuxAdcChannels_t; + + +/** + * \brief Data structure to hold Gain compensation settings for the main receive channels + **/ +typedef struct +{ + uint8_t rx1Offset; /*!< These parameter contains the Rx1 offset word used for the gain compensation + when the gain index is at its maximum setting. + It has a range of 0 to 0x1F with a resolution is 0.5dB per LSB. */ + uint8_t rx2Offset; /*!< These parameter contains the Rx2 offset word used for the gain compensation + when the gain index is at its maximum setting. + It has a range of 0 to 0x1F with a resolution is 0.5dB per LSB. */ + uint8_t compStep; /*!< These bits contains the value in dB that the total Rx gain changes + when there is an LSB change in the gain index according to the following settings: + compStep | dB ramp + ---------|------------ + 0 | 0.25dB + 1 | 0.5dB + 2 | 1.0dB + 3 | 2.0dB + 4 | 3.0dB + 5 | 4.0dB + 6 | 6.0dB + 7 | Not valid defaulted to 0.25dB */ +} mykonosGainComp_t; + +/** + * \brief Data structure to hold Gain compensation settings for the observation channel + **/ +typedef struct +{ + uint8_t obsRxOffset; /*!< These parameter contains the Rx1 offset word used for the gain compensation + when the gain index is at its maximum setting. + It has a range of 0 to 0x1F with a resolution is 0.5dB per LSB. */ + uint8_t compStep; /*!< These bits contains the value in dB that the total Rx gain changes + when there is an LSB change in the gain index according to the following settings: + compStep | dB ramp + ---------|------------ + 0 | 0.25dB + 1 | 0.5dB + 2 | 1.0dB + 3 | 2.0dB + 4 | 3.0dB + 5 | 4.0dB + 6 | 6.0dB + 7 | Not valid defaulted to 0.25dB */ +} mykonosObsRxGainComp_t; + +/** + * \brief Data structure to hold floating point formatter settings for the floating point + * number generation + **/ +typedef struct +{ + uint8_t roundMode; /*! -#ifdef _XPARAMETERS_PS_H_ -#include "util.h" -#include "xtime_l.h" -#endif +#include "platform_drivers.h" +#include "xparameters.h" /******************************************************************************/ -/************************ Functions Definitions *******************************/ +/********************** Macros and Constants Definitions **********************/ /******************************************************************************/ +#define DDR_MEM_BASEADDR XPAR_DDR_MEM_BASEADDR +#define GPIO_0_DEVICE_ID XPAR_PS7_GPIO_0_DEVICE_ID + +//#define FREQ_CTRL_DEVICE_ID XPAR_AXI_9731_FREQ_CTRL_DEVICE_ID +//#define GAIN_CTRL_DEVICE_ID XPAR_AXI_9731_RX_GAIN_DEVICE_ID +//#define ATTN_CTRL_DEVICE_ID XPAR_AXI_9731_TX_ATTN_DEVICE_ID +// +//#define FREQ_CTRL_INTR_ID XPAR_FABRIC_AXI_9731_FREQ_CTRL_IP2INTC_IRPT_INTR +//#define GAIN_CTRL_INTR_ID XPAR_FABRIC_AXI_9731_RX_GAIN_IP2INTC_IRPT_INTR +//#define ATTN_CTRL_INTR_ID XPAR_FABRIC_AXI_9731_TX_ATTN_IP2INTC_IRPT_INTR + +#define GPIO_OFFSET 54 +#define AD9528_CS 1 +#define AD9371_CS 2 + +#define TX_FREQ_INTR_MASK XGPIO_IR_CH1_MASK +#define RX_FREQ_INTR_MASK XGPIO_IR_CH2_MASK +#define TX1_ATTN_INTR_MASK XGPIO_IR_CH1_MASK +#define TX2_ATTN_INTR_MASK XGPIO_IR_CH2_MASK +#define RX1_ATTN_INTR_MASK XGPIO_IR_CH1_MASK +#define RX2_ATTN_INTR_MASK XGPIO_IR_CH2_MASK + +#define AXI_GPIO_BANK_1 1 +#define AXI_GPIO_BANK_2 2 + +//#define DAC_GPIO_PLDDR_BYPASS GPIO_OFFSET + 60 +#define AD9528_RESET_B GPIO_OFFSET + 4 +#define AD9528_SYSREF_REQ GPIO_OFFSET + 3 +#define AD9371_RESET_B GPIO_OFFSET + 1 -/** - * @brief Generate microseconds delay. - * @param usecs - Delay in microseconds. - * @return None. - */ -void udelay(uint32_t usecs) -{ -#ifdef _XPARAMETERS_PS_H_ - usleep(usecs); -#else - usleep_MB(usecs); #endif -} - -/** - * @brief Generate miliseconds delay. - * @param msecs - Delay in miliseconds. - * @return None. - */ -void mdelay(uint32_t msecs) -{ -#ifdef _XPARAMETERS_PS_H_ - usleep(msecs * 1000); -#else - usleep_MB(msecs * 1000); -#endif -} - -/** - * @brief Get current time. - * @return Current time structure from system start (seconds, microseconds). - */ -struct time get_time(void) -{ - struct time t = {0, 0}; -#ifdef _XPARAMETERS_PS_H_ - unsigned long long Xtime_Global; - uint32_t rem; - - XTime_GetTime(&Xtime_Global); - t.s = div_u64_rem(Xtime_Global, COUNTS_PER_SECOND, &rem); - t.us = div_u64((uint64_t)rem * 1000000, COUNTS_PER_SECOND); -#endif - - return t; -} diff --git a/src/hardware/platform_drivers.c b/src/hardware/platform_drivers.c new file mode 100644 index 0000000..407c661 --- /dev/null +++ b/src/hardware/platform_drivers.c @@ -0,0 +1,395 @@ +/***************************************************************************//** + * @file platform_drivers.c + * @brief Implementation of Xilinx Platform Drivers. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2018(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include +#include +#include "platform_drivers.h" + +/******************************************************************************/ +/************************ Functions Definitions *******************************/ +/******************************************************************************/ + +/** + * @brief Initialize the SPI communication peripheral. + * @param desc - The SPI descriptor. + * @param init_param - The structure that contains the SPI parameters. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t spi_init(struct spi_desc **desc, + const struct spi_init_param *param) +{ + spi_desc *descriptor; + int32_t ret; + + descriptor = (struct spi_desc *) calloc(1, sizeof(*descriptor)); + if (!descriptor) + return FAILURE; + + descriptor->mode = param->mode; + descriptor->chip_select = param->chip_select; + descriptor->flags = param->flags; + +#ifdef _XPARAMETERS_PS_H_ + descriptor->config = XSpiPs_LookupConfig(param->id); + if (descriptor->config == NULL) + goto error; + + ret = XSpiPs_CfgInitialize(&descriptor->instance, + descriptor->config, descriptor->config->BaseAddress); + if (ret != 0) + goto error; + + XSpiPs_SetOptions(&descriptor->instance, + XSPIPS_MASTER_OPTION | + ((descriptor->flags & SPI_CS_DECODE) ? + XSPIPS_DECODE_SSELECT_OPTION : 0) | + XSPIPS_FORCE_SSELECT_OPTION | + ((descriptor->mode & SPI_CPOL) ? + XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) | + ((descriptor->mode & SPI_CPHA) ? + XSPIPS_CLK_PHASE_1_OPTION : 0)); + + XSpiPs_SetClkPrescaler(&descriptor->instance, + XSPIPS_CLK_PRESCALE_64); + + XSpiPs_SetSlaveSelect(&descriptor->instance, 0xf); +#else + ret = XSpi_Initialize(&descriptor->instance, param->id); + if (ret != 0) + goto error; + + XSpi_SetOptions(&descriptor->instance, + XSP_MASTER_OPTION | + ((descriptor->mode & SPI_CPOL) ? + XSP_CLK_ACTIVE_LOW_OPTION : 0) | + ((descriptor->mode & SPI_CPHA) ? + XSP_CLK_PHASE_1_OPTION : 0)); + + XSpi_Start(&descriptor->instance); + + XSpi_IntrGlobalDisable(&descriptor->instance); +#endif + + *desc = descriptor; + + return SUCCESS; + +error: + free(descriptor); + + return FAILURE; +} + +/** + * @brief Free the resources allocated by spi_init(). + * @param desc - The SPI descriptor. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t spi_remove(struct spi_desc *desc) +{ + if (desc) { + // Unused variable - fix compiler warning + } + + return SUCCESS; +} + +/** + * @brief Write and read data to/from SPI. + * @param desc - The SPI descriptor. + * @param data - The buffer with the transmitted/received data. + * @param bytes_number - Number of bytes to write/read. + * @return SUCCESS in case of success, FAILURE otherwise. + */ + +int32_t spi_write_and_read(struct spi_desc *desc, + uint8_t *data, + uint8_t bytes_number) +{ +#ifdef _XPARAMETERS_PS_H_ + XSpiPs_SetOptions(&desc->instance, + XSPIPS_MASTER_OPTION | + ((desc->flags & SPI_CS_DECODE) ? + XSPIPS_DECODE_SSELECT_OPTION : 0) | + XSPIPS_FORCE_SSELECT_OPTION | + ((desc->mode & SPI_CPOL) ? + XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) | + ((desc->mode & SPI_CPHA) ? + XSPIPS_CLK_PHASE_1_OPTION : 0)); + + XSpiPs_SetSlaveSelect(&desc->instance, desc->chip_select); + // 0xf & ~desc->chip_select); + XSpiPs_PolledTransfer(&desc->instance, + data, data, bytes_number); +#else + XSpi_SetOptions(&desc->instance, + XSP_MASTER_OPTION | + ((desc->mode & SPI_CPOL) ? + XSP_CLK_ACTIVE_LOW_OPTION : 0) | + ((desc->mode & SPI_CPHA) ? + XSP_CLK_PHASE_1_OPTION : 0)); + + XSpi_SetSlaveSelect(&desc->instance, + desc->chip_select); + + XSpi_Transfer(&desc->instance, + data, data, bytes_number); +#endif + return 0; +} + +/** + * @brief Obtain the GPIO decriptor. + * @param desc - The GPIO descriptor. + * @param gpio_number - The number of the GPIO. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_get(struct gpio_desc **desc, + uint8_t gpio_number) +{ + gpio_desc *descriptor; + int32_t ret; + + descriptor = (struct gpio_desc *) malloc(sizeof(*descriptor)); + if (!descriptor) + return FAILURE; + +#ifdef _XPARAMETERS_PS_H_ + descriptor->config = XGpioPs_LookupConfig(0); + if (descriptor->config == NULL) + goto error; + + ret = XGpioPs_CfgInitialize(&descriptor->instance, + descriptor->config, descriptor->config->BaseAddr); + if (ret != 0) + goto error; +#else + ret = XGpio_Initialize(&descriptor->instance, 0); + if (ret != 0) + goto error; +#endif + + descriptor->number = gpio_number; + + *desc = descriptor; + + return SUCCESS; + +error: + free(descriptor); + + return FAILURE; +} + +/** + * @brief Free the resources allocated by gpio_get(). + * @param desc - The SPI descriptor. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_remove(struct gpio_desc *desc) +{ + if (desc) { + // Unused variable - fix compiler warning + } + + return SUCCESS; +} + +/** + * @brief Enable the input direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_direction_input(struct gpio_desc *desc) +{ + if (desc) { + // Unused variable - fix compiler warning + } + + return 0; +} + +/** + * @brief Enable the output direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: GPIO_HIGH + * GPIO_LOW + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_direction_output(struct gpio_desc *desc, + uint8_t value) +{ +#ifdef _XPARAMETERS_PS_H_ + XGpioPs_SetDirectionPin(&desc->instance, desc->number, 1); + + XGpioPs_SetOutputEnablePin(&desc->instance, desc->number, 1); + + XGpioPs_WritePin(&desc->instance, desc->number, value); +#else + uint8_t pin = desc->number; + uint8_t channel; + uint32_t reg_val; + + if (pin >= 32) { + channel = 2; + pin -= 32; + } else + channel = 1; + + reg_val = XGpio_GetDataDirection(&desc->instance, channel); + reg_val &= ~(1 << pin); + XGpio_SetDataDirection(&desc->instance, channel, reg_val); + + reg_val = XGpio_DiscreteRead(&desc->instance, channel); + if(value) + reg_val |= (1 << pin); + else + reg_val &= ~(1 << pin); + XGpio_DiscreteWrite(&desc->instance, channel, reg_val); +#endif + + return SUCCESS; +} + +/** + * @brief Get the direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param direction - The direction. + * Example: GPIO_OUT + * GPIO_IN + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_get_direction(struct gpio_desc *desc, + uint8_t *direction) +{ + if (desc) { + // Unused variable - fix compiler warning + } + + if (direction) { + // Unused variable - fix compiler warning + } + + return 0; +} + +/** + * @brief Set the value of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: GPIO_HIGH + * GPIO_LOW + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_set_value(struct gpio_desc *desc, + uint8_t value) +{ +#ifdef _XPARAMETERS_PS_H_ + XGpioPs_WritePin(&desc->instance, desc->number, value); +#else + uint8_t pin = desc->number; + uint8_t channel; + uint32_t reg_val; + + if (pin >= 32) { + channel = 2; + pin -= 32; + } else + channel = 1; + + reg_val = XGpio_DiscreteRead(&desc->instance, channel); + if(value) + reg_val |= (1 << pin); + else + reg_val &= ~(1 << pin); + XGpio_DiscreteWrite(&desc->instance, channel, reg_val); +#endif + + return 0; +} + +/** + * @brief Get the value of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: GPIO_HIGH + * GPIO_LOW + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int32_t gpio_get_value(struct gpio_desc *desc, + uint8_t *value) +{ + if (desc) { + // Unused variable - fix compiler warning + } + + if (value) { + // Unused variable - fix compiler warning + } + + return 0; +} + +/** + * @brief Generate microseconds delay. + * @param usecs - Delay in microseconds. + * @return None. + */ +void udelay(uint32_t usecs) +{ + usleep(usecs); +} + +/** + * @brief Generate miliseconds delay. + * @param msecs - Delay in miliseconds. + * @return None. + */ +void mdelay(uint32_t msecs) +{ +#ifdef _XPARAMETERS_PS_H_ + usleep(msecs * 1000); +#else + usleep(msecs * 50); // FIXME +#endif +} diff --git a/src/hardware/platform_drivers.h b/src/hardware/platform_drivers.h new file mode 100644 index 0000000..64b7ed3 --- /dev/null +++ b/src/hardware/platform_drivers.h @@ -0,0 +1,204 @@ +/***************************************************************************//** + * @file platform_drivers.h + * @brief Header file of Xilinx Platform Drivers. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2018(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef PLATFORM_DRIVERS_H_ +#define PLATFORM_DRIVERS_H_ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include +#include +#ifdef _XPARAMETERS_PS_H_ +#include +#include +#else +#include +#include +#endif + +/******************************************************************************/ +/********************** Macros and Constants Definitions **********************/ +/******************************************************************************/ + +#define SUCCESS 0 +#define FAILURE -1 + +#define SPI_CPHA 0x01 +#define SPI_CPOL 0x02 + +#define SPI_CS_DECODE 0x01 +#define SPI_CS_DECODE_DISABLE 0x00 + +#define GPIO_OUT 0x01 +#define GPIO_IN 0x00 + +#define GPIO_HIGH 0x01 +#define GPIO_LOW 0x00 + +/******************************************************************************/ +/*************************** Types Declarations *******************************/ +/******************************************************************************/ + +typedef enum i2c_type { + XILINX_I2C +} i2c_type; + +typedef struct i2c_init_param { + enum i2c_type type; + uint32_t id; + uint32_t max_speed_hz; + uint8_t slave_address; +} i2c_init_param; + +typedef struct i2c_desc { + enum i2c_type type; + uint32_t id; + uint32_t max_speed_hz; + uint8_t slave_address; +} i2c_desc; + +typedef enum spi_type { + XILINX_SPI +} spi_type; + +/** + * @enum spi_mode + * @brief SPI configuration for clock phase and polarity. + */ +typedef enum spi_mode { + /** Data on rising, shift out on falling */ + SPI_MODE_0 = (0 | 0), + /** Data on falling, shift out on rising */ + SPI_MODE_1 = (0 | SPI_CPHA), + /** Data on falling, shift out on rising */ + SPI_MODE_2 = (SPI_CPOL | 0), + /** Data on rising, shift out on falling */ + SPI_MODE_3 = (SPI_CPOL | SPI_CPHA) +} spi_mode; + +typedef struct spi_init_param { + enum spi_type type; + uint32_t id; + uint32_t max_speed_hz; + enum spi_mode mode; + uint8_t chip_select; + uint32_t flags; +} spi_init_param; + +typedef struct spi_desc { + enum spi_type type; + uint32_t id; + uint32_t max_speed_hz; + enum spi_mode mode; + uint8_t chip_select; + uint32_t flags; +#ifdef _XPARAMETERS_PS_H_ + XSpiPs_Config *config; + XSpiPs instance; +#else + XSpi instance; +#endif +} spi_desc; + +typedef enum gpio_type { + XILINX_GPIO +} gpio_type; + +typedef struct gpio_desc { + enum gpio_type type; + uint32_t id; + uint8_t number; +#ifdef _XPARAMETERS_PS_H_ + XGpioPs_Config *config; + XGpioPs instance; +#else + XGpio instance; +#endif +} gpio_desc; + +/******************************************************************************/ +/************************ Functions Declarations ******************************/ +/******************************************************************************/ + +/* Initialize the SPI communication peripheral. */ +int32_t spi_init(struct spi_desc **desc, + const struct spi_init_param *param); + +/* Free the resources allocated by spi_init() */ +int32_t spi_remove(struct spi_desc *desc); + +/* Write and read data to/from SPI. */ +int32_t spi_write_and_read(struct spi_desc *desc, + uint8_t *data, + uint8_t bytes_number); + +/* Obtain the GPIO decriptor. */ +int32_t gpio_get(struct gpio_desc **desc, + uint8_t gpio_number); + +/* Free the resources allocated by gpio_get() */ +int32_t gpio_remove(struct gpio_desc *desc); + +/* Enable the input direction of the specified GPIO. */ +int32_t gpio_direction_input(struct gpio_desc *desc); + +/* Enable the output direction of the specified GPIO. */ +int32_t gpio_direction_output(struct gpio_desc *desc, + uint8_t value); + +/* Get the direction of the specified GPIO. */ +int32_t gpio_get_direction(struct gpio_desc *desc, + uint8_t *direction); + +/* Set the value of the specified GPIO. */ +int32_t gpio_set_value(struct gpio_desc *desc, + uint8_t value); + +/* Get the value of the specified GPIO. */ +int32_t gpio_get_value(struct gpio_desc *desc, + uint8_t *value); + +/* Generate microseconds delay. */ +void udelay(uint32_t usecs); + +/* Generate miliseconds delay. */ +void mdelay(uint32_t msecs); + +#endif // PLATFORM_DRIVERS_H_ diff --git a/src/include/error.h b/src/include/error.h index 0b878d5..0626c02 100644 --- a/src/include/error.h +++ b/src/include/error.h @@ -38,7 +38,7 @@ #endif #define FAILURE -1 -#define EPARAM -2 /*!< Data crc check failed */ +#define EPARAM -2 /*!< Invalid parameters */ #define ECRC -3 /*!< Data crc check failed */ #define EDINVAL -4 /*!< Device is invalid (sleep or power off) */ #define EDCONF -5 /*!< Device confugure error */ @@ -53,4 +53,4 @@ /** @} ERRORNO*/ -/** @} COMMON_MACRO*/ \ No newline at end of file +/** @} COMMON_MACRO*/ diff --git a/src/include/ring_buffer.h b/src/include/ring_buffer.h new file mode 100644 index 0000000..47234b0 --- /dev/null +++ b/src/include/ring_buffer.h @@ -0,0 +1,101 @@ +#include +#include +#include +/** + * @file + * Prototypes and structures for the ring buffer module. + */ + +#ifndef __RINGBUFFER_H +#define __RINGBUFFER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Structure which holds a ring buffer. + * The buffer contains a buffer array + * as well as metadata for the ring buffer. + */ +typedef struct RING_BUFFER { + uint8_t *buffer; ///< Buffer memory + size_t tail; ///< Index of tail + size_t head; ///< Index of head + size_t capacity; ///< Capacity of buffer + size_t size; ///< Size of data stored in buffer +} RING_BUFFER; + +/** + * Initialize a ringbuffer . + * @param capacity capacity of the ringbuffer + * @return The initialized ringbuffer pointer, NULL of not enough memory + */ +RING_BUFFER *RingBuff_Create(size_t capacity); + +/** + * Destroy a ringbuffer . + * @param rb The buffer to destroyed. + */ +void RingBuff_Destroy(RING_BUFFER *rb); + +/** + * Flush all the data stored in ring buffer + * @param rb The buffer to be flushed. + */ +void RingBuff_Flush(RING_BUFFER *rb); + +/** + * Adds an array of bytes to a ring buffer. + * @param rb The buffer in which the data should be placed. + * @param data A pointer to the array of bytes to place in the queue. + * @param size The size of the array. + */ +size_t RingBuff_Push(RING_BUFFER *rb, const uint8_t *data, size_t len); + +/** + * Returns the len oldest bytes in a ring buffer. + * @param rb The buffer from which the data should be returned. + * @param data A pointer to the array at which the data should be placed. + * @param len The maximum number of bytes to return. + * @return The number of bytes returned. + */ +size_t RingBuff_Pop(RING_BUFFER *rb, uint8_t *data, size_t len); + +/** + * Peeks a ring buffer, i.e. returns an element without removing it. + * @param rb The buffer from which the data should be returned. + * @param data A pointer to the location at which the data should be placed. + * @param len The maximum number of bytes to return. + * @return the number of bytes returned. + */ +size_t RingBuff_Peek(const RING_BUFFER *rb, uint8_t *data, size_t len); + +/** + * Returns the number of items in a ring buffer. + * @param rb The buffer for which the number of items should be returned. + * @return The number of items in the ring buffer. + */ +size_t RingBuff_Size(RING_BUFFER *rb); + + +/** + * Returns whether a ring buffer is empty. + * @param buffer The buffer for which it should be returned whether it is empty. + * @return 1 if empty; 0 otherwise. + */ +uint8_t RingBuff_isEmpty(RING_BUFFER *rb); + +/** + * Returns whether a ring buffer is full. + * @param buffer The buffer for which it should be returned whether it is full. + * @return 1 if full; 0 otherwise. + */ +uint8_t RingBuff_isFull(RING_BUFFER *rb); + +#ifdef __cplusplus +} +#endif + +#endif /* __RINGBUFFER_H */ diff --git a/src/include/trng.h b/src/include/trng.h deleted file mode 100644 index 1c469b3..0000000 --- a/src/include/trng.h +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************************//** - * @file trng.h - * @brief Header file of true random number generator - * @author Mihail Chindris (mihail.chindris@analog.com) -******************************************************************************** - * @copyright - * Copyright 2020(c) Analog Devices, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Analog Devices, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - The use of this software may or may not infringe the patent rights - * of one or more patent holders. This license does not release you - * from the requirement that you obtain separate licenses from these - * patent holders to use this software. - * - Use of the software either in source or binary form, must be run - * on or directly connected to an Analog Devices Inc. component. - * - * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*******************************************************************************/ - -#ifndef _TRNG_H_ -#define _TRNG_H_ - -/******************************************************************************/ -/***************************** Include Files **********************************/ -/******************************************************************************/ - -#include - -/******************************************************************************/ -/*************************** Types Declarations *******************************/ -/******************************************************************************/ - -/** - * @struct trng_platform_ops - * @brief Structure holding TRNG function pointers that point to the platform - * specific function - */ -struct trng_platform_ops; - -/** - * @struct trng_desc - * @brief TRNG Descriptor - */ -struct trng_desc { - /** Platform ops */ - const struct trng_platform_ops *platform_ops; - /** Platform specific parameters */ - void *extra; -}; - -/** - * @struct trng_init_param - * @brief Init parameter for TRNG - */ -struct trng_init_param { - /** Device id */ - uint32_t dev_id; - /** Platform specific parameter */ - void *extra; - /** Platform ops */ - const struct trng_platform_ops *platform_ops; -}; - -/** - * @struct trng_platform_ops - * @brief Structure holding TRNG function pointers that point to the platform - * specific function - */ -struct trng_platform_ops { - /** TRNG initialization function pointer */ - int (*init)(struct trng_desc **, - const struct trng_init_param *); - /** Fill buffer with random numbers */ - int (*fill_buffer)(struct trng_desc *, uint8_t *, uint32_t); - /** TRNG remove function pointer */ - int (*remove)(struct trng_desc *); -}; - -/******************************************************************************/ -/************************ Functions Declarations ******************************/ -/******************************************************************************/ - -/* Initialize descriptor */ -int trng_init(struct trng_desc **desc, - const struct trng_init_param *param); - -/* Free resources allocated in descriptor */ -int trng_remove(struct trng_desc *desc); - -/* Fill buffer with random numbers */ -int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff, - uint32_t len); - -#endif // _TRNG_H_ diff --git a/src/mpc/mpc.c b/src/mpc/mpc.c new file mode 100644 index 0000000..e32a539 --- /dev/null +++ b/src/mpc/mpc.c @@ -0,0 +1,702 @@ +/*****************************************************************************/ +/** + * Description: MPC protocol implementation file. + * + * Date: 2023-05-06 10:13 + * Last Edit Time: [2023-05-06 21:45] + * + * Revisions: Rev 0.0 + * History: + * [2023-05-06]: Initial version. + * [2023-09-13]: Update to 485 protocol-20220816 + * + * Copyright(c) 2021 Beijing Institute of Technology. + * Lab of Communication and Network + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include +#include +#include +#include +#include "mpc.h" +#include "util.h" +#include "common.h" +#include "error.h" +#include "circ_queue.h" +#include "xbram.h" +#include "xgpio.h" + +#include "../system_monitor.h" + +/************************** Constant Definitions *****************************/ +// Common Field +// -- Command word +#define WD_CMD 0x00 + +// -- Production type +#define WD_PRD 0x01 +#define PRD_DL_K 0xDD +#define PRD_DL_S 0xEE +#define PRD_ALL 0xFF + +// Self-Test +#define CMD_SELF_TEST 0xE1 +// -- Request +// -- -- -- +// -- Response +// -- -- Self-Test Result +#define ST_RSP_LEN 16 +#define WD_ST_RET 0x02 +#define ST_RET_OK 0xAA +#define ST_RET_ERROR 0x55 +#define ST_RET_INFO_LEN 13 +// -- -- Signal processor PS voltage +#define WD_SP_FPGA_VOLT 0x03 +// -- -- Signal processor PS AUX voltage +#define WD_SP_CLK_STATE 0x04 +// -- -- Signal processor DDR voltage +#define WD_SP_AD_LOCK_STATE 0x05 +// -- -- Signal processor PL voltage +#define WD_SP_AD_TEMP_0 0x06 +// -- -- Signal processor PL AUX voltage +#define WD_SP_AD_TEMP_1 0x07 +// -- -- Signal processor Bram voltage +#define WD_SP_FPGA_TEMP 0x08 + +// Config load +#define CMD_CONFIG 0xE3 +// -- Request +#define WD_EN_CMD 0x02 +#define EN_CMD_ON_HIGH_POWER 0x66 +#define EN_CMD_ON_LOW_POWER 0x77 +#define EN_CMD_SILENT 0x88 + +#define WD_SPEED_CMD 0x03 +#define SPEED_CMD_2K 0x11 +#define SPEED_CMD_128K 0x22 +#define SPEED_CMD_256K 0x33 +// -- Response +// -- -- none response + +// Remote Test +#define RM_TEST_RESP_LEN 158 +// -- Request +// Remote Test FLJ +#define CMD_FLJ_RM_TEST 0xE6 +// Remote Test LJ +#define CMD_LJ_RM_TEST 0xF6 +#define WD_RM_TEST 0x02 +#define RM_TEST_CODE 0x99 +// -- Response +#define WD_TIME_STAMP 0x02 +#define WD_TIME_STAMP_LEN 8 +#define WD_SYSBUS_LOG 0x0A +#define WD_SYSBUS_LOG_LEN 14 +#define WD_LINK_LOG 0x18 +#define WD_LINK_LOG_LEN 64 +#define WD_PHY_LOG 0x58 +#define WD_PHY_LOG_LEN 57 +#define WD_HARDWARE_ST 0x91 +#define WD_HARDWARE_ST_LEN 13 + +// Service Data +// -- Request +#define DATA_DLUL_LEN 510 +#define CMD_DATA_DL 0x92 +#define CMD_DATA_UL 0xA2 +#define WD_DATA_SEQID_L 2U +#define WD_DATA_SEQID_H 3U +#define WD_DATA_PKTNUM 4U +#define WD_DATA_PKTSEQ 5U +#define WD_DATA_DLEN_L 6U +#define WD_DATA_DLEN_H 7U +#define WD_DATA_PAYLOAD 8U +#define DATA_PAYLOAD_MAX 502U +// -- Response +// -- -- none response + +// My Production Type +#define MY_PRD_ID PRD_DL_K +#define MPC_SVC_MAX 1024 + +/************************** Function Prototypes ******************************/ +static int32_t Mpc_ReceiveSvcDate(MPC *instPtr, uint8_t *msg); +/**************************** Type Definitions *******************************/ +/************************** Variable Definitions *****************************/ +// TODO: better approach? +#include "../networking/link_layer/link_layer.h" +#include "../networking/phy_layer/phy_layer.h" +extern L2_INST *linkInstPtr; +extern L2_CONFIG linkConfig; + +inline bool Mpc_IsEnable(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (instPtr->isEnable); +} + +inline bool Mpc_IsReqPending(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->rxQueue)); +} + +inline bool Mpc_IsRsqPending(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->txQueue)); +} + +inline bool Mpc_IsTxBusy(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!instPtr->isTxDone); +} + +inline bool Mpc_IsRxBusy(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!instPtr->isRxDone); +} + +inline bool Mpc_IsSvcUpPending(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->rxSvcQueue)); +} + +inline bool Mpc_IsSvcDownPending(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->txSvcQueue)); +} + +inline bool Mpc_PushSvcFrame(MPC *instPtr, void* buff) { + ASSERT(instPtr != NULL); + ASSERT(buff != NULL); + return CircQueuePush(instPtr->rxSvcQueue, buff); +} + +inline bool Mpc_PopSvcFrame(MPC *instPtr, void** buff) { + ASSERT(instPtr != NULL); + ASSERT(buff != NULL); + return CircQueuePop(instPtr->txSvcQueue, buff); +} + +/** + * @brief Generate System Bus SelfTest response. + */ +static int32_t Mpc_GenSelfTestRsp(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + MPC_HW_FRAME *mpcRsp; + uint8_t *msg; + if (Mpc_IsEnable(instPtr) == false) + { + DBG_ERROR("System is not enabled!\n"); + return EIGNORE; + } + mpcRsp = malloc(sizeof(MPC_HW_FRAME)); + if (mpcRsp == NULL) + { + DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n"); + return ENOMEM; + } + mpcRsp->len = ST_RSP_LEN; + msg = mpcRsp->data + FRAME_PAYLOAD_POFFSET; + + HWSTATE *hwStatsPtr = &(instPtr->hwState); + + msg[WD_CMD] = CMD_SELF_TEST; + msg[WD_PRD] = MY_PRD_ID; + SysMonitor_GetHardwareStatus(hwStatsPtr); + if (Mpc_IsEnable(instPtr)) + { + msg[WD_ST_RET] = (hwStatsPtr->isSpOk && hwStatsPtr->isAntOk) ? ST_RET_OK : ST_RET_ERROR; + } + else + { + msg[WD_ST_RET] = (hwStatsPtr->isSpOk) ? ST_RET_OK : ST_RET_ERROR; + } + // apply status and omit 2 bytes of overhead. + memcpy(msg + WD_SP_FPGA_VOLT, &(hwStatsPtr->spFpgaVolt), ST_RET_INFO_LEN); + + if (CircQueuePush(instPtr->txQueue, (void *)mpcRsp) == false) + { + free(mpcRsp); + DBG_ERROR("SystemBus::TX Queue overflowed!\n"); + return EQUEUE; + } + return SUCCESS; +} + +/** + * @brief Apply system configuration + */ +static int32_t Mpc_SystemConfig(MPC *instPtr, uint8_t *msg) +{ + PHY_INST *phyRef = linkInstPtr->config.phyInstPtr; + TMC_INST *tmcRef = linkInstPtr->config.tmcInstPtr; + switch (msg[WD_SPEED_CMD]) { + case SPEED_CMD_2K: + Linklayer_UpdateSpeedMode(linkInstPtr, L2_SPEED_2KBPS); + break; + case SPEED_CMD_128K: + Linklayer_UpdateSpeedMode(linkInstPtr, L2_SPEED_128KBPS); + break; + case SPEED_CMD_256K: + Linklayer_UpdateSpeedMode(linkInstPtr, L2_SPEED_256KBPS); + break; + default: + DBG_ERROR("Unexpected config command 0x%02X:0x%02X", + WD_SPEED_CMD, msg[WD_SPEED_CMD]); + return EIGNORE; + } + + if (msg[WD_EN_CMD] == EN_CMD_ON_HIGH_POWER) + { + // high power config + Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_FULL); + Linklayer_Start(linkInstPtr); + instPtr->isEnable = true; + } + else if (msg[WD_EN_CMD] == EN_CMD_ON_LOW_POWER) + { + // low power config + Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_LOW); + Linklayer_Start(linkInstPtr); + instPtr->isEnable = true; + } + else if (msg[WD_EN_CMD] == EN_CMD_SILENT) + { + // silence config + // TODO: better approach? + instPtr->isEnable = false; + Linklayer_Halt(linkInstPtr); + Phy_AntConfigMode(phyRef, PHY_ANT_MODE_STANDBY); + TIME_WORD pullTime = {0, 0}; + pullTime.int_part = TimeCtrl_GetIntCnt(tmcRef) + 1; + if (Phy_SetTimeWord(phyRef, &pullTime, PHY_TIME_WORD_POLL) != SUCCESS) + { + DBG_ERROR("Physical set pull time failed.\n"); + } + Phy_SetupNextSlot(phyRef, PHY_TOR_RX, L1_10KBPS_10MS_FRAME, NULL); + } + else + { + // Ignore current command + DBG_ERROR("Unexpected config command 0x%02X:0x%02X", + WD_EN_CMD, msg[WD_EN_CMD]); + return EIGNORE; + } + instPtr->mpcLog.lastConfig[0] = msg[WD_EN_CMD]; + instPtr->mpcLog.lastConfig[1] = msg[WD_SPEED_CMD]; + return SUCCESS; +} + + +/** + * @brief Receive service data from upper layer + */ +static int32_t Mpc_ReceiveSvcDate(MPC *instPtr, uint8_t *msg) +{ + ASSERT(instPtr != NULL); + ASSERT(msg != NULL); + uint8_t numPack = msg[WD_DATA_PKTNUM]; + uint8_t seqNo = msg[WD_DATA_PKTSEQ]; + size_t dlen = (size_t)msg[WD_DATA_DLEN_L] | ((size_t)msg[WD_DATA_DLEN_H] << 8); + if(seqNo > numPack) { + DBG_ERROR("Invalid service packet sequence number (%u/%u).\n", seqNo, numPack); + return EPARAM; + } + if(dlen > 502) { + DBG_ERROR("Invalid service data packet length %u.\n", dlen); + return EPARAM; + } + if (instPtr->currSvcBuff == NULL) + { + instPtr->currSvcBuff = RingBuff_Create(MPC_SVC_MAX); + if(instPtr->currSvcBuff == NULL) { + return ENOMEM; + } + } + + size_t tmpLen = RingBuff_Push(instPtr->currSvcBuff, &(msg[WD_DATA_PAYLOAD]), dlen); + if(tmpLen < dlen) { + DBG_ERROR("Ring buffer overflowed.\n"); + ASSERT(true); + } + // TODO: Check packet consistency + if(numPack == 0 || seqNo == numPack) { + if(CircQueuePush(instPtr->txSvcQueue, (void*)instPtr->currSvcBuff) == false) { + DBG_ERROR("txSvcQueue overflowed.\n"); + RingBuff_Destroy(instPtr->currSvcBuff); + return EQUEUE; + } + instPtr->currSvcBuff = NULL; + } + instPtr->mpcLog.svcUpCnt++; + return SUCCESS; +} + + +/** + * @brief Upload service data to upper layer + */ +int32_t Mpc_UploadSvcData(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + RING_BUFFER *buff; + if(CircQueuePop(instPtr->rxSvcQueue, (void**)(&buff)) == false) { + DBG_ERROR("No service data need to be uploaded.\n"); + return EIGNORE; + } + uint8_t numPack = RingBuff_Size(buff) / DATA_PAYLOAD_MAX; + uint8_t cntPack = 0; + MPC_HW_FRAME *mpcRsp; + uint8_t *rsp; + size_t sentLen; + while(RingBuff_Size(buff) > 0) { + mpcRsp = malloc(sizeof(MPC_HW_FRAME)); + if (mpcRsp == NULL) + { + DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n"); + return ENOMEM; + } + mpcRsp->len = DATA_DLUL_LEN; + rsp = mpcRsp->data + FRAME_PAYLOAD_POFFSET; + + rsp[WD_CMD] = CMD_DATA_UL; + rsp[WD_PRD] = MY_PRD_ID; + rsp[WD_DATA_SEQID_L] = instPtr->mpcLog.svcUpCnt & 0xFF; + rsp[WD_DATA_SEQID_H] = (instPtr->mpcLog.svcUpCnt >> 8) & 0xFF; + rsp[WD_DATA_PKTNUM] = numPack; + rsp[WD_DATA_PKTSEQ] = cntPack; + sentLen = RingBuff_Pop(buff, &(rsp[WD_DATA_PAYLOAD]), DATA_PAYLOAD_MAX); + rsp[WD_DATA_DLEN_L] = sentLen & 0xFF; + rsp[WD_DATA_DLEN_H] = (sentLen >> 8) & 0xFF; + + if (CircQueuePush(instPtr->txQueue, (void *)mpcRsp) == false) + { + RingBuff_Destroy(buff); + free(mpcRsp); + DBG_WARNING("SystemBus::TX Queue overflowed!\n"); + return EQUEUE; + } + instPtr->mpcLog.svcUpCnt++; + } + RingBuff_Destroy(buff); + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Initialize MPC instance. + * + * @param InstPtr A double pointer to MPC instance. + * @param config A pointer to MPC configurations. + * + * @return Error code. + * + ******************************************************************************/ +int32_t Mpc_Init(MPC **instPtr, MPC_CONFIG *config) +{ + ASSERT(instPtr != NULL); + ASSERT(config != NULL); + MPC_HW_CONFIG mpcHwConfig; + int32_t Status; + (*instPtr) = malloc(sizeof(MPC)); + if ((*instPtr) == NULL) + { + return ENOMEM; + } + (*instPtr)->rxQueue = NULL; + (*instPtr)->txQueue = NULL; + (*instPtr)->mpchwDesc = NULL; + (*instPtr)->txSvcQueue = NULL; + (*instPtr)->rxSvcQueue = NULL; + (*instPtr)->currSvcBuff = NULL; + + memcpy(&((*instPtr)->config), config, sizeof(MPC_CONFIG)); + memset(&((*instPtr)->mpcLog), 0x00, sizeof(SYSBUSLOG)); + memset(&((*instPtr)->linkLog), 0x00, sizeof(LINKLOG)); + memset(&((*instPtr)->phyLog), 0x00, sizeof(PHYLOG)); + memset(&((*instPtr)->hwState), 0x00, sizeof(HWSTATE)); + + XBram_Config *bramConfigPtr; + XBram mpcBram; + + bramConfigPtr = XBram_LookupConfig(config->bramId); + if (bramConfigPtr == NULL) + { + Mpc_Destroy(*instPtr); + return EDCONF; + } + Status = XBram_CfgInitialize(&mpcBram, bramConfigPtr, + bramConfigPtr->CtrlBaseAddress); + if (Status != SUCCESS) + { + Mpc_Destroy(*instPtr); + return Status; + } + /* + * Execute the BRAM driver selftest. + */ + Status = XBram_SelfTest(&mpcBram, 0); + if (Status != SUCCESS) + { + Mpc_Destroy(*instPtr); + return Status; + } + + mpcHwConfig.txBuffAddr = mpcBram.Config.MemBaseAddress; + mpcHwConfig.rxBuffAddr = mpcBram.Config.MemBaseAddress; + mpcHwConfig.gpioId = config->gpioId; + + Status = MpcHw_Init(&((*instPtr)->mpchwDesc), &mpcHwConfig); + if (Status != SUCCESS) + { + Mpc_Destroy(*instPtr); + return ENOMEM; + } + if (CircQueueCreate(&((*instPtr)->txQueue), (*instPtr)->config.txQueueMax) == false) + { + Mpc_Destroy(*instPtr); + return ENOMEM; + } + if (CircQueueCreate(&((*instPtr)->rxQueue), (*instPtr)->config.rxQueueMax) == false) + { + Mpc_Destroy(*instPtr); + return ENOMEM; + } + if (CircQueueCreate(&((*instPtr)->txSvcQueue), (*instPtr)->config.rxQueueMax) == false) + { + Mpc_Destroy(*instPtr); + return ENOMEM; + } + if (CircQueueCreate(&((*instPtr)->rxSvcQueue), (*instPtr)->config.rxQueueMax) == false) + { + Mpc_Destroy(*instPtr); + return ENOMEM; + } + (*instPtr)->isEnable = false; // nothing received. + (*instPtr)->isRxDone = false; // nothing received. + (*instPtr)->isTxDone = true; // nothing to be sent. + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Destroy MPC instance. + * + * @param InstPtr A pointer to MPC instance. + * + * @return None. + * + ******************************************************************************/ +void Mpc_Destroy(MPC *instPtr) +{ + if (instPtr == NULL) + { + return; + } + free(instPtr->mpchwDesc); + CircQueueFree(instPtr->txQueue); + CircQueueFree(instPtr->rxQueue); + CircQueueFree(instPtr->txSvcQueue); + CircQueueFree(instPtr->rxSvcQueue); + free(instPtr); +} + + +/*****************************************************************************/ +/** + * @brief Generate a remote test response message. + * + * @param instPtr A pointer to MPC instance. + * + * @return SUCCESS + * error code + * + ******************************************************************************/ +int32_t Mpc_PendRemoteTest(MPC *instPtr) +{ + MPC_HW_FRAME *mpcRsp; + uint8_t *msg; + if (!Mpc_IsEnable(instPtr)) + { + DBG_ERROR("System is not enabled!\n"); + return EIGNORE; + } + mpcRsp = malloc(sizeof(MPC_HW_FRAME)); + if (mpcRsp == NULL) + { + DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n"); + return ENOMEM; + } + msg = mpcRsp->data + FRAME_PAYLOAD_POFFSET; + mpcRsp->len = RM_TEST_RESP_LEN; + if (L2_GetNodeType(linkInstPtr) == L2_NODE_HEAD) + { + // head node config + msg[WD_CMD] = CMD_FLJ_RM_TEST; + } + else + { + msg[WD_CMD] = CMD_LJ_RM_TEST; + } + msg[WD_PRD] = MY_PRD_ID; + + TIME_WORD tmWord; + uint64_t time; + TimeCtrl_GetCurrentTime(linkInstPtr->config.tmcInstPtr, &tmWord); + time = (uint64_t)tmWord.int_part * TIME_FRAC_MAX + tmWord.frac_part; + memcpy(msg + WD_TIME_STAMP, &time, WD_TIME_STAMP_LEN); + SysMonitor_GetLinklayerLog(&(instPtr->linkLog)); + SysMonitor_GetPhysicalLayerLog(&(instPtr->phyLog)); + SysMonitor_GetHardwareStatus(&(instPtr->hwState)); + memcpy(msg + WD_SYSBUS_LOG, &(instPtr->mpcLog), WD_SYSBUS_LOG_LEN); + memcpy(msg + WD_LINK_LOG, &(instPtr->linkLog), WD_LINK_LOG_LEN); + memcpy(msg + WD_PHY_LOG, &(instPtr->phyLog), WD_PHY_LOG_LEN); + memcpy(msg + WD_HARDWARE_ST, &(instPtr->hwState.spFpgaVolt), WD_HARDWARE_ST_LEN); + + if (CircQueuePush(instPtr->txQueue, (void *)mpcRsp) == false) + { + free(mpcRsp); + DBG_WARNING("SystemBus::TX Queue overflowed!\n"); + return EQUEUE; + } + instPtr->mpcLog.remoteCnt++; + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief A handler function. This handler evaluate the message from system + * bus receive queue, and make appropriate response. + * + * @param instPtr A pointer to MPC instance. + * + * @return None + * + ******************************************************************************/ +int32_t Mpc_HandleCmd(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + int32_t Status; + MPC_HW_FRAME *mpcReq; + uint8_t *reqMsg; + if (CircQueuePop(instPtr->rxQueue, (void **)(&mpcReq)) == false) + { + DBG_WARNING("SystemBus::Nothing to be handled.\n"); + return EIGNORE; + } + reqMsg = mpcReq->data + FRAME_PAYLOAD_POFFSET; + if (reqMsg[WD_PRD] != MY_PRD_ID && reqMsg[WD_PRD] != PRD_ALL) + { + DBG_WARNING("SystemBus::Production code mismatch!\n"); + return EIGNORE; + } + + switch (reqMsg[WD_CMD]) + { + case CMD_CONFIG: + Status = Mpc_SystemConfig(instPtr, reqMsg); + if (Status == SUCCESS) + { + Status = Mpc_GenSelfTestRsp(instPtr); + } + break; + case CMD_DATA_DL: + Status = Mpc_ReceiveSvcDate(instPtr, reqMsg); + break; + default: + DBG_ERROR("SystemBus::Unknown command code!\n"); + Status = FAILURE; + break; + } + free(mpcReq); + return Status; +} + +/*****************************************************************************/ +/** + * @brief This function send a repose frame from MPC tx queue. + * + * @param instPtr A pointer to MPC instance. + * + * @return None + * + ******************************************************************************/ +int32_t Mpc_MakeResp(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + int32_t Status; + MPC_HW_FRAME *mpcRsp; + if (CircQueuePop(instPtr->txQueue, (void **)(&mpcRsp)) == false) + { + DBG_WARNING("SystemBus::Nothing to be sent.\n"); + return EIGNORE; + } + instPtr->isTxDone = false; // A transmission procedure is started. + Status = MpcHw_Send(instPtr->mpchwDesc, mpcRsp); + free(mpcRsp); + return Status; +} + +/*****************************************************************************/ +/** + * @brief This function handles the mpc tx irq events. + * + * @param instPtr A pointer to MPC instance. + * + * @return None + * + ******************************************************************************/ +int32_t Mpc_TxIrqHandler(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + // nothing special... + instPtr->isTxDone = true; // A transmission procedure finished. + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief This function handles the mpc rx irq events. + * + * @param instPtr A pointer to MPC instance. + * + * @return None + * + ******************************************************************************/ +int32_t Mpc_RxIrqHandler(MPC *instPtr) +{ + ASSERT(instPtr != NULL); + int32_t Status; + MPC_HW_FRAME *mpcReq; + instPtr->isRxDone = true; // whether reception successes or not, receiving procedure ended. + mpcReq = malloc(sizeof(MPC_HW_FRAME)); + if (mpcReq == NULL) + { + return ENOMEM; + } + Status = MpcHw_Recv(instPtr->mpchwDesc, mpcReq); + if (Status != SUCCESS) + { + DBG_ERROR("SystemBus::RX error!\n"); + free(mpcReq); + return Status; + } + if (CircQueuePush(instPtr->rxQueue, (void *)mpcReq) == false) + { + DBG_ERROR("SystemBus::RX Queue overflowed!\n"); + free(mpcReq); + return EQUEUE; + } + instPtr->isRxDone = false; // another reception is undergoing. + return SUCCESS; +} diff --git a/src/mpc/mpc.h b/src/mpc/mpc.h new file mode 100644 index 0000000..7c2f768 --- /dev/null +++ b/src/mpc/mpc.h @@ -0,0 +1,82 @@ +/*****************************************************************************/ +/** + * Description: MPC protocol head file. + * + * Date: 2023-05-06 10:12 + * Last Edit Time: [2023-05-06 10:13] + * + * Revisions: Rev 0.0 + * History: + * [2023-05-06]: Initial version. + * + * Copyright(c) 2021 Beijing Institute of Technology. + * + ******************************************************************************/ + +#ifndef __MPC_H_ +#define __MPC_H_ + +/***************************** Include Files *********************************/ +#include +#include +#include "mpc_hw.h" // MPC driver +#include "circ_queue.h" +#include "ring_buffer.h" +#include "../system_monitor.h" + +/************************** Constant Definitions *****************************/ +/************************** Data Type Definitions ****************************/ +// Definition of MPC instance. +typedef struct +{ + uint32_t bramId; + uint32_t gpioId; + uint32_t txQueueMax; + uint32_t rxQueueMax; +} MPC_CONFIG; + +typedef struct +{ + MPC_CONFIG config; + SYSBUSLOG mpcLog; // mpc log + LINKLOG linkLog; // Link layer log + PHYLOG phyLog; // Physical layer log + HWSTATE hwState; // Hardware status + MPC_HW *mpchwDesc; + RING_BUFFER *currSvcBuff; + CIRC_QUEUE *txQueue; ///< tx queue for systembus message + CIRC_QUEUE *rxQueue; ///< rx queue for systembus message + CIRC_QUEUE *txSvcQueue; ///< tx queue for service data + CIRC_QUEUE *rxSvcQueue; ///< rx queue for service data + bool isEnable; + bool isRxDone; + bool isTxDone; +} MPC; + +/************************** Function Prototypes ******************************/ + +int32_t Mpc_Init(MPC **instPtr, MPC_CONFIG *config); +void Mpc_Destroy(MPC *instPtr); + +int32_t Mpc_HandleCmd(MPC *instPtr); +int32_t Mpc_PendRemoteTest(MPC *instPtr); +int32_t Mpc_MakeResp(MPC *instPtr); +int32_t Mpc_UploadSvcData(MPC *instPtr); + +int32_t Mpc_TxIrqHandler(MPC *instPtr); +int32_t Mpc_RxIrqHandler(MPC *instPtr); + +bool Mpc_IsEnable(MPC *instPtr); + +bool Mpc_IsReqPending(MPC *instPtr); +bool Mpc_IsRsqPending(MPC *instPtr); + +bool Mpc_IsTxBusy(MPC *instPtr); +bool Mpc_IsRxBusy(MPC *instPtr); + +bool Mpc_IsSvcUpPending(MPC *instPtr); +bool Mpc_IsSvcDownPending(MPC *instPtr); +bool Mpc_PushSvcFrame(MPC *instPtr, void* buff); +bool Mpc_PopSvcFrame(MPC *instPtr, void** buff); + +#endif //__MPC_H_ diff --git a/src/mpc/mpc_hw.c b/src/mpc/mpc_hw.c new file mode 100644 index 0000000..109df82 --- /dev/null +++ b/src/mpc/mpc_hw.c @@ -0,0 +1,140 @@ +/*****************************************************************************/ +/** + * Description: MPC uart driver implementation file. + * + * Date: 2023-05-06 10:59 + * LastEditTime: 2023-05-06 21:56 + * Revisions: Rev 0.0 + * History: + * [2023-05-06]: Initial version. + * + * Copyright(c) 2022 Beijing Institute of Technology. + * + ******************************************************************************/ + +/***************************** Include Files *******************************/ +#include +#include +#include +#include +#include "mpc_hw.h" +#include "common.h" +#include "error.h" + +// Control and status register +#define MODULE_VERSION 0 +#define MPC_STATUS 4 +#define MPC_SEND_CMD 8 +#define MPC_RECV_CNT 12 + +// Status code +#define MPC_STATUS_TX_BUSY 0x00010000 +#define MPC_STATUS_RX_BUSY 0x01000000 +// Data buffer register +#define MPC_TXBUFF_MAX 512 +#define MPC_RXBUFF_MAX 512 + +// Frame Data offsets +#define FRAME_HEAD_LOW 0x02 +#define FRAME_HEAD_HIGH 0x53 +#define FRAME_TAIL_LOW 0x32 +#define FRAME_TAIL_HIGH 0x20 + +#define FRAME_HEAD_LEN 2 +#define FRAME_TAIL_LEN 2 +#define FRAME_DUMMY_LEN 1 // Dummy +#define FRAME_OVERHEAD_LEN 2 // CheckSum, Dummy and + +#define MPC_STATUS_CH 1 +#define MPC_CONFIG_CH 2 + +#define MPC_CONFIG_SEND_TRIG 0x00000002 +/*************************** Function Definitions ****************************/ + +/*****************************************************************************/ +/** + * @brief Instance initial + * + * @param instPtr A pointer to frame uart instance structure. + * @param config Base address of frame uart, refer to "xparameters.h" + * + * @return None. + * + ******************************************************************************/ +int MpcHw_Init(MPC_HW **instPtr, MPC_HW_CONFIG *config) +{ + ASSERT(instPtr != NULL); + ASSERT(config != NULL); + uint32_t Status; + (*instPtr) = malloc(sizeof(MPC_HW)); + if ((*instPtr) == NULL) + { + return FAILURE; + } + (*instPtr)->config.txBuffAddr = config->txBuffAddr; + (*instPtr)->config.rxBuffAddr = config->rxBuffAddr; + Status = XGpio_Initialize(&((*instPtr)->gpioDesc), config->gpioId); + if (Status != SUCCESS) { + DBG_ERROR("MPC gpio Initialization Failed.\n"); + free(*instPtr); + return FAILURE; + } + XGpio_SetDataDirection(&((*instPtr)->gpioDesc), MPC_CONFIG_CH, 0x00000000); + XGpio_SetDataDirection(&((*instPtr)->gpioDesc), MPC_STATUS_CH, 0xFFFFFFFF); + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Send a MPC frame. + * + * @param instPtr A pointer to MPC_HW instance structure. + * @param buff A pointer to send data buffer + * @param dLen A integer indicate the send data buffer length in byte. + * + * @return + * + ******************************************************************************/ +int MpcHw_Send(MPC_HW *instPtr, MPC_HW_FRAME *frame) +{ + ASSERT(instPtr != NULL); + ASSERT(frame != NULL); + size_t sendLen; + uint8_t *sendBuff = (uint8_t*) instPtr->config.txBuffAddr; + sendLen = frame->len + FRAME_OVERHEAD_LEN; + if (sendLen > MPC_TXBUFF_MAX || frame->len == 0) + { + return FAILURE; + } + frame->data[0] = FRAME_HEAD_LOW; + frame->data[1] = FRAME_HEAD_HIGH; + memcpy(sendBuff, frame->data, sendLen); + + // Start Sending + uint32_t gpioVal = XGpio_DiscreteRead(&(instPtr->gpioDesc), MPC_CONFIG_CH); + gpioVal ^= MPC_CONFIG_SEND_TRIG; + XGpio_DiscreteWrite(&(instPtr->gpioDesc), MPC_CONFIG_CH, gpioVal); + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Get last MPC frame. + * + * @param instPtr A pointer to MPC_HW instance structure. + * @param buff A pointer to receive data buffer. + * + * @return + * + ******************************************************************************/ +int MpcHw_Recv(MPC_HW *instPtr, MPC_HW_FRAME *frame) +{ + ASSERT(instPtr != NULL); + ASSERT(frame != NULL); + uint8_t *recvBuff = (uint8_t *)(instPtr->config.rxBuffAddr); + memcpy(frame->data, recvBuff, MPC_FRAME_MAX); + frame->len = MPC_FRAME_MAX; + frame->isValid = true; + return SUCCESS; +} + diff --git a/src/mpc/mpc_hw.h b/src/mpc/mpc_hw.h new file mode 100644 index 0000000..89493ae --- /dev/null +++ b/src/mpc/mpc_hw.h @@ -0,0 +1,98 @@ +/*****************************************************************************/ +/** + * Description: MPC uart driver implementation file. + * + * Date: 2023-05-06 10:59 + * LastEditTime: 2023-05-06 21:48 + * Revisions: Rev 0.0 + * History: + * [2023-05-06]: Initial version. + * + * Copyright(c) 2022 Beijing Institute of Technology. + * + ******************************************************************************/ + +#ifndef __MPC_HW_H +#define __MPC_HW_H + +/**************************** Include Files *****************************/ +#include +#include +#include "util.h" +#include "xgpio.h" + +#define MPC_FRAME_MAX 512 +#define FRAME_PAYLOAD_POFFSET 2 // CheckSum, Dummy and DataLen +/**************************** Type Definitions *****************************/ +/** + * + * Write a value to a SYSTEMBUS_UART register. A 32 bit write is performed. + * If the component is implemented in a smaller width, only the least + * significant data is written. + * + * @param baseAddr is the base address of the SYSTEMBUS_UARTdevice. + * @param offset is the register offset from the base to write to. + * @param data is the data written to the register. + * + * @return None. + * + * @note + * C-style signature: + * void MPC_HW_mWriteReg(uint32_t BaseAddress, unsigned RegOffset, uint32_t Data) + * + */ +#define MPC_HW_mWriteReg(baseAddr, offset, data) \ + IO_Out32((baseAddr) + (offset), (uint32_t)(data)) + +/** + * + * Read a value from a SYSTEMBUS_UART register. A 32 bit read is performed. + * If the component is implemented in a smaller width, only the least + * significant data is read from the register. The most significant data + * will be read as 0. + * + * @param baseAddr is the base address of the SYSTEMBUS_UART device. + * @param offset is the register offset from the base to write to. + * + * @return Data is the data from the register. + * + * @note + * C-style signature: + * uint32_t MPC_HW_mReadReg(uint32_t BaseAddress, unsigned RegOffset) + * + */ +#define MPC_HW_mReadReg(baseAddr, offset) \ + IO_In32((baseAddr) + (offset)) + +typedef struct +{ + uintptr_t txBuffAddr; + uintptr_t rxBuffAddr; + uint32_t gpioId; +} MPC_HW_CONFIG; + +typedef struct +{ + MPC_HW_CONFIG config; + XGpio gpioDesc; +} MPC_HW; + +typedef struct +{ + uint16_t len; + uint8_t checkSum; + uint8_t isValid; + uint8_t data[MPC_FRAME_MAX]; +} MPC_HW_FRAME; + +/************************** Function Prototypes ******************************/ +// Instance initial +int MpcHw_Init(MPC_HW **instPtr, MPC_HW_CONFIG *config); + +// Send a MPC frame. +int MpcHw_Send(MPC_HW *instPtr, MPC_HW_FRAME *frame); + +// Get last MPC frame. +int MpcHw_Recv(MPC_HW *instPtr, MPC_HW_FRAME *frame); + +#endif // __MPC_HW_H diff --git a/src/networking/link_layer/framing.c b/src/networking/link_layer/framing.c index f926b1b..dff9581 100644 --- a/src/networking/link_layer/framing.c +++ b/src/networking/link_layer/framing.c @@ -29,7 +29,6 @@ #include "link_layer.h" /************************** Constant Definitions *****************************/ - /*****************************************************************************/ /** * @brief Insert a data chunk to a bit array. @@ -42,7 +41,7 @@ * @return NONE * ******************************************************************************/ -void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk) +inline void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk) { ASSERT(frame != NULL); ASSERT(chunk != NULL); @@ -61,13 +60,33 @@ void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void * @return NONE * ******************************************************************************/ -void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk) +inline void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk) { ASSERT(frame != NULL); ASSERT(chunk != NULL); memcpy(chunk, frame + offset, bytes); } +/*****************************************************************************/ +/** + * @brief Insert a integer to a bit array. + * + * @param frame pointer to target bit array. + * @param offset offset of insert start position. + * @param bytes the number of bytes of integer + * @param val data value + * + * @return NONE + * + ******************************************************************************/ +void L2_FrameInsertInteger(uint8_t *frame, size_t offset, size_t bytes, uint64_t val) +{ + ASSERT(bytes <= 4 && bytes > 0); + uint64_t _val = val; + L2_FrameInsertChunk(frame, offset, bytes, &_val); +} + + /*****************************************************************************/ /** * @brief Generate crc of specified data. diff --git a/src/networking/link_layer/link_layer.c b/src/networking/link_layer/link_layer.c index f4aba4b..2444507 100644 --- a/src/networking/link_layer/link_layer.c +++ b/src/networking/link_layer/link_layer.c @@ -27,10 +27,7 @@ #include "common.h" #include "util.h" #include "circ_queue.h" -#include "../time_ctrl/time_ctrl.h" -#ifndef EMULATION -#include "../config/app_config.h" -#endif +#include "time_ctrl/time_ctrl.h" /************************** Constant Definitions *****************************/ #define NET_START_TIME_INFTY UINT32_MAX #define LINK_BROCK_THRESHOLD L2_SLOTS_PER_FRAME // 0.5 secods @@ -159,12 +156,18 @@ static void L2_FrameStateUpdate(L2_INST *instPtr) instPtr->log.cfmRecvCnt++; instPtr->log.cfmCorrectCnt = isValid ? instPtr->log.cfmCorrectCnt + 1 : instPtr->log.cfmCorrectCnt; break; - case L2_SVC_FRAME: -#ifndef DATALINK_ENABLE_BERTEST - isValid = L2_CrcCheck(instPtr->recvPktData, L2_SVC_PACK_LEN, L2_CRC16_1021); -#else - isValid = true; -#endif + case L2_SVC_2K_FRAME: + isValid = L2_CrcCheck(instPtr->recvPktData, L2_SVC_PACK_2K_LEN, L2_CRC16_1021); + instPtr->log.svcRecvCnt++; + instPtr->log.svcCorrectCnt = isValid ? instPtr->log.svcCorrectCnt + 1 : instPtr->log.svcCorrectCnt; + break; + case L2_SVC_128K_FRAME: + isValid = L2_CrcCheck(instPtr->recvPktData, L2_SVC_PACK_128K_LEN, L2_CRC16_1021); + instPtr->log.svcRecvCnt++; + instPtr->log.svcCorrectCnt = isValid ? instPtr->log.svcCorrectCnt + 1 : instPtr->log.svcCorrectCnt; + break; + case L2_SVC_256K_FRAME: + isValid = L2_CrcCheck(instPtr->recvPktData, L2_SVC_PACK_256K_LEN, L2_CRC16_1021); instPtr->log.svcRecvCnt++; instPtr->log.svcCorrectCnt = isValid ? instPtr->log.svcCorrectCnt + 1 : instPtr->log.svcCorrectCnt; break; @@ -333,6 +336,15 @@ inline L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr) return instPtr->frame.curr; } +/** + * @brief Get the current working speed mode. + */ +inline L2_SPEED_MODE L2_GetCurrentSpeedMode(L2_INST *instPtr) +{ + ASSERT(instPtr != NULL); + return instPtr->speedMode; +} + /** * @brief Get the tx/rx state of current slot. */ @@ -422,8 +434,12 @@ L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame) case L2_ADV_FRAME: return L1_10KBPS_20MS_FRAME; case L2_CFM_FRAME: - case L2_SVC_FRAME: + case L2_SVC_2K_FRAME: return L1_40KBPS_20MS_FRAME; + case L2_SVC_128K_FRAME: + return L1_200KBPS_5MS_FRAME; + case L2_SVC_256K_FRAME: + return L1_1M2BPS_5MS_FRAME; default: return L1_NONE_FRAME; } @@ -471,6 +487,7 @@ int32_t Linklayer_Init(L2_INST **instPtr, const L2_CONFIG *config) // Clear random content memset(*instPtr, 0x00, sizeof(L2_INST)); + (*instPtr)->speedMode = config->speedMode; (*instPtr)->sendPktData = NULL; (*instPtr)->recvPktData = NULL; (*instPtr)->schdEventPool = NULL; @@ -802,8 +819,25 @@ int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event) else if (instPtr->nextState == L2_NORMAL_STATE) { UpdateMainSate(instPtr, L2_NORMAL_STATE); - instPtr->rtneConfig.rtneTable = normalTable; - instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable); + switch(L2_GetCurrentSpeedMode(instPtr)){ + case L2_SPEED_NONE : + DBG_WARNING("Speed mode not configured, fallback to 2Kbps mode.\n"); + case L2_SPEED_2KBPS : + instPtr->rtneConfig.rtneTable = normalTable2K; + instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable2K); + break; + case L2_SPEED_128KBPS : + instPtr->rtneConfig.rtneTable = normalTable128K; + instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable128K); + break; + case L2_SPEED_256KBPS : + instPtr->rtneConfig.rtneTable = normalTable256K; + instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable256K); + break; + default: + DBG_ERROR("Unknown speed mode %d.\n", instPtr->speedMode); + ASSERT(true); + } } else { @@ -856,7 +890,9 @@ int32_t Linklayer_PktHandler(L2_INST *instPtr, L2_FRAME_TYPE frameType) case L2_CFM_FRAME: Status = L2_Scan_PktHandler(instPtr, instPtr->recvPktData); break; - case L2_SVC_FRAME: + case L2_SVC_2K_FRAME: + case L2_SVC_128K_FRAME: + case L2_SVC_256K_FRAME: Status = L2_Service_PktHandler(instPtr, instPtr->recvPktData); break; default: @@ -880,7 +916,6 @@ static int32_t IntcNodeTTL(NODE_ENTRY *node, const void *param) /** * @brief Utility function to check connection to node is still valid. */ -#ifdef DATALINK_ENABLE_AUTORECONNECT static bool IsNodeConnected(NODE_ENTRY *node) { ASSERT(node != NULL); @@ -895,7 +930,6 @@ static bool IsNodeConnected(NODE_ENTRY *node) return false; } } -#endif /*****************************************************************************/ /** @@ -937,7 +971,9 @@ static int32_t Linklayer_Routine(L2_INST *instPtr) case L2_SLOT_CONFIRM: Status = L2_Scan_Routine(instPtr, &rtneEntry); break; - case L2_SLOT_SERVICE: + case L2_SLOT_SERVICE_2K: + case L2_SLOT_SERVICE_128K: + case L2_SLOT_SERVICE_256K: Status = L2_Service_Routine(instPtr, &rtneEntry); break; default: @@ -956,7 +992,7 @@ static int32_t Linklayer_Routine(L2_INST *instPtr) uint32_t increment = 1; L2_IterEditNode(instPtr->nodeList, &increment, IntcNodeTTL); -#ifdef DATALINK_ENABLE_AUTORECONNECT +//#ifdef DATALINK_ENABLE_AUTORECONNECT if (L2_GetMainState(instPtr) != L2_INIT_STATE) { L2_IterDeleteNode(instPtr->nodeList, IsNodeConnected); @@ -970,7 +1006,7 @@ static int32_t Linklayer_Routine(L2_INST *instPtr) AssertL2Event(instPtr, &l2Event); } } -#endif +//#endif return Status; } @@ -1165,7 +1201,7 @@ int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE f ASSERT(instPtr != NULL); PHY_INST *phyRef = instPtr->config.phyInstPtr; int32_t Status; - if (frameType < L2_SCAN_FRAME || frameType > L2_SVC_FRAME) + if (frameType < L2_SCAN_FRAME || frameType > L2_SVC_256K_FRAME) { return FAILURE; } @@ -1182,7 +1218,9 @@ int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE f case L2_CFM_FRAME: instPtr->log.cfmTxCnt++; break; - case L2_SVC_FRAME: + case L2_SVC_2K_FRAME: + case L2_SVC_128K_FRAME: + case L2_SVC_256K_FRAME: instPtr->log.svcTxCnt++; break; default: @@ -1200,7 +1238,9 @@ int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE f case L2_CFM_FRAME: instPtr->log.cfmRxCnt++; break; - case L2_SVC_FRAME: + case L2_SVC_2K_FRAME: + case L2_SVC_128K_FRAME: + case L2_SVC_256K_FRAME: instPtr->log.svcRxCnt++; break; default: @@ -1284,5 +1324,16 @@ int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE f } return Status; } + +int32_t Linklayer_UpdateSpeedMode(L2_INST *instPtr, L2_SPEED_MODE mode) { + ASSERT(instPtr != NULL); + if(mode < L2_SPEED_2KBPS || mode > L2_SPEED_256KBPS){ + DBG_ERROR("Unsurpport speed mode, %d.\n", mode); + return EIGNORE; + } + instPtr->speedMode = mode; + return SUCCESS; +} + /** @} LinkLayer_Main*/ /** @} LinkLayer*/ diff --git a/src/networking/link_layer/link_layer.h b/src/networking/link_layer/link_layer.h index cbe8ad2..2c68431 100644 --- a/src/networking/link_layer/link_layer.h +++ b/src/networking/link_layer/link_layer.h @@ -25,8 +25,8 @@ #include "schdevent.h" #include "node_list.h" #include "circ_queue.h" -#include "../phy_layer/phy_layer.h" -#include "../../system_monitor.h" +#include "networking/phy_layer/phy_layer.h" +#include "system_monitor.h" /************************** Constant Definitions *****************************/ /***************** Macros (Inline Functions) Definitions *********************/ #define AssertL2Event(instPtr, event) (Linklayer_EventHandler((instPtr), (event))) @@ -45,6 +45,9 @@ typedef struct uint8_t netScale; ///< net scale PHY_INST *phyInstPtr; ///< pointer to system physical layer instance TMC_INST *tmcInstPtr; ///< pointer to system timer controller layer instance + L2_SPEED_MODE speedMode;///< service speed mode + PUSHUP_HANDLE pushUpHandle; + POPUP_HANDLE popUpHandle; } L2_CONFIG; /** @@ -104,6 +107,7 @@ typedef struct L2_RTNE_CONFIG rtneConfig; ///< current routine table configuration and status. L2_SCAN_FSM *scanFSM; ///< FSM of scan net (link set up) L2_SVC_FSM *serviceFSM; ///< FSM of service net (data service) + L2_SPEED_MODE speedMode; uint8_t *sendPktData; ///< send data buffer uint8_t *recvPktData; ///< received data buffer L2_LOG log; ///< Linklayer operating log @@ -114,7 +118,9 @@ typedef struct /************************** Variable Definitions *****************************/ extern L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD]; -extern L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD]; +extern L2_RTNE_TABLE_ENTRY *normalTable2K[L2_NORMAL_RTNE_PERIOD]; +extern L2_RTNE_TABLE_ENTRY *normalTable128K[L2_NORMAL_RTNE_PERIOD]; +extern L2_RTNE_TABLE_ENTRY *normalTable256K[L2_NORMAL_RTNE_PERIOD]; /************************** Function Prototypes ******************************/ /** * @defgroup LinkLayer_Main @@ -130,6 +136,7 @@ int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event); int32_t Linklayer_PktHandler(L2_INST *instPtr, L2_FRAME_TYPE frameType); int32_t L2_SteerBeam2Node(L2_INST *instPtr, uint8_t nodeId); int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE frameType); +int32_t Linklayer_UpdateSpeedMode(L2_INST *instPtr, L2_SPEED_MODE mode); /** @} LinkLayer_Main*/ /** @@ -138,6 +145,7 @@ int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE f */ void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk); void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk); +void L2_FrameInsertInteger(uint8_t *frame, size_t offset, size_t bytes, uint64_t val); int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType); bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType); /** @} LinkLayer_Framing*/ @@ -174,7 +182,6 @@ int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr); void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr); void L2_Service_Destroy(L2_SVC_FSM *svcFSMPtr); int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg); -int32_t L2_Service_Proc(L2_INST *instPtr); int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry); /** @} LinkLayer_Service*/ @@ -206,6 +213,7 @@ L2_TOR_TYPE L2_GetLastTor(L2_INST *instPtr); uint32_t L2_GetCurrentFrameNum(L2_INST *instPtr); uint32_t L2_GetCurrentSlotNum(L2_INST *instPtr); L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr); +L2_SPEED_MODE L2_GetCurrentSpeedMode(L2_INST *instPtr); L2_TOR_TYPE L2_GetCurrentTor(L2_INST *instPtr); uint32_t L2_GetNextFrameNum(L2_INST *instPtr); uint32_t L2_GetNextSlotNum(L2_INST *instPtr); @@ -213,8 +221,9 @@ L2_FRAME_TYPE L2_GetNextFrameType(L2_INST *instPtr); L2_TOR_TYPE L2_GetNextTor(L2_INST *instPtr); L2_FRAME_TYPE L2_GetLastOptFrameType(L2_INST *instPtr); L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame); + /** @} LinkLayer_Utility*/ #endif /* __LINK_LAYER_H_ */ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/link_layer/link_layer_types.h b/src/networking/link_layer/link_layer_types.h index 1e9f46e..92956ca 100644 --- a/src/networking/link_layer/link_layer_types.h +++ b/src/networking/link_layer/link_layer_types.h @@ -21,12 +21,10 @@ /***************************** Include Files *********************************/ #include #include +#include "ring_buffer.h" #include "geometry/coord.h" #include "geometry/quaternion.h" -#include "../phy_layer/phy_layer.h" -#ifndef EMULATION -#include "../config/app_config.h" -#endif +#include "networking/phy_layer/phy_layer.h" /************************** Constant Definitions *****************************/ /** * @name Linklayer_Common_Constants @@ -158,7 +156,9 @@ typedef enum L2_SLOT_SCAN = 2, L2_SLOT_ADVERTISE = 3, L2_SLOT_CONFIRM = 4, - L2_SLOT_SERVICE = 5, + L2_SLOT_SERVICE_2K = 5, + L2_SLOT_SERVICE_128K = 6, + L2_SLOT_SERVICE_256K = 7, } L2_SLOT_TYPE; /** @@ -170,9 +170,22 @@ typedef enum L2_SCAN_FRAME = 1, L2_ADV_FRAME = 2, L2_CFM_FRAME = 3, - L2_SVC_FRAME = 4 + L2_SVC_2K_FRAME = 4, + L2_SVC_128K_FRAME = 5, + L2_SVC_256K_FRAME = 6 } L2_FRAME_TYPE; +/** + * @enum L2_SPEED_MODE + */ +typedef enum +{ + L2_SPEED_NONE = 0, + L2_SPEED_2KBPS = 1, + L2_SPEED_128KBPS = 2, + L2_SPEED_256KBPS = 3, +} L2_SPEED_MODE; + /** * @enum L2_CRC_TYPE */ @@ -234,12 +247,10 @@ typedef struct uint32_t txCnt; ///< tx frame count uint32_t rxCnt; ///< rx frame count uint32_t rxdCnt; ///< received frame count -#ifdef DATALINK_ENABLE_BERTEST - uint32_t bitTotal; ///< received bits count - uint32_t bitError; ///< error bits count - double lossRate; ///< packet loss rate - double errorRate; ///< bit error rate -#endif + uint8_t currTxSeq; ///< seqid of current tx frame sub-packet + uint8_t currRxSeq; ///< seqid of current rx frame sub-packet + RING_BUFFER *currTxBuff; ///< a ring buffer to store data to be sent + RING_BUFFER *currRxBuff; ///< a ring buffer to store data received } L2_SVC_FSM; /** @@ -255,8 +266,12 @@ typedef struct L2_RTNE_TABLE_ENTRY *next; ///< next routine entry } L2_RTNE_CONFIG; + +typedef bool (*PUSHUP_HANDLE) (RING_BUFFER *buff); +typedef bool (*POPUP_HANDLE) (RING_BUFFER **buff); + /************************** Variable Definitions *****************************/ #endif /* __LINK_LAYER_DEF_H_ */ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/link_layer/msg_def.h b/src/networking/link_layer/msg_def.h index 6c03db3..ad52584 100644 --- a/src/networking/link_layer/msg_def.h +++ b/src/networking/link_layer/msg_def.h @@ -1,6 +1,6 @@ /*****************************************************************************/ /** - * @file msg_def.c + * @file msg_def.h * @author FanHao (hao_fan_bit_ee@163.com) * @brief DF Linklayer message definition constants. * @version 0.0 @@ -20,14 +20,34 @@ * @name LinkLayer_MSG_Constants * @{ */ + + #ifndef __L2_MSG_DEF_H_ #define __L2_MSG_DEF_H_ +#include "link_layer.h" + #define L2_PACK_LEN_MAX 512 // bytes #define L2_ADV_PACK_LEN 28 // bytes #define L2_CMF_PACK_LEN 268 // bytes -#define L2_SVC_PACK_LEN 268 // bytes +#define L2_SVC_PACK_2K_LEN 30 // bytes: 16(128b) payload + 12 head + 2 crc +#define L2_SVC_PACK_128K_LEN 174 // bytes: 160(1280b) payload + 12 head + 2 crc +#define L2_SVC_PACK_256K_LEN 334 // bytes: 320(2560b) payload + 12 head + 2 crc + +#define L2_ASSEMBLE_INTEGER(buff, offset, val) { \ + L2_FrameInsertInteger(buff, offset, offset##_LEN, val); \ + } +#define L2_ASSEMBLE_FLOAT(buff, offset, ptr) { \ + L2_FrameInsertChunk(buff, offset, sizeof(float), ptr); \ + } +#define L2_ASSEMBLE_DOUBLE(buff, offset, ptr) { \ + L2_FrameInsertChunk(buff, offset, sizeof(double), ptr); \ + } + +#define L2_DEASSEMBLE(buff, offset, ptr) { \ + L2_FrameGetChunk(buff, offset, offset##_LEN, ptr); \ + } // Common structure: // [bytes] [name] @@ -96,35 +116,20 @@ // service payload structure: // [bytes] [name] -// 4 position x -// 4 position y -// 4 position z -// 4 speed x -// 4 speed y -// 4 speed z -// 234 payload -// 2 crc -#define L2_MSG_SVC_SRC_POSX 8 -#define L2_MSG_SVC_SRC_POSX_LEN 4 -#define L2_MSG_SVC_SRC_POSY 12 -#define L2_MSG_SVC_SRC_POSY_LEN 4 -#define L2_MSG_SVC_SRC_POSZ 16 -#define L2_MSG_SVC_SRC_POSZ_LEN 4 -#define L2_MSG_SVC_SRC_SPEEDX 20 -#define L2_MSG_SVC_SRC_SPEEDX_LEN 4 -#define L2_MSG_SVC_SRC_SPEEDY 24 -#define L2_MSG_SVC_SRC_SPEEDY_LEN 4 -#define L2_MSG_SVC_SRC_SPEEDZ 28 -#define L2_MSG_SVC_SRC_SPEEDZ_LEN 4 -#define L2_MSG_SVC_PAYLOAD_ID 32 -#define L2_MSG_SVC_PAYLOAD_ID_LEN 4 -#define L2_MSG_SVC_PAYLOAD 36 -#define L2_MSG_SVC_PAYLOAD_LEN 230 -#define L2_MSG_SVC_CRC 266 +// 1 packet flag +// 1 packet id +// 2 data length +#define L2_MSG_SVC_PKTFLG 8 // 0-no subpacket, 1-subpacket 2-last subpacket +#define L2_MSG_SVC_PKTFLG_LEN 1 +#define L2_MSG_SVC_PKTID 9 +#define L2_MSG_SVC_PKTID_LEN 1 +#define L2_MSG_SVC_DLEN 10 +#define L2_MSG_SVC_DLEN_LEN 2 +#define L2_MSG_SVC_PAYLOAD 12 #define L2_MSG_SVC_CRC_LEN 2 #endif //__L2_MSG_DEF_H_ /** @} LinkLayer_MSG_Constants*/ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/link_layer/routine_table.c b/src/networking/link_layer/routine_table.c index 9f69fc3..0e18682 100644 --- a/src/networking/link_layer/routine_table.c +++ b/src/networking/link_layer/routine_table.c @@ -137,127 +137,362 @@ L2_RTNE_TABLE_ENTRY intraScanSubT[L2_SLOTS_PER_FRAME] = { {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, }; -L2_RTNE_TABLE_ENTRY normalSub[L2_SLOTS_PER_FRAME] = { +L2_RTNE_TABLE_ENTRY normalSub2K[L2_SLOTS_PER_FRAME] = { // SubFrame 0 - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, // SubFrame 1 - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, // SubFrame 2 - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, // SubFrame 3 - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, // SubFrame 4 - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x01, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x02, 0x01, 0x02}, - {L2_SLOT_SERVICE, 0x03, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x01, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x02, 0x01, 0x02}, + {L2_SLOT_SERVICE_2K, 0x03, 0x01, 0x02}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, - {L2_SLOT_SERVICE, 0x00, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x01, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x02, 0x02, 0x01}, - {L2_SLOT_SERVICE, 0x03, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x01, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x02, 0x02, 0x01}, + {L2_SLOT_SERVICE_2K, 0x03, 0x02, 0x01}, {L2_SLOT_IDLE, 0x00, 0x00, 0x00}, }; + +L2_RTNE_TABLE_ENTRY normalSub128K[L2_SLOTS_PER_FRAME] = { +// SubFrame 0 + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + +// SubFrame 1 + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + +// SubFrame 2 + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + +// SubFrame 3 + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + +// SubFrame 4 + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_128K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_128K, 0x00, 0x02, 0x01}, +}; + +L2_RTNE_TABLE_ENTRY normalSub256K[L2_SLOTS_PER_FRAME] = { +// SubFrame 0 + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + +// SubFrame 1 + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + +// SubFrame 2 + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + +// SubFrame 3 + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + +// SubFrame 4 + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, + {L2_SLOT_SERVICE_256K, 0x00, 0x01, 0x02}, + {L2_SLOT_SERVICE_256K, 0x00, 0x02, 0x01}, +}; + L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD] = { intraScanSubT }; -L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD] = +L2_RTNE_TABLE_ENTRY *normalTable2K[L2_NORMAL_RTNE_PERIOD] = { - normalSub + normalSub2K +}; + +L2_RTNE_TABLE_ENTRY *normalTable128K[L2_NORMAL_RTNE_PERIOD] = +{ + normalSub128K +}; + +L2_RTNE_TABLE_ENTRY *normalTable256K[L2_NORMAL_RTNE_PERIOD] = +{ + normalSub256K }; /** @} RoutineTable*/ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/link_layer/scan.c b/src/networking/link_layer/scan.c index d66824a..44c83ac 100644 --- a/src/networking/link_layer/scan.c +++ b/src/networking/link_layer/scan.c @@ -28,7 +28,7 @@ #include "node_list.h" #include "error.h" #include "common.h" -#include "../phy_layer/phy_layer.h" +#include "networking/phy_layer/phy_layer.h" /************************** Constant Definitions *****************************/ #define ADV_LISTEN_TIMEOUT 40 @@ -357,7 +357,6 @@ static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dst { ASSERT(instPtr != NULL); int32_t Status; - uint32_t dataChunk; uint8_t *buff = instPtr->sendPktData; if ((type < L2_ADV_FRAME) || (type > L2_CFM_FRAME)) { @@ -366,70 +365,49 @@ static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dst } // Common section of link layer package - dataChunk = L2_GetNextFrameNum(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk); - dataChunk = L2_GetNextSlotNum(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk); - dataChunk = L2_GetNodeId(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk); - dataChunk = dstId; - L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_FRAME_NUM, L2_GetNextFrameNum(instPtr)); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_SLOT_NUM, L2_GetNextSlotNum(instPtr)); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_SRC_ID, L2_GetNodeId(instPtr)); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_DST_ID, dstId); switch (type) { case L2_ADV_FRAME: { - dataChunk = L2_ADV_FRAME; - L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_TYPE, L2_ADV_FRAME); SysMonitor_GetSysinfo(&(instPtr->sysInfo)); // insert position and speed info - L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &(instPtr->sysInfo.posX)); - L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &(instPtr->sysInfo.posY)); - L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_ADV_SRC_POSX, &(instPtr->sysInfo.posX)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_ADV_SRC_POSY, &(instPtr->sysInfo.posY)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_ADV_SRC_POSZ, &(instPtr->sysInfo.posZ)); // Insert net start time - L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &(instPtr->netStartTime)); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_ADV_SRC_NETSTART_TIME, instPtr->netStartTime); // Append CRC Status = L2_CrcAppend(buff, L2_ADV_PACK_LEN - L2_MSG_ADV_SVC_CRC_LEN, L2_MSG_ADV_SVC_CRC, L2_CRC16_1021); if (Status != SUCCESS) { DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status); - return Status; + ASSERT(true); } break; } case L2_CFM_FRAME: { - dataChunk = L2_CFM_FRAME; - L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk); + L2_ASSEMBLE_INTEGER(buff, L2_MSG_TYPE, L2_CFM_FRAME); SysMonitor_GetSysinfo(&(instPtr->sysInfo)); // insert position and speed info - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &(instPtr->sysInfo.posX)); - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &(instPtr->sysInfo.posY)); - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ)); - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX)); - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY)); - L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_POSX, &(instPtr->sysInfo.posX)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_POSY, &(instPtr->sysInfo.posY)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_POSZ, &(instPtr->sysInfo.posZ)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_SPEEDX, &(instPtr->sysInfo.vX)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_SPEEDY, &(instPtr->sysInfo.vY)); + L2_ASSEMBLE_FLOAT(buff, L2_MSG_CFM_SRC_SPEEDZ, &(instPtr->sysInfo.vZ)); // Packing extra payload - uint32_t dataId; - if (L2_GetNodeType(instPtr) == L2_NODE_HEAD) - { - SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX); - } - else - { - SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX); - } - - L2_FrameInsertChunk(buff, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId); - if (dataId == DATA_ID_NONE) - { - memset(buff + L2_MSG_CFM_PAYLOAD, 0xAA, L2_MSG_CFM_PAYLOAD_LEN); - } - + memset(buff + L2_MSG_CFM_PAYLOAD, 0xAA, L2_MSG_CFM_PAYLOAD_LEN); // Append CRC Status = L2_CrcAppend(buff, L2_CMF_PACK_LEN - L2_MSG_CFM_CRC_LEN, L2_MSG_CFM_CRC, L2_CRC16_1021); if (Status != SUCCESS) @@ -437,10 +415,6 @@ static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dst DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status); return Status; } - - // Logging... - memcpy(instPtr->log.txLog.data, buff, L2_CMF_PACK_LEN); - instPtr->log.txLog.dataId = dataId; break; } default: @@ -469,7 +443,7 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) int32_t Status; L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM; L2_FRAME_TYPE frameType = L2_NONE_FRAME; - L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType); + L2_DEASSEMBLE(msg, L2_MSG_TYPE, &frameType); switch (frameType) { case L2_SCAN_FRAME: @@ -487,7 +461,7 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) break; } uint8_t nodeId; - L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId); + L2_DEASSEMBLE(msg, L2_MSG_SRC_ID, &nodeId); NODE_ENTRY *node; node = L2_GetNodeById(instPtr->nodeList, nodeId); if (node == NULL) @@ -502,11 +476,11 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) } // Update node info. float nodePos; - L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_ADV_SRC_POSX, &nodePos); node->nodeInfo.pos.x = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_ADV_SRC_POSY, &nodePos); node->nodeInfo.pos.y = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_ADV_SRC_POSZ, &nodePos); node->nodeInfo.pos.z = (double)nodePos; node->nodeInfo.beamNo = Phy_LastScanBeamNo(instPtr->config.phyInstPtr); @@ -515,7 +489,7 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) uint32_t netstartTime; // Update net start time. - L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &netstartTime); + L2_DEASSEMBLE(msg, L2_MSG_ADV_SRC_NETSTART_TIME, &netstartTime); L2_EVENT netSetupDoneEvent = { .event = L2_EV_NET_ADV_UPDATE, .msg = &netstartTime}; @@ -523,8 +497,8 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) // Calculate time deviation uint32_t frameNum, slotNum = 0; - L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum); - L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum); + L2_DEASSEMBLE(msg, L2_MSG_FRAME_NUM, &frameNum); + L2_DEASSEMBLE(msg, L2_MSG_SLOT_NUM, &slotNum); Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev)); if (Status != SUCCESS) { @@ -543,7 +517,7 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) case L2_CFM_FRAME: { uint8_t nodeId; - L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId); + L2_DEASSEMBLE(msg, L2_MSG_SRC_ID, &nodeId); NODE_ENTRY *node; node = L2_GetNodeById(instPtr->nodeList, nodeId); if (node == NULL) @@ -558,18 +532,18 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) } // Update node info. float nodePos; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_POSX, &nodePos); node->nodeInfo.pos.x = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_POSY, &nodePos); node->nodeInfo.pos.y = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &nodePos); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_POSZ, &nodePos); node->nodeInfo.pos.z = (double)nodePos; float nodeSpeed; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &nodeSpeed); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_SPEEDX, &nodeSpeed); node->nodeInfo.speed.x = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &nodeSpeed); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_SPEEDY, &nodeSpeed); node->nodeInfo.speed.y = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &nodeSpeed); + L2_DEASSEMBLE(msg, L2_MSG_CFM_SRC_SPEEDZ, &nodeSpeed); node->nodeInfo.speed.z = (double)nodePos; // Reset node ttl @@ -577,8 +551,8 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) // Calculate time deviation uint32_t frameNum, slotNum = 0; - L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum); - L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum); + L2_DEASSEMBLE(msg, L2_MSG_FRAME_NUM, &frameNum); + L2_DEASSEMBLE(msg, L2_MSG_SLOT_NUM, &slotNum); Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev)); if (Status != SUCCESS) { @@ -625,24 +599,6 @@ int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg) (void)AssertL2Event(instPtr, &l2Event); } } - - // Get data payload - uint32_t dataId; - L2_FrameGetChunk(msg, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId); - - if (L2_GetNodeType(instPtr) == L2_NODE_HEAD) - { - SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX); - } - else - { - SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX); - } - - // Logging... - memcpy(instPtr->log.rxLog.data, msg, L2_CMF_PACK_LEN); - instPtr->log.rxLog.dataId = dataId; - Status = SUCCESS; break; } diff --git a/src/networking/link_layer/service.c b/src/networking/link_layer/service.c index 2f83863..7c00f31 100644 --- a/src/networking/link_layer/service.c +++ b/src/networking/link_layer/service.c @@ -28,51 +28,69 @@ #include "error.h" #include "common.h" #include "circ_queue.h" -#ifndef EMULATION -#include "../config/app_config.h" -#endif /************************** Constant Definitions *****************************/ +#define SERVICE_MAX 1024 +#define PAYLOAD_LEN_2K (128/8) //Byte +#define PAYLOAD_LEN_128K (1280/8) //Byte +#define PAYLOAD_LEN_256K (2560/8) //Byte +#define PACKET_TYPE_NONE 0 +#define PACKET_TYPE_SINGLE 1 +#define PACKET_TYPE_SUBPKT 2 +#define PACKET_TYPE_LASTPKT 3 + /***************** Macros (Inline Functions) Definitions *********************/ /**************************** Type Definitions *******************************/ /************************** Function Prototypes ******************************/ static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId); +static inline bool prepareCurrRx(L2_INST *instPtr); +static inline void resetCurrRx(L2_INST *instPtr); +static inline bool uploadCurrRx(L2_INST *instPtr); +static inline bool updateCurrTx(L2_INST *instPtr); /************************** Variable Definitions *****************************/ +static inline bool prepareCurrRx(L2_INST *instPtr) { + ASSERT(instPtr != NULL); + if(instPtr->serviceFSM->currRxBuff != NULL) { + return true; + } + instPtr->serviceFSM->currRxBuff = RingBuff_Create(SERVICE_MAX); + if(instPtr->serviceFSM->currRxBuff == NULL) + { + DBG_ERROR("Not enough space to initialize serviceFSM->currRxBuff ring buffer...\n"); + return false; + } + return true; +} -static uint8_t testData[L2_PACK_LEN_MAX] = -{ - 0x39, 0x85, 0x02, 0xF0, 0xC7, 0x6A, 0xE8, 0xB4, 0xE7, 0xAB, 0xC9, 0xDC, 0x0B, 0x41, 0x42, 0xE0, - 0xED, 0x21, 0x07, 0x62, 0x4E, 0x80, 0xA0, 0xE1, 0xAC, 0x77, 0x9B, 0x1F, 0x48, 0x0B, 0x58, 0xB9, - 0x45, 0xA5, 0x24, 0xEF, 0xF3, 0x71, 0x2E, 0x84, 0x6C, 0x22, 0xB3, 0x05, 0xEB, 0x75, 0xF2, 0x0B, - 0x45, 0x73, 0x01, 0xA8, 0x1E, 0x00, 0x21, 0x3E, 0x03, 0x86, 0x55, 0x59, 0x98, 0x5C, 0x61, 0xA2, - 0xE8, 0x20, 0x0E, 0x7A, 0xD5, 0x72, 0xAF, 0xF4, 0xBC, 0xB3, 0x6F, 0xFE, 0xB3, 0x78, 0x6A, 0x59, - 0x73, 0xBD, 0x97, 0xBE, 0x44, 0xA4, 0x9B, 0x71, 0x11, 0x45, 0x37, 0xFE, 0xB3, 0x71, 0xEF, 0x1E, - 0x3A, 0x2B, 0x58, 0x07, 0xF6, 0x01, 0x1C, 0x73, 0x28, 0x11, 0xA8, 0x15, 0xA2, 0x58, 0x32, 0x2E, - 0x7D, 0x35, 0x9C, 0xE4, 0x98, 0x7F, 0x9C, 0x81, 0x32, 0xAA, 0xC4, 0x87, 0x16, 0x26, 0x23, 0x95, - 0x57, 0xC9, 0xD4, 0x34, 0xCE, 0x63, 0x78, 0x7E, 0xD4, 0x3C, 0x16, 0x1D, 0x80, 0xC0, 0x55, 0xBF, - 0xB5, 0xD6, 0x0C, 0xA5, 0xB9, 0x0A, 0x14, 0x5B, 0x4D, 0x52, 0xF2, 0xA9, 0x7A, 0x08, 0x67, 0x8E, - 0xEB, 0x67, 0x34, 0x7F, 0x7A, 0x35, 0xAF, 0xD9, 0x07, 0x52, 0x30, 0x38, 0x70, 0xC9, 0x41, 0xF8, - 0x36, 0x61, 0x32, 0x72, 0xA4, 0x7A, 0xEA, 0x21, 0xB4, 0xBF, 0xAA, 0xCF, 0x93, 0x4F, 0xE1, 0x5C, - 0xA0, 0xFB, 0xD0, 0x2B, 0xA3, 0x82, 0x2E, 0x69, 0x7D, 0xB7, 0x76, 0x88, 0xF7, 0x5C, 0xF3, 0x82, - 0xC6, 0x6D, 0x49, 0x92, 0x64, 0x88, 0x9A, 0x43, 0xEE, 0xE9, 0x93, 0xC3, 0x70, 0x50, 0x22, 0xF1, - 0xD3, 0x2B, 0xCF, 0xA9, 0xE5, 0x69, 0x22, 0xF9, 0xBF, 0x78, 0x9A, 0xA4, 0x5A, 0x3D, 0x2E, 0x2A, - 0x23, 0xE3, 0x51, 0x8F, 0x1A, 0xC1, 0xAF, 0x47, 0x9C, 0x14, 0xCE, 0xB9, 0xCD, 0xD0, 0x02, 0xB7, - 0xB8, 0x81, 0xCC, 0x44, 0xE7, 0xA2, 0x6F, 0x32, 0x8C, 0x78, 0x79, 0x10, 0xF3, 0xE1, 0xB0, 0x7C, - 0xAB, 0x40, 0xDB, 0xF9, 0x99, 0xE7, 0x27, 0x30, 0x53, 0x67, 0x00, 0xE8, 0x33, 0x6D, 0xFC, 0x4D, - 0xDC, 0xB0, 0xFC, 0x3D, 0xEF, 0x8D, 0x43, 0xAF, 0x7E, 0x41, 0x69, 0xDA, 0xFD, 0xDF, 0x2F, 0xF8, - 0xEC, 0xFB, 0x6A, 0x65, 0xE7, 0xEC, 0xC7, 0x53, 0x1B, 0x14, 0xDF, 0xBD, 0x0C, 0x54, 0x57, 0xD2, - 0x56, 0x15, 0xF4, 0x34, 0xE2, 0xFB, 0x12, 0xA0, 0xA2, 0xDE, 0x82, 0xF5, 0x04, 0x81, 0x9B, 0x08, - 0xB6, 0x8C, 0x7B, 0xE0, 0xAA, 0xDF, 0xC9, 0x92, 0x9D, 0x5F, 0x2D, 0xF7, 0x4A, 0x0B, 0xFF, 0xA5, - 0xAA, 0xDC, 0xD6, 0x3F, 0x56, 0xB2, 0x6A, 0x3C, 0x6F, 0xAA, 0xAC, 0x84, 0xAC, 0x3F, 0x3D, 0x05, - 0x96, 0x12, 0x44, 0x39, 0x1C, 0xD1, 0xFA, 0xBE, 0x6B, 0x1A, 0xCD, 0x31, 0x29, 0x41, 0x31, 0xA3, - 0xA8, 0x0D, 0x87, 0xEB, 0x96, 0x21, 0x39, 0xD6, 0x3B, 0x11, 0x50, 0xB5, 0xFE, 0x44, 0x0E, 0x74, - 0x31, 0x12, 0xA1, 0x66, 0x49, 0xFD, 0x2D, 0x75, 0x72, 0xF9, 0xC8, 0xD9, 0x6C, 0xC9, 0x11, 0x74, - 0x2E, 0xEB, 0x20, 0x33, 0x3D, 0x2C, 0x5E, 0xEA, 0x39, 0x31, 0x88, 0xC7, 0xD1, 0x93, 0x95, 0xD8, - 0x9E, 0x87, 0x93, 0xBC, 0x09, 0x17, 0xC9, 0xA2, 0x59, 0x18, 0x51, 0x8F, 0xBF, 0x55, 0x45, 0x81, - 0x8D, 0xFD, 0xAF, 0xB2, 0x21, 0xB7, 0xD8, 0xA8, 0x00, 0x2E, 0x70, 0x73, 0x2F, 0x74, 0xBC, 0x61, - 0x0A, 0x8E, 0xE3, 0x0A, 0x92, 0x82, 0xD2, 0x82, 0xBA, 0xE4, 0x3E, 0x8E, 0xBB, 0xC7, 0xA2, 0x8F, - 0x68, 0xE1, 0x29, 0x34, 0x7C, 0xB4, 0x22, 0xCF, 0x36, 0x8F, 0x9D, 0x63, 0x9D, 0x04, 0x8F, 0x4A, - 0xFB, 0x84, 0xBB, 0x6B, 0x97, 0x2C, 0x15, 0xC9, 0x37, 0x4F, 0x40, 0xD7, 0x47, 0x50, 0x39, 0x97 -}; +static inline void resetCurrRx(L2_INST *instPtr) { + ASSERT(instPtr != NULL); + ASSERT(instPtr->serviceFSM->currRxBuff != NULL); + RingBuff_Flush(instPtr->serviceFSM->currRxBuff); + instPtr->serviceFSM->currRxSeq = 0; +} + +static inline bool uploadCurrRx(L2_INST *instPtr) { + ASSERT(instPtr != NULL); + ASSERT(instPtr->config.pushUpHandle != NULL); + bool ret = instPtr->config.pushUpHandle(instPtr->serviceFSM->currRxBuff); + instPtr->serviceFSM->currRxBuff = NULL; + instPtr->serviceFSM->currRxSeq = 0; + return ret; +} + +static inline bool updateCurrTx(L2_INST *instPtr) { + ASSERT(instPtr != NULL); + ASSERT(instPtr->config.popUpHandle != NULL); + if(instPtr->serviceFSM->currTxBuff == NULL) { + instPtr->serviceFSM->currTxSeq = 0; + return (instPtr->config.popUpHandle(&(instPtr->serviceFSM->currTxBuff))); + } + if(RingBuff_Size(instPtr->serviceFSM->currTxBuff) == 0) { + free(instPtr->serviceFSM->currTxBuff); + instPtr->serviceFSM->currTxSeq = 0; + return (instPtr->config.popUpHandle(&(instPtr->serviceFSM->currTxBuff))); + } + return true; +} /*****************************************************************************/ /** @@ -88,76 +106,83 @@ static uint8_t testData[L2_PACK_LEN_MAX] = ******************************************************************************/ static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId) { -#ifndef DATALINK_ENABLE_BERTEST ASSERT(instPtr != NULL); int32_t Status; - uint32_t dataChunk; - uint8_t *buff = instPtr->sendPktData; - - // Common section of link layer package - dataChunk = L2_GetNextFrameNum(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk); - dataChunk = L2_GetNextSlotNum(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk); - dataChunk = L2_GetNodeId(instPtr); - L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk); - dataChunk = dstId; - L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk); + uint8_t *sendBuff = instPtr->sendPktData; + size_t payloadMax, packetLen; switch (type) { - case L2_SVC_FRAME: - { - dataChunk = L2_SVC_FRAME; - L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk); - - SysMonitor_GetSysinfo(&(instPtr->sysInfo)); - // insert position and speed info - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &(instPtr->sysInfo.posX)); - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &(instPtr->sysInfo.posY)); - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ)); - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX)); - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY)); - L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ)); - - uint32_t dataId; - if (L2_GetNodeType(instPtr) == L2_NODE_HEAD) - { - SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX); - } - else - { - SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX); - } - - L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId); - if (dataId == DATA_ID_NONE) - { - L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD, L2_MSG_SVC_PAYLOAD_LEN, testData); - } - - Status = L2_CrcAppend(buff, L2_SVC_PACK_LEN - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_CRC, L2_CRC16_1021); - if (Status != SUCCESS) - { - DBG_ERROR("Fail to append CRC...\n"); - return Status; - } - - memcpy(instPtr->log.txLog.data, buff, L2_SVC_PACK_LEN); - instPtr->log.txLog.dataId = dataId; + case L2_SVC_2K_FRAME: + packetLen = L2_SVC_PACK_2K_LEN; + payloadMax = PAYLOAD_LEN_2K; + break; + case L2_SVC_128K_FRAME: + packetLen = L2_SVC_PACK_128K_LEN; + payloadMax = PAYLOAD_LEN_128K; + break; + case L2_SVC_256K_FRAME: + packetLen = L2_SVC_PACK_256K_LEN; + payloadMax = PAYLOAD_LEN_256K; break; - } default: - { DBG_ERROR("Unexpected frame type: %" PRIu8 ".\n", type); return EPARAM; break; } + // Common section of link layer package + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_FRAME_NUM, L2_GetNextFrameNum(instPtr)); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SLOT_NUM, L2_GetNextSlotNum(instPtr)); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SRC_ID, L2_GetNodeId(instPtr)); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_DST_ID, dstId); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_TYPE, type); + + // TODO: check + // If no data need to be sent, send dummy data + if(updateCurrTx(instPtr) == false) { + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SVC_PKTFLG, PACKET_TYPE_NONE); + Status = L2_CrcAppend(sendBuff, packetLen - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_PAYLOAD + payloadMax, L2_CRC16_1021); + if (Status != SUCCESS) + { + DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status); + ASSERT(true); + } + return EIGNORE; } + RING_BUFFER *svcData = instPtr->serviceFSM->currTxBuff; + + size_t sentLen = RingBuff_Pop(svcData, sendBuff + L2_MSG_SVC_PAYLOAD, packetLen); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SVC_DLEN, sentLen); + + // Packet type + uint32_t pktType = PACKET_TYPE_NONE; + if(RingBuff_Size(svcData) == 0) + { + if(instPtr->serviceFSM->currTxSeq == 0) + { + pktType = PACKET_TYPE_SINGLE; + } + else + { + pktType = PACKET_TYPE_LASTPKT; + } + } + else + { + pktType = PACKET_TYPE_SUBPKT; + } + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SVC_PKTFLG, pktType); + L2_ASSEMBLE_INTEGER(sendBuff, L2_MSG_SVC_PKTID, instPtr->serviceFSM->currTxSeq); + + Status = L2_CrcAppend(sendBuff, packetLen - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_PAYLOAD + payloadMax, L2_CRC16_1021); + if (Status != SUCCESS) + { + DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status); + ASSERT(true); + } + instPtr->serviceFSM->currTxSeq++; + memcpy(instPtr->log.txLog.data, sendBuff, packetLen); + instPtr->log.txLog.dataId = instPtr->serviceFSM->rxdCnt; return SUCCESS; -#else - DBG_ERROR("Unexpected call of Service_Packing in BER test mode.\n"); - return EUNEXP; -#endif } /*****************************************************************************/ @@ -175,118 +200,109 @@ int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg) ASSERT(instPtr != NULL); ASSERT(msg != NULL); int32_t Status; -#ifndef DATALINK_ENABLE_BERTEST L2_FRAME_TYPE frameType = L2_NONE_FRAME; L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType); + size_t packetLen; switch (frameType) { - case L2_SVC_FRAME: + case L2_SVC_2K_FRAME: + packetLen = L2_SVC_PACK_2K_LEN; + break; + case L2_SVC_128K_FRAME: + packetLen = L2_SVC_PACK_128K_LEN; + break; + case L2_SVC_256K_FRAME: + packetLen = L2_SVC_PACK_256K_LEN; + break; + default: + DBG_ERROR("Unexpected frame type: %" PRIu8 ".\n", type); + return EPARAM; + break; + } + + uint8_t nodeId; + L2_DEASSEMBLE(msg, L2_MSG_DST_ID, &nodeId); + if(nodeId != L2_GetNodeId(instPtr)) { + DBG_ERROR("Packet not addressed to me, dropping...\n"); + return EIGNORE; + } + NODE_ENTRY *node; + node = L2_GetNodeById(instPtr->nodeList, nodeId); + if (node == NULL) { - uint8_t nodeId; - L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId); - NODE_ENTRY *node; - node = L2_GetNodeById(instPtr->nodeList, nodeId); + node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER); if (node == NULL) { - node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER); - if (node == NULL) - { - DBG_ERROR("Failed to append new node [id: %" PRIu8 "]", nodeId); - Status = ENOMEM; - break; - } + DBG_ERROR("Failed to append new node [id: %" PRIu8 "]", nodeId); + ASSERT(true); } - - // Update node info. - float nodePos; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &nodePos); - node->nodeInfo.pos.x = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &nodePos); - node->nodeInfo.pos.y = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &nodePos); - node->nodeInfo.pos.z = (double)nodePos; - float nodeSpeed; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &nodeSpeed); - node->nodeInfo.speed.x = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &nodeSpeed); - node->nodeInfo.speed.y = (double)nodePos; - L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &nodeSpeed); - node->nodeInfo.speed.z = (double)nodePos; - - // Reset node ttl - node->ttlCnt = 0; - - // Calculate time deviation - uint32_t frameNum, slotNum = 0; - L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum); - L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum); - Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev)); - if (Status != SUCCESS) - { - DBG_ERROR("Failed to compute time deviation.\n") - break; - } - - uint32_t dataId; - L2_FrameGetChunk(msg, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId); - - if (L2_GetNodeType(instPtr) == L2_NODE_HEAD) - { - SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX); - } - else - { - SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX); - } - - // Logging - memcpy(instPtr->log.rxLog.data, msg, L2_SVC_PACK_LEN); - instPtr->log.rxLog.dataId = dataId; - instPtr->serviceFSM->rxdCnt++; - -#ifdef DATALINK_ENABLE_AUTOTIMESYNC - // Implement a auto time sync. - if (L2_GetNodeType(instPtr) != L2_NODE_HEAD) - { - // Time sync. - L2_TimeAdjust(instPtr, &(instPtr->log.timeDev)); - } -#endif - break; } - default: - DBG_ERROR("Unsupported frame type: %" PRIu8 ".\n", frameType); - break; - } - return Status; -#else - uint32_t errorBits = 0; - for (int i = 0; i < L2_SVC_PACK_LEN; i++) - { - errorBits += count_ones(msg[i] ^ testData[i]); - } - - instPtr->serviceFSM->bitError += errorBits; - instPtr->serviceFSM->bitTotal += L2_SVC_PACK_LEN * 8; + // Reset node ttl + node->ttlCnt = 0; // Calculate time deviation - uint32_t frameNum, slotNum = 0; - L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum); - L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum); - Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev)); + uint32_t frameNum = 0; + uint32_t slotNum = 0; + int64_t timeDev = 0; + L2_DEASSEMBLE(msg, L2_MSG_FRAME_NUM, &frameNum); + L2_DEASSEMBLE(msg, L2_MSG_SLOT_NUM, &slotNum); + Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &timeDev); if (Status != SUCCESS) { DBG_ERROR("Failed to compute time deviation.\n") - return Status; + ASSERT(true); } + instPtr->log.timeDev = timeDev; + // Implement a auto time sync. if (L2_GetNodeType(instPtr) != L2_NODE_HEAD) { - // Time sync. - L2_TimeAdjust(instPtr, &(instPtr->log.timeDev)); + L2_TimeAdjust(instPtr, &timeDev); } - return SUCCESS; -#endif + + // TODO: check + uint8_t pktType, pktId; + L2_DEASSEMBLE(msg, L2_MSG_SVC_PKTFLG, &pktType); + L2_DEASSEMBLE(msg, L2_MSG_SVC_PKTID, &pktId); + + if(pktType != PACKET_TYPE_SINGLE && pktType != PACKET_TYPE_SUBPKT && pktType != PACKET_TYPE_LASTPKT) + { + DBG_INFO("Dummy packet, discard...\n"); + return SUCCESS; + } + + if(prepareCurrRx(instPtr) == false) { + DBG_ERROR("Failed to prepare prepareCurrRx.\n"); + return ENOMEM; + } + + if(pktId != instPtr->serviceFSM->currRxSeq) + { + DBG_ERROR("Packet loss occurred discard all...\n"); + resetCurrRx(instPtr); + return FAILURE; + } + + size_t pushLen, dlen = 0; + RING_BUFFER *svcData = instPtr->serviceFSM->currRxBuff; + L2_DEASSEMBLE(msg, L2_MSG_SVC_DLEN, &dlen); + pushLen = RingBuff_Push(svcData, msg + L2_MSG_SVC_PAYLOAD, dlen); + if(pushLen < dlen) { + DBG_ERROR("Receiving ring buffer overflowed.\n") + ASSERT(true); + } + instPtr->serviceFSM->currRxSeq++; + + if(pktType == PACKET_TYPE_SINGLE || pktType == PACKET_TYPE_LASTPKT) + { + uploadCurrRx(instPtr); + } + + instPtr->serviceFSM->rxdCnt++; + memcpy(instPtr->log.rxLog.data, msg, packetLen); + instPtr->log.rxLog.dataId = instPtr->serviceFSM->rxdCnt; + + return Status; } /*****************************************************************************/ @@ -326,12 +342,10 @@ void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr) svcFSMPtr->txCnt = 0; svcFSMPtr->rxCnt = 0; svcFSMPtr->rxdCnt = 0; -#ifdef DATALINK_ENABLE_BERTEST - svcFSMPtr->bitTotal = 0; - svcFSMPtr->bitError = 0; - svcFSMPtr->lossRate = 0; - svcFSMPtr->errorRate = 0; -#endif + svcFSMPtr->currTxSeq = 0; + svcFSMPtr->currRxSeq = 0; + svcFSMPtr->currTxBuff = NULL; + svcFSMPtr->currRxBuff = NULL; } /*****************************************************************************/ @@ -399,40 +413,40 @@ int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntr Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120); instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120; } - + L2_FRAME_TYPE frameType = L2_NONE_FRAME; switch (rtneEntry->slotType) { - case L2_SLOT_SERVICE: - if (torState == L2_TOR_TX) - { - svcFSMPtr->txCnt++; -#ifndef DATALINK_ENABLE_BERTEST - // Packing service data - Service_Packing(instPtr, L2_SVC_FRAME, rtneEntry->dst); -#else - memcpy(instPtr->sendPktData, testData, L2_SVC_PACK_LEN); -#endif - } - else - { - svcFSMPtr->rxCnt++; - } - L2_SetupNextSlot(instPtr, torState, L2_SVC_FRAME); + case L2_SLOT_SERVICE_2K: + frameType = L2_SVC_2K_FRAME; + break; + case L2_SLOT_SERVICE_128K: + frameType = L2_SVC_128K_FRAME; + break; + case L2_SLOT_SERVICE_256K: + frameType = L2_SVC_256K_FRAME; break; default: DBG_ERROR("UNKNOWN slot type [%" PRIu8 "].\n", rtneEntry->slotType); return FAILURE; } -#ifdef DATALINK_ENABLE_BERTEST - uint32_t pktLoss; - pktLoss = svcFSMPtr->rxCnt - svcFSMPtr->rxdCnt; - svcFSMPtr->lossRate = (svcFSMPtr->rxCnt == 0) ? 0 : (double)pktLoss / (double)svcFSMPtr->rxCnt; - svcFSMPtr->errorRate = (svcFSMPtr->bitTotal == 0) ? 0 : (double)svcFSMPtr->bitError / (double)svcFSMPtr->bitTotal; - DBG_PRINT("Packet Loss Rate -- Total: %lu, Loss: %lu.\n", instPtr->log.svcRxCnt, pktLoss); - DBG_PRINT("Bit Error Rate -- Total:%lu, Error:%lu.\n", svcFSMPtr->bitTotal, svcFSMPtr->bitError); -#endif + if (torState == L2_TOR_TX) + { + if(Service_Packing(instPtr, frameType, rtneEntry->dst) == SUCCESS) + { + svcFSMPtr->txCnt++; + } + else + { + torState = L2_TOR_SUSPEND; + } + } + else + { + svcFSMPtr->rxCnt++; + } + L2_SetupNextSlot(instPtr, torState, frameType); return SUCCESS; } /** @} LinkLayer_Service*/ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/link_layer/time_sync.c b/src/networking/link_layer/time_sync.c index a6f914b..11582e5 100644 --- a/src/networking/link_layer/time_sync.c +++ b/src/networking/link_layer/time_sync.c @@ -23,7 +23,7 @@ #include #include #include "link_layer.h" -#include "../phy_layer/phy_layer.h" +#include "networking/phy_layer/phy_layer.h" #include "error.h" #include "common.h" @@ -102,4 +102,4 @@ void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev) /** @} LinkLayer_TimeSync*/ -/** @} LinkLayer*/ \ No newline at end of file +/** @} LinkLayer*/ diff --git a/src/networking/phy_layer/phy_layer.c b/src/networking/phy_layer/phy_layer.c index 57d2a15..25b3cd4 100644 --- a/src/networking/phy_layer/phy_layer.c +++ b/src/networking/phy_layer/phy_layer.c @@ -321,7 +321,7 @@ uint32_t Phy_GetTimeComp(L1_FRAME_TYPE frameType) /*****************************************************************************/ /** - * @brief Get frame type of the frame in receive data buffer (Base on PL Record). + * @brief Get frame type of the frame in receive data buffer (Base on PL Record). * * @param instPtr A pointer to physical layer control instance. * @@ -1390,4 +1390,4 @@ void Phy_GetLastReceivedSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotSta /** @} PhysicalLayer_Receive_Estimations*/ -/** @} PhysicalLayer*/ \ No newline at end of file +/** @} PhysicalLayer*/ diff --git a/src/networking/phy_layer/phy_layer.h b/src/networking/phy_layer/phy_layer.h index 327de08..2271e2e 100644 --- a/src/networking/phy_layer/phy_layer.h +++ b/src/networking/phy_layer/phy_layer.h @@ -25,10 +25,9 @@ #ifndef EMULATION #include "xbram.h" #include "xadcps.h" -#include "../config/app_config.h" #endif -#include "../../system_monitor.h" -#include "../../time_ctrl/time_ctrl.h" +#include "system_monitor.h" +#include "time_ctrl/time_ctrl.h" /************************** Constant Definitions *****************************/ /** * @name PhysicalLayer_Common_Constant @@ -312,4 +311,4 @@ int32_t Phy_SetBeamAngle(PHY_INST *phyInstPtr, double offAx, double rndAx); #endif // PHY_CTRL_H_ -/** @} PhysicalLayer*/ \ No newline at end of file +/** @} PhysicalLayer*/ diff --git a/src/main.c b/src/node_app.c similarity index 88% rename from src/main.c rename to src/node_app.c index 1b88d78..b7162f2 100644 --- a/src/main.c +++ b/src/node_app.c @@ -29,18 +29,20 @@ #include "error.h" #include "timer.h" #include "system_monitor.h" -#include "config/app_config.h" -#include "dev_profile/dev_profile.h" #include "systembus/systembus.h" #include "networking/phy_layer/phy_layer.h" #include "networking/link_layer/link_layer.h" +#include "node_config/app_config.h" +#include "node_config/dev_profile/dev_profile.h" /************************** Function Prototypes ******************************/ -int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr); -void Phy_IntrHandler(void *context); -void PeriodicPull_Handler(void *callBackRef); -void ScuTimer_IntrHandler(void *context); -void Systembus_IntrHandler(void *context); +static int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr); +static void Phy_IntrHandler(void *context); +static void PeriodicPull_Handler(void *callBackRef); +static void ScuTimer_IntrHandler(void *context); +static void Systembus_IntrHandler(void *context); +static bool LinklayerPush2Up(RING_BUFFER *buff); +static bool LinklayerPopFromUp(RING_BUFFER **buff); /************************** Constant Definitions *****************************/ struct callback_desc phy_callback_desc = { @@ -71,7 +73,9 @@ L2_CONFIG linkConfig = { .headId = 1U, .netScale = 2U, .phyInstPtr = NULL, // physical layer reference - .tmcInstPtr = NULL + .tmcInstPtr = NULL, + .pushUpHandle = LinklayerPush2Up, + .popUpHandle = LinklayerPopFromUp }; // L2_CONFIG linkConfig = { @@ -81,7 +85,9 @@ L2_CONFIG linkConfig = { // .headId = 1U, // .netScale = 2U, // .phyInstPtr = NULL, // physical layer reference -// .tmcInstPtr = NULL +// .tmcInstPtr = NULL, +// .pushUpHandle = LinklayerPush2Up, +// .popUpHandle = LinklayerPopFromUp // }; static PHY_CONFIG phyConfig = { @@ -117,14 +123,19 @@ static SYSBUS_CONFIG sysbusConfig = { .rxQueueMax = 16U }; /*********************** Driver Instance Definitions **************************/ -static struct irq_ctrl_desc *intcDescPtr = NULL; // General interrupt controller descriptor +static struct irq_ctrl_desc *intcDescPtr = NULL; static struct timer_desc *logTmPtr = NULL; static SYSBUS *sysbusDescPtr = NULL; static PHY_INST *phyInstPtr = NULL; static TMC_INST *tmcInstPtr = NULL; L2_INST *linkInstPtr = NULL; - +static bool LinklayerPush2Up(RING_BUFFER *buff){ + return SystemBus_PushSvcFrame(sysbusDescPtr, (void*)buff); +} +static bool LinklayerPopFromUp(RING_BUFFER **buff) { + return SystemBus_PopSvcFrame(sysbusDescPtr, (void**)buff); +} /****************************************************************************/ /** * This function is responsible for initializing the SCUGIC instance, looking @@ -137,7 +148,7 @@ L2_INST *linkInstPtr = NULL; * FAILURE if initialization failed. * *****************************************************************************/ -int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) +static int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) { int32_t Status; struct xil_irq_desc *xil_dev; @@ -218,8 +229,8 @@ int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) } // Enable interrupts -// irq_enable(descPtr, PHY_INTR_ID); -// irq_enable(descPtr, PERIODIC_5MS_INTR_ID); + irq_enable(descPtr, PHY_INTR_ID); + irq_enable(descPtr, PERIODIC_5MS_INTR_ID); irq_enable(descPtr, SYSBUS_INTR_ID); irq_enable(descPtr, SCUTIMER_INTR_ID); @@ -243,7 +254,7 @@ int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) * @return None. * *****************************************************************************/ -void Phy_IntrHandler(void *context) +static void Phy_IntrHandler(void *context) { Phy_UpdateState(phyInstPtr); } // PhyIntr_Handler @@ -258,7 +269,7 @@ void Phy_IntrHandler(void *context) * @return None. * *****************************************************************************/ -void PeriodicPull_Handler(void *callBackRef) +static void PeriodicPull_Handler(void *callBackRef) { int32_t Status; Status = Linklayer_Proc(linkInstPtr); @@ -278,7 +289,7 @@ void PeriodicPull_Handler(void *callBackRef) * @return None. * ******************************************************************************/ -void Systembus_IntrHandler(void *context) +static void Systembus_IntrHandler(void *context) { int32_t Status; Status = SystemBus_IntrHandler(sysbusDescPtr); @@ -297,7 +308,7 @@ void Systembus_IntrHandler(void *context) * @return None. * ******************************************************************************/ -void ScuTimer_IntrHandler(void *context) +static void ScuTimer_IntrHandler(void *context) { int32_t Status; struct xil_timer_desc *xdesc; @@ -417,7 +428,7 @@ int main(void) DBG_PRINT("Physical started...\n"); Phy_Start(phyInstPtr); - + // Linklayer_Start(linkInstPtr); @@ -441,5 +452,13 @@ int main(void) DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); } } + if(SystemBus_IsSvcUpPending(sysbusDescPtr)) + { + Status = SystemBus_UploadSvcData(sysbusDescPtr); + if (Status != SUCCESS) + { + DBG_ERROR("SystemBus_UploadSvcData exit with ErrorCode: %" PRId32 ".\n", Status); + } + } } } // main diff --git a/src/config/app_config.h b/src/node_config/app_config.h similarity index 83% rename from src/config/app_config.h rename to src/node_config/app_config.h index 624db68..893ca4d 100644 --- a/src/config/app_config.h +++ b/src/node_config/app_config.h @@ -36,9 +36,6 @@ // 1 - print only errors // other - print nothing -#define DATALINK_ENABLE_AUTORECONNECT -#define DATALINK_ENABLE_AUTOTIMESYNC -// #define DATALINK_ENABLE_BERTEST /************ Hardware Configs ************/ #define CPU_CLK_HZ XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ @@ -54,7 +51,7 @@ // Physical Layer Configs #define PHY_DEVICE_ID 0X00 #define PHY_BASEADDR XPAR_PHYC_BASEADDR -#define PHY_BEAM_FORMING_ENABLE + // -- Antenna Bram Configs #define PHY_ANTCONFIG_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_CONFIG_BRAM_CTRL_DEVICE_ID #define PHY_ANTINFO_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_BEAM_BRAM_CTRL_DEVICE_ID @@ -82,17 +79,4 @@ // INTC configis #define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID - -// Configuration Check -#if defined(PHY_BEAM_SET_PRESET) && !defined(PHY_BEAM_FORMING_ENABLE) -#define PHY_BEAM_FORMING_ENABLE -#warning To impliment beam scan must enable beam forming... -#endif - -#if defined(DATALINK_ENABLE_BERTEST) -#if !defined(DATALINK_ENABLE_AUTOTIMESYNC) -#warning To enbale bit error rate test, auto time-sync should be enabled... -#endif -#endif - #endif //__APP_CONFIG_H_ diff --git a/src/dev_profile/config b/src/node_config/dev_profile/config similarity index 100% rename from src/dev_profile/config rename to src/node_config/dev_profile/config diff --git a/src/dev_profile/dev_profile.h b/src/node_config/dev_profile/dev_profile.h similarity index 100% rename from src/dev_profile/dev_profile.h rename to src/node_config/dev_profile/dev_profile.h diff --git a/src/node_config/dev_profile/global_timer_profile.c b/src/node_config/dev_profile/global_timer_profile.c new file mode 100644 index 0000000..eae497a --- /dev/null +++ b/src/node_config/dev_profile/global_timer_profile.c @@ -0,0 +1,11 @@ +#include "dev_profile.h" +#include "global_timer.h" +#include "../app_config.h" + +struct global_timer_init_param globaltimer_init_param = { + .base_addr = GLOBAL_TIMER_BASEADDR, + .id = GLOBAL_TIMER_DEVICE_ID, + .freq_hz = GLOBAL_TIMER_CLK_HZ, + .load_value = 0x0000000000000000 +}; + diff --git a/src/dev_profile/intc_profile.c b/src/node_config/dev_profile/intc_profile.c similarity index 73% rename from src/dev_profile/intc_profile.c rename to src/node_config/dev_profile/intc_profile.c index ae8990e..6c22c3e 100644 --- a/src/dev_profile/intc_profile.c +++ b/src/node_config/dev_profile/intc_profile.c @@ -1,7 +1,7 @@ #include "dev_profile.h" #include "irq.h" -#include "../config/app_config.h" -#include "../drivers/platform/xilinx_irq.h" +#include "drivers/platform/xilinx_irq.h" +#include "../app_config.h" struct xil_irq_init_param xil_intc_init_param = { .type = IRQ_PS diff --git a/src/dev_profile/timer_profile.c b/src/node_config/dev_profile/timer_profile.c similarity index 79% rename from src/dev_profile/timer_profile.c rename to src/node_config/dev_profile/timer_profile.c index 044b164..83ba92c 100644 --- a/src/dev_profile/timer_profile.c +++ b/src/node_config/dev_profile/timer_profile.c @@ -1,7 +1,7 @@ #include "dev_profile.h" #include "timer.h" -#include "../config/app_config.h" -#include "../drivers/platform/xilinx_timer.h" +#include "drivers/platform/xilinx_timer.h" +#include "../app_config.h" struct xil_timer_init_param xil_scutimer_init_param = { .active_tmr = 0, diff --git a/src/system_monitor.h b/src/system_monitor.h index 1a940a1..939d847 100644 --- a/src/system_monitor.h +++ b/src/system_monitor.h @@ -120,11 +120,11 @@ typedef struct __attribute__((packed)) { // SystemBus log - uint16_t lastConfig; ///< Last valid config \n + uint8_t lastConfig[2]; ///< Last valid config \n // byte 0: 0x11 FLJ, 0x00 LJ \n // byte 1: 0x66 Full Power, 0x88 Low Power - uint32_t pollCnt; ///< number of poll commands - uint32_t svcCnt; ///< number of service commands + uint32_t svcDownCnt; ///< number of service packet from upper layer + uint32_t svcUpCnt; ///< number of service packet to upper layer uint32_t remoteCnt; ///< number of remote check commands } SYSBUSLOG; diff --git a/src/systembus/systembus.c b/src/systembus/systembus.c index 9df3428..3ff8e48 100644 --- a/src/systembus/systembus.c +++ b/src/systembus/systembus.c @@ -25,13 +25,16 @@ #include "systembus_psuart.h" #include "error.h" #include "circ_queue.h" -#include "../system_monitor.h" +#include "ring_buffer.h" +#include "system_monitor.h" /** * @addtogroup SystemBus_Protocol_Routine * @{ */ +#define SYSBUS_SVC_MAX 1024 + /************************** Function Prototypes ******************************/ static int32_t SystemBus_StartListen(SYSBUS *instPtr); static int32_t SystemBus_GenSelfTestRsp(SYSBUS *instPtr); @@ -41,8 +44,8 @@ static int32_t SystemBus_ModeSwicth(SYSBUS *instPtr, uint16_t *msg); /**************************** Type Definitions *******************************/ /************************** Variable Definitions *****************************/ // TODO: better approach? -#include "../networking/link_layer/link_layer.h" -#include "../networking/phy_layer/phy_layer.h" +#include "networking/link_layer/link_layer.h" +#include "networking/phy_layer/phy_layer.h" extern L2_INST *linkInstPtr; extern L2_CONFIG linkConfig; @@ -58,6 +61,30 @@ inline bool SystemBus_IsRsqPending(SYSBUS *instPtr) return (!isCircQueueEmpty(instPtr->txQueue)); } +inline bool SystemBus_IsSvcUpPending(SYSBUS *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->rxSvcQueue)); +} + +inline bool SystemBus_IsSvcDownPending(SYSBUS *instPtr) +{ + ASSERT(instPtr != NULL); + return (!isCircQueueEmpty(instPtr->txSvcQueue)); +} + +inline bool SystemBus_PushSvcFrame(SYSBUS *instPtr, void* buff) { + ASSERT(instPtr != NULL); + ASSERT(buff != NULL); + return CircQueuePush(instPtr->rxSvcQueue, buff); +} + +inline bool SystemBus_PopSvcFrame(SYSBUS *instPtr, void** buff) { + ASSERT(instPtr != NULL); + ASSERT(buff != NULL); + return CircQueuePop(instPtr->txSvcQueue, buff); +} + inline bool SystemBus_IsTxBusy(SYSBUS *instPtr) { ASSERT(instPtr != NULL); @@ -139,7 +166,7 @@ static int32_t SystemBus_BindingConfig(SYSBUS *instPtr, uint16_t *msg) } uint16_t* rsp = (uint16_t*)sysbusRsp->data; rsp[WD_CMD] = RSP_CONFIG; - rsp[WD_RSP_STATE] = RSP_STA_OK; // TODO: + rsp[WD_RSP_STATE] = RSP_STA_OK; sysbusRsp->len = RSP_CONFIG_LEN; if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false) { @@ -161,18 +188,26 @@ static int32_t SystemBus_PowerUp(SYSBUS *instPtr, uint16_t *msg) return EIGNORE; } - // TODO: configure speed, power mode PHY_INST *phyRef = linkInstPtr->config.phyInstPtr; TMC_INST *tmcRef = linkInstPtr->config.tmcInstPtr; - bool reconfig = false; + + // TODO: speed configure. + switch (msg[WD_PWUP_BACKWARD]) { + case SPEED_NEW_2KBPS: + + break; + case SPEED_NEW_128KBPS: + break; + case SPEED_NEW_256KBPS: + break; + default: + DBG_ERROR("Unsurpport speed mode 0x%04X.\n", msg[WD_PWUP_BACKWARD]); + return EPARAM; + } if (msg[WD_PWUP_SATMODE] == PWUP_SATMODE_UP) { - // full power config - Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_FULL); - if (reconfig || !L2_isStarted(linkInstPtr)) - { - Linklayer_Reconfig(linkInstPtr, &linkConfig); - } + // TODO: confirm default power config power config + Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_LOW); Linklayer_Start(linkInstPtr); } else if (msg[WD_PWUP_SATMODE] == PWUP_SATMODE_DOWN) @@ -196,8 +231,10 @@ static int32_t SystemBus_PowerUp(SYSBUS *instPtr, uint16_t *msg) WD_EN_CMD, msg[WD_EN_CMD]); return EIGNORE; } - // TODO: speed configure. - instPtr->sysbusLog.lastConfig = msg[WD_PWUP_SATMODE]; + + + instPtr->sysbusLog.lastConfig[0] = msg[WD_PWUP_SATMODE] & 0xFF; + instPtr->sysbusLog.lastConfig[1] = (msg[WD_PWUP_BACKWARD] >> 4) & 0x0F & msg[WD_PWUP_FORWARD] & 0xF0; SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME)); @@ -248,13 +285,13 @@ static int32_t SystemBus_ModeSwicth(SYSBUS *instPtr, uint16_t *msg) WD_EN_CMD, msg[WD_EN_CMD]); return EIGNORE; } - instPtr->sysbusLog.lastConfig = msg[WD_MODESW_SATMODE_0]; + instPtr->sysbusLog.lastConfig[0] = msg[WD_MODESW_SATMODE_0] & 0xFF; SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME)); if (sysbusRsp == NULL) { - DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n"); + DBG_ERROR("Failed to allocate memory for MODE SWITCH Response!\n"); return ENOMEM; } uint16_t* rsp = (uint16_t*)sysbusRsp->data; @@ -270,6 +307,109 @@ static int32_t SystemBus_ModeSwicth(SYSBUS *instPtr, uint16_t *msg) return SUCCESS; } +/** + * @brief Receive service data from upper layer + */ +static int32_t SystemBus_ReceiveSvcDate(SYSBUS *instPtr, uint16_t *msg) +{ + ASSERT(instPtr != NULL); + ASSERT(msg != NULL); + if (msg[WD_DATA_SATID] != SATID_NEW) { + return EIGNORE; + } + uint8_t numPack = msg[WD_DATA_SEQPKT] & 0x00FF; + uint8_t seqNo = (msg[WD_DATA_SEQPKT]>>8) & 0x00FF; + size_t dlen = msg[WD_DATA_DLEN]; + if(seqNo > numPack) { + DBG_ERROR("Invalid service packet sequence number (%u/%u).\n", seqNo, numPack); + return EPARAM; + } + if(dlen > 500) { + DBG_ERROR("Invalid service data packet length %u.\n", dlen); + return EPARAM; + } + if (instPtr->currSvcBuff == NULL) + { + instPtr->currSvcBuff = RingBuff_Create(SYSBUS_SVC_MAX); + if(instPtr->currSvcBuff == NULL) { + return ENOMEM; + } + } + + if(instPtr->currSvcSeq != seqNo) { + DBG_ERROR("Inconsistent packet seqID %u (should be %u).\n", seqNo, instPtr->currSvcSeq); + DBG_ERROR("Restart receiving process.\n"); + RingBuff_Flush(instPtr->currSvcBuff); + instPtr->currSvcSeq = 0; + return FAILURE; + } + + size_t tmpLen = RingBuff_Push(instPtr->currSvcBuff, (uint8_t*)&(msg[WD_DATA_PAYLOAD]), dlen); + if(tmpLen < dlen) { + DBG_ERROR("Ring buffer overflowed.\n"); + ASSERT(true); + } + + if(numPack == 0 || seqNo == numPack) { + if(CircQueuePush(instPtr->txSvcQueue, (void**)&(instPtr->currSvcBuff)) == false) { + DBG_ERROR("txSvcQueue overflowed.\n"); + RingBuff_Destroy(instPtr->currSvcBuff); + return EQUEUE; + } + instPtr->currSvcBuff = NULL; + instPtr->currSvcSeq = 0; + } + instPtr->sysbusLog.svcUpCnt++; + return SUCCESS; +} + + +/** + * @brief Upload service data to upper layer + */ +int32_t SystemBus_UploadSvcData(SYSBUS *instPtr) +{ + ASSERT(instPtr != NULL); + RING_BUFFER *buff; + if(CircQueuePop(instPtr->txSvcQueue, (void**)(&buff)) == false) { + DBG_ERROR("No service data need to be uploaded.\n"); + return EIGNORE; + } + uint8_t numPack = RingBuff_Size(buff) / DATA_PAYLOAD_MAX; + uint8_t cntPack = 0; + while(RingBuff_Size(buff) > 0) { + size_t sentLen; + uint16_t seqId = ((uint16_t)numPack) | ((uint16_t)cntPack << 8); + SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME)); + + if (sysbusRsp == NULL) + { + DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n"); + return ENOMEM; + } + uint16_t *rsp = (uint16_t*)sysbusRsp->data; + ASSEMBLE_MSG_IMMEDIATE(rsp, WD_CMD, CMD_DATA_UL); + ASSEMBLE_MSG_IMMEDIATE(rsp, WD_DATA_SATID, SATID_NEW); + ASSEMBLE_MSG_IMMEDIATE(rsp, WD_DATA_SEQID, instPtr->sysbusLog.svcUpCnt); + ASSEMBLE_MSG_IMMEDIATE(rsp, WD_DATA_SEQPKT, seqId); + sentLen = RingBuff_Pop(buff, (uint8_t*)&(rsp[WD_DATA_PAYLOAD]), DATA_PAYLOAD_MAX); + ASSEMBLE_MSG_IMMEDIATE(rsp, WD_DATA_DLEN, sentLen); + sysbusRsp->len = DATA_DLUL_LEN; + if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false) + { + RingBuff_Destroy(buff); + free(sysbusRsp); + DBG_WARNING("SystemBus::TX Queue overflowed!\n"); + // TODO: check + ASSERT(true); +// return EQUEUE; + } + instPtr->sysbusLog.svcUpCnt++; + } + RingBuff_Destroy(buff); + return SUCCESS; +} + /** * @brief Generate System Bus remote check command response */ @@ -422,6 +562,9 @@ int32_t SystemBus_HandleCmd(SYSBUS *instPtr) case CMD_MODE_SWITCH: Status = SystemBus_ModeSwicth(instPtr, msg); break; + case CMD_DATA_DL: + Status = SystemBus_ReceiveSvcDate(instPtr, msg); + break; default: DBG_ERROR("SystemBus::Unknown command code!\n"); Status = FAILURE; @@ -450,6 +593,7 @@ int32_t SystemBus_MakeResp(SYSBUS *instPtr) return EIGNORE; } Status = SysbusPSUart_Send(instPtr->uartInst, sysbusRsp); + free(sysbusRsp); return Status; } @@ -475,9 +619,15 @@ int32_t SystemBus_Init(SYSBUS **instPtr, SYSBUS_CONFIG *config) { return ENOMEM; } + + (*instPtr)->uartInst = NULL; (*instPtr)->rxQueue = NULL; (*instPtr)->txQueue = NULL; - (*instPtr)->uartInst = NULL; + (*instPtr)->txSvcQueue = NULL; + (*instPtr)->rxSvcQueue = NULL; + (*instPtr)->currSvcSeq = 0; + (*instPtr)->currSvcBuff = NULL; + memcpy(&((*instPtr)->config), config, sizeof(SYSBUS_CONFIG)); memset(&((*instPtr)->sysbusLog), 0x00, sizeof(SYSBUSLOG)); memset(&((*instPtr)->linkLog), 0x00, sizeof(LINKLOG)); @@ -499,6 +649,16 @@ int32_t SystemBus_Init(SYSBUS **instPtr, SYSBUS_CONFIG *config) SystemBus_Destroy(*instPtr); return ENOMEM; } + if (CircQueueCreate(&((*instPtr)->txSvcQueue), (*instPtr)->config.rxQueueMax) == false) + { + SystemBus_Destroy(*instPtr); + return ENOMEM; + } + if (CircQueueCreate(&((*instPtr)->rxSvcQueue), (*instPtr)->config.rxQueueMax) == false) + { + SystemBus_Destroy(*instPtr); + return ENOMEM; + } return SystemBus_StartListen(*instPtr); } @@ -519,8 +679,10 @@ void SystemBus_Destroy(SYSBUS *instPtr) return; } SysbusPSUart_Destroy(instPtr->uartInst); - free(instPtr->txQueue); - free(instPtr->rxQueue); + CircQueueFree(instPtr->txQueue); + CircQueueFree(instPtr->rxQueue); + CircQueueFree(instPtr->txSvcQueue); + CircQueueFree(instPtr->rxSvcQueue); free(instPtr); } diff --git a/src/systembus/systembus.h b/src/systembus/systembus.h index 616b473..ce3ed44 100644 --- a/src/systembus/systembus.h +++ b/src/systembus/systembus.h @@ -23,7 +23,8 @@ #include #include "systembus_psuart.h" #include "circ_queue.h" -#include "../system_monitor.h" +#include "ring_buffer.h" +#include "system_monitor.h" /************************** Constant Definitions *****************************/ /************************** Data Type Definitions ****************************/ @@ -51,8 +52,12 @@ typedef struct PHYLOG phyLog; ///< Physical layer log HWSTATE hwState; ///< Hardware status SYSBUS_PSUART *uartInst; ///< physical uart controller instance - CIRC_QUEUE *txQueue; ///< tx queue - CIRC_QUEUE *rxQueue; ///< rx queue + uint32_t currSvcSeq; + RING_BUFFER *currSvcBuff; + CIRC_QUEUE *txQueue; ///< tx queue for systembus message + CIRC_QUEUE *rxQueue; ///< rx queue for systembus message + CIRC_QUEUE *txSvcQueue; ///< tx queue for service data + CIRC_QUEUE *rxSvcQueue; ///< rx queue for service data } SYSBUS; /************************** Function Prototypes ******************************/ @@ -67,12 +72,17 @@ void SystemBus_Destroy(SYSBUS *instPtr); int32_t SystemBus_HandleCmd(SYSBUS *instPtr); int32_t SystemBus_MakeResp(SYSBUS *instPtr); int32_t SystemBus_GenRemoteCheckRsp(SYSBUS *instPtr); +int32_t SystemBus_UploadSvcData(SYSBUS *instPtr); /** @} */ int32_t SystemBus_IntrHandler(SYSBUS *instPtr); bool SystemBus_IsReqPending(SYSBUS *instPtr); bool SystemBus_IsRsqPending(SYSBUS *instPtr); +bool SystemBus_IsSvcUpPending(SYSBUS *instPtr); +bool SystemBus_IsSvcDownPending(SYSBUS *instPtr); +bool SystemBus_PushSvcFrame(SYSBUS *instPtr, void* buff); +bool SystemBus_PopSvcFrame(SYSBUS *instPtr, void** buff); bool SystemBus_IsTxBusy(SYSBUS *instPtr); bool SystemBus_IsRxBusy(SYSBUS *instPtr); diff --git a/src/systembus/systembus_msg.h b/src/systembus/systembus_msg.h index 5d4538c..86ec5cf 100644 --- a/src/systembus/systembus_msg.h +++ b/src/systembus/systembus_msg.h @@ -49,7 +49,7 @@ #define SPEED_TT_90K6BPS 0x008B #define SPEED_NEW_128KBPS 0x009B #define SPEED_NEW_256KBPS 0x00AB -#define SPEED_NEW_75BPS 0x00BB +#define SPEED_NEW_2KBPS 0x00BB // Configure load #define CMD_CONFIG 0x0002 @@ -138,6 +138,7 @@ // Service Data // -- Request +#define DATA_DLUL_LEN 510U #define CMD_DATA_DL 0x0092 #define CMD_DATA_UL 0x00A2 #define WD_DATA_SATID 1U @@ -145,6 +146,7 @@ #define WD_DATA_SEQPKT 3U #define WD_DATA_DLEN 4U #define WD_DATA_PAYLOAD 5U +#define DATA_PAYLOAD_MAX 500U // -- Response // -- -- none response diff --git a/src/systembus/systembus_psuart.c b/src/systembus/systembus_psuart.c index e75fc62..0242ed7 100644 --- a/src/systembus/systembus_psuart.c +++ b/src/systembus/systembus_psuart.c @@ -148,6 +148,9 @@ int SysbusPSUart_Init(SYSBUS_PSUART **instPtr, const SYSBUS_PSUART_CONFIG *confi void SysbusPSUart_Destroy(SYSBUS_PSUART *instPtr) { + if(instPtr == NULL) { + return; + } XUartPs_SetInterruptMask(&(instPtr->hwInst), 0x00000000); free(instPtr->currTxMsg); free(instPtr->currRxMsg); diff --git a/src/systembus/systembus_psuart.h b/src/systembus/systembus_psuart.h index 6930075..192b031 100644 --- a/src/systembus/systembus_psuart.h +++ b/src/systembus/systembus_psuart.h @@ -44,7 +44,7 @@ #define SYSBUS_PSUART_1_5_STOP_BIT XUARTPS_FORMAT_1_5_STOP_BIT /**< 1.5 stop bits */ #define SYSBUS_PSUART_1_STOP_BIT XUARTPS_FORMAT_1_STOP_BIT /**< 1 stop bit */ -#define SYSBUS_MAX_TRANS_LEN 1024 +#define SYSBUS_MAX_TRANS_LEN 512 #define SYSBUS_MIN_TRANS_LEN 4 /** diff --git a/src/util/circ_queue.c b/src/util/circ_queue.c index 578d2d6..1d381ce 100644 --- a/src/util/circ_queue.c +++ b/src/util/circ_queue.c @@ -40,7 +40,8 @@ inline bool isCircQueueEmpty(CIRC_QUEUE *queue) void CircQueueFree(CIRC_QUEUE *queue) { - ASSERT(queue != NULL); + if(queue == NULL) + return; if (queue->data) free(queue->data); free(queue); @@ -129,4 +130,4 @@ bool CircQueuePop(CIRC_QUEUE *queue, void **data) return true; } /** @} CircularQueue*/ -/** @} Utility*/ \ No newline at end of file +/** @} Utility*/ diff --git a/src/util/ring_buffer.c b/src/util/ring_buffer.c new file mode 100644 index 0000000..22213fc --- /dev/null +++ b/src/util/ring_buffer.c @@ -0,0 +1,158 @@ +#include "ring_buffer.h" +#include "common.h" +#include +#include + +/** + * @file + * Implementation of ring rb functions. + */ + +inline size_t RingBuff_Size(RING_BUFFER *rb) { + return (rb->size); +} + +inline uint8_t RingBuff_isEmpty(RING_BUFFER *rb) { + return (rb->size == 0); +} + +inline uint8_t RingBuff_isFull(RING_BUFFER *rb) { + return (rb->size == rb->capacity); +} + +static inline size_t Get_Available2Write(const RING_BUFFER *rb) +{ + return (rb->capacity - rb->size); +} + +RING_BUFFER *RingBuff_Create(size_t capacity) +{ + if(capacity <= 1) { + return NULL; + } + RING_BUFFER *rb = malloc(sizeof(RING_BUFFER)); + if (rb == NULL){ + return rb; + } + rb->buffer = malloc(capacity); + if(rb->buffer == NULL) { + free(rb); + return NULL; + } + rb->tail = 0; + rb->head = 0; + rb->size = 0; + rb->capacity = capacity; + return rb; +} + +void RingBuff_Destroy(RING_BUFFER *rb) +{ + if(rb == NULL) { + return; + } + free(rb->buffer); + free(rb); +} + +void RingBuff_Flush(RING_BUFFER *rb) +{ + ASSERT(rb != NULL); + rb->tail = 0; + rb->head = 0; + rb->size = 0; +} + +size_t RingBuff_Push(RING_BUFFER *rb, const uint8_t *data, size_t len) +{ + ASSERT(rb != NULL); + ASSERT(data != NULL); + if (len == 0) + { + return 0; + } + size_t canWrite = Get_Available2Write(rb); + if (canWrite == 0) + { + return 0; + } + + if (len > canWrite) + { + len = canWrite; + } + + size_t endSpace = rb->capacity - rb->head; + if (len <= endSpace) + { + memcpy(&(rb->buffer[rb->head]), data, len); + rb->head = (rb->head + len) % rb->capacity; + } + else + { + size_t remain = len - endSpace; + memcpy(&(rb->buffer[rb->head]), data, endSpace); + memcpy(&(rb->buffer[0]), data + endSpace, remain); + rb->head = remain; + } + rb->size += len; + return len; +} + +size_t RingBuff_Pop(RING_BUFFER *rb, uint8_t *data, size_t len) +{ + ASSERT(rb != NULL); + ASSERT(data != NULL); + size_t canRead = rb->size; + if (canRead == 0 || len == 0) + return 0; + + if (len > canRead) + { + len = canRead; + } + + size_t endSpace = rb->capacity - rb->tail; + if (len <= endSpace) + { + memcpy(data, &rb->buffer[rb->tail], len); + rb->tail = (rb->tail + len) % rb->capacity; + } + else + { + size_t remain = len - endSpace; + memcpy(data, &(rb->buffer[rb->tail]), endSpace); + memcpy(data + endSpace, &(rb->buffer[0]), len - endSpace); + rb->tail = remain; + } + rb->size -= len; + return len; +} + +size_t RingBuff_Peek(const RING_BUFFER *rb, uint8_t *data, size_t len) +{ + ASSERT(rb != NULL); + ASSERT(data != NULL); + size_t canRead = rb->size; + if (canRead == 0 || len == 0){ + return 0; + } + + if (len > canRead) + { + len = canRead; + } + + size_t endSpace = rb->capacity - rb->tail; + if (len <= endSpace) + { + memcpy(data, &rb->buffer[rb->tail], len); + } + else + { + memcpy(data, &rb->buffer[rb->tail], endSpace); + size_t remain = len - endSpace; + memcpy(data + endSpace, &rb->buffer[0], remain); + } + return len; +}