diff options
author | Sylvain Miermont <smiermont@semtech.com> | 2013-10-22 18:23:52 +0200 |
---|---|---|
committer | Sylvain Miermont <smiermont@semtech.com> | 2013-10-24 09:29:51 +0200 |
commit | 4977430ef31fb52994fed42b9cb180930ed943d0 (patch) | |
tree | 27f4fadea5fa35f25933d59bcd7b99cca8c965c8 | |
parent | b922932d1c9869d82042b600db2382d8c15f63dc (diff) | |
download | lora_gateway-4977430ef31fb52994fed42b9cb180930ed943d0.tar.gz lora_gateway-4977430ef31fb52994fed42b9cb180930ed943d0.tar.bz2 lora_gateway-4977430ef31fb52994fed42b9cb180930ed943d0.zip |
Beta 8v1.b8
- API: lgw_receive now return info on RX frequency and RF path for each packet (no need to keep track of RF/IF settings)
- Unified some portion of the code with the 470 MHz variant of the HAL (use SX1255 radios instead of SX1257)
- Improved AGC and ARB firmwares
- Adding -Wall -Wextra for compilation, fixing all the new warnings for cleaner code
- Fixed bugs in handling of FSK datarate
- test_loragw_hal now dumps the content of all Lora registers after configuration in reg_dump.log
39 files changed, 3790 insertions, 377 deletions
diff --git a/libloragw/Makefile b/libloragw/Makefile index 38d2fae..6c004f1 100644 --- a/libloragw/Makefile +++ b/libloragw/Makefile @@ -3,8 +3,8 @@ include library.cfg # constant symbols CC=gcc -CFLAGS=-O2 -Iinc -I. -C99FLAGS=-O2 -std=c99 -Iinc -I. +CFLAGS=-O2 -Wall -Wextra -Iinc -I. +C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. # configuration-dependant symbols ifeq ($(LGW_PHY),native) diff --git a/libloragw/VERSION b/libloragw/VERSION index 87b0704..eafdd0f 100644 --- a/libloragw/VERSION +++ b/libloragw/VERSION @@ -1,5 +1,5 @@ /* Software library version: */ -#define VERSION_LIBRARY "beta7" +#define VERSION_LIBRARY "beta8" /* API version */ #define VERSION_API "beta" diff --git a/libloragw/doc/CHANGELOG.TXT b/libloragw/doc/CHANGELOG.TXT index 4ec6bd7..f1d4a64 100644 --- a/libloragw/doc/CHANGELOG.TXT +++ b/libloragw/doc/CHANGELOG.TXT @@ -1,6 +1,16 @@ Lora Gateway HAL changelog ========================== + Beta 8 (from beta 7) +--------------------- + + * API: lgw_receive now return info on RX frequency and RF path for each packet (no need to keep track of RF/IF settings) + * Unified some portion of the code with the 470 MHz variant of the HAL (use SX1255 radios instead of SX1257) + * Improved AGC and ARB firmwares + * Adding -Wall -Wextra for compilation, fixing all the new warnings for cleaner code + * Fixed bugs in handling of FSK datarate + * test_loragw_hal now dumps the content of all Lora registers after configuration in reg_dump.log + Beta 7 (from beta 5) --------------------- diff --git a/libloragw/doc/LICENSE.TXT b/libloragw/doc/LICENSE.TXT index eab9548..e406dcb 100644 --- a/libloragw/doc/LICENSE.TXT +++ b/libloragw/doc/LICENSE.TXT @@ -1,8 +1,8 @@ -THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND +Copyright (C) 2013 SEMTECH S.A. + + THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER. CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT -OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION +OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. - -Copyright (C) SEMTECH S.A. diff --git a/libloragw/inc/loragw_hal.h b/libloragw/inc/loragw_hal.h index 08aa945..0739f37 100644 --- a/libloragw/inc/loragw_hal.h +++ b/libloragw/inc/loragw_hal.h @@ -104,8 +104,8 @@ Description: #define DR_LORA_SF11 0x20 #define DR_LORA_SF12 0x40 #define DR_LORA_MULTI 0x7E -/* NOTE: for FSK directly use baudrate between 300 bauds and 250 kbauds */ -#define DR_FSK_MIN 300 +/* NOTE: for FSK directly use baudrate between 500 bauds and 250 kbauds */ +#define DR_FSK_MIN 500 #define DR_FSK_MAX 250000 /* values available for the 'coderate' parameters (Lora only) */ @@ -179,13 +179,15 @@ struct lgw_conf_rxif_s { @brief Structure containing the metadata of a packet that was received and a pointer to the payload */ struct lgw_pkt_rx_s { + uint32_t freq_hz; /*!> central frequency of the IF chain */ uint8_t if_chain; /*!> by which IF chain was packet received */ uint8_t status; /*!> status of the received packet */ + uint32_t count_us; /*!> internal gateway counter for timestamping, 1 microsecond resolution */ + uint8_t rf_chain; /*!> through which RF chain the packet was received */ uint8_t modulation; /*!> modulation used by the packet */ uint8_t bandwidth; /*!> modulation bandwidth (Lora only) */ - uint16_t datarate; /*!> RX datarate of the packet */ - uint8_t coderate; /*!> error-correcting code of the packet */ - uint32_t count_us; /*!> internal gateway counter for timestamping, 1 microsecond resolution */ + uint32_t datarate; /*!> RX datarate of the packet (SF for Lora) */ + uint8_t coderate; /*!> error-correcting code of the packet (Lora only) */ float rssi; /*!> average packet RSSI in dB */ float snr; /*!> average packet SNR, in dB (Lora only) */ float snr_min; /*!> minimum packet SNR, in dB (Lora only) */ @@ -207,10 +209,10 @@ struct lgw_pkt_tx_s { int8_t rf_power; /*!> TX power, in dBm */ uint8_t modulation; /*!> modulation to use for the packet */ uint8_t bandwidth; /*!> modulation bandwidth (Lora only) */ + uint32_t datarate; /*!> TX datarate (baudrate for FSK, SF for Lora) */ + uint8_t coderate; /*!> error-correcting code of the packet (Lora only) */ bool invert_pol; /*!> invert signal polarity, for orthogonal downlinks (Lora only) */ uint8_t f_dev; /*!> frequency deviation, in kHz (FSK only) */ - uint16_t datarate; /*!> TX datarate (baudrate for FSK) */ - uint8_t coderate; /*!> error-correcting code of the packet (Lora only) */ uint16_t preamble; /*!> set the preamble length, 0 for default */ bool no_crc; /*!> if true, do not send a CRC in the packet */ bool no_header; /*!> if true, enable implicit header mode (Lora), fixed length (FSK) */ diff --git a/libloragw/src/agc_fw.var b/libloragw/src/agc_fw.var index 7d30fb9..a85a22e 100644 --- a/libloragw/src/agc_fw.var +++ b/libloragw/src/agc_fw.var @@ -11,218 +11,218 @@ Description: */ static uint8_t agc_firmware[MCU_AGC_FW_BYTE] = { -0x8A, 0x51, 0x11, 0x28, 0xFF, 0xBF, 0xFF, 0xBF, 0x80, 0x40, 0x03, 0x4E, 0x83, 0x52, 0x03, 0x53, -0xA8, 0xC0, 0x04, 0x88, 0xA9, 0x00, 0x0A, 0xC8, 0xAA, 0x00, 0x01, 0x88, 0xAB, 0x40, 0x8A, 0x51, -0x79, 0x6E, 0x8A, 0x51, 0x3A, 0x2E, 0xA2, 0x70, 0x84, 0x80, 0x37, 0xF0, 0x83, 0x52, 0x03, 0x53, -0xB3, 0x40, 0x04, 0x88, 0xB4, 0x00, 0x08, 0xF0, 0xB5, 0x40, 0x33, 0x48, 0x84, 0x80, 0x83, 0x93, -0x00, 0x48, 0xB6, 0x40, 0xB3, 0xCA, 0x34, 0x08, 0x84, 0x80, 0x36, 0x48, 0x80, 0x40, 0xB4, 0x8A, -0xB5, 0x0B, 0x1D, 0xA8, 0x2B, 0xA8, 0x19, 0x54, 0x99, 0x50, 0x19, 0x95, 0x99, 0x91, 0x19, 0x52, -0x99, 0x92, 0x18, 0x56, 0x38, 0x68, 0x90, 0x30, 0xB3, 0x40, 0x33, 0x48, 0x8B, 0x00, 0x39, 0xA8, -0x8B, 0x41, 0x98, 0x10, 0x18, 0x11, 0x98, 0x51, 0x97, 0x81, 0x9C, 0x41, 0x9A, 0x41, 0x9B, 0x81, -0x9E, 0x81, 0x83, 0x96, 0x03, 0x53, 0xE4, 0x41, 0xE5, 0x81, 0xD2, 0x41, 0xD2, 0x8A, 0x0F, 0xB0, -0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xDA, 0x40, 0xCA, 0x41, -0xD3, 0x81, 0xD3, 0xCA, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xDB, 0x80, 0x06, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xCB, 0x40, 0x02, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD4, 0x00, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xDC, 0x40, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xCC, 0x00, 0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD5, 0x40, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xDD, 0x80, 0x12, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xCD, 0x40, 0x04, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD6, 0x40, 0x0F, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xDE, 0x80, 0x18, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xCE, 0x40, 0x04, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD7, 0x80, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xDF, 0xC0, 0x1E, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xCF, 0x80, 0x05, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD8, 0x00, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xE0, 0xC0, 0x24, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD0, 0xC0, 0x05, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD9, 0x40, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xE1, 0x00, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xD1, 0x00, 0xB2, 0x41, 0xB3, 0x81, 0xB4, 0x41, 0xB5, 0x81, 0xB6, 0x81, 0xB7, 0xC1, -0xB8, 0x41, 0xB9, 0x81, 0xBA, 0x81, 0x06, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xBB, 0x80, 0x0C, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xBC, 0x40, 0x12, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xBD, 0x80, 0x18, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xBE, 0x80, 0x1E, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xBF, 0xC0, 0x24, 0x30, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xC0, 0x80, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, -0x83, 0x96, 0x03, 0x53, 0xC1, 0xC0, 0xEB, 0xC1, 0x02, 0xF0, 0x6B, 0x82, 0x03, 0x5C, 0x39, 0xE9, -0x3A, 0xE9, 0x3C, 0xE9, 0xB2, 0xE9, 0xB2, 0xE9, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x83, 0x93, -0x80, 0x81, 0x08, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, -0xE6, 0xBE, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, -0x03, 0x53, 0xB3, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xB3, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x5B, 0x29, -0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0xBE, 0x84, 0x80, -0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB4, 0x00, 0x34, 0x87, 0x33, 0x44, 0xB5, 0x40, 0x35, 0x48, -0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x6B, 0x88, 0x83, 0x52, 0x03, 0x53, 0xB6, 0x40, 0x36, 0x48, -0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x0C, 0x30, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x83, 0x52, -0x03, 0x53, 0x98, 0x95, 0x98, 0x51, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, -0x83, 0x93, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x03, 0x30, 0x03, 0xD0, 0xB3, 0x0D, -0xFF, 0x7E, 0x03, 0x9D, 0x8E, 0xE9, 0x03, 0xD0, 0x33, 0xCD, 0xB4, 0x00, 0x34, 0x08, 0x96, 0x00, -0x83, 0x96, 0x03, 0x53, 0x6B, 0xD8, 0x9D, 0x29, 0xA1, 0xA9, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, -0xA4, 0xA9, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x18, 0x55, 0x18, 0x11, 0x01, 0xF0, 0xB3, 0x40, -0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xEB, 0x47, 0x02, 0xF0, 0x6B, 0x82, 0x03, 0x5C, 0xB1, 0xE9, -0xB2, 0xE9, 0x3C, 0xE9, 0xEA, 0x81, 0x08, 0xF0, 0x6A, 0x42, 0x03, 0x5C, 0xB8, 0xE9, 0xB9, 0x29, -0xBB, 0x69, 0xF9, 0x69, 0xF9, 0x69, 0x07, 0x70, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x83, 0x93, -0x80, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, -0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x96, 0x00, 0x83, 0x96, 0x03, 0x53, 0x6A, 0x48, 0xA2, 0x3E, -0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x95, 0x00, 0x98, 0x54, -0x98, 0x10, 0x01, 0xF0, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xEA, 0x07, 0x08, 0xF0, -0x6A, 0x42, 0x03, 0x5C, 0xEC, 0x29, 0xED, 0x69, 0xBB, 0x69, 0xF9, 0x69, 0xF9, 0x69, 0xF9, 0x69, -0x83, 0x52, 0x03, 0x53, 0x18, 0x9E, 0xF5, 0x69, 0xF6, 0x69, 0x04, 0x2A, 0x18, 0x12, 0x2B, 0xA8, -0x04, 0x2A, 0x83, 0x52, 0x03, 0x53, 0x93, 0x5F, 0xFE, 0xA9, 0xFF, 0xE9, 0x04, 0x2A, 0x8A, 0x51, -0x38, 0x64, 0x8A, 0x51, 0x04, 0x2A, 0x04, 0x2A, 0x83, 0x96, 0x03, 0x53, 0x68, 0x08, 0xCA, 0x7E, -0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xE4, 0x00, 0x66, 0x48, 0xB2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, -0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xE5, 0x40, 0x83, 0x52, 0x03, 0x53, 0x1E, 0x48, -0x01, 0xBE, 0xB3, 0x40, 0x33, 0x48, 0x9E, 0x40, 0x83, 0x96, 0x03, 0x53, 0x65, 0x48, 0x64, 0x87, -0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x97, 0x40, 0x83, 0x96, 0x03, 0x53, 0x69, 0x48, -0xCA, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, -0x03, 0x53, 0xE4, 0x00, 0x67, 0x88, 0xB2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, -0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xE5, 0x40, 0x65, 0x48, 0x64, 0x87, 0x83, 0x52, -0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x9C, 0x00, 0x17, 0x48, 0xB3, 0x40, 0x33, 0x48, 0x9A, 0x00, -0x83, 0x96, 0x03, 0x53, 0xEA, 0x81, 0x08, 0xF0, 0x6A, 0x42, 0x03, 0x5C, 0x58, 0xAA, 0x59, 0xEA, -0x5B, 0x2A, 0xE3, 0x2A, 0xE3, 0x2A, 0x6A, 0x48, 0xA2, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, -0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x95, 0x00, 0x0D, 0x08, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6A, 0x48, 0xAA, 0x7E, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6A, 0x48, 0xAA, 0x7E, 0x84, 0x80, 0x88, 0x30, 0x00, 0x42, 0x03, 0x5C, 0x79, 0x2A, -0x7A, 0x2A, 0xA2, 0xAA, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x0F, 0xB0, 0x00, 0x42, 0x03, 0x18, -0x82, 0x6A, 0x83, 0xAA, 0xA2, 0xAA, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, -0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, -0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6A, 0x48, 0xC2, 0x3E, -0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x33, 0x48, 0x96, 0x00, 0x98, 0x54, -0x98, 0x10, 0xD6, 0x2A, 0x83, 0x96, 0x03, 0x53, 0x6A, 0x48, 0xAA, 0x7E, 0x84, 0x80, 0x2D, 0xB0, -0x00, 0x42, 0x03, 0x18, 0xAC, 0xEA, 0xAD, 0x2A, 0xD6, 0x2A, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, -0x08, 0xF0, 0x00, 0x42, 0x03, 0x5C, 0xB5, 0x2A, 0xB6, 0x2A, 0xD6, 0x2A, 0x6A, 0x48, 0xC2, 0x3E, -0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6A, 0x48, 0xC2, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, -0x33, 0x48, 0x96, 0x00, 0x98, 0x54, 0x98, 0x10, 0xD6, 0x2A, 0xD6, 0x2A, 0x01, 0xF0, 0x83, 0x52, -0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xEA, 0x07, 0x08, 0xF0, 0x6A, 0x42, 0x03, 0x5C, -0xE2, 0xEA, 0xE3, 0x2A, 0x5B, 0x2A, 0xEB, 0xC1, 0x02, 0xF0, 0x6B, 0x82, 0x03, 0x5C, 0xE9, 0x2A, -0xEA, 0x2A, 0xEC, 0x2A, 0xF9, 0x69, 0xF9, 0x69, 0x6B, 0xD8, 0xEF, 0xAA, 0xF3, 0x6A, 0x83, 0x52, -0x03, 0x53, 0x18, 0x14, 0xF6, 0x6A, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x0E, 0x08, 0xB3, 0x40, -0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xE3, 0x40, 0x88, 0x30, 0x63, 0x42, 0x03, 0x5C, 0x01, 0x6B, -0x02, 0x6B, 0x34, 0xEB, 0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, 0x0B, 0x70, 0x83, 0x93, 0x00, 0x42, -0x03, 0x18, 0x0B, 0xEB, 0x0C, 0xAB, 0x34, 0xEB, 0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, 0x00, 0x48, -0x01, 0xBE, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, 0xE6, 0xBE, -0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, -0xE6, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x03, 0x30, 0x03, 0xD0, -0xB3, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x27, 0x2B, 0x03, 0xD0, 0x33, 0xCD, 0xB4, 0x00, 0x34, 0x08, -0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0x6F, 0xAB, 0x2D, 0xB0, 0x83, 0x96, 0x03, 0x53, 0x63, 0x42, -0x03, 0x18, 0x3B, 0x6B, 0x3C, 0x2B, 0x6F, 0xAB, 0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, 0x09, 0x30, -0x83, 0x93, 0x00, 0x42, 0x03, 0x5C, 0x45, 0xEB, 0x46, 0xEB, 0x6F, 0xAB, 0x6B, 0x88, 0xE6, 0xBE, -0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6B, 0x88, 0xE6, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, -0x03, 0x30, 0x03, 0xD0, 0xB3, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x61, 0xEB, 0x03, 0xD0, 0x33, 0xCD, -0xB4, 0x00, 0x34, 0x08, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0x6F, 0xAB, 0x6F, 0xAB, 0x83, 0x52, -0x0F, 0x48, 0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xE2, 0x00, 0x29, 0x70, 0x62, 0x02, -0x03, 0x5C, 0x7B, 0xAB, 0x7C, 0x6B, 0xCD, 0x6B, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x07, 0x70, -0x83, 0x93, 0x00, 0x42, 0x03, 0x18, 0x85, 0xEB, 0x86, 0xEB, 0xCD, 0x6B, 0x6B, 0x88, 0xE8, 0x7E, -0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD2, 0x7E, 0x84, 0x80, 0x00, 0x48, -0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xB3, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, -0xA4, 0xEB, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0xBE, -0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB4, 0x00, 0x34, 0x87, 0x33, 0x44, 0xB5, 0x40, -0x35, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x6B, 0x88, 0x83, 0x52, 0x03, 0x53, 0xB6, 0x40, -0x36, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x0C, 0x30, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, -0x83, 0x52, 0x03, 0x53, 0x98, 0x95, 0x98, 0x51, 0x26, 0xAC, 0x0F, 0xB0, 0x83, 0x96, 0x03, 0x53, -0x62, 0x02, 0x03, 0x18, 0xD4, 0x2B, 0xD5, 0x6B, 0x26, 0xAC, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, -0x83, 0x93, 0x80, 0x88, 0x03, 0x59, 0xDD, 0xAB, 0xDE, 0xAB, 0x26, 0xAC, 0x6B, 0x88, 0xE8, 0x7E, -0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x83, 0x96, 0x03, 0x53, -0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x83, 0x52, 0x03, 0x53, 0x33, 0x48, 0x80, 0x40, 0x83, 0x96, -0x03, 0x53, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD2, 0x7E, 0x84, 0x80, 0x00, 0x48, -0x83, 0x52, 0x03, 0x53, 0xB3, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xB3, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, -0xFC, 0xAB, 0x83, 0x96, 0x03, 0x53, 0x6B, 0x88, 0xE8, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0xBE, -0x84, 0x80, 0x00, 0x48, 0x83, 0x52, 0x03, 0x53, 0xB4, 0x00, 0x34, 0x87, 0x33, 0x44, 0xB5, 0x40, -0x35, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x6B, 0x88, 0x83, 0x52, 0x03, 0x53, 0xB6, 0x40, -0x36, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x0C, 0x30, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, -0x83, 0x52, 0x03, 0x53, 0x98, 0x95, 0x98, 0x51, 0x26, 0xAC, 0x26, 0xAC, 0x01, 0xF0, 0x83, 0x52, -0xB3, 0x40, 0x33, 0x48, 0x83, 0x96, 0x03, 0x53, 0xEB, 0x47, 0x02, 0xF0, 0x6B, 0x82, 0x03, 0x5C, -0x32, 0xAC, 0x33, 0xEC, 0xEC, 0x2A, 0xF9, 0x69, 0xF9, 0x69, 0xF9, 0x69, 0x8A, 0x51, 0x11, 0x28, -0x83, 0x52, 0x03, 0x53, 0x18, 0x12, 0x00, 0xB0, 0x13, 0xDB, 0x01, 0xF0, 0xAE, 0x40, 0x2E, 0x48, -0xB2, 0x00, 0x00, 0xB0, 0x18, 0x18, 0x01, 0xF0, 0xAE, 0x40, 0x2E, 0x48, 0xB0, 0xC0, 0x32, 0x58, -0x4A, 0xAC, 0x4E, 0xEC, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x51, 0xAC, 0x83, 0x52, 0x03, 0x53, -0x18, 0xD0, 0x12, 0xC8, 0xAE, 0x40, 0x2E, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, -0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x04, 0xF0, -0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x11, 0xC8, 0xAE, 0x40, 0x2E, 0x48, -0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, -0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x05, 0x30, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x83, 0x52, -0x03, 0x53, 0x10, 0x88, 0xAE, 0x40, 0x2E, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, -0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x06, 0x30, -0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x07, 0x70, 0x83, 0x52, 0x03, 0x53, 0xAE, 0x40, 0x2E, 0x48, -0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, -0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x00, 0xB0, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x83, 0x52, -0x03, 0x53, 0x93, 0x1D, 0xA4, 0xAC, 0xA5, 0xEC, 0xB8, 0xEC, 0x1D, 0xB0, 0xAE, 0x40, 0x2E, 0x48, -0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, -0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x08, 0xF0, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0xCC, 0xEC, -0x3B, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xAE, 0x40, 0x2E, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, -0x83, 0x52, 0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, -0x08, 0xF0, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x0F, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xAE, 0x40, -0x2E, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, -0x2F, 0x88, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x00, 0xB0, 0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, -0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0x99, 0x92, 0x32, 0x08, 0x03, 0x9D, 0xE8, 0xEC, 0xEB, 0x6C, -0x19, 0x51, 0x99, 0xD5, 0xED, 0x6C, 0x19, 0x10, 0x99, 0x94, 0x93, 0x1D, 0xF0, 0xEC, 0xF4, 0x2C, -0x83, 0x52, 0x03, 0x53, 0x19, 0x96, 0xF7, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0x93, 0xD9, -0xFA, 0x6C, 0xFE, 0xAC, 0x83, 0x52, 0x03, 0x53, 0x99, 0xD6, 0x01, 0x6D, 0x83, 0x52, 0x03, 0x53, -0x99, 0x92, 0x02, 0x6D, 0x93, 0x1B, 0x05, 0xAD, 0x06, 0xAD, 0x02, 0x6D, 0x07, 0xED, 0x32, 0x08, -0x03, 0x9D, 0x0B, 0xED, 0x0E, 0xED, 0x99, 0x91, 0x19, 0x95, 0x11, 0xAD, 0x99, 0x50, 0x19, 0x54, -0x11, 0xAD, 0x03, 0x30, 0xAE, 0x40, 0x2E, 0x48, 0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, -0x03, 0x53, 0x32, 0x08, 0xAF, 0x80, 0x2F, 0x88, 0x83, 0x96, 0x03, 0x53, 0xA1, 0xC0, 0x00, 0xB0, -0x8A, 0x51, 0x16, 0xA6, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xB1, 0x41, 0x2D, 0x2D, 0x31, 0x08, -0x01, 0xBE, 0xAE, 0x40, 0x2E, 0x48, 0xB1, 0x00, 0x2D, 0x2D, 0x64, 0x70, 0x31, 0x02, 0x03, 0x5C, -0x32, 0xED, 0x33, 0x2D, 0x27, 0x2D, 0x18, 0x56, 0x30, 0x18, 0x37, 0x6D, 0x3B, 0x6D, 0x83, 0x52, -0x03, 0x53, 0x18, 0x14, 0x3E, 0x6D, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x08, 0x40, 0x83, 0x52, -0x03, 0x53, 0x18, 0x12, 0x00, 0xB0, 0x13, 0xDB, 0x01, 0xF0, 0xA2, 0xC0, 0x22, 0xC8, 0xA6, 0x00, -0x00, 0xB0, 0x18, 0x18, 0x01, 0xF0, 0xA2, 0xC0, 0x22, 0xC8, 0xA4, 0xC0, 0x26, 0x58, 0x51, 0xED, -0x55, 0x2D, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x58, 0xED, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, -0x12, 0xC8, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, -0x04, 0xF0, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x11, 0xC8, 0xA2, 0xC0, -0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, 0x05, 0x30, 0x8A, 0x51, -0x5D, 0x26, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x10, 0x88, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, -0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, 0x06, 0x30, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, -0x07, 0x70, 0x83, 0x52, 0x03, 0x53, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, 0xA3, 0x00, -0x23, 0x08, 0xC0, 0x80, 0x00, 0xB0, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, -0x93, 0x1D, 0x93, 0x2D, 0x94, 0xED, 0xA1, 0xED, 0x1D, 0xB0, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, -0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, 0x08, 0xF0, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, -0xAF, 0xAD, 0x3B, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, -0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, 0x08, 0xF0, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, 0x0F, 0xB0, -0x83, 0x52, 0x03, 0x53, 0xA2, 0xC0, 0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, -0xC0, 0x80, 0x00, 0xB0, 0x8A, 0x51, 0x5D, 0x26, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, -0x99, 0x92, 0x26, 0x08, 0x03, 0x9D, 0xC5, 0x2D, 0xC8, 0xED, 0x19, 0x51, 0x99, 0xD5, 0xCA, 0x2D, -0x19, 0x10, 0x99, 0x94, 0x93, 0x1D, 0xCD, 0x6D, 0xD1, 0x2D, 0x83, 0x52, 0x03, 0x53, 0x19, 0x96, -0xD4, 0x2D, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0x93, 0xD9, 0xD7, 0xAD, 0xDB, 0xAD, 0x83, 0x52, -0x03, 0x53, 0x99, 0xD6, 0xDE, 0xAD, 0x83, 0x52, 0x03, 0x53, 0x99, 0x92, 0xDF, 0xED, 0x93, 0x1B, -0xE2, 0x2D, 0xE3, 0x6D, 0xDF, 0xED, 0xE4, 0x2D, 0x26, 0x08, 0x03, 0x9D, 0xE8, 0x2D, 0xEB, 0xAD, -0x99, 0x91, 0x19, 0x95, 0xEE, 0xAD, 0x99, 0x50, 0x19, 0x54, 0xEE, 0xAD, 0x03, 0x30, 0xA2, 0xC0, -0x22, 0xC8, 0xBF, 0xC0, 0x26, 0x08, 0xA3, 0x00, 0x23, 0x08, 0xC0, 0x80, 0x00, 0xB0, 0x8A, 0x51, -0x5D, 0x26, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xA5, 0x41, 0x04, 0x6E, 0x25, 0x08, 0x01, 0xBE, -0xA2, 0xC0, 0x22, 0xC8, 0xA5, 0x00, 0x04, 0x6E, 0x64, 0x70, 0x25, 0x02, 0x03, 0x5C, 0x09, 0xAE, -0x0A, 0xAE, 0xFE, 0xED, 0x18, 0x56, 0x24, 0x18, 0x0E, 0xEE, 0x12, 0xAE, 0x83, 0x52, 0x03, 0x53, -0x18, 0x14, 0x15, 0xEE, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, -0xAD, 0x40, 0x83, 0x96, 0x03, 0x53, 0x21, 0xC8, 0x03, 0x9D, 0x1F, 0x6E, 0x2B, 0x2E, 0x20, 0x88, -0x83, 0x52, 0x03, 0x53, 0xAC, 0x00, 0x2C, 0x08, 0x88, 0x80, 0x2D, 0x48, 0x80, 0x38, 0xAC, 0x00, -0x2C, 0x08, 0x86, 0xC0, 0x39, 0x2E, 0x83, 0x96, 0x03, 0x53, 0x20, 0x88, 0x83, 0x52, 0x03, 0x53, -0xAC, 0x00, 0x2C, 0x08, 0x88, 0x80, 0x2D, 0x48, 0x80, 0x38, 0xAC, 0x00, 0x2C, 0x08, 0x85, 0xC0, -0x39, 0x2E, 0x08, 0x40, 0x8A, 0x51, 0x92, 0xA6, 0x8A, 0x51, 0xB7, 0x80, 0x8A, 0x51, 0x93, 0xE6, -0x8A, 0x51, 0xB8, 0x00, 0x8A, 0x51, 0x94, 0xA6, 0x8A, 0x51, 0xB9, 0x40, 0x8A, 0x51, 0x95, 0xE6, -0x8A, 0x51, 0xBA, 0x40, 0x8A, 0x51, 0x96, 0xE6, 0x8A, 0x51, 0xBB, 0x80, 0x8A, 0x51, 0x97, 0x26, -0x8A, 0x51, 0xBC, 0x40, 0x8A, 0x51, 0x98, 0xA6, 0x8A, 0x51, 0xBD, 0x80, 0x8A, 0x51, 0x99, 0xE6, -0x8A, 0x51, 0xBE, 0x80, 0x83, 0x01, 0x8A, 0x51, 0x13, 0x68, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, -0x40, 0x88, 0x03, 0x9D, 0x64, 0xEE, 0x6E, 0x6E, 0x3F, 0xC8, 0xA0, 0x80, 0x20, 0x88, 0x88, 0x80, -0x21, 0xC8, 0x80, 0x38, 0xA0, 0x80, 0x20, 0x88, 0x86, 0xC0, 0x78, 0x2E, 0x3F, 0xC8, 0xA0, 0x80, -0x20, 0x88, 0x88, 0x80, 0x21, 0xC8, 0x80, 0x38, 0xA0, 0x80, 0x20, 0x88, 0x85, 0xC0, 0x78, 0x2E, -0x08, 0x40, 0x8B, 0xDC, 0x7C, 0x6E, 0x7D, 0xAE, 0x81, 0xAE, 0x8A, 0x51, 0x3F, 0x65, 0x8A, 0x51, -0x81, 0xAE, 0x10, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA7, 0x40, 0x27, 0x48, 0x8B, 0x00, 0x2B, 0x48, -0x81, 0x80, 0x2A, 0x08, 0x8A, 0xC0, 0x29, 0x08, 0x84, 0x80, 0x28, 0x4E, 0x83, 0xC0, 0x80, 0x0E, -0x00, 0xCE, 0x09, 0x80, 0x00, 0xF4, 0x01, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, -0x06, 0x74, 0x07, 0xB4, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0x8A, 0x51, 0x0D, 0x68, 0xFF, 0xBF, 0xFF, 0xBF, 0x80, 0x40, 0x03, 0x4E, 0x83, 0x52, 0x03, 0x53, +0xA6, 0x00, 0x0A, 0xC8, 0xA7, 0x40, 0x8A, 0x51, 0x17, 0x2B, 0x8A, 0x51, 0x4B, 0xEC, 0x95, 0x41, +0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81, +0x19, 0x54, 0x19, 0x95, 0x18, 0x56, 0x8B, 0x41, 0x0F, 0xB0, 0xBE, 0xC1, 0xBE, 0x0A, 0xC9, 0x00, +0x02, 0xF0, 0xB3, 0x81, 0xBF, 0xC0, 0x0F, 0xB0, 0xCA, 0x00, 0x06, 0x30, 0xB4, 0x00, 0x03, 0x30, +0xC0, 0x80, 0x0F, 0xB0, 0xCB, 0x40, 0x0C, 0x30, 0xB5, 0x40, 0x03, 0x30, 0xC1, 0xC0, 0x0C, 0x30, +0xCC, 0x00, 0x12, 0x30, 0xB6, 0x40, 0x03, 0x30, 0xC2, 0xC0, 0x09, 0x30, 0xCD, 0x40, 0x18, 0x30, +0xB7, 0x80, 0x04, 0xF0, 0xC3, 0x00, 0x0C, 0x30, 0xCE, 0x40, 0x1E, 0xB0, 0xB8, 0x00, 0x04, 0xF0, +0xC4, 0xC0, 0x09, 0x30, 0xCF, 0x80, 0x24, 0x30, 0xB9, 0x40, 0x05, 0x30, 0xC5, 0x00, 0x0C, 0x30, +0xD0, 0xC0, 0x2A, 0x70, 0xBA, 0x40, 0x05, 0x30, 0xC6, 0x00, 0x09, 0x30, 0xD1, 0x00, 0x30, 0x30, +0xBB, 0x80, 0x06, 0x30, 0xC7, 0x40, 0x0C, 0x30, 0xD2, 0x00, 0x36, 0xB0, 0xBC, 0x40, 0x06, 0x30, +0xC8, 0xC0, 0x09, 0x30, 0xD3, 0x40, 0x3C, 0xB0, 0xBD, 0x80, 0xE3, 0x81, 0x63, 0x48, 0x60, 0xFE, +0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x3E, 0xBE, +0x84, 0x80, 0x00, 0x48, 0xAE, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xAE, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, +0x6C, 0xA8, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x49, 0x3E, 0x84, 0x80, 0x03, 0xD0, +0x00, 0xCD, 0x2E, 0x44, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x63, 0x48, 0x83, 0x96, 0xA1, 0xC0, +0x0C, 0x30, 0x8A, 0x51, 0x03, 0x63, 0x8A, 0x51, 0x63, 0x48, 0x5E, 0xBE, 0x84, 0x80, 0x08, 0xF0, +0x80, 0x40, 0x63, 0x48, 0x5E, 0xBE, 0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00, 0x63, 0xDC, +0x95, 0xA8, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x98, 0x68, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, +0x18, 0x55, 0x18, 0x11, 0x02, 0xF0, 0xE3, 0xCA, 0x63, 0x42, 0x03, 0x5C, 0x5E, 0xE8, 0xE2, 0x41, +0x62, 0x08, 0x5A, 0x7E, 0x84, 0x80, 0x07, 0x70, 0x83, 0x93, 0x80, 0x40, 0x62, 0x08, 0x5A, 0x7E, +0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x98, 0x54, 0x98, 0x10, 0x04, 0xF0, +0xE2, 0x8A, 0x62, 0x02, 0x03, 0x5C, 0xA0, 0x28, 0x93, 0x5F, 0xB9, 0xE8, 0x8A, 0x51, 0xCF, 0x21, +0x8A, 0x51, 0xE2, 0x41, 0x62, 0x08, 0x95, 0x00, 0x62, 0x08, 0x2F, 0xBE, 0x84, 0x80, 0x0D, 0x08, +0x83, 0x93, 0x80, 0x40, 0x62, 0x08, 0x2F, 0xBE, 0x84, 0x80, 0x88, 0x30, 0x00, 0x42, 0x62, 0x08, +0x03, 0x5C, 0xD5, 0xE8, 0x5A, 0x7E, 0x84, 0x80, 0x0F, 0xB0, 0x00, 0x42, 0x62, 0x08, 0x03, 0x18, +0xD5, 0xE8, 0x5A, 0x7E, 0x84, 0x80, 0x00, 0x8A, 0xE7, 0x28, 0x2F, 0xBE, 0x84, 0x80, 0x2D, 0xB0, +0x00, 0x42, 0x03, 0x18, 0xF4, 0xE8, 0x62, 0x08, 0x5A, 0x7E, 0x84, 0x80, 0x08, 0xF0, 0x00, 0x42, +0x03, 0x5C, 0xF4, 0xE8, 0x62, 0x08, 0x5A, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xAE, 0x40, +0x62, 0x08, 0x5A, 0x7E, 0x84, 0x80, 0x2E, 0x48, 0x80, 0x40, 0x62, 0x08, 0x5A, 0x7E, 0x84, 0x80, +0x00, 0x48, 0x96, 0x00, 0x98, 0x54, 0x98, 0x10, 0x04, 0xF0, 0xE2, 0x8A, 0x62, 0x02, 0x03, 0x5C, +0xBA, 0xE8, 0xE3, 0x81, 0x63, 0xDC, 0x00, 0xE9, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x03, 0x69, +0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x63, 0x48, 0x56, 0x7E, 0x84, 0x80, 0x0E, 0x08, 0x83, 0x93, +0x80, 0x40, 0x63, 0x48, 0x56, 0x7E, 0x84, 0x80, 0x88, 0x30, 0x00, 0x42, 0x63, 0x48, 0x03, 0x5C, +0x1C, 0xA9, 0x5E, 0xBE, 0x84, 0x80, 0x0B, 0x70, 0x00, 0x42, 0x63, 0x48, 0x03, 0x18, 0x1C, 0xA9, +0x5E, 0xBE, 0x84, 0x80, 0x00, 0x8A, 0x2E, 0xE9, 0x56, 0x7E, 0x84, 0x80, 0x2D, 0xB0, 0x00, 0x42, +0x63, 0x48, 0x03, 0x18, 0x3D, 0x29, 0x5E, 0xBE, 0x84, 0x80, 0x09, 0x30, 0x00, 0x42, 0x63, 0x48, +0x03, 0x5C, 0x3D, 0x29, 0x5E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xAE, 0x40, 0x63, 0x48, +0x5E, 0xBE, 0x84, 0x80, 0x2E, 0x48, 0x80, 0x40, 0x63, 0x48, 0x5E, 0xBE, 0x84, 0x80, 0x00, 0xCE, +0xF0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0x63, 0x48, 0x54, 0x3E, 0x84, 0x80, 0x0F, 0x48, +0x80, 0x40, 0x63, 0x48, 0x54, 0x3E, 0x84, 0x80, 0x29, 0x70, 0x00, 0x42, 0x63, 0x48, 0x03, 0x5C, +0x68, 0xA9, 0x60, 0xFE, 0x84, 0x80, 0x0A, 0x30, 0x00, 0x42, 0x63, 0x48, 0x03, 0x18, 0x68, 0xA9, +0x60, 0xFE, 0x84, 0x80, 0x00, 0x8A, 0xAE, 0x40, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x2E, 0x48, +0x80, 0x40, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, +0xAE, 0x40, 0x05, 0x30, 0x03, 0xD0, 0xAE, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x62, 0xA9, 0x8D, 0xE9, +0x54, 0x3E, 0x84, 0x80, 0x0F, 0xB0, 0x00, 0x42, 0x03, 0x18, 0xA2, 0xA9, 0x63, 0x48, 0x60, 0xFE, +0x84, 0x80, 0x80, 0x88, 0x03, 0x59, 0xA2, 0xA9, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x00, 0x48, +0xFF, 0x7E, 0xAE, 0x40, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, 0x2E, 0x48, 0x80, 0x40, 0x63, 0x48, +0x60, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xAE, 0x40, 0x05, 0x30, +0x03, 0xD0, 0xAE, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x88, 0x69, 0x63, 0x48, 0x60, 0xFE, 0x84, 0x80, +0x00, 0x48, 0x49, 0x3E, 0x84, 0x80, 0x03, 0xD0, 0x00, 0xCD, 0x2E, 0x44, 0x83, 0x96, 0xA0, 0x80, +0x83, 0x52, 0x63, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x0C, 0x30, 0x8A, 0x51, 0x03, 0x63, 0x8A, 0x51, +0x98, 0x95, 0x98, 0x51, 0x02, 0xF0, 0xE3, 0xCA, 0x63, 0x42, 0x03, 0x5C, 0xFA, 0x28, 0x60, 0xC8, +0x33, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD8, 0x00, 0x06, 0x30, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, +0x5E, 0x88, 0xF8, 0xBE, 0x8A, 0x51, 0x38, 0x64, 0x8A, 0x51, 0xD9, 0x40, 0x58, 0x87, 0x97, 0x40, +0x61, 0x08, 0x33, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD8, 0x00, 0x06, 0x30, 0x83, 0x96, 0xA0, 0x80, +0x83, 0x52, 0x5F, 0xC8, 0xF8, 0xBE, 0x8A, 0x51, 0x38, 0x64, 0x8A, 0x51, 0xD9, 0x40, 0x58, 0x87, +0x9C, 0x00, 0x17, 0x48, 0x9B, 0x40, 0x60, 0xC8, 0x9A, 0x00, 0x9E, 0x81, 0xB4, 0xA8, 0x18, 0x12, +0x00, 0xB0, 0x13, 0xDB, 0x01, 0xF0, 0xAD, 0x40, 0x00, 0xB0, 0x18, 0x18, 0x01, 0xF0, 0xAB, 0x40, +0x2D, 0xDC, 0xDE, 0x69, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0xE1, 0xE9, 0x83, 0x52, 0x03, 0x53, +0x18, 0xD0, 0x12, 0xC8, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, +0x04, 0xF0, 0x03, 0x63, 0x8A, 0x51, 0x11, 0xC8, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, +0x83, 0x96, 0xA1, 0xC0, 0x05, 0x30, 0x03, 0x63, 0x8A, 0x51, 0x10, 0x88, 0x83, 0x96, 0xA0, 0x80, +0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x06, 0x30, 0x03, 0x63, 0x8A, 0x51, 0x83, 0x96, +0xA0, 0xC1, 0xA0, 0x0A, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0x03, 0x63, +0x8A, 0x51, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x05, 0x30, +0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, +0x03, 0x63, 0x8A, 0x51, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, +0x83, 0x52, 0x03, 0x53, 0x93, 0x1D, 0x28, 0x6A, 0x19, 0x96, 0x99, 0xD6, 0x2E, 0xB0, 0x2B, 0xEA, +0x19, 0x96, 0x99, 0x92, 0x3A, 0xB0, 0xAC, 0x00, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, +0x83, 0x96, 0xA1, 0xC0, 0x08, 0xF0, 0x03, 0x63, 0x8A, 0x51, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, +0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x2D, 0x48, 0x03, 0x59, 0x42, 0x6A, +0x19, 0x51, 0x43, 0xAA, 0x19, 0x10, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, +0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x2D, 0x48, 0x03, 0x59, 0x50, 0x6A, 0x99, 0xD5, 0x51, 0xAA, +0x99, 0x94, 0x32, 0x70, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x0D, 0x70, +0x83, 0x96, 0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, +0x03, 0x63, 0x8A, 0x51, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, +0x83, 0x52, 0x03, 0x53, 0x93, 0x1B, 0x68, 0xAA, 0x99, 0x92, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, +0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0x0A, 0x30, 0x83, 0x96, +0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x2D, 0x48, 0x03, 0x59, +0x83, 0xAA, 0x99, 0x91, 0x84, 0x6A, 0x99, 0x50, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, +0xEA, 0xE2, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x2C, 0x08, 0x0F, 0x39, 0x03, 0x59, 0xB0, 0xAA, +0xFF, 0xB0, 0xAC, 0xC7, 0x2C, 0x08, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, +0xA1, 0xC0, 0x08, 0xF0, 0x03, 0x63, 0x8A, 0x51, 0x05, 0x30, 0x85, 0xAA, 0xF0, 0xB0, 0xAC, 0xC7, +0x2C, 0x08, 0x83, 0x96, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x08, 0xF0, +0x03, 0x63, 0x8A, 0x51, 0x05, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, +0x83, 0x52, 0x03, 0x53, 0x2C, 0x08, 0x30, 0xB9, 0x03, 0x9D, 0x9E, 0x2A, 0x05, 0x30, 0x83, 0x96, +0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0x03, 0x63, 0x8A, 0x51, +0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x03, 0x30, 0x83, 0x96, +0x03, 0x53, 0xA0, 0x80, 0x83, 0x52, 0x2D, 0x48, 0x83, 0x96, 0xA1, 0xC0, 0x00, 0xB0, 0x03, 0x63, +0x8A, 0x51, 0x0A, 0x30, 0x83, 0x96, 0xA0, 0x80, 0xA1, 0x01, 0xEA, 0xE2, 0x8A, 0x51, 0x83, 0x52, +0x03, 0x53, 0x2D, 0x48, 0x03, 0x59, 0xDE, 0x6A, 0x19, 0x95, 0xDF, 0xAA, 0x19, 0x54, 0x18, 0x56, +0x2B, 0xDC, 0xE6, 0x2A, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, +0x18, 0xD0, 0x08, 0x40, 0x83, 0x52, 0xA9, 0x41, 0xAA, 0x41, 0x2A, 0x08, 0x80, 0x7A, 0xA8, 0xC0, +0x83, 0x96, 0x21, 0xC8, 0x80, 0x7A, 0x83, 0x52, 0x28, 0xC2, 0x03, 0x9D, 0xFB, 0xAA, 0x83, 0x96, +0x20, 0x88, 0x83, 0x52, 0x29, 0x02, 0x03, 0x18, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, 0xA9, 0x8A, +0x03, 0x59, 0xAA, 0x8A, 0xED, 0x6A, 0x83, 0x52, 0xA8, 0xC0, 0x83, 0x96, 0x21, 0xC8, 0x03, 0x59, +0x10, 0x6B, 0x20, 0x88, 0x83, 0x52, 0x88, 0x80, 0x28, 0xC8, 0x80, 0x38, 0x86, 0xC0, 0x08, 0x40, +0x20, 0x88, 0x83, 0x52, 0x88, 0x80, 0x28, 0xC8, 0x80, 0x38, 0x85, 0xC0, 0x08, 0x40, 0x8B, 0xDC, +0x1A, 0xEB, 0x23, 0xA3, 0x10, 0xF0, 0x8B, 0x00, 0x27, 0x48, 0x8A, 0xC0, 0x26, 0x8E, 0x83, 0xC0, +0x80, 0x0E, 0x00, 0xCE, 0x09, 0x80, 0x18, 0x12, 0x00, 0xB0, 0x13, 0xDB, 0x01, 0xF0, 0xA5, 0x00, +0x00, 0xB0, 0x18, 0x18, 0x01, 0xF0, 0xA3, 0x00, 0x25, 0x9C, 0x32, 0xEB, 0x83, 0x52, 0x03, 0x53, +0x18, 0x14, 0x35, 0x2B, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x12, 0xC8, 0xE4, 0x00, 0x25, 0x08, +0xE5, 0x40, 0x04, 0xF0, 0x28, 0x24, 0x8A, 0x51, 0x11, 0xC8, 0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, +0x05, 0x30, 0x28, 0x24, 0x8A, 0x51, 0x10, 0x88, 0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x06, 0x30, +0x28, 0x24, 0x8A, 0x51, 0xE4, 0x41, 0xE4, 0x8A, 0x25, 0x08, 0xE5, 0x40, 0x00, 0xB0, 0x28, 0x24, +0x8A, 0x51, 0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x05, 0x30, 0x83, 0x52, +0x03, 0x53, 0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x00, 0xB0, 0x28, 0x24, 0x8A, 0x51, 0x0A, 0x30, +0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x93, 0x1D, 0x6C, 0x2B, +0x19, 0x96, 0x99, 0xD6, 0x2E, 0xB0, 0x6F, 0xAB, 0x19, 0x96, 0x99, 0x92, 0x3A, 0xB0, 0xA4, 0xC0, +0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x08, 0xF0, 0x28, 0x24, 0x8A, 0x51, 0x0A, 0x30, 0xE4, 0x00, +0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x25, 0x08, 0x03, 0x59, 0x82, 0xAB, +0x19, 0x51, 0x83, 0xEB, 0x19, 0x10, 0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, +0x83, 0x52, 0x03, 0x53, 0x25, 0x08, 0x03, 0x59, 0x8F, 0x6B, 0x99, 0xD5, 0x90, 0xAB, 0x99, 0x94, +0x32, 0x70, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x0D, 0x70, 0x83, 0x52, 0x03, 0x53, +0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x00, 0xB0, 0x28, 0x24, 0x8A, 0x51, 0x0A, 0x30, 0xE4, 0x00, +0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x93, 0x1B, 0xA3, 0x2B, 0x99, 0x92, +0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, +0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x25, 0x08, +0x03, 0x59, 0xBC, 0x6B, 0x99, 0x91, 0xBD, 0xAB, 0x99, 0x50, 0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, +0x14, 0x24, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x24, 0xC8, 0x0F, 0x39, 0x03, 0x59, 0xE1, 0x2B, +0xFF, 0xB0, 0xA4, 0x87, 0x24, 0xC8, 0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x08, 0xF0, 0x28, 0x24, +0x8A, 0x51, 0x05, 0x30, 0xBE, 0xAB, 0xF0, 0xB0, 0xA4, 0x87, 0x24, 0xC8, 0xE4, 0x00, 0x25, 0x08, +0xE5, 0x40, 0x08, 0xF0, 0x28, 0x24, 0x8A, 0x51, 0x05, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, +0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x24, 0xC8, 0x30, 0xB9, 0x03, 0x9D, 0xD3, 0x6B, 0x05, 0x30, +0xE4, 0x00, 0x25, 0x08, 0xE5, 0x40, 0x00, 0xB0, 0x28, 0x24, 0x8A, 0x51, 0x0A, 0x30, 0xE4, 0x00, +0xE5, 0x81, 0x14, 0x24, 0x8A, 0x51, 0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xE4, 0x00, 0x25, 0x08, +0xE5, 0x40, 0x00, 0xB0, 0x28, 0x24, 0x8A, 0x51, 0x0A, 0x30, 0xE4, 0x00, 0xE5, 0x81, 0x14, 0x24, +0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x25, 0x08, 0x03, 0x59, 0x08, 0x2C, 0x19, 0x95, 0x09, 0x6C, +0x19, 0x54, 0x18, 0x56, 0x23, 0x9C, 0x10, 0x2C, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x08, 0x40, +0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x08, 0x40, 0xA1, 0x01, 0xA2, 0x01, 0x22, 0xC8, 0x80, 0x7A, +0xA0, 0x80, 0x65, 0x48, 0x80, 0x7A, 0x20, 0x82, 0x03, 0x9D, 0x20, 0x2C, 0x64, 0x08, 0x21, 0xC2, +0x03, 0x18, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, 0xA1, 0x4A, 0x03, 0x59, 0xA2, 0x4A, 0x16, 0xAC, +0xA0, 0x80, 0x65, 0x48, 0x03, 0x59, 0x32, 0xAC, 0x64, 0x08, 0x88, 0x80, 0x20, 0x88, 0x80, 0x38, +0x86, 0xC0, 0x08, 0x40, 0x64, 0x08, 0x88, 0x80, 0x20, 0x88, 0x80, 0x38, 0x85, 0xC0, 0x08, 0x40, +0xA9, 0x00, 0xA8, 0x01, 0x29, 0x9C, 0x40, 0x2C, 0x83, 0x96, 0x20, 0x88, 0x83, 0x52, 0xA8, 0x87, +0x83, 0x96, 0x03, 0xD0, 0xA0, 0x4D, 0x83, 0x52, 0x03, 0xD0, 0xA9, 0x8C, 0xA9, 0x48, 0x03, 0x9D, +0x3A, 0xEC, 0x28, 0xC8, 0x08, 0x40, 0x83, 0x01, 0x8A, 0x51, 0x0F, 0xA8, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, diff --git a/libloragw/src/arb_fw.var b/libloragw/src/arb_fw.var index 014a8e5..fae1ef3 100644 --- a/libloragw/src/arb_fw.var +++ b/libloragw/src/arb_fw.var @@ -11,7 +11,7 @@ Description: */ static uint8_t arb_firmware[MCU_ARB_FW_BYTE] = { -0x8A, 0x51, 0x0E, 0xEE, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0x8A, 0x51, 0x18, 0xAE, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, @@ -203,70 +203,70 @@ static uint8_t arb_firmware[MCU_ARB_FW_BYTE] = { 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, -0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0x64, 0xC0, 0x80, 0x81, -0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x07, 0xEE, 0xDC, 0x81, 0x83, 0x93, -0x20, 0xF0, 0x84, 0x80, 0x57, 0xF0, 0x8A, 0x51, 0x06, 0x66, 0x8A, 0x51, 0xDD, 0xC1, 0xDE, 0xC1, -0xA0, 0x30, 0x84, 0x80, 0xA9, 0xB0, 0x8A, 0x51, 0x06, 0x66, 0x83, 0x01, 0x8A, 0x51, 0x44, 0xAE, -0x83, 0x52, 0xD7, 0x80, 0xDC, 0x90, 0x96, 0x00, 0x57, 0x88, 0x96, 0x00, 0x57, 0x88, 0x96, 0x00, -0x57, 0x88, 0x96, 0x00, 0x8D, 0xDC, 0x08, 0x40, 0x15, 0x54, 0xDC, 0xD4, 0x0D, 0xDD, 0x2E, 0x2E, -0x10, 0x88, 0x83, 0x96, 0xA6, 0x00, 0x83, 0x52, 0x11, 0xC8, 0x83, 0x96, 0xA7, 0x40, 0x83, 0x52, -0x0F, 0x48, 0x83, 0x96, 0xA8, 0xC0, 0x83, 0x52, 0x0E, 0x08, 0x83, 0x96, 0xA4, 0xC0, 0x83, 0x52, -0x12, 0xC8, 0xDD, 0x80, 0x15, 0x10, 0x08, 0x40, 0x8A, 0x51, 0x99, 0xE6, 0x8A, 0x51, 0x83, 0x52, -0x0D, 0x58, 0x61, 0xEE, 0x83, 0x96, 0xA5, 0x41, 0x08, 0xF0, 0x25, 0x02, 0x03, 0x18, 0x47, 0x2E, -0x83, 0x52, 0x5C, 0x94, 0x83, 0x96, 0x25, 0x08, 0x8A, 0x51, 0x20, 0x26, 0x8A, 0x51, 0xDC, 0x1C, -0x5C, 0x2E, 0x8A, 0x51, 0xF0, 0xE6, 0x8A, 0x51, 0x0D, 0x58, 0x47, 0x2E, 0x83, 0x96, 0xA5, 0x8A, -0x4C, 0xEE, 0x5C, 0xDC, 0x47, 0x2E, 0x8A, 0x51, 0x68, 0xA6, 0x8A, 0x51, 0x5C, 0x50, 0x47, 0x2E, -0xDE, 0xC1, 0x08, 0xF0, 0x5E, 0x82, 0x03, 0x18, 0x08, 0x40, 0x5E, 0x88, 0x28, 0xFE, 0x84, 0x80, -0x83, 0x93, 0x00, 0xCB, 0x97, 0x6E, 0x5E, 0x88, 0x28, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, -0x40, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x97, 0x40, 0x5E, 0x88, 0x20, 0xBE, 0x84, 0x80, 0x00, 0x48, -0x98, 0xC0, 0x5E, 0x88, 0x30, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x99, 0x00, 0x5E, 0x88, 0x38, 0x3E, -0x84, 0x80, 0x00, 0x48, 0x9A, 0x00, 0x5E, 0x88, 0x9B, 0x40, 0x5E, 0x88, 0x48, 0xFE, 0x84, 0x80, -0x00, 0x48, 0x9C, 0x00, 0x95, 0x94, 0x95, 0x94, 0x95, 0x94, 0x95, 0x94, 0x95, 0x50, 0xDE, 0x0A, -0x69, 0x2E, 0x95, 0x41, 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, -0x9C, 0x41, 0x9E, 0x81, 0xDE, 0xC1, 0x08, 0xF0, 0x5E, 0x82, 0x03, 0x18, 0xC1, 0xEE, 0x5E, 0x88, -0x30, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, 0x38, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, -0x48, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, 0x20, 0xBE, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, -0x40, 0xBE, 0x84, 0x80, 0x80, 0x81, 0x5E, 0x88, 0x28, 0xFE, 0x84, 0x80, 0x80, 0x81, 0xDE, 0x0A, -0xA3, 0x2E, 0x83, 0x96, 0xA5, 0x41, 0x83, 0x52, 0x5C, 0x50, 0xDC, 0x90, 0x5C, 0x91, 0x83, 0x96, -0xA8, 0x01, 0xA0, 0xC1, 0xA1, 0x01, 0xA2, 0x01, 0xA3, 0x41, 0x83, 0x52, 0x97, 0x81, 0x98, 0x01, -0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x83, 0x96, 0xA6, 0x41, 0xA7, 0x81, 0xA8, 0x01, -0xA4, 0x01, 0x83, 0x52, 0xDD, 0xC1, 0xDE, 0xC1, 0x83, 0x96, 0xA5, 0x41, 0x83, 0x52, 0x02, 0xF0, -0x5C, 0x50, 0xDC, 0x90, 0x5C, 0x91, 0xD0, 0xC0, 0x03, 0x30, 0xD1, 0x00, 0xD2, 0x00, 0x04, 0xF0, -0xD3, 0x40, 0x05, 0x30, 0xD4, 0x00, 0x06, 0x30, 0xD5, 0x40, 0x07, 0x70, 0xD6, 0x40, 0x08, 0x40, -0x5C, 0x91, 0xDE, 0xC1, 0x08, 0xF0, 0x5E, 0x82, 0x03, 0x18, 0xA2, 0x2F, 0x0A, 0x30, 0x83, 0x96, -0x28, 0xC2, 0x83, 0x52, 0x03, 0x5C, 0x5C, 0xD5, 0x83, 0x96, 0x27, 0x48, 0xA1, 0xC0, 0xA0, 0xC1, -0x26, 0x08, 0xA0, 0x47, 0x03, 0x18, 0xA1, 0x4A, 0x83, 0x52, 0x5E, 0x88, 0x30, 0xFE, 0x84, 0x80, -0x83, 0x93, 0x00, 0x48, 0xD9, 0x40, 0x5E, 0x88, 0x38, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, -0xA3, 0x00, 0x83, 0x52, 0x59, 0x48, 0x83, 0x96, 0xA2, 0xC0, 0x01, 0xF0, 0x83, 0x52, 0xD9, 0x40, -0x5E, 0xCA, 0x1C, 0x2F, 0x03, 0xD0, 0xD9, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0x1A, 0x2F, 0x59, 0x48, -0x13, 0x45, 0x03, 0x9D, 0x28, 0xEF, 0x5E, 0x88, 0x28, 0xFE, 0x84, 0x80, 0x00, 0xCB, 0x9C, 0x6F, -0x5E, 0x88, 0x40, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x5D, 0xC6, 0x03, 0x9D, 0x9C, 0x6F, 0x5E, 0x88, -0x20, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, 0x24, 0x06, 0x03, 0x9D, 0x3B, 0xAF, 0x83, 0x52, -0x03, 0x53, 0x5C, 0xD5, 0x9C, 0x6F, 0x83, 0x52, 0x5D, 0x88, 0x4A, 0x3E, 0x84, 0x80, 0x00, 0x48, -0x83, 0x96, 0x22, 0x47, 0x83, 0x52, 0xD9, 0x40, 0x83, 0x96, 0x23, 0x08, 0x03, 0x18, 0x23, 0x4A, -0x83, 0x52, 0xDA, 0x40, 0x80, 0x7A, 0xDB, 0x80, 0x83, 0x96, 0x21, 0xC8, 0x80, 0x7A, 0x83, 0x52, -0x5B, 0x82, 0x03, 0x9D, 0x57, 0xAF, 0x83, 0x96, 0x20, 0x88, 0x83, 0x52, 0x59, 0x42, 0x03, 0x5C, -0x9C, 0x6F, 0x83, 0x52, 0x03, 0x53, 0x5D, 0x88, 0x4A, 0x3E, 0x84, 0x80, 0x83, 0x96, 0x23, 0x08, -0x83, 0x52, 0xDA, 0x40, 0x83, 0x93, 0x00, 0x48, 0x83, 0x96, 0x22, 0xC2, 0x83, 0x52, 0xD9, 0x40, -0x03, 0x5C, 0xDA, 0xC3, 0x83, 0x96, 0x21, 0xC8, 0x80, 0x7A, 0x83, 0x52, 0xDB, 0x80, 0x5A, 0x48, -0x80, 0x7A, 0x5B, 0x82, 0x03, 0x9D, 0x77, 0xEF, 0x59, 0x48, 0x83, 0x96, 0x20, 0x82, 0x03, 0x5C, -0x9C, 0x6F, 0x83, 0x52, 0x03, 0x53, 0x5E, 0x88, 0x48, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, -0x02, 0xBE, 0xD9, 0x40, 0x00, 0xB0, 0x03, 0x18, 0x01, 0xF0, 0xDA, 0x40, 0x80, 0x7A, 0xDB, 0x80, -0x80, 0xF0, 0x5B, 0x82, 0x03, 0x9D, 0x90, 0xEF, 0x83, 0x96, 0x28, 0xC8, 0x83, 0x52, 0x59, 0x42, -0x03, 0x18, 0x37, 0xAF, 0x83, 0x52, 0x03, 0x53, 0x5E, 0x88, 0x28, 0xFE, 0x84, 0x80, 0x83, 0x93, -0x80, 0x81, 0x5E, 0x88, 0xE8, 0x27, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x5C, 0xD9, 0xA2, 0x2F, -0xDE, 0x0A, 0xF2, 0x6E, 0x5C, 0xD9, 0x08, 0x40, 0xDE, 0xC1, 0x08, 0xF0, 0x5E, 0x82, 0x03, 0x18, -0x08, 0x40, 0x01, 0xF0, 0xD9, 0x40, 0x5E, 0xCA, 0xAF, 0xEF, 0x03, 0xD0, 0xD9, 0x0D, 0xFF, 0x7E, -0x03, 0x9D, 0xAD, 0xAF, 0x59, 0x48, 0x13, 0x45, 0x03, 0x9D, 0xE6, 0xAF, 0x5E, 0x88, 0x28, 0xFE, -0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0xE6, 0xAF, 0x5E, 0x88, 0x30, 0xFE, 0x84, 0x80, -0x83, 0x96, 0x26, 0x08, 0x80, 0x40, 0x83, 0x52, 0x5E, 0x88, 0x38, 0x3E, 0x84, 0x80, 0x83, 0x96, -0x27, 0x48, 0x80, 0x40, 0x83, 0x52, 0x5E, 0x88, 0x48, 0xFE, 0x84, 0x80, 0x83, 0x96, 0x28, 0xC8, -0x80, 0x40, 0x83, 0x52, 0x5E, 0x88, 0x20, 0xBE, 0x84, 0x80, 0x83, 0x96, 0x24, 0xC8, 0x80, 0x40, -0x83, 0x52, 0x5E, 0x88, 0x40, 0xBE, 0x84, 0x80, 0x5D, 0x88, 0x80, 0x40, 0x5E, 0x88, 0x28, 0xFE, -0x84, 0x80, 0x80, 0x81, 0x80, 0xCA, 0x9E, 0xCA, 0x5C, 0xD5, 0x08, 0x40, 0xDE, 0x0A, 0xA5, 0x6F, -0xD8, 0x00, 0x9B, 0x40, 0x15, 0x95, 0x15, 0x95, 0x15, 0x95, 0x15, 0x95, 0x15, 0x95, 0x15, 0x95, -0x15, 0x95, 0x15, 0x51, 0x01, 0xF0, 0xD7, 0x80, 0x58, 0x4A, 0xF8, 0xAF, 0x03, 0xD0, 0xD7, 0x4D, -0xFF, 0x7E, 0x03, 0x9D, 0xF6, 0xEF, 0x57, 0x88, 0x13, 0x45, 0x03, 0x59, 0x08, 0x40, 0xF2, 0xAF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0x64, 0xC0, 0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x11, 0xAE, +0xD2, 0x41, 0x83, 0x93, 0x21, 0x30, 0x84, 0x80, 0x48, 0x30, 0x8A, 0x51, 0x10, 0x26, 0x8A, 0x51, +0x83, 0x96, 0xA7, 0x81, 0xA0, 0x30, 0x84, 0x80, 0xA7, 0xF0, 0x8A, 0x51, 0x10, 0x26, 0x83, 0x01, +0x8A, 0x51, 0x2A, 0xEE, 0x8A, 0x51, 0x50, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x0D, 0x58, 0x47, 0x2E, +0xC2, 0x01, 0x83, 0x96, 0x27, 0x94, 0x83, 0x52, 0x42, 0xC8, 0x8A, 0x51, 0xF2, 0x26, 0x8A, 0x51, +0x83, 0x52, 0x03, 0x53, 0x52, 0x9C, 0x3F, 0xAE, 0x8A, 0x51, 0x2C, 0xE7, 0x8A, 0x51, 0x0D, 0x58, +0x2D, 0x2E, 0x04, 0xF0, 0xC2, 0x4A, 0x42, 0xC2, 0x03, 0x18, 0x2D, 0x2E, 0x31, 0xEE, 0x83, 0x96, +0x27, 0xDC, 0x4D, 0x2E, 0x8A, 0x51, 0xA1, 0xA6, 0x8A, 0x51, 0x83, 0x96, 0x27, 0x50, 0x2D, 0x2E, +0x95, 0x41, 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, +0x9E, 0x81, 0xC7, 0x81, 0x04, 0xF0, 0x47, 0x42, 0x03, 0x18, 0x78, 0x2E, 0x47, 0x48, 0x31, 0x3E, +0x84, 0x80, 0x80, 0x81, 0x47, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x80, 0x81, 0x47, 0x48, 0x3D, 0xBE, +0x84, 0x80, 0x80, 0x81, 0x47, 0x48, 0x29, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x47, 0x48, 0x39, 0x7E, +0x84, 0x80, 0x80, 0x81, 0x47, 0x48, 0x2D, 0x7E, 0x84, 0x80, 0x80, 0x81, 0xC7, 0xCA, 0x5A, 0x2E, +0xC3, 0x41, 0xC4, 0x01, 0xC6, 0x41, 0xC1, 0x01, 0xC5, 0x41, 0x83, 0x96, 0x27, 0x50, 0x83, 0x52, +0x02, 0xF0, 0x52, 0x10, 0xD2, 0x50, 0x83, 0x96, 0xA0, 0x80, 0x03, 0x30, 0xA1, 0xC0, 0xA2, 0xC0, +0x04, 0xF0, 0xA3, 0x00, 0x05, 0x30, 0xA4, 0xC0, 0x06, 0x30, 0xA5, 0x00, 0x07, 0x70, 0xA6, 0x00, +0x83, 0x52, 0xA0, 0xC1, 0xA1, 0xC0, 0x06, 0x30, 0xA2, 0xC0, 0x05, 0x30, 0xA3, 0x00, 0x04, 0xF0, +0xA4, 0xC0, 0x03, 0x30, 0xA5, 0x00, 0x02, 0xF0, 0xA6, 0x00, 0xA7, 0x81, 0xA7, 0xCA, 0xA8, 0x01, +0x08, 0x40, 0x83, 0x52, 0xC7, 0x81, 0x04, 0xF0, 0x47, 0x42, 0x03, 0x18, 0x08, 0x40, 0x47, 0x48, +0x2D, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0xCB, 0xF0, 0x2E, 0x47, 0x48, 0x2D, 0x7E, 0x84, 0x80, +0x80, 0x81, 0x47, 0x48, 0x39, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x97, 0x40, 0x47, 0x48, 0x29, 0x3E, +0x84, 0x80, 0x00, 0x48, 0x98, 0xC0, 0x47, 0x48, 0x31, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x99, 0x00, +0x47, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x9A, 0x00, 0x47, 0x48, 0x21, 0xFE, 0x84, 0x80, +0x00, 0x48, 0x9B, 0x40, 0x47, 0x48, 0x3D, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x9C, 0x00, 0x95, 0x94, +0x0A, 0x30, 0xD3, 0x40, 0xD4, 0x41, 0x18, 0xA7, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x95, 0x50, +0x0A, 0x30, 0xD3, 0x40, 0xD4, 0x41, 0x18, 0xA7, 0x8A, 0x51, 0x01, 0xF0, 0x83, 0x52, 0x03, 0x53, +0xCB, 0x40, 0x47, 0x48, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x8A, 0xE9, 0x6E, 0x03, 0xD0, +0xCB, 0x0D, 0xFF, 0x7E, 0x03, 0x9D, 0xE7, 0xAE, 0x4B, 0x48, 0x13, 0x45, 0x03, 0x59, 0xDD, 0xAE, +0xC7, 0xCA, 0xA3, 0x2E, 0xCB, 0x40, 0x52, 0x10, 0x96, 0x00, 0x0A, 0x30, 0xD3, 0x40, 0xD4, 0x41, +0x18, 0xA7, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x8D, 0xDC, 0x08, 0x40, 0x52, 0x54, 0x15, 0x54, +0x0A, 0x30, 0xD3, 0x40, 0xD4, 0x41, 0x18, 0xA7, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0x0D, 0xDD, +0x05, 0xEF, 0x10, 0x88, 0xC3, 0x00, 0x11, 0xC8, 0xC4, 0xC0, 0x0F, 0x48, 0xC6, 0x00, 0x0E, 0x08, +0xC1, 0xC0, 0x12, 0xC8, 0xC5, 0x00, 0x15, 0x10, 0x0A, 0x30, 0xD3, 0x40, 0xD4, 0x41, 0x18, 0xEF, +0xC9, 0x41, 0xCA, 0x41, 0x4A, 0x08, 0x80, 0x7A, 0xC8, 0xC0, 0x54, 0x08, 0x80, 0x7A, 0x48, 0xC2, +0x03, 0x9D, 0x24, 0xEF, 0x53, 0x48, 0x49, 0x02, 0x03, 0x18, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, +0xC9, 0x8A, 0x03, 0x59, 0xCA, 0x8A, 0x1A, 0x2F, 0xD2, 0x50, 0xC7, 0x81, 0x04, 0xF0, 0x47, 0x42, +0x03, 0x18, 0xBF, 0x2F, 0x0A, 0x30, 0x46, 0x02, 0x03, 0x18, 0x38, 0x2F, 0xD2, 0x94, 0xBB, 0xEF, +0x01, 0xF0, 0xC8, 0xC0, 0x47, 0x48, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x8A, 0x42, 0xEF, +0x03, 0xD0, 0xC8, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 0x40, 0xAF, 0x48, 0xC8, 0x13, 0x45, 0x03, 0x9D, +0x4E, 0x6F, 0x47, 0x48, 0x2D, 0x7E, 0x84, 0x80, 0x00, 0xCB, 0xBB, 0xEF, 0x47, 0x48, 0x39, 0x7E, +0x84, 0x80, 0x00, 0x48, 0x45, 0x46, 0x03, 0x9D, 0xBB, 0xEF, 0x44, 0xC8, 0xD1, 0x00, 0xD0, 0x01, +0x43, 0x08, 0xD0, 0x87, 0x03, 0x18, 0xD1, 0x8A, 0x47, 0x48, 0x31, 0x3E, 0x84, 0x80, 0x00, 0x48, +0xC8, 0xC0, 0x47, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xCD, 0x40, 0x48, 0xC8, 0xCC, 0x00, +0x45, 0x08, 0x0C, 0xBC, 0xC8, 0xC0, 0xFF, 0xB0, 0xC8, 0x4A, 0xC9, 0x00, 0x0F, 0xB0, 0xCA, 0x00, +0x74, 0x6F, 0x4A, 0x8D, 0xCA, 0x8C, 0xC9, 0x8C, 0xC8, 0x8B, 0x71, 0x6F, 0x83, 0x52, 0x03, 0x53, +0x49, 0x08, 0xCE, 0x40, 0x4A, 0x08, 0xCF, 0x80, 0x47, 0x48, 0x29, 0x3E, 0x84, 0x80, 0x83, 0x93, +0x00, 0x48, 0x41, 0x06, 0x03, 0x9D, 0xBB, 0xEF, 0x50, 0xC8, 0xFF, 0x7E, 0xC8, 0xC0, 0x51, 0x08, +0x03, 0x18, 0x01, 0xBE, 0xFF, 0x7E, 0xC9, 0x00, 0x4E, 0x48, 0x48, 0x05, 0xCA, 0x00, 0x4F, 0x88, +0x49, 0x45, 0xCB, 0x40, 0x4D, 0x86, 0x03, 0x9D, 0x97, 0xAF, 0x4C, 0x08, 0x4A, 0x46, 0x03, 0x59, +0x36, 0x6F, 0x4E, 0x48, 0x50, 0x05, 0xC8, 0xC0, 0x4F, 0x88, 0x51, 0x45, 0xC9, 0x00, 0x4D, 0x86, +0x03, 0x9D, 0xA4, 0x2F, 0x4C, 0x08, 0x48, 0x06, 0x03, 0x59, 0x36, 0x6F, 0x50, 0xC8, 0x01, 0xBE, +0xC8, 0xC0, 0x51, 0x08, 0x03, 0x18, 0x01, 0xBE, 0x00, 0x7E, 0xC9, 0x00, 0x4E, 0x48, 0x48, 0x05, +0xCA, 0x00, 0x4F, 0x88, 0x49, 0x45, 0xCB, 0x40, 0x4D, 0x86, 0x03, 0x9D, 0xB9, 0xAF, 0x4C, 0x08, +0x4A, 0x46, 0x03, 0x59, 0x36, 0x6F, 0xD2, 0x98, 0xBF, 0x2F, 0xC7, 0xCA, 0x2E, 0x6F, 0xD2, 0x98, +0x08, 0x40, 0xC7, 0x81, 0x04, 0xF0, 0x47, 0x42, 0x03, 0x18, 0x08, 0x40, 0x01, 0xF0, 0xC8, 0xC0, +0x47, 0x48, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x8A, 0xD0, 0x2F, 0x03, 0xD0, 0xC8, 0x8D, +0xFF, 0x7E, 0x03, 0x9D, 0xCE, 0xAF, 0x48, 0xC8, 0x13, 0x45, 0x03, 0x9D, 0xFE, 0x2F, 0x47, 0x48, +0x2D, 0x7E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0xFE, 0x2F, 0x47, 0x48, 0x31, 0x3E, 0x84, 0x80, +0x43, 0x08, 0x80, 0x40, 0x47, 0x48, 0x35, 0x7E, 0x84, 0x80, 0x44, 0xC8, 0x80, 0x40, 0x47, 0x48, +0x3D, 0xBE, 0x84, 0x80, 0x46, 0x08, 0x80, 0x40, 0x47, 0x48, 0x29, 0x3E, 0x84, 0x80, 0x41, 0xC8, +0x80, 0x40, 0x47, 0x48, 0x39, 0x7E, 0x84, 0x80, 0x45, 0x08, 0x80, 0x40, 0x47, 0x48, 0x2D, 0x7E, +0x84, 0x80, 0x80, 0x81, 0x80, 0xCA, 0xA0, 0x0A, 0xD2, 0x94, 0x08, 0x40, 0xC7, 0xCA, 0xC2, 0x2F, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, diff --git a/libloragw/src/loragw_hal.c b/libloragw/src/loragw_hal.c index a57d9f1..930f13e 100644 --- a/libloragw/src/loragw_hal.c +++ b/libloragw/src/loragw_hal.c @@ -36,7 +36,7 @@ Description: #else #define DEBUG_MSG(str) #define DEBUG_PRINTF(fmt, args...) - #define DEBUG_ARRAY(a,b,c) + #define DEBUG_ARRAY(a,b,c) for(a=0;a!=0;){} #define CHECK_NULL(a) if(a==NULL){return LGW_HAL_ERROR;} #endif @@ -61,25 +61,25 @@ const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; #define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ /* -SX1275 frequency setting : +SX1257 frequency setting : F_register(24bit) = F_rf (Hz) / F_step(Hz) = F_rf (Hz) * 2^19 / F_xtal(Hz) + = F_rf (Hz) * 2^19 / 32e6 = F_rf (Hz) * 256/15625 */ -#define SX1257_DENOM 15625 /* pll settings denominator when the numerator is 2^8 */ +#define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */ -#define SX1257_CLK_OUT 1 -#define SX1257_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ -#define SX1257_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ -#define SX1257_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ -#define SX1257_TX_PLL_BW 3 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ -#define SX1257_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ -#define SX1257_TX_DAC_BW 7 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ -#define SX1257_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ -#define SX1257_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ -#define SX1257_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW (kHz) */ -#define SX1257_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ -#define SX1257_RXBB_BW 2 +#define SX125x_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ +#define SX125x_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ +#define SX125x_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ +#define SX125x_TX_PLL_BW 3 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ +#define SX125x_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ +#define SX125x_TX_DAC_BW 7 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ +#define SX125x_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ +#define SX125x_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ +#define SX125x_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW (kHz) */ +#define SX125x_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ +#define SX125x_RXBB_BW 2 #define RSSI_OFFSET_LORA_MULTI -128.0 /* calibrated value */ #define RSSI_OFFSET_LORA_STD -167.0 /* calibrated for all bandwidth */ @@ -115,7 +115,7 @@ the _start function assumes static bool lgw_is_started = false; static bool rf_enable[LGW_RF_CHAIN_NB] = {0, 0}; -static uint32_t rf_rx_freq[LGW_IF_CHAIN_NB] = {0, 0}; /* absolute, in Hz */ +static uint32_t rf_rx_freq[LGW_RF_CHAIN_NB] = {0, 0}; /* absolute, in Hz */ static bool if_enable[LGW_IF_CHAIN_NB] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static bool if_rf_chain[LGW_IF_CHAIN_NB] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* for each IF, 0 -> radio A, 1 -> radio B */ @@ -135,9 +135,9 @@ static uint32_t fsk_rx_dr = 0; /* FSK modem datarate in bauds */ int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size); -void sx125x_write(uint8_t rf_chain, uint8_t addr, uint8_t data); +void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data); -uint8_t sx125x_read(uint8_t rf_chain, uint8_t addr); +uint8_t sx125x_read(uint8_t channel, uint8_t addr); int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz); @@ -148,7 +148,6 @@ void lgw_constant_adjust(void); /* size is the firmware size in bytes (not 14b words) */ int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size) { - int32_t read_value; int reg_rst; int reg_sel; @@ -292,24 +291,28 @@ int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); return -1; } - - /* misc */ - sx125x_write(rf_chain, 0x10, SX1257_TX_DAC_CLK_SEL + SX1257_CLK_OUT*2); + + if (rf_chain == 0) { /* Enable 'clock out' for radio A only */ + sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL + 2); + } else { + sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL); + } + sx125x_write(rf_chain, 0x26, 0X2D); /* Disable gm of oscillator block */ /* Tx gain and trim */ - sx125x_write(rf_chain, 0x08, SX1257_TX_MIX_GAIN + SX1257_TX_DAC_GAIN*16); - sx125x_write(rf_chain, 0x0A, SX1257_TX_ANA_BW + SX1257_TX_PLL_BW*32); - sx125x_write(rf_chain, 0x0B, SX1257_TX_DAC_BW); + sx125x_write(rf_chain, 0x08, SX125x_TX_MIX_GAIN + SX125x_TX_DAC_GAIN*16); + sx125x_write(rf_chain, 0x0A, SX125x_TX_ANA_BW + SX125x_TX_PLL_BW*32); + sx125x_write(rf_chain, 0x0B, SX125x_TX_DAC_BW); /* Rx gain and trim */ - sx125x_write(rf_chain, 0x0C, 0 + SX1257_RX_BB_GAIN*2 + SX1257_RX_LNA_GAIN*32); - sx125x_write(rf_chain, 0x0D, SX1257_RXBB_BW + SX1257_RX_ADC_TRIM*4 + SX1257_RX_ADC_BW*32); + sx125x_write(rf_chain, 0x0C, 0 + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32); + sx125x_write(rf_chain, 0x0D, SX125x_RXBB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32); /* set RX PLL frequency */ - part_int = freq_hz / SX1257_DENOM; /* integer part, gives the MSB and the middle byte */ - part_frac = ((freq_hz % SX1257_DENOM) << 8) / SX1257_DENOM; /* fractional part, gives LSB */ - sx125x_write(rf_chain, 0x01,0xFF & (part_int >> 8)); /* Most Significant Byte */ - sx125x_write(rf_chain, 0x02,0xFF & part_int); /* middle byte */ + part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ + part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + sx125x_write(rf_chain, 0x01,0xFF & part_int); /* Most Significant Byte */ + sx125x_write(rf_chain, 0x02,0xFF & (part_frac >> 8)); /* middle byte */ sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */ /* start and PLL lock */ @@ -321,9 +324,9 @@ int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */ sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */ ++cpt_attempts; - DEBUG_PRINTF("Note: SX1257 #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts); + DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts); wait_ms(1); - } while(sx125x_read(rf_chain, 0x11) & 0x02 == 0); + } while((sx125x_read(rf_chain, 0x11) & 0x02) == 0); return 0; } @@ -340,7 +343,7 @@ void lgw_constant_adjust(void) { // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */ // lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 1 */ lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,9); /* default 7 */ - lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ + lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,9); /* default 5 */ lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,7); /* default 8 */ // lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,32); /* default 32 */ lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ @@ -608,7 +611,6 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { int lgw_start(void) { int i, j; int reg_stat; - int32_t read_value; if (lgw_is_started == true) { DEBUG_MSG("Note: Lora Gateway already started, restarting it now\n"); @@ -747,7 +749,6 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { int nb_pkt_fetch; /* loop variable and return value */ struct lgw_pkt_rx_s *p; /* pointer to the current structure in the struct array */ uint8_t buff[255+RX_METADATA_NB]; /* buffer to store the result of SPI read bursts */ - uint16_t data_addr; /* address read from the FIFO and programmed before the data buffer read operation */ int s; /* size of the payload, uses to address metadata */ int ifmod; /* type of if_chain/modem a packet was received by */ int stat_fifo; /* the packet status as indicated in the FIFO */ @@ -864,6 +865,10 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { p->count_us = (uint32_t)buff[s+6] + ((uint32_t)buff[s+7] << 8) + ((uint32_t)buff[s+8] << 16) + ((uint32_t)buff[s+9] << 24); p->crc = (uint16_t)buff[s+10] + ((uint16_t)buff[s+11] << 8); + /* get back info from configuration so that application doesn't have to keep track of it */ + p->rf_chain = (uint8_t)if_rf_chain[p->if_chain]; + p->freq_hz = (uint32_t)((int32_t)rf_rx_freq[p->rf_chain] + if_freq[p->if_chain]); + /* advance packet FIFO */ lgw_reg_w(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, 0); } @@ -874,13 +879,13 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_send(struct lgw_pkt_tx_s pkt_data) { + int i; uint8_t buff[256+TX_METADATA_NB]; /* buffer to prepare the packet to send + metadata before SPI write burst */ uint32_t part_int; /* integer part for PLL register value calculation */ uint32_t part_frac; /* fractional part for PLL register value calculation */ uint16_t fsk_dr_div; /* divider to configure for target datarate */ int transfer_size = 0; /* data to transfer from host to TX databuffer */ int payload_offset = 0; /* start of the payload content in the databuffer */ - int i; /* check if the gateway is running */ if (lgw_is_started == false) { @@ -953,10 +958,10 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { payload_offset = TX_METADATA_NB; /* start the payload just after the metadata */ /* metadata 0 to 2, TX PLL frequency */ - part_int = pkt_data.freq_hz / SX1257_DENOM; /* integer part, gives the MSB and the middle byte */ - part_frac = ((pkt_data.freq_hz % SX1257_DENOM) << 8) / SX1257_DENOM; /* fractional part, gives LSB */ - buff[0] = 0xFF & (part_int >> 8); /* Most Significant Byte */ - buff[1] = 0xFF & part_int; /* middle byte */ + part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ + part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + buff[0] = 0xFF & part_int; /* Most Significant Byte */ + buff[1] = 0xFF & (part_frac >> 8); /* middle byte */ buff[2] = 0xFF & part_frac; /* Least Significant Byte */ /* metadata 3 to 6, timestamp trigger value */ @@ -1053,7 +1058,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { buff[13] = 0xFF & pkt_data.preamble; /* metadata 14 & 15, FSK baudrate */ - fsk_dr_div = LGW_XTAL_FREQU / pkt_data.datarate; + fsk_dr_div = (uint16_t)((uint32_t)LGW_XTAL_FREQU / pkt_data.datarate); /* Ok for datarate between 500bps and 250kbps */ buff[14] = 0xFF & (fsk_dr_div >> 8); buff[15] = 0xFF & fsk_dr_div; diff --git a/libloragw/src/loragw_reg.c b/libloragw/src/loragw_reg.c index fea9784..68bba55 100644 --- a/libloragw/src/loragw_reg.c +++ b/libloragw/src/loragw_reg.c @@ -479,7 +479,6 @@ int lgw_disconnect(void) { /* soft-reset function */ int lgw_soft_reset(void) { - int32_t read_value; /* check if SPI is initialised */ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) { DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); @@ -610,7 +609,7 @@ int lgw_reg_r(uint16_t register_id, int32_t *reg_value) { int spi_stat = LGW_SPI_SUCCESS; struct lgw_reg_s r; uint8_t bufu[4] = "\x00\x00\x00\x00"; - int8_t *bufs = bufu; + int8_t *bufs = (int8_t *)bufu; int i, size_byte; uint32_t u = 0; diff --git a/libloragw/src/loragw_spi.ftdi.c b/libloragw/src/loragw_spi.ftdi.c index 7b71901..8a16cca 100644 --- a/libloragw/src/loragw_spi.ftdi.c +++ b/libloragw/src/loragw_spi.ftdi.c @@ -177,7 +177,7 @@ int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) uint8_t command; uint8_t *out_buf = NULL; int size_to_do, buf_size, chunk_size, offset; - int a, b, c; + int a=0, b=0, c=0; int i; /* check input parameters */ @@ -243,7 +243,7 @@ int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) struct mpsse_context *mpsse = spi_target; uint8_t command; int size_to_do, chunk_size, offset; - int a, b, c, d; + int a=0, b=0, c=0, d=0; int i; /* check input parameters */ diff --git a/libloragw/src/loragw_spi.native.c b/libloragw/src/loragw_spi.native.c index f5f0701..64e9427 100644 --- a/libloragw/src/loragw_spi.native.c +++ b/libloragw/src/loragw_spi.native.c @@ -59,7 +59,7 @@ Description: int lgw_spi_open(void **spi_target_ptr) { int *spi_device = NULL; int dev; - int a,b,c; + int a=0, b=0; int i; /* check input variables */ diff --git a/libloragw/tst/test_loragw_hal.c b/libloragw/tst/test_loragw_hal.c index a210bee..6afcc45 100644 --- a/libloragw/tst/test_loragw_hal.c +++ b/libloragw/tst/test_loragw_hal.c @@ -28,6 +28,7 @@ Description: #include <signal.h> /* sigaction */ #include "loragw_hal.h" +#include "loragw_reg.h" #include "loragw_aux.h" /* -------------------------------------------------------------------------- */ @@ -60,7 +61,7 @@ static void sig_handler(int sigio) { /* -------------------------------------------------------------------------- */ /* --- MAIN FUNCTION -------------------------------------------------------- */ -int main(int argc, char **argv) +int main() { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ @@ -73,14 +74,13 @@ int main(int argc, char **argv) int i, j; int nb_pkt; - uint8_t x; uint32_t tx_cnt = 0; unsigned long loop_cnt = 0; - int tx_path = 0; - struct lgw_pkt_tx_s txs; uint8_t status_var = 0; + FILE * reg_dump = NULL; + /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; @@ -109,32 +109,29 @@ int main(int argc, char **argv) ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = -300000; - ifconf.bandwidth = BW_125KHZ; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(0, ifconf); /* chain 0: Lora 125kHz, all SF, on 865.7 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 300000; - ifconf.bandwidth = BW_125KHZ; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(1, ifconf); /* chain 1: Lora 125kHz, all SF, on 866.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = -300000; - ifconf.bandwidth = BW_125KHZ; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(2, ifconf); /* chain 2: Lora 125kHz, all SF, on 867.7 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 300000; - ifconf.bandwidth = BW_125KHZ; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(3, ifconf); /* chain 3: Lora 125kHz, all SF, on 868.3 MHz */ /* set configuration for Lora 'stand alone' channel */ + memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 0; @@ -143,44 +140,52 @@ int main(int argc, char **argv) lgw_rxif_setconf(8, ifconf); /* chain 8: Lora 250kHz, SF10, on 866.0 MHz */ /* set configuration for FSK channel */ + memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 0; ifconf.bandwidth = BW_250KHZ; ifconf.datarate = 64000; - lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, fdev 32kHz, variable payload, on 868.0 MHz */ + lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, on 868.0 MHz */ /* set configuration for TX packet */ - memset(&txs, 0, sizeof(txs)); - txs.freq_hz = 867000000; - txs.tx_mode = IMMEDIATE; - txs.modulation = MOD_LORA; - txs.bandwidth = BW_250KHZ; - txs.datarate = DR_LORA_SF10; - txs.coderate = CR_LORA_4_5; - strcpy((char *)txs.payload, "TX.TEST.LORA.GW.????" ); - txs.size = 20; - txs.preamble = 6; - txs.rf_chain = 0; + memset(&txpkt, 0, sizeof(txpkt)); + txpkt.freq_hz = 867000000; + txpkt.tx_mode = IMMEDIATE; + txpkt.modulation = MOD_LORA; + txpkt.bandwidth = BW_250KHZ; + txpkt.datarate = DR_LORA_SF10; + txpkt.coderate = CR_LORA_4_5; + strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); + txpkt.size = 20; + txpkt.preamble = 6; + txpkt.rf_chain = 0; /* - memset(&txs, 0, sizeof(txs)); - txs.freq_hz = 867000000; - txs.tx_mode = IMMEDIATE; - txs.modulation = MOD_FSK; - txs.f_dev = 50; - txs.datarate = 64000; - strcpy((char *)txs.payload, "TX.TEST.LORA.GW.????" ); - txs.size = 20; - txs.preamble = 4; - txs.rf_chain = 0; + memset(&txpkt, 0, sizeof(txpkt)); + txpkt.freq_hz = 867000000; + txpkt.tx_mode = IMMEDIATE; + txpkt.modulation = MOD_FSK; + txpkt.f_dev = 50; + txpkt.datarate = 64000; + strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); + txpkt.size = 20; + txpkt.preamble = 4; + txpkt.rf_chain = 0; */ -// printf("***\n%s\n***\n", lgw_version_info()); + printf("*** Library version information ***\n%s\n***\n", lgw_version_info()); /* connect, configure and start the Lora gateway */ lgw_start(); + /* once configured, dump content of registers to a file, for reference */ + reg_dump = fopen("reg_dump.log", "w"); + if (reg_dump != NULL) { + lgw_reg_check(reg_dump); + fclose(reg_dump); + } + while ((quit_sig != 1) && (exit_sig != 1)) { loop_cnt++; @@ -248,13 +253,13 @@ int main(int argc, char **argv) /* send a packet every X loop */ if (loop_cnt%16 == 0) { /* 32b counter in the payload, big endian */ - txs.payload[16] = 0xff & (tx_cnt >> 24); - txs.payload[17] = 0xff & (tx_cnt >> 16); - txs.payload[18] = 0xff & (tx_cnt >> 8); - txs.payload[19] = 0xff & tx_cnt; - i = lgw_send(txs); /* non-blocking scheduling of TX packet */ + txpkt.payload[16] = 0xff & (tx_cnt >> 24); + txpkt.payload[17] = 0xff & (tx_cnt >> 16); + txpkt.payload[18] = 0xff & (tx_cnt >> 8); + txpkt.payload[19] = 0xff & tx_cnt; + i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ j = 0; - printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txs.rf_chain, i); + printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txpkt.rf_chain, i); do { ++j; wait_ms(100); diff --git a/libloragw/tst/test_loragw_reg.c b/libloragw/tst/test_loragw_reg.c index 2b80109..21ff8ee 100644 --- a/libloragw/tst/test_loragw_reg.c +++ b/libloragw/tst/test_loragw_reg.c @@ -24,7 +24,7 @@ Description: #define BURST_TEST_LENGTH 8192 -int main(int argc, char **argv) +int main() { int32_t read_value, test_value; uint16_t lfsr; diff --git a/libloragw/tst/test_loragw_spi.c b/libloragw/tst/test_loragw_spi.c index 0eae55d..e288df5 100644 --- a/libloragw/tst/test_loragw_spi.c +++ b/libloragw/tst/test_loragw_spi.c @@ -34,7 +34,7 @@ Description: /* -------------------------------------------------------------------------- */ /* --- MAIN FUNCTION -------------------------------------------------------- */ -int main(int argc, char **argv) +int main() { int i; void *spi_target = NULL; diff --git a/loragw_band_survey/LICENSE.TXT b/loragw_band_survey/LICENSE.TXT new file mode 100644 index 0000000..e406dcb --- /dev/null +++ b/loragw_band_survey/LICENSE.TXT @@ -0,0 +1,8 @@ +Copyright (C) 2013 SEMTECH S.A. + + THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND +(2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER. +CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR +CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT +OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION +CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. diff --git a/loragw_band_survey/Makefile b/loragw_band_survey/Makefile new file mode 100644 index 0000000..da10ef6 --- /dev/null +++ b/loragw_band_survey/Makefile @@ -0,0 +1,36 @@ +### Application-specific constants + +APP_NAME=loragw_band_survey + +### constant symbols + +CC=gcc +CFLAGS=-O2 -Wall -Wextra -Iinc +C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc +FLAG_AUX= + +### constants for Lora Gateway HAL library + +LGW_PATH=../loragw_hal +LGW_INC=-I$(LGW_PATH)/inc +#LGW_LNK=-lloragw -lrt +LGW_LNK=-lloragw -lrt -lmpsse +# add libmpsse or not, depending on what option you compiled the libloragw with + +### general build targets + +all: $(APP_NAME) + +clean: + rm -f obj/*.o + rm -f $(APP_NAME) + +### sub-modules compilation + +### main program compilation and assembly + +obj/$(APP_NAME).o: src/$(APP_NAME).c src/rssi_fw.var + $(CC) -c $(C99FLAGS) -o obj/$(APP_NAME).o $(LGW_INC) src/$(APP_NAME).c $(FLAG_AUX) + +$(APP_NAME): $(LGW_PATH)/libloragw.a obj/$(APP_NAME).o + $(CC) -o $(APP_NAME) obj/$(APP_NAME).o -L$(LGW_PATH) $(LGW_LNK) diff --git a/loragw_band_survey/README.TXT b/loragw_band_survey/README.TXT new file mode 100644 index 0000000..da4e672 --- /dev/null +++ b/loragw_band_survey/README.TXT @@ -0,0 +1,57 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Lora Gateway RF band survey application +======================================== + +1. Introduction +---------------- + +This software is used to scan the RF band and measure background RSSI and some +measurement of interferer pattern. +The RSSI is purposefully skew towards high values, to detect high power +interferers (eg. a gateway installed in the beam of a powerful base station), +and not to characterize the noise floor, or accurately measure the time-domain +profile of interferers. + +2. Dependencies +---------------- + +This software call functions in the loragw_reg and loragw_reg sub-modules of +loragwlib. loragw_spi is used indirectly, and the loragw_hal sub-module is not +used at all, except for constants define at the top level. + +It has been qualified with the Lora Getway HAL library version beta8, and should +be compatible with any compatible later version that use the same API, or a +downward-compatible one. + +Because some non-public functions from loragw_hal had to be re-implemented, any +change in the IP might affect this program even if an updated Lora Getway HAL +library is provided. +Connecting an incompatible concentrator board should give you the error: +"ERROR: fail to connect to concentrator board" + +3. Usage +--------- + +To stop the application before the end of the measurement, press Ctrl+C. + +By default, the program scans the whole band (start and stop frequency defined in +the loragw_hal.h file) with a 200 kHz measurement step. +Use -f option to change start and stop frequency, and measurement step. + +The resolution bandwidth of the scan is 200 kHz and cannot be set by the user. + +The measurement results are put in a CSV file whose name include a UTC timestamp +of measurement starting time in ISO 8601 recommended compact format: +yyyymmddThhmmssZ (eg. 20131009T172345Z for October 9th, 2013 at 5:23:45PM UTC) + +4. Changelog +------------- + +2013-10-18, beta 1 +Initial version. diff --git a/loragw_band_survey/obj/.gitkeep b/loragw_band_survey/obj/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/loragw_band_survey/obj/.gitkeep diff --git a/loragw_band_survey/src/loragw_band_survey.c b/loragw_band_survey/src/loragw_band_survey.c new file mode 100644 index 0000000..dc37eef --- /dev/null +++ b/loragw_band_survey/src/loragw_band_survey.c @@ -0,0 +1,451 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + Configure Lora concentrator board and record received packets in a log file +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* fprintf sprintf fopen */ + +#include <signal.h> /* sigaction */ +#include <time.h> /* time strftime gmtime */ +#include <unistd.h> /* getopt */ +#include <stdlib.h> /* EXIT_* constants */ + +#include "loragw_hal.h" /* only for min and max frequency constants */ +#include "loragw_reg.h" +#include "loragw_aux.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr, args) + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define MCU_ARB 0 +#define MCU_AGC 1 + +const uint32_t rf_rx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_LOWFREQ; +const uint32_t rf_rx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_UPFREQ; + +#define MCU_ARB_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ +#define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ + +/* +SX1257 frequency setting : +F_register(24bit) = F_rf (Hz) / F_step(Hz) + = F_rf (Hz) * 2^19 / F_xtal(Hz) + = F_rf (Hz) * 2^19 / 32e6 + = F_rf (Hz) * 256/15625 +*/ +#define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */ + +#define SX125x_CLK_OUT 1 +#define SX125x_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ +#define SX125x_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ +#define SX125x_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ +#define SX125x_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW (kHz) */ +#define SX125x_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ +#define SX125x_RXBB_BW 2 + +#define RF_CHAIN 0 /* we'll use radio A only */ + +#define PLL_LOCK_MAX_ATTEMPTS 6 +#define MEAS_IF (-100000) /* IF in Hz for the RSSI measurement */ +#define RSSI_OFFSET 0.0 /* TODO: calibration */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +#include "rssi_fw.var" /* external definition of the variable */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size); + +void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data); + +uint8_t sx125x_read(uint8_t channel, uint8_t addr); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +/* size is the firmware size in bytes (not 14b words) */ +int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size) { + int reg_rst; + int reg_sel; + + /* check parameters */ + if (target == MCU_ARB) { + if (size != MCU_ARB_FW_BYTE) { + MSG("ERROR: NOT A VALID SIZE FOR MCU ARG FIRMWARE\n"); + return -1; + } + reg_rst = LGW_MCU_RST_0; + reg_sel = LGW_MCU_SELECT_MUX_0; + }else if (target == MCU_AGC) { + if (size != MCU_AGC_FW_BYTE) { + MSG("ERROR: NOT A VALID SIZE FOR MCU AGC FIRMWARE\n"); + return -1; + } + reg_rst = LGW_MCU_RST_1; + reg_sel = LGW_MCU_SELECT_MUX_1; + } else { + MSG("ERROR: NOT A VALID TARGET FOR LOADING FIRMWARE\n"); + return -1; + } + + /* reset the targeted MCU */ + lgw_reg_w(reg_rst, 1); + + /* set mux to access MCU program RAM and set address to 0 */ + lgw_reg_w(reg_sel, 0); + lgw_reg_w(LGW_MCU_PROM_ADDR, 0); + + /* write the program in one burst */ + lgw_reg_wb(LGW_MCU_PROM_DATA, firmware, size); + + /* give back control of the MCU program ram to the MCU */ + lgw_reg_w(reg_sel, 1); + + return 0; +} + +void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data) { + int reg_add, reg_dat, reg_cs; + + /* checking input parameters */ + if (channel >= LGW_RF_CHAIN_NB) { + MSG("ERROR: INVALID RF_CHAIN\n"); + return; + } + if (addr >= 0x7F) { + MSG("ERROR: ADDRESS OUT OF RANGE\n"); + return; + } + + /* selecting the target radio */ + switch (channel) { + case 0: + reg_add = LGW_SPI_RADIO_A__ADDR; + reg_dat = LGW_SPI_RADIO_A__DATA; + reg_cs = LGW_SPI_RADIO_A__CS; + break; + + case 1: + reg_add = LGW_SPI_RADIO_B__ADDR; + reg_dat = LGW_SPI_RADIO_B__DATA; + reg_cs = LGW_SPI_RADIO_B__CS; + break; + + default: + MSG("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); + return; + } + + /* SPI master data write procedure */ + lgw_reg_w(reg_cs, 0); + lgw_reg_w(reg_add, 0x80 | addr); /* MSB at 1 for write operation */ + lgw_reg_w(reg_dat, data); + lgw_reg_w(reg_cs, 1); + lgw_reg_w(reg_cs, 0); + + return; +} + +uint8_t sx125x_read(uint8_t channel, uint8_t addr) { + int reg_add, reg_dat, reg_cs, reg_rb; + int32_t read_value; + + /* checking input parameters */ + if (channel >= LGW_RF_CHAIN_NB) { + MSG("ERROR: INVALID RF_CHAIN\n"); + return 0; + } + if (addr >= 0x7F) { + MSG("ERROR: ADDRESS OUT OF RANGE\n"); + return 0; + } + + /* selecting the target radio */ + switch (channel) { + case 0: + reg_add = LGW_SPI_RADIO_A__ADDR; + reg_dat = LGW_SPI_RADIO_A__DATA; + reg_cs = LGW_SPI_RADIO_A__CS; + reg_rb = LGW_SPI_RADIO_A__DATA_READBACK; + break; + + case 1: + reg_add = LGW_SPI_RADIO_B__ADDR; + reg_dat = LGW_SPI_RADIO_B__DATA; + reg_cs = LGW_SPI_RADIO_B__CS; + reg_rb = LGW_SPI_RADIO_B__DATA_READBACK; + break; + + default: + MSG("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); + return 0; + } + + /* SPI master data read procedure */ + lgw_reg_w(reg_cs, 0); + lgw_reg_w(reg_add, addr); /* MSB at 0 for read operation */ + lgw_reg_w(reg_dat, 0); + lgw_reg_w(reg_cs, 1); + lgw_reg_w(reg_cs, 0); + lgw_reg_r(reg_rb, &read_value); + + return (uint8_t)read_value; +} + +/* describe command line options */ +void usage(void) { + MSG( "Available options:\n"); + MSG( "-h print this help\n"); + MSG( "-f <Fstart>:<Fstop> or <Fstart>:<Fstop>:<Fstep> in MHz (scient. nota. OK)\n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i; /* temporary variable(s) */ + int32_t reg_val; + + /* user chosen parameters */ + double f1 = 0.0; + double f2 = 0.0; + double fs = 0.0; + + /* frequency scan parameters (default values) */ + uint32_t f_start = rf_rx_lowfreq[RF_CHAIN]; /* in Hz */ + uint32_t f_stop = rf_rx_upfreq[RF_CHAIN]; /* in Hz */ + uint32_t f_step = 200000; /* 200 kHz step by default */ + + /* RSSI measurement results */ + int8_t rssi_max; /* max RSSI during X measurements */ + int high_count; /* nb of measurements above a threshold defined by maximum RSSI */ + + /* clock, log file and log rotation management */ + FILE * log_file = NULL; + char log_file_name[64]; + char iso_date[20]; + time_t now_time; + + /* variables for PLL register calculation */ + uint32_t f_target; /* loop variable */ + uint32_t freq_hz; + uint32_t part_int; + uint32_t part_frac; + int cpt_attempts = 0; + + /* parse command line options */ + while ((i = getopt (argc, argv, "hf:")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_SUCCESS; + + case 'f': + sscanf(optarg, "%lf:%lf:%lf", &f1, &f2, &fs); + /* check configuration sanity */ + if (f2 < f1) { + MSG("ERROR: stop frequency must be bigger than start frequency\n"); + return EXIT_FAILURE; + } + if ((f1 < 30.0) || (f1 > 3000.0)) { + MSG("ERROR: invalid start frequency %f MHz\n", f1); + return EXIT_FAILURE; + } + if ((f2 < 30.0) || (f2 > 3000.0)) { + MSG("ERROR: invalid stop frequency %f MHz\n", f2); + return EXIT_FAILURE; + } + f_start = (uint32_t)((f1*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ + f_stop = (uint32_t)((f2*1e6) + 0.5); + if (fs > 0.01) { + f_step = (uint32_t)((fs*1e6) + 0.5); + } + break; + + default: + MSG("ERROR: argument parsing use -h option for help\n"); + usage(); + return EXIT_FAILURE; + } + } + printf("Scanning from %u Hz to %u Hz with a %u Hz frequency step\n", f_start, f_stop, f_step); + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* establish connection with concentrator and reset it */ + if (lgw_connect() == LGW_REG_ERROR) { + MSG("ERROR: fail to connect to concentrator board\n"); + return EXIT_FAILURE; + } + lgw_soft_reset(); + + /* Ungate concentrator clock, switch on the radios and reset them */ + lgw_reg_w(LGW_GLOBAL_EN, 1); + lgw_reg_w(LGW_RADIO_A_EN,1); + lgw_reg_w(LGW_RADIO_B_EN,1); + wait_ms(500); + lgw_reg_w(LGW_RADIO_RST,1); + wait_ms(5); + lgw_reg_w(LGW_RADIO_RST,0); + wait_ms(5); + + /* enter basic parameters for the radio */ + sx125x_write(RF_CHAIN, 0x10, SX125x_TX_DAC_CLK_SEL + SX125x_CLK_OUT*2); + sx125x_write(RF_CHAIN, 0x0C, 0 + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32); /* not required, firmware should take care of that */ + sx125x_write(RF_CHAIN, 0x0D, SX125x_RXBB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32); + + /* configure the IF and concentrator parameters */ + lgw_reg_w(LGW_IF_FREQ_0, -282); /* default -384 */ + lgw_reg_w(LGW_IF_FREQ_1, -128); /* default -128 */ + + lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,9); /* default 7 */ + lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ + lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,3); /* default 8 */ + lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ + lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,90); /* default 100 */ + + /* Load firmware */ + load_firmware(MCU_AGC, rssi_firmware, MCU_AGC_FW_BYTE); + lgw_reg_w(LGW_FORCE_HOST_FE_CTRL,0); + lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN,0); + + /* open log file */ + time(&now_time); + strftime(iso_date,ARRAY_SIZE(iso_date),"%Y%m%dT%H%M%SZ",gmtime(&now_time)); /* format yyyymmddThhmmssZ */ + sprintf(log_file_name, "band_survey_%s.csv", iso_date); + log_file = fopen(log_file_name, "a"); /* create log file, append if file already exist */ + if (log_file == NULL) { + MSG("ERROR: impossible to create log file %s\n", log_file_name); + return EXIT_FAILURE; + } + i = fprintf(log_file, "\"Frequency (Hz)\",\"RSSI (dB)\",\"high meas (nb)\"\n"); + if (i < 0) { + MSG("ERROR: impossible to write to log file %s\n", log_file_name); + return EXIT_FAILURE; + } + + /* main loop */ + f_target = f_start; + + while ((quit_sig != 1) && (exit_sig != 1) && (f_target <= f_stop)) { + + /* set PLL to target frequency */ + freq_hz = f_target - MEAS_IF; + part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ + part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + sx125x_write(RF_CHAIN, 0x01,0xFF & part_int); /* Most Significant Byte */ + sx125x_write(RF_CHAIN, 0x02,0xFF & (part_frac >> 8)); /* middle byte */ + sx125x_write(RF_CHAIN, 0x03,0xFF & part_frac); /* Least Significant Byte */ + + /* start and PLL lock */ + cpt_attempts = 0; + do { + if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) { + MSG("ERROR: fail to lock PLL\n"); + return -1; + } + sx125x_write(RF_CHAIN, 0x00, 1); /* enable Xtal oscillator */ + sx125x_write(RF_CHAIN, 0x00, 3); /* Enable RX (PLL+FE) */ + ++cpt_attempts; + wait_ms(1); + } while((sx125x_read(RF_CHAIN, 0x11) & 0x02) == 0); + + /* give control of the radio to the MCU and get it out of reset */ + lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); + lgw_reg_w(LGW_MCU_RST_1, 0); + + /* wait for the firmware to finish running and fetch the result */ + do { + wait_ms(1); + lgw_reg_r(LGW_MCU_AGC_STATUS, ®_val); + } while (reg_val != 1); + + lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x20); + lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); + rssi_max = (int8_t)reg_val; + + lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x21); + lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); + high_count = reg_val; + + lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x22); + lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); + high_count += (reg_val << 8); + + /* log the measurement */ + i = fprintf(log_file, "%u, %i, %u\n", f_target, rssi_max, high_count); + if (i < 0) { + MSG("ERROR: impossible to write to log file %s\n", log_file_name); + return EXIT_FAILURE; + } + + /* reset MCU and take back control of radio */ + lgw_reg_w(LGW_MCU_RST_1, 1); + lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,1); + + /* iterate loop */ + f_target += f_step; + } + + fclose(log_file); + lgw_soft_reset(); + lgw_disconnect(); + + printf("Exiting Lora concentrator band survey program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_band_survey/src/rssi_fw.var b/loragw_band_survey/src/rssi_fw.var new file mode 100644 index 0000000..8e3befc --- /dev/null +++ b/loragw_band_survey/src/rssi_fw.var @@ -0,0 +1,526 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + firmware for RSSI survey +*/ + +static uint8_t rssi_firmware[MCU_AGC_FW_BYTE] = { +0x8A, 0x51, 0x4D, 0x2D, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0x64, 0xC0, +0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x38, 0xED, 0xC2, 0xC0, +0xC1, 0x01, 0x54, 0x08, 0x42, 0x18, 0xC1, 0x87, 0x03, 0xD0, 0xD4, 0xCD, 0x03, 0xD0, 0xC2, 0x4C, +0xC2, 0x08, 0x03, 0x9D, 0x41, 0xAD, 0x41, 0xC8, 0x08, 0x40, 0x83, 0x93, 0x23, 0x70, 0x84, 0x80, +0x41, 0x30, 0x8A, 0x51, 0x37, 0x25, 0x8A, 0x51, 0xD2, 0x41, 0xD3, 0x81, 0xA0, 0x30, 0x84, 0x80, +0xAC, 0xB0, 0x8A, 0x51, 0x37, 0x25, 0x83, 0x01, 0x8A, 0x51, 0xB8, 0x2D, 0xC1, 0xC0, 0xFD, 0x70, +0x41, 0xC2, 0x03, 0x18, 0x16, 0xB4, 0xE1, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x15, 0xB4, 0xC9, 0xB0, +0x41, 0xC2, 0x03, 0x18, 0x14, 0x74, 0xB3, 0xF0, 0x41, 0xC2, 0x03, 0x18, 0x13, 0xB4, 0xA0, 0x30, +0x41, 0xC2, 0x03, 0x18, 0x12, 0x74, 0x8F, 0xF0, 0x41, 0xC2, 0x03, 0x18, 0x11, 0x74, 0x7F, 0x70, +0x41, 0xC2, 0x03, 0x18, 0x10, 0x34, 0x71, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x0F, 0xF4, 0x65, 0xB0, +0x41, 0xC2, 0x03, 0x18, 0x0E, 0xB4, 0x5A, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x0D, 0xB4, 0x51, 0x70, +0x41, 0xC2, 0x03, 0x18, 0x0C, 0x74, 0x48, 0x30, 0x41, 0xC2, 0x03, 0x18, 0x0B, 0xB4, 0x40, 0xF0, +0x41, 0xC2, 0x03, 0x18, 0x0A, 0x74, 0x39, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x09, 0x74, 0x33, 0xB0, +0x41, 0xC2, 0x03, 0x18, 0x08, 0x34, 0x2E, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x07, 0xB4, 0x29, 0x70, +0x41, 0xC2, 0x03, 0x18, 0x06, 0x74, 0x25, 0x70, 0x41, 0xC2, 0x03, 0x18, 0x05, 0x74, 0x21, 0x30, +0x41, 0xC2, 0x03, 0x18, 0x04, 0x34, 0x1D, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x03, 0x74, 0x1A, 0x70, +0x41, 0xC2, 0x03, 0x18, 0x02, 0x34, 0x17, 0xB0, 0x41, 0xC2, 0x03, 0x18, 0x01, 0x34, 0x00, 0xF4, +0x8A, 0x51, 0x59, 0xE6, 0x8A, 0x51, 0x23, 0x70, 0xA0, 0x80, 0xA1, 0x01, 0xA2, 0x01, 0xCF, 0xC1, +0xD0, 0x01, 0xBB, 0xC1, 0x8A, 0x51, 0x11, 0xA7, 0x8A, 0x51, 0x3C, 0x48, 0x2E, 0x7E, 0x84, 0x80, +0x83, 0x93, 0x00, 0x48, 0xCB, 0x40, 0x06, 0x30, 0xD4, 0x00, 0x40, 0x88, 0xF8, 0xBE, 0x8A, 0x51, +0x3F, 0x65, 0x8A, 0x51, 0xCC, 0x00, 0xBD, 0xC1, 0x02, 0xF0, 0x3D, 0x82, 0x03, 0x18, 0x0D, 0xEE, +0x06, 0x30, 0xD4, 0x00, 0x3D, 0x88, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xF9, 0xFE, 0x8A, 0x51, +0x3F, 0x65, 0x8A, 0x51, 0xC3, 0x00, 0x3D, 0x88, 0x47, 0x7E, 0x84, 0x80, 0x43, 0x08, 0x80, 0x40, +0x3D, 0x88, 0x39, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x8A, 0x51, 0x5E, 0x25, 0x8A, 0x51, 0xC3, 0x00, +0x3D, 0x88, 0x49, 0x3E, 0x84, 0x80, 0x43, 0x08, 0x80, 0x40, 0x3D, 0x88, 0x49, 0x3E, 0x84, 0x80, +0x00, 0x48, 0xC3, 0x00, 0x3D, 0x88, 0x47, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x43, 0x87, 0xC4, 0xC0, +0x4B, 0x48, 0x44, 0x47, 0xC5, 0x00, 0x4C, 0x08, 0x45, 0x87, 0xC6, 0x00, 0x3D, 0x88, 0x4D, 0x7E, +0x84, 0x80, 0x46, 0x08, 0x80, 0x40, 0xBD, 0x0A, 0xD4, 0x2D, 0x4D, 0x48, 0xD1, 0x00, 0x02, 0xF0, +0xBD, 0xC1, 0xBD, 0x0A, 0x3D, 0x82, 0x03, 0x18, 0x23, 0xEE, 0x3D, 0x88, 0x4D, 0x7E, 0x84, 0x80, +0x00, 0x48, 0x51, 0x02, 0x03, 0x18, 0x21, 0xAE, 0x3D, 0x88, 0x4D, 0x7E, 0x84, 0x80, 0x00, 0x48, +0xD1, 0x00, 0x02, 0xF0, 0x11, 0xAE, 0xBB, 0xC8, 0x03, 0x9D, 0x2C, 0xEE, 0x51, 0x08, 0x20, 0x82, +0x03, 0x18, 0x2C, 0xEE, 0x51, 0x08, 0xA0, 0x80, 0x20, 0x88, 0xF4, 0xBE, 0xC3, 0x00, 0xFF, 0xB0, +0x03, 0x18, 0x00, 0xB0, 0xC4, 0xC0, 0x80, 0x7A, 0xC5, 0x00, 0x80, 0xF0, 0x45, 0x02, 0x03, 0x9D, +0x3B, 0x6E, 0x51, 0x08, 0x43, 0x02, 0x03, 0x18, 0x48, 0xAE, 0x30, 0x30, 0x83, 0x52, 0x03, 0x53, +0x51, 0x02, 0x03, 0x5C, 0x48, 0xAE, 0xA1, 0x4A, 0x21, 0xC8, 0x03, 0x9D, 0x48, 0xAE, 0xA2, 0x4A, +0x83, 0x52, 0x64, 0x70, 0x03, 0x53, 0xD0, 0x4A, 0x50, 0xC2, 0x03, 0x5C, 0xC1, 0xED, 0x28, 0x30, +0xCF, 0x0A, 0x4F, 0x82, 0x03, 0x5C, 0xC0, 0xAD, 0x81, 0x30, 0xA0, 0x47, 0x01, 0xF0, 0x9B, 0x40, +0x58, 0xEE, 0x19, 0x54, 0x99, 0x50, 0x19, 0x95, 0x99, 0x91, 0x8B, 0x41, 0x18, 0xD0, 0x95, 0x41, +0x98, 0x10, 0x18, 0x11, 0x98, 0x51, 0x9B, 0x81, 0x9A, 0x41, 0x9E, 0x81, 0x97, 0x81, 0x9C, 0x41, +0x83, 0x96, 0x0F, 0xB0, 0xA0, 0xC1, 0xA0, 0x0A, 0x83, 0x52, 0xA3, 0x00, 0x02, 0xF0, 0xAE, 0x81, +0x83, 0x96, 0xA1, 0xC0, 0x0F, 0xB0, 0x83, 0x52, 0xA4, 0xC0, 0x06, 0x30, 0xAF, 0x80, 0x03, 0x30, +0x83, 0x96, 0xA2, 0xC0, 0x0F, 0xB0, 0x83, 0x52, 0xA5, 0x00, 0x0C, 0x30, 0xB0, 0xC0, 0x03, 0x30, +0x83, 0x96, 0xA3, 0x00, 0x0C, 0x30, 0x83, 0x52, 0xA6, 0x00, 0x12, 0x30, 0xB1, 0x00, 0x03, 0x30, +0x83, 0x96, 0xA4, 0xC0, 0x09, 0x30, 0x83, 0x52, 0xA7, 0x40, 0x18, 0x30, 0xB2, 0x00, 0x04, 0xF0, +0x83, 0x96, 0xA5, 0x00, 0x0C, 0x30, 0x83, 0x52, 0xA8, 0xC0, 0x1E, 0xB0, 0xB3, 0x40, 0x04, 0xF0, +0x83, 0x96, 0xA6, 0x00, 0x09, 0x30, 0x83, 0x52, 0xA9, 0x00, 0x24, 0x30, 0xB4, 0x00, 0x05, 0x30, +0x83, 0x96, 0xA7, 0x40, 0x0C, 0x30, 0x83, 0x52, 0xAA, 0x00, 0x2A, 0x70, 0xB5, 0x40, 0x05, 0x30, +0x83, 0x96, 0xA8, 0xC0, 0x09, 0x30, 0x83, 0x52, 0xAB, 0x40, 0x30, 0x30, 0xB6, 0x40, 0x06, 0x30, +0x83, 0x96, 0xA9, 0x00, 0x0C, 0x30, 0x83, 0x52, 0xAC, 0x00, 0x36, 0xB0, 0xB7, 0x80, 0x06, 0x30, +0x83, 0x96, 0xAA, 0x00, 0x09, 0x30, 0x83, 0x52, 0xAD, 0x40, 0x3C, 0xB0, 0xB8, 0x00, 0xD3, 0x81, +0xF8, 0x6E, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, 0x04, 0xF0, 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, +0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xC1, 0xC0, 0x05, 0x30, +0x03, 0xD0, 0xC1, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 0xD0, 0xEE, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, +0x00, 0x48, 0x23, 0x3E, 0x84, 0x80, 0x03, 0xD0, 0x00, 0xCD, 0x41, 0xC4, 0x88, 0x80, 0x8C, 0x70, +0x85, 0xC0, 0x53, 0x48, 0x40, 0xBE, 0x84, 0x80, 0x08, 0xF0, 0x80, 0x40, 0x53, 0x48, 0x40, 0xBE, +0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00, 0x53, 0xDC, 0xF2, 0x6E, 0x83, 0x52, 0x03, 0x53, +0x18, 0x14, 0xF5, 0xAE, 0x83, 0x52, 0x03, 0x53, 0x18, 0xD0, 0x18, 0x55, 0x18, 0x11, 0xD3, 0xCA, +0x53, 0x48, 0x03, 0x59, 0xC1, 0xEE, 0xBD, 0xC1, 0x02, 0xF0, 0x3D, 0x82, 0x03, 0x18, 0x08, 0x40, +0x3D, 0x88, 0x3E, 0xBE, 0x84, 0x80, 0x07, 0x70, 0x83, 0x93, 0x80, 0x40, 0x3D, 0x88, 0x3E, 0xBE, +0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x3D, 0x88, 0x95, 0x00, 0x98, 0x54, 0x98, 0x10, 0xBD, 0x0A, +0xFC, 0xAE, 0xBD, 0xC1, 0x02, 0xF0, 0x3D, 0x82, 0x03, 0x18, 0x54, 0x2F, 0x3D, 0x88, 0x95, 0x00, +0x3D, 0x88, 0x39, 0x7E, 0x84, 0x80, 0x0D, 0x08, 0x83, 0x93, 0x80, 0x40, 0x3D, 0x88, 0x39, 0x7E, +0x84, 0x80, 0x88, 0x30, 0x00, 0x42, 0x3D, 0x88, 0x03, 0x5C, 0x31, 0x2F, 0x3E, 0xBE, 0x84, 0x80, +0x0F, 0xB0, 0x00, 0x42, 0x3D, 0x88, 0x03, 0x18, 0x31, 0x2F, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x8A, +0x43, 0x2F, 0x39, 0x7E, 0x84, 0x80, 0x2D, 0xB0, 0x00, 0x42, 0x03, 0x18, 0x52, 0x2F, 0x3D, 0x88, +0x3E, 0xBE, 0x84, 0x80, 0x08, 0xF0, 0x00, 0x42, 0x03, 0x5C, 0x52, 0x2F, 0x3D, 0x88, 0x3E, 0xBE, +0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xC1, 0xC0, 0x3D, 0x88, 0x3E, 0xBE, 0x84, 0x80, 0x41, 0xC8, +0x80, 0x40, 0x3D, 0x88, 0x3E, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x98, 0x54, 0x98, 0x10, +0xBB, 0xC1, 0xBB, 0x0A, 0xBD, 0x0A, 0x12, 0xEF, 0xD3, 0x81, 0x53, 0x48, 0x03, 0x9D, 0x08, 0x40, +0x53, 0xDC, 0x5E, 0xAF, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x61, 0x2F, 0x83, 0x52, 0x03, 0x53, +0x18, 0xD0, 0x53, 0x48, 0xAB, 0xBE, 0x84, 0x80, 0x0E, 0x08, 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, +0xAB, 0xBE, 0x84, 0x80, 0x88, 0x30, 0x00, 0x42, 0x53, 0x48, 0x03, 0x5C, 0x7A, 0xAF, 0x40, 0xBE, +0x84, 0x80, 0x0B, 0x70, 0x00, 0x42, 0x53, 0x48, 0x03, 0x18, 0x7A, 0xAF, 0x40, 0xBE, 0x84, 0x80, +0x00, 0x8A, 0x8C, 0x2F, 0xAB, 0xBE, 0x84, 0x80, 0x2D, 0xB0, 0x00, 0x42, 0x53, 0x48, 0x03, 0x18, +0x9D, 0xAF, 0x40, 0xBE, 0x84, 0x80, 0x09, 0x30, 0x00, 0x42, 0x53, 0x48, 0x03, 0x5C, 0x9D, 0xAF, +0x40, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xC1, 0xC0, 0x53, 0x48, 0x40, 0xBE, 0x84, 0x80, +0x41, 0xC8, 0x80, 0x40, 0x53, 0x48, 0x40, 0xBE, 0x84, 0x80, 0x00, 0xCE, 0xF0, 0x39, 0x96, 0x00, +0x18, 0x55, 0x18, 0x11, 0xBB, 0xC1, 0xBB, 0x0A, 0x53, 0x48, 0x52, 0x3E, 0x84, 0x80, 0x0F, 0x48, +0x80, 0x40, 0x53, 0x48, 0x52, 0x3E, 0x84, 0x80, 0x29, 0x70, 0x00, 0x42, 0x53, 0x48, 0x03, 0x5C, +0xC8, 0x2F, 0x3C, 0x7E, 0x84, 0x80, 0x0A, 0x30, 0x00, 0x42, 0x53, 0x48, 0x03, 0x18, 0xC8, 0x2F, +0x3C, 0x7E, 0x84, 0x80, 0x00, 0x8A, 0xC1, 0xC0, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, 0x41, 0xC8, +0x80, 0x40, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, +0xC1, 0xC0, 0x05, 0x30, 0x03, 0xD0, 0xC1, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 0xC2, 0x2F, 0xEE, 0xEF, +0x52, 0x3E, 0x84, 0x80, 0x0F, 0xB0, 0x00, 0x42, 0x03, 0x18, 0xFE, 0x2F, 0x53, 0x48, 0x3C, 0x7E, +0x84, 0x80, 0x05, 0x30, 0x00, 0x42, 0x03, 0x5C, 0xFE, 0x2F, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, +0x00, 0x48, 0xFF, 0x7E, 0xC1, 0xC0, 0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, 0x41, 0xC8, 0x80, 0x40, +0x53, 0x48, 0x3C, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xC1, 0xC0, +0x05, 0x30, 0x03, 0xD0, 0xC1, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 0xE9, 0xAF, 0x53, 0x48, 0x3C, 0x7E, +0x84, 0x80, 0x00, 0x48, 0x23, 0x3E, 0x84, 0x80, 0x03, 0xD0, 0x00, 0xCD, 0x41, 0xC4, 0x88, 0x80, +0x8C, 0x70, 0x85, 0xC0, 0x98, 0x95, 0x98, 0x51, 0xBB, 0xC1, 0xBB, 0x0A, 0xD3, 0xCA, 0x55, 0x6F, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, +0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF +}; diff --git a/loragw_pkt_logger/LICENSE.TXT b/loragw_pkt_logger/LICENSE.TXT new file mode 100644 index 0000000..b46b1f5 --- /dev/null +++ b/loragw_pkt_logger/LICENSE.TXT @@ -0,0 +1,33 @@ + --- For the parson library (parson.c and parson.h) --- + + Parson ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 Krzysztof Gabis + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + --- For the rest of the code --- + +Copyright (C) 2013 SEMTECH S.A. + + THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND +(2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER. +CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR +CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT +OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION +CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. diff --git a/loragw_pkt_logger/Makefile b/loragw_pkt_logger/Makefile new file mode 100644 index 0000000..6b90495 --- /dev/null +++ b/loragw_pkt_logger/Makefile @@ -0,0 +1,39 @@ +### Application-specific constants + +APP_NAME=loragw_pkt_logger + +### constant symbols + +CC=gcc +CFLAGS=-O2 -Wall -Wextra -Iinc +C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc +FLAG_AUX= + +### constants for Lora Gateway HAL library + +LGW_PATH=../loragw_hal +LGW_INC=-I$(LGW_PATH)/inc +#LGW_LNK=-lloragw -lrt +LGW_LNK=-lloragw -lrt -lmpsse +# add libmpsse or not, depending on what option you compiled the libloragw with + +### general build targets + +all: $(APP_NAME) + +clean: + rm -f obj/*.o + rm -f $(APP_NAME) + +### sub-modules compilation + +obj/parson.o: src/parson.c + $(CC) -c $(C99FLAGS) -o obj/parson.o $(LGW_INC) src/parson.c $(FLAG_AUX) + +### main program compilation and assembly + +obj/$(APP_NAME).o: src/$(APP_NAME).c + $(CC) -c $(C99FLAGS) -o obj/$(APP_NAME).o $(LGW_INC) src/$(APP_NAME).c $(FLAG_AUX) + +$(APP_NAME): $(LGW_PATH)/libloragw.a obj/$(APP_NAME).o obj/parson.o + $(CC) -o $(APP_NAME) obj/$(APP_NAME).o obj/parson.o -L$(LGW_PATH) $(LGW_LNK) diff --git a/loragw_pkt_logger/README.TXT b/loragw_pkt_logger/README.TXT new file mode 100644 index 0000000..278d026 --- /dev/null +++ b/loragw_pkt_logger/README.TXT @@ -0,0 +1,88 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Lora Gateway packet logger +=========================== + +1. Introduction +---------------- + +This software is used to set up a Lora concentrator using a JSON configuration +file and then record all the packets received in a log file, indefinitely, until +the user stops the application. +No filtering is done and all packets that are Lora packets with the correct RF +parameters (frequency, datarate, bandwidth) should appear in the log. + +2. Dependencies +---------------- + +This program uses the Parson library (http://kgabis.github.com/parson/) by +Krzysztof Gabis for JSON parsing. +Many thanks to him for that very practical and well written library. + +This program is a typical example of Lora Gateway HAL usage for receiving +packets. + +Only high-level functions are used (the ones contained in loragw_hal) so there +is no hardware dependencies assuming the HAL is matched with the proper version +of the hardware. +Data structures of the received packets are accessed by name (ie. not at a +binary level) so new functionalities can be added to the API without affecting +that program at all. + +It was tested with beta8 of the libloragw library, and should be compatible +with any later version of the library assuming the API is downward-compatible. + +3. Usage +--------- + +To stop the application, press Ctrl+C. + +The only optional parameter when launching the application is the log rotation +time (in seconds). + +The way the program takes configuration files into account is the following: + * if there is a debug_conf.json parse it, others are ignored + * if there is a global_conf.json parse it, look for the next file + * if there is a local_conf.json parse it +If some parameters are defined in both global and local configuration files, the +local definition overwrites the global definition. + +The global configuration file should be exactly the same throughout your +network, contain all global parameters (parameters for "sensor" radio channels) +and preferably default "safe" values for parameters that are specific for each +gateway (eg. specify a default MAC address). + +The local configuration file should contain parameters that are specific to each +gateway (eg. MAC address, frequency for backhaul radio channels). + +In each configuration file, the program looks for a JSON object named +"SX1301_conf" that should contain the parameters for the Lora concentrator board +(RF channels definition, modem parameters, etc) and another JSON object called +"gateway_conf" that should contain the gateway parameters (gateway MAC address, +IP address of the Lora MAC controller, network authentication parameters, etc). + +To learn more about the JSON configuration format, read the provided JSON files +and the API documentation. A dedicated document will be available later on. + +The received packets are put in a CSV file whose name include the MAC address of +the gateway in hexadecimal format and a UTC timestamp of log starting time in +ISO 8601 recommended compact format: +yyyymmddThhmmssZ (eg. 20131009T172345Z for October 9th, 2013 at 5:23:45PM UTC) + +To able continuous monitoring, the current log file is closed is closed and a +new one is opened every hour (by default, rotation interval is settable by the +user using -r command line option). +No packet is lost during that rotation of log file. +Every log file but the current one can then be modified, uploaded and/or deleted +without any consequence for the program execution. + +4. Changelog +------------- + +2013-10-18, beta 1 +Initial version. diff --git a/loragw_pkt_logger/global_conf.json b/loragw_pkt_logger/global_conf.json new file mode 100644 index 0000000..6bc8f06 --- /dev/null +++ b/loragw_pkt_logger/global_conf.json @@ -0,0 +1,46 @@ +{ + "SX1301_conf": { + "radio_0": { + "enable": true, + "freq": 868200000 + }, + "chan_multiSF_0": { + "enable": true, + "radio": 0, + "if": -100000, + "note": "Lora MAC channel, 125kHz, all SF, 868.1 MHz" + }, + "chan_multiSF_1": { + "enable": true, + "radio": 0, + "if": 100000, + "note": "Lora MAC channel, 125kHz, all SF, 868.3 MHz" + }, + "chan_multiSF_2": { + "enable": true, + "radio": 0, + "if": 300000, + "note": "Lora MAC channel, 125kHz, all SF, 868.5 MHz" + }, + "chan_Lora_std": { + "enable": true, + "radio": 0, + "if": 100000, + "bandwidth": 250000, + "spread_factor": 7, + "note": "Lora MAC channel, 250kHz, SF7, 868.3 MHz" + }, + + "chan_FSK": { + "enable": true, + "radio": 0, + "if": 100000, + "bandwidth": 250000, + "datarate": 100000, + "note": "FSK 100kbps channel, 868.3 MHz" + } + }, + "gateway_conf": { + "gateway_ID": "AA555A0000000000" + } +} diff --git a/loragw_pkt_logger/inc/parson.h b/loragw_pkt_logger/inc/parson.h new file mode 100644 index 0000000..00728b1 --- /dev/null +++ b/loragw_pkt_logger/inc/parson.h @@ -0,0 +1,100 @@ +/* + Parson ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 Krzysztof Gabis + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef parson_parson_h +#define parson_parson_h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stddef.h> /* size_t */ + +/* Types and enums */ +typedef struct json_object_t JSON_Object; +typedef struct json_array_t JSON_Array; +typedef struct json_value_t JSON_Value; + +typedef enum json_value_type { + JSONError = 0, + JSONNull = 1, + JSONString = 2, + JSONNumber = 3, + JSONObject = 4, + JSONArray = 5, + JSONBoolean = 6 +} JSON_Value_Type; + +/* Parses first JSON value in a file, returns NULL in case of error */ +JSON_Value * json_parse_file(const char *filename); + +/* Parses first JSON value in a string, returns NULL in case of error */ +JSON_Value * json_parse_string(const char *string); + +/* JSON Object */ +JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); +const char * json_object_get_string (const JSON_Object *object, const char *name); +JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); +JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); +double json_object_get_number (const JSON_Object *object, const char *name); +int json_object_get_boolean(const JSON_Object *object, const char *name); + +/* dotget functions enable addressing values with dot notation in nested objects, + just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). + Because valid names in JSON can contain dots, some values may be inaccessible + this way. */ +JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); +const char * json_object_dotget_string (const JSON_Object *object, const char *name); +JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); +JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); +double json_object_dotget_number (const JSON_Object *object, const char *name); +int json_object_dotget_boolean(const JSON_Object *object, const char *name); + +/* Functions to get available names */ +size_t json_object_get_count(const JSON_Object *object); +const char * json_object_get_name (const JSON_Object *object, size_t index); + +/* JSON Array */ +JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); +const char * json_array_get_string (const JSON_Array *array, size_t index); +JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); +JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); +double json_array_get_number (const JSON_Array *array, size_t index); +int json_array_get_boolean(const JSON_Array *array, size_t index); +size_t json_array_get_count (const JSON_Array *array); + +/* JSON Value */ +JSON_Value_Type json_value_get_type (const JSON_Value *value); +JSON_Object * json_value_get_object (const JSON_Value *value); +JSON_Array * json_value_get_array (const JSON_Value *value); +const char * json_value_get_string (const JSON_Value *value); +double json_value_get_number (const JSON_Value *value); +int json_value_get_boolean(const JSON_Value *value); +void json_value_free (JSON_Value *value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/loragw_pkt_logger/local_conf.json b/loragw_pkt_logger/local_conf.json new file mode 100644 index 0000000..624893d --- /dev/null +++ b/loragw_pkt_logger/local_conf.json @@ -0,0 +1,5 @@ +{ + "gateway_conf": { + "gateway_ID": "AA555A0000000101" + } +} diff --git a/loragw_pkt_logger/obj/.gitkeep b/loragw_pkt_logger/obj/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/loragw_pkt_logger/obj/.gitkeep diff --git a/loragw_pkt_logger/src/loragw_pkt_logger.c b/loragw_pkt_logger/src/loragw_pkt_logger.c new file mode 100644 index 0000000..b3200ba --- /dev/null +++ b/loragw_pkt_logger/src/loragw_pkt_logger.c @@ -0,0 +1,565 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + Configure Lora concentrator and record received packets in a log file +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf sprintf fopen fputs */ + +#include <string.h> /* memset */ +#include <signal.h> /* sigaction */ +#include <time.h> /* time clock_gettime strftime gmtime clock_nanosleep*/ +#include <unistd.h> /* getopt access */ +#include <stdlib.h> /* atoi */ + +#include "parson.h" +#include "loragw_hal.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr,"loragw_pkt_logger: " args) /* message that is destined to the user */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* configuration variables needed by the application */ +uint64_t lgwm = 0; /* Lora gateway MAC address */ +char lgwm_str[17]; + +/* clock and log file management */ +time_t now_time; +time_t log_start_time; +FILE * log_file = NULL; +char log_file_name[64]; + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +int parse_SX1301_configuration(const char * conf_file); + +int parse_gateway_configuration(const char * conf_file); + +void open_log(void); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +int parse_SX1301_configuration(const char * conf_file) { + int i; + const char conf_obj[] = "SX1301_conf"; + char param_name[32]; /* used to generate variable parameter names */ + struct lgw_conf_rxrf_s rfconf; + struct lgw_conf_rxif_s ifconf; + JSON_Value *root_val; + JSON_Object *root = NULL; + JSON_Object *conf = NULL; + JSON_Value *val; + uint32_t sf, bw; + + /* try to parse JSON */ + root_val = json_parse_file(conf_file); + root = json_value_get_object(root_val); + if (root == NULL) { + MSG("ERROR: %s id not a valid JSON file\n", conf_file); + exit(EXIT_FAILURE); + } + conf = json_object_get_object(root, conf_obj); + if (conf == NULL) { + MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj); + return -1; + } else { + MSG("INFO: %s does contain a JSON object named %s, parsing SX1301 parameters\n", conf_file, conf_obj); + } + + /* set configuration for RF chains */ + for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { + memset(&rfconf, 0, sizeof(rfconf)); /* initialize configuration structure */ + sprintf(param_name, "radio_%i", i); /* compose parameter path inside JSON structure */ + val = json_object_get_value(conf, param_name); /* fetch value (if possible) */ + if (json_value_get_type(val) != JSONObject) { + MSG("INFO: no configuration for radio %i\n", i); + continue; + } + /* there is an object to configure that radio, let's parse it */ + sprintf(param_name, "radio_%i.enable", i); + val = json_object_dotget_value(conf, param_name); + if (json_value_get_type(val) == JSONBoolean) { + rfconf.enable = (bool)json_value_get_boolean(val); + } else { + rfconf.enable = false; + } + if (rfconf.enable == false) { /* radio disabled, nothing else to parse */ + MSG("INFO: radio %i disabled\n", i); + } else { /* radio enabled, will parse the other parameters */ + sprintf(param_name, "radio_%i.freq", i); + rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf, param_name); + MSG("INFO: radio %i enabled, center frequency %u\n", i, rfconf.freq_hz); + } + /* all parameters parsed, submitting configuration to the HAL */ + if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) { + MSG("WARNING: invalid configuration for radio %i\n", i); + } + } + + /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ + for (i = 0; i < LGW_MULTI_NB; ++i) { + memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */ + sprintf(param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */ + val = json_object_get_value(conf, param_name); /* fetch value (if possible) */ + if (json_value_get_type(val) != JSONObject) { + MSG("INFO: no configuration for Lora multi-SF channel %i\n", i); + continue; + } + /* there is an object to configure that Lora multi-SF channel, let's parse it */ + sprintf(param_name, "chan_multiSF_%i.enable", i); + val = json_object_dotget_value(conf, param_name); + if (json_value_get_type(val) == JSONBoolean) { + ifconf.enable = (bool)json_value_get_boolean(val); + } else { + ifconf.enable = false; + } + if (ifconf.enable == false) { /* Lora multi-SF channel disabled, nothing else to parse */ + MSG("INFO: Lora multi-SF channel %i disabled\n", i); + } else { /* Lora multi-SF channel enabled, will parse the other parameters */ + sprintf(param_name, "chan_multiSF_%i.radio", i); + ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, param_name); + sprintf(param_name, "chan_multiSF_%i.if", i); + ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, param_name); + // TODO: handle individual SF enabling and disabling (spread_factor) + MSG("INFO: Lora multi-SF channel %i enabled, radio %i selected, IF %i Hz, 125 kHz bandwidth, SF 7 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz); + } + /* all parameters parsed, submitting configuration to the HAL */ + if (lgw_rxif_setconf(i, ifconf) != LGW_HAL_SUCCESS) { + MSG("WARNING: invalid configuration for Lora multi-SF channel %i\n", i); + } + } + + /* set configuration for Lora standard channel */ + memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */ + val = json_object_get_value(conf, "chan_Lora_std"); /* fetch value (if possible) */ + if (json_value_get_type(val) != JSONObject) { + MSG("INFO: no configuration for Lora standard channel\n"); + } else { + val = json_object_dotget_value(conf, "chan_Lora_std.enable"); + if (json_value_get_type(val) == JSONBoolean) { + ifconf.enable = (bool)json_value_get_boolean(val); + } else { + ifconf.enable = false; + } + if (ifconf.enable == false) { + MSG("INFO: Lora standard channel %i disabled\n", i); + } else { + ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.radio"); + ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_Lora_std.if"); + bw = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.bandwidth"); + switch(bw) { + case 500000: ifconf.bandwidth = BW_500KHZ; break; + case 250000: ifconf.bandwidth = BW_250KHZ; break; + case 125000: ifconf.bandwidth = BW_125KHZ; break; + default: ifconf.bandwidth = BW_UNDEFINED; + } + sf = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.spread_factor"); + switch(sf) { + case 7: ifconf.datarate = DR_LORA_SF7; break; + case 8: ifconf.datarate = DR_LORA_SF8; break; + case 9: ifconf.datarate = DR_LORA_SF9; break; + case 10: ifconf.datarate = DR_LORA_SF10; break; + case 11: ifconf.datarate = DR_LORA_SF11; break; + case 12: ifconf.datarate = DR_LORA_SF12; break; + default: ifconf.datarate = DR_UNDEFINED; + } + MSG("INFO: Lora standard channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, SF %u\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf); + } + if (lgw_rxif_setconf(8, ifconf) != LGW_HAL_SUCCESS) { + MSG("WARNING: invalid configuration for Lora standard channel\n"); + } + } + + /* set configuration for FSK channel */ + memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */ + val = json_object_get_value(conf, "chan_FSK"); /* fetch value (if possible) */ + if (json_value_get_type(val) != JSONObject) { + MSG("INFO: no configuration for FSK channel\n"); + } else { + val = json_object_dotget_value(conf, "chan_FSK.enable"); + if (json_value_get_type(val) == JSONBoolean) { + ifconf.enable = (bool)json_value_get_boolean(val); + } else { + ifconf.enable = false; + } + if (ifconf.enable == false) { + MSG("INFO: FSK channel %i disabled\n", i); + } else { + ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_FSK.radio"); + ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_FSK.if"); + bw = (uint32_t)json_object_dotget_number(conf, "chan_FSK.bandwidth"); + switch(bw) { + case 500000: ifconf.bandwidth = BW_500KHZ; break; + case 250000: ifconf.bandwidth = BW_250KHZ; break; + case 125000: ifconf.bandwidth = BW_125KHZ; break; + case 62500: ifconf.bandwidth = BW_62K5HZ; break; + case 31200: ifconf.bandwidth = BW_31K2HZ; break; + case 15600: ifconf.bandwidth = BW_15K6HZ; break; + case 7800: ifconf.bandwidth = BW_7K8HZ; break; + default: ifconf.bandwidth = BW_UNDEFINED; + } + ifconf.datarate = (uint32_t)json_object_dotget_number(conf, "chan_FSK.datarate"); + MSG("INFO: FSK channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate); + } + if (lgw_rxif_setconf(9, ifconf) != LGW_HAL_SUCCESS) { + MSG("WARNING: invalid configuration for FSK channel\n"); + } + } + json_value_free(root_val); + return 0; +} + +int parse_gateway_configuration(const char * conf_file) { + const char conf_obj[] = "gateway_conf"; + JSON_Value *root_val; + JSON_Object *root = NULL; + JSON_Object *conf = NULL; + unsigned long long ull = 0; + + /* try to parse JSON */ + root_val = json_parse_file(conf_file); + root = json_value_get_object(root_val); + if (root == NULL) { + MSG("ERROR: %s id not a valid JSON file\n", conf_file); + exit(EXIT_FAILURE); + } + conf = json_object_get_object(root, conf_obj); + if (conf == NULL) { + MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj); + return -1; + } else { + MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj); + } + + /* getting network parameters (only those necessary for the packet logger) */ + sscanf(json_object_dotget_string(conf, "gateway_ID"), "%llx", &ull); + lgwm = ull; + MSG("INFO: gateway MAC address is configured to %016llX\n", ull); + + json_value_free(root_val); + return 0; +} + +void open_log(void) { + int i; + char iso_date[20]; + + strftime(iso_date,ARRAY_SIZE(iso_date),"%Y%m%dT%H%M%SZ",gmtime(&now_time)); /* format yyyymmddThhmmssZ */ + log_start_time = now_time; /* keep track of when the log was started, for log rotation */ + + sprintf(log_file_name, "pktlog_%s_%s.csv", lgwm_str, iso_date); + log_file = fopen(log_file_name, "a"); /* create log file, append if file already exist */ + if (log_file == NULL) { + MSG("ERROR: impossible to create log file %s\n", log_file_name); + exit(EXIT_FAILURE); + } + + i = fprintf(log_file, "\"gateway ID\",\"node MAC\",\"UTC timestamp\",\"us count\",\"frequency\",\"RF chain\",\"RX chain\",\"status\",\"size\",\"modulation\",\"bandwidth\",\"datarate\",\"coderate\",\"RSSI\",\"SNR\",\"payload\"\n"); + if (i < 0) { + MSG("ERROR: impossible to write to log file %s\n", log_file_name); + exit(EXIT_FAILURE); + } + + MSG("INFO: Now writing to log file %s\n", log_file_name); + return; +} + +/* describe command line options */ +void usage(void) { + MSG( "Available options:\n"); + MSG( " -h print this help\n"); + MSG( " -r <int> rotate log file every N seconds (-1 disable log rotation)\n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i, j; /* loop and temporary variables */ + struct timespec sleep_time = {0, 3000000}; /* 3 ms */ + + /* clock and log rotation management */ + int log_rotate_interval = 3600; /* by default, rotation every hour */ + int time_check = 0; /* variable used to limit the number of calls to time() function */ + unsigned long pkt_in_log = 0; /* count the number of packet written in each log file */ + + /* configuration file related */ + const char global_conf_fname[] = "global_conf.json"; /* contain global (typ. network-wide) configuration */ + const char local_conf_fname[] = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */ + const char debug_conf_fname[] = "debug_conf.json"; /* if present, all other configuration files are ignored */ + + /* allocate memory for packet fetching and processing */ + struct lgw_pkt_rx_s rxpkt[16]; /* array containing up to 16 inbound packets metadata */ + struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ + int nb_pkt; + + /* local timestamp variables until we get accurate GPS time */ + struct timespec fetch_time; + char fetch_timestamp[30]; + struct tm * x; + + /* parse command line options */ + while ((i = getopt (argc, argv, "hr:")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_FAILURE; + break; + + case 'r': + log_rotate_interval = atoi(optarg); + if ((log_rotate_interval == 0) || (log_rotate_interval < -1)) { + MSG( "ERROR: Invalid argument for -r option\n"); + return EXIT_FAILURE; + } + break; + + default: + MSG("ERROR: argument parsing use -h option for help\n"); + usage(); + return EXIT_FAILURE; + } + } + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* configuration files management */ + if (access(debug_conf_fname, R_OK) == 0) { + /* if there is a debug conf, parse only the debug conf */ + MSG("INFO: found debug configuration file %s, other configuration files will be ignored\n", debug_conf_fname); + parse_SX1301_configuration(debug_conf_fname); + parse_gateway_configuration(debug_conf_fname); + } else if (access(global_conf_fname, R_OK) == 0) { + /* if there is a global conf, parse it and then try to parse local conf */ + MSG("INFO: found global configuration file %s, trying to parse it\n", global_conf_fname); + parse_SX1301_configuration(global_conf_fname); + parse_gateway_configuration(global_conf_fname); + if (access(local_conf_fname, R_OK) == 0) { + MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname); + parse_SX1301_configuration(local_conf_fname); + parse_gateway_configuration(local_conf_fname); + } + } else if (access(local_conf_fname, R_OK) == 0) { + /* if there is only a local conf, parse it and that's all */ + MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname); + parse_SX1301_configuration(local_conf_fname); + parse_gateway_configuration(local_conf_fname); + } else { + MSG("ERROR: failed to find any configuration file named %s, %s or %s\n", global_conf_fname, local_conf_fname, debug_conf_fname); + return EXIT_FAILURE; + } + + /* starting the concentrator */ + i = lgw_start(); + if (i == LGW_HAL_SUCCESS) { + MSG("INFO: concentrator started, packet can now be received\n"); + } else { + MSG("ERROR: failed to start the concentrator\n"); + return EXIT_FAILURE; + } + + /* transform the MAC address into a string */ + sprintf(lgwm_str, "%016llX", lgwm); + + /* opening log file and writing CSV header*/ + time(&now_time); + open_log(); + + /* main loop */ + while ((quit_sig != 1) && (exit_sig != 1)) { + /* fetch packets */ + nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); + if (nb_pkt == LGW_HAL_ERROR) { + MSG("ERROR: failed packet fetch, exiting\n"); + return EXIT_FAILURE; + } else if (nb_pkt == 0) { + clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL); /* wait a short time if no packets */ + } else { + /* local timestamp generation until we get accurate GPS time */ + clock_gettime(CLOCK_REALTIME, &fetch_time); + x = gmtime(&(fetch_time.tv_sec)); + sprintf(fetch_timestamp,"%04i-%02i-%02i %02i:%02i:%02i.%03liZ",(x->tm_year)+1900,(x->tm_mon)+1,x->tm_mday,x->tm_hour,x->tm_min,x->tm_sec,(fetch_time.tv_nsec)/1000000); /* ISO 8601 format */ + } + + /* log packets */ + for (i=0; i < nb_pkt; ++i) { + p = &rxpkt[i]; + + /* writing gateway ID */ + fprintf(log_file, "%016llX,", lgwm); + + /* writing node MAC address */ + fputs("\"\",", log_file); // TODO: need to parse payload + + /* writing UTC timestamp*/ + fprintf(log_file, "\"%s\",", fetch_timestamp); + // TODO: replace with GPS time when available + + /* writing internal clock */ + fprintf(log_file, "%010u,", p->count_us); + + /* writing RX frequency */ + fprintf(log_file, "%10u,", p->freq_hz); + + /* writing RF chain */ + fprintf(log_file, "%u,", p->rf_chain); + + /* writing RX modem/IF chain */ + fprintf(log_file, "%2d,", p->if_chain); + + /* writing status */ + switch(p->status) { + case STAT_CRC_OK: fputs("\"CRC_OK\" ,", log_file); break; + case STAT_CRC_BAD: fputs("\"CRC_BAD\",", log_file); break; + case STAT_NO_CRC: fputs("\"NO_CRC\" ,", log_file); break; + case STAT_UNDEFINED:fputs("\"UNDEF\" ,", log_file); break; + default: fputs("\"ERR\" ,", log_file); + } + + /* writing payload size */ + fprintf(log_file, "%3u,", p->size); + + /* writing modulation */ + switch(p->modulation) { + case MOD_LORA: fputs("\"LORA\",", log_file); break; + case MOD_FSK: fputs("\"FSK\" ,", log_file); break; + default: fputs("\"ERR\" ,", log_file); + } + + /* writing bandwidth */ + switch(p->bandwidth) { + case BW_500KHZ: fputs("500000,", log_file); break; + case BW_250KHZ: fputs("250000,", log_file); break; + case BW_125KHZ: fputs("125000,", log_file); break; + case BW_62K5HZ: fputs("62500 ,", log_file); break; + case BW_31K2HZ: fputs("31200 ,", log_file); break; + case BW_15K6HZ: fputs("15600 ,", log_file); break; + case BW_7K8HZ: fputs("7800 ,", log_file); break; + case BW_UNDEFINED: fputs("0 ,", log_file); break; + default: fputs("-1 ,", log_file); + } + + /* writing datarate */ + if (p->modulation == MOD_LORA) { + switch (p->datarate) { + case DR_LORA_SF7: fputs("\"SF7\" ,", log_file); break; + case DR_LORA_SF8: fputs("\"SF8\" ,", log_file); break; + case DR_LORA_SF9: fputs("\"SF9\" ,", log_file); break; + case DR_LORA_SF10: fputs("\"SF10\" ,", log_file); break; + case DR_LORA_SF11: fputs("\"SF11\" ,", log_file); break; + case DR_LORA_SF12: fputs("\"SF12\" ,", log_file); break; + default: fputs("\"ERR\" ,", log_file); + } + } else if (p->modulation == MOD_FSK) { + fprintf(log_file, "\"%6u\",", p->datarate); + } else { + fputs("\"ERR\" ,", log_file); + } + + /* writing coderate */ + switch (p->coderate) { + case CR_LORA_4_5: fputs("\"4/5\",", log_file); break; + case CR_LORA_4_6: fputs("\"2/3\",", log_file); break; + case CR_LORA_4_7: fputs("\"4/7\",", log_file); break; + case CR_LORA_4_8: fputs("\"1/2\",", log_file); break; + case CR_UNDEFINED: fputs("\"\" ,", log_file); break; + default: fputs("\"ERR\",", log_file); + } + + /* writing packet RSSI */ + fprintf(log_file, "%+.0f,", p->rssi); + + /* writing packet average SNR */ + fprintf(log_file, "%+5.1f,", p->snr); + + /* writing hex-encoded payload (bundled in 32-bit words) */ + fputs("\"", log_file); + for (j = 0; j < p->size; ++j) { + if ((j > 0) && (j%4 == 0)) fputs("-", log_file); + fprintf(log_file, "%02X", p->payload[j]); + } + fputs("\"\n", log_file); + ++pkt_in_log; + } + + /* check time and rotate log file if necessary */ + ++time_check; + if (time_check >= 8) { + time_check = 0; + time(&now_time); + if (difftime(now_time, log_start_time) > log_rotate_interval) { + fclose(log_file); + MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log); + pkt_in_log = 0; + open_log(); + } + } + } + + if (exit_sig == 1) { + /* clean up before leaving */ + i = lgw_stop(); + if (i == LGW_HAL_SUCCESS) { + MSG("INFO: concentrator stopped successfully\n"); + } else { + MSG("WARNING: failed to stop concentrator successfully\n"); + } + fclose(log_file); + MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log); + } + + MSG("INFO: Exiting packet logger program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_pkt_logger/src/parson.c b/loragw_pkt_logger/src/parson.c new file mode 100644 index 0000000..54eae2c --- /dev/null +++ b/loragw_pkt_logger/src/parson.c @@ -0,0 +1,647 @@ +/* + Parson ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 Krzysztof Gabis + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "parson.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#define ERROR 0 +#define SUCCESS 1 +#define STARTING_CAPACITY 15 +#define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */ +#define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */ +#define MAX_NESTING 19 +#define sizeof_token(a) (sizeof(a) - 1) +#define skip_char(str) ((*str)++) +#define skip_whitespaces(str) while (isspace(**str)) { skip_char(str); } +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define parson_malloc(a) malloc(a) +#define parson_free(a) free((void*)a) +#define parson_realloc(a, b) realloc(a, b) + +/* Type definitions */ +typedef union json_value_value { + const char *string; + double number; + JSON_Object *object; + JSON_Array *array; + int boolean; + int null; +} JSON_Value_Value; + +struct json_value_t { + JSON_Value_Type type; + JSON_Value_Value value; +}; + +struct json_object_t { + const char **names; + JSON_Value **values; + size_t count; + size_t capacity; +}; + +struct json_array_t { + JSON_Value **items; + size_t count; + size_t capacity; +}; + +/* Various */ +static int try_realloc(void **ptr, size_t new_size); +static char * parson_strndup(const char *string, size_t n); +static int is_utf(const unsigned char *string); +static int is_decimal(const char *string, size_t length); + +/* JSON Object */ +static JSON_Object * json_object_init(void); +static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value); +static int json_object_resize(JSON_Object *object, size_t capacity); +static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n); +static void json_object_free(JSON_Object *object); + +/* JSON Array */ +static JSON_Array * json_array_init(void); +static int json_array_add(JSON_Array *array, JSON_Value *value); +static int json_array_resize(JSON_Array *array, size_t capacity); +static void json_array_free(JSON_Array *array); + +/* JSON Value */ +static JSON_Value * json_value_init_object(void); +static JSON_Value * json_value_init_array(void); +static JSON_Value * json_value_init_string(const char *string); +static JSON_Value * json_value_init_number(double number); +static JSON_Value * json_value_init_boolean(int boolean); +static JSON_Value * json_value_init_null(void); + +/* Parser */ +static void skip_quotes(const char **string); +static const char * get_processed_string(const char **string); +static JSON_Value * parse_object_value(const char **string, size_t nesting); +static JSON_Value * parse_array_value(const char **string, size_t nesting); +static JSON_Value * parse_string_value(const char **string); +static JSON_Value * parse_boolean_value(const char **string); +static JSON_Value * parse_number_value(const char **string); +static JSON_Value * parse_null_value(const char **string); +static JSON_Value * parse_value(const char **string, size_t nesting); + +/* Various */ +static int try_realloc(void **ptr, size_t new_size) { + void *reallocated_ptr = parson_realloc(*ptr, new_size); + if (!reallocated_ptr) { return ERROR; } + *ptr = reallocated_ptr; + return SUCCESS; +} + +static char * parson_strndup(const char *string, size_t n) { + char *output_string = (char*)parson_malloc(n + 1); + if (!output_string) { return NULL; } + output_string[n] = '\0'; + strncpy(output_string, string, n); + return output_string; +} + +static int is_utf(const unsigned char *s) { + return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]); +} + +static int is_decimal(const char *string, size_t length) { + if (length > 1 && string[0] == '0' && string[1] != '.') { return 0; } + if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { return 0; } + while (length--) { if (strchr("xX", string[length])) { return 0; } } + return 1; +} + +/* JSON Object */ +static JSON_Object * json_object_init(void) { + JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); + if (!new_obj) { return NULL; } + new_obj->names = (const char**)NULL; + new_obj->values = (JSON_Value**)NULL; + new_obj->capacity = 0; + new_obj->count = 0; + return new_obj; +} + +static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { + size_t index; + if (object->count >= object->capacity) { + size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY); + if (new_capacity > OBJECT_MAX_CAPACITY) { return ERROR; } + if (json_object_resize(object, new_capacity) == ERROR) { return ERROR; } + } + if (json_object_get_value(object, name) != NULL) { return ERROR; } + index = object->count; + object->names[index] = parson_strndup(name, strlen(name)); + if (!object->names[index]) { return ERROR; } + object->values[index] = value; + object->count++; + return SUCCESS; +} + +static int json_object_resize(JSON_Object *object, size_t capacity) { + if (try_realloc((void**)&object->names, capacity * sizeof(char*)) == ERROR) { return ERROR; } + if (try_realloc((void**)&object->values, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; } + object->capacity = capacity; + return SUCCESS; +} + +static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) { + size_t i, name_length; + for (i = 0; i < json_object_get_count(object); i++) { + name_length = strlen(object->names[i]); + if (name_length != n) { continue; } + if (strncmp(object->names[i], name, n) == 0) { return object->values[i]; } + } + return NULL; +} + +static void json_object_free(JSON_Object *object) { + while(object->count--) { + parson_free(object->names[object->count]); + json_value_free(object->values[object->count]); + } + parson_free(object->names); + parson_free(object->values); + parson_free(object); +} + +/* JSON Array */ +static JSON_Array * json_array_init(void) { + JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); + if (!new_array) { return NULL; } + new_array->items = (JSON_Value**)NULL; + new_array->capacity = 0; + new_array->count = 0; + return new_array; +} + +static int json_array_add(JSON_Array *array, JSON_Value *value) { + if (array->count >= array->capacity) { + size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); + if (new_capacity > ARRAY_MAX_CAPACITY) { return ERROR; } + if (!json_array_resize(array, new_capacity)) { return ERROR; } + } + array->items[array->count] = value; + array->count++; + return SUCCESS; +} + +static int json_array_resize(JSON_Array *array, size_t capacity) { + if (try_realloc((void**)&array->items, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; } + array->capacity = capacity; + return SUCCESS; +} + +static void json_array_free(JSON_Array *array) { + while (array->count--) { json_value_free(array->items[array->count]); } + parson_free(array->items); + parson_free(array); +} + +/* JSON Value */ +static JSON_Value * json_value_init_object(void) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONObject; + new_value->value.object = json_object_init(); + if (!new_value->value.object) { parson_free(new_value); return NULL; } + return new_value; +} + +static JSON_Value * json_value_init_array(void) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONArray; + new_value->value.array = json_array_init(); + if (!new_value->value.array) { parson_free(new_value); return NULL; } + return new_value; +} + +static JSON_Value * json_value_init_string(const char *string) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONString; + new_value->value.string = string; + return new_value; +} + +static JSON_Value * json_value_init_number(double number) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONNumber; + new_value->value.number = number; + return new_value; +} + +static JSON_Value * json_value_init_boolean(int boolean) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONBoolean; + new_value->value.boolean = boolean; + return new_value; +} + +static JSON_Value * json_value_init_null(void) { + JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } + new_value->type = JSONNull; + return new_value; +} + +/* Parser */ +static void skip_quotes(const char **string) { + skip_char(string); + while (**string != '\"') { + if (**string == '\0') { return; } + if (**string == '\\') { skip_char(string); if (**string == '\0') { return; }} + skip_char(string); + } + skip_char(string); +} + +/* Returns contents of a string inside double quotes and parses escaped + characters inside. + Example: "\u006Corem ipsum" -> lorem ipsum */ +static const char * get_processed_string(const char **string) { + const char *string_start = *string; + char *output, *processed_ptr, *unprocessed_ptr, current_char; + unsigned int utf_val; + skip_quotes(string); + if (**string == '\0') { return NULL; } + output = parson_strndup(string_start + 1, *string - string_start - 2); + if (!output) { return NULL; } + processed_ptr = unprocessed_ptr = output; + while (*unprocessed_ptr) { + current_char = *unprocessed_ptr; + if (current_char == '\\') { + unprocessed_ptr++; + current_char = *unprocessed_ptr; + switch (current_char) { + case '\"': case '\\': case '/': break; + case 'b': current_char = '\b'; break; + case 'f': current_char = '\f'; break; + case 'n': current_char = '\n'; break; + case 'r': current_char = '\r'; break; + case 't': current_char = '\t'; break; + case 'u': + unprocessed_ptr++; + if (!is_utf((const unsigned char*)unprocessed_ptr) || + sscanf(unprocessed_ptr, "%4x", &utf_val) == EOF) { + parson_free(output); return NULL; + } + if (utf_val < 0x80) { + current_char = utf_val; + } else if (utf_val < 0x800) { + *processed_ptr++ = (utf_val >> 6) | 0xC0; + current_char = ((utf_val | 0x80) & 0xBF); + } else { + *processed_ptr++ = (utf_val >> 12) | 0xE0; + *processed_ptr++ = (((utf_val >> 6) | 0x80) & 0xBF); + current_char = ((utf_val | 0x80) & 0xBF); + } + unprocessed_ptr += 3; + break; + default: + parson_free(output); + return NULL; + break; + } + } else if ((unsigned char)current_char < 0x20) { /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */ + parson_free(output); + return NULL; + } + *processed_ptr = current_char; + processed_ptr++; + unprocessed_ptr++; + } + *processed_ptr = '\0'; + if (try_realloc((void**)&output, strlen(output) + 1) == ERROR) { return NULL; } + return output; +} + +static JSON_Value * parse_value(const char **string, size_t nesting) { + if (nesting > MAX_NESTING) { return NULL; } + skip_whitespaces(string); + switch (**string) { + case '{': + return parse_object_value(string, nesting + 1); + case '[': + return parse_array_value(string, nesting + 1); + case '\"': + return parse_string_value(string); + case 'f': case 't': + return parse_boolean_value(string); + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return parse_number_value(string); + case 'n': + return parse_null_value(string); + default: + return NULL; + } +} + +static JSON_Value * parse_object_value(const char **string, size_t nesting) { + JSON_Value *output_value = json_value_init_object(), *new_value = NULL; + JSON_Object *output_object = json_value_get_object(output_value); + const char *new_key = NULL; + if (!output_value) { return NULL; } + skip_char(string); + skip_whitespaces(string); + if (**string == '}') { skip_char(string); return output_value; } /* empty object */ + while (**string != '\0') { + new_key = get_processed_string(string); + skip_whitespaces(string); + if (!new_key || **string != ':') { + json_value_free(output_value); + return NULL; + } + skip_char(string); + new_value = parse_value(string, nesting); + if (!new_value) { + parson_free(new_key); + json_value_free(output_value); + return NULL; + } + if(!json_object_add(output_object, new_key, new_value)) { + parson_free(new_key); + parson_free(new_value); + json_value_free(output_value); + return NULL; + } + parson_free(new_key); + skip_whitespaces(string); + if (**string != ',') { break; } + skip_char(string); + skip_whitespaces(string); + } + skip_whitespaces(string); + if (**string != '}' || /* Trim object after parsing is over */ + json_object_resize(output_object, json_object_get_count(output_object)) == ERROR) { + json_value_free(output_value); + return NULL; + } + skip_char(string); + return output_value; +} + +static JSON_Value * parse_array_value(const char **string, size_t nesting) { + JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL; + JSON_Array *output_array = json_value_get_array(output_value); + if (!output_value) { return NULL; } + skip_char(string); + skip_whitespaces(string); + if (**string == ']') { /* empty array */ + skip_char(string); + return output_value; + } + while (**string != '\0') { + new_array_value = parse_value(string, nesting); + if (!new_array_value) { + json_value_free(output_value); + return NULL; + } + if(json_array_add(output_array, new_array_value) == ERROR) { + parson_free(new_array_value); + json_value_free(output_value); + return NULL; + } + skip_whitespaces(string); + if (**string != ',') { break; } + skip_char(string); + skip_whitespaces(string); + } + skip_whitespaces(string); + if (**string != ']' || /* Trim array after parsing is over */ + json_array_resize(output_array, json_array_get_count(output_array)) == ERROR) { + json_value_free(output_value); + return NULL; + } + skip_char(string); + return output_value; +} + +static JSON_Value * parse_string_value(const char **string) { + const char *new_string = get_processed_string(string); + if (!new_string) { return NULL; } + return json_value_init_string(new_string); +} + +static JSON_Value * parse_boolean_value(const char **string) { + size_t true_token_size = sizeof_token("true"); + size_t false_token_size = sizeof_token("false"); + if (strncmp("true", *string, true_token_size) == 0) { + *string += true_token_size; + return json_value_init_boolean(1); + } else if (strncmp("false", *string, false_token_size) == 0) { + *string += false_token_size; + return json_value_init_boolean(0); + } + return NULL; +} + +static JSON_Value * parse_number_value(const char **string) { + char *end; + double number = strtod(*string, &end); + JSON_Value *output_value; + if (is_decimal(*string, end - *string)) { + *string = end; + output_value = json_value_init_number(number); + } else { + output_value = NULL; + } + return output_value; +} + +static JSON_Value * parse_null_value(const char **string) { + size_t token_size = sizeof_token("null"); + if (strncmp("null", *string, token_size) == 0) { + *string += token_size; + return json_value_init_null(); + } + return NULL; +} + +/* Parser API */ +JSON_Value * json_parse_file(const char *filename) { + FILE *fp = fopen(filename, "r"); + size_t file_size; + char *file_contents; + JSON_Value *output_value; + if (!fp) { return NULL; } + fseek(fp, 0L, SEEK_END); + file_size = ftell(fp); + rewind(fp); + file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1)); + if (!file_contents) { fclose(fp); return NULL; } + if (fread(file_contents, file_size, 1, fp) < 1) { fclose(fp); return NULL; } + fclose(fp); + file_contents[file_size] = '\0'; + output_value = json_parse_string(file_contents); + parson_free(file_contents); + return output_value; +} + +JSON_Value * json_parse_string(const char *string) { + if (!string || (*string != '{' && *string != '[')) { return NULL; } + return parse_value((const char**)&string, 0); +} + +/* JSON Object API */ +JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) { + return json_object_nget_value(object, name, strlen(name)); +} + +const char * json_object_get_string(const JSON_Object *object, const char *name) { + return json_value_get_string(json_object_get_value(object, name)); +} + +double json_object_get_number(const JSON_Object *object, const char *name) { + return json_value_get_number(json_object_get_value(object, name)); +} + +JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) { + return json_value_get_object(json_object_get_value(object, name)); +} + +JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) { + return json_value_get_array(json_object_get_value(object, name)); +} + +int json_object_get_boolean(const JSON_Object *object, const char *name) { + return json_value_get_boolean(json_object_get_value(object, name)); +} + +JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) { + const char *dot_position = strchr(name, '.'); + if (!dot_position) { return json_object_get_value(object, name); } + object = json_value_get_object(json_object_nget_value(object, name, dot_position - name)); + return json_object_dotget_value(object, dot_position + 1); +} + +const char * json_object_dotget_string(const JSON_Object *object, const char *name) { + return json_value_get_string(json_object_dotget_value(object, name)); +} + +double json_object_dotget_number(const JSON_Object *object, const char *name) { + return json_value_get_number(json_object_dotget_value(object, name)); +} + +JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) { + return json_value_get_object(json_object_dotget_value(object, name)); +} + +JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) { + return json_value_get_array(json_object_dotget_value(object, name)); +} + +int json_object_dotget_boolean(const JSON_Object *object, const char *name) { + return json_value_get_boolean(json_object_dotget_value(object, name)); +} + +size_t json_object_get_count(const JSON_Object *object) { + return object ? object->count : 0; +} + +const char * json_object_get_name(const JSON_Object *object, size_t index) { + if (index >= json_object_get_count(object)) { return NULL; } + return object->names[index]; +} + +/* JSON Array API */ +JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) { + if (index >= json_array_get_count(array)) { return NULL; } + return array->items[index]; +} + +const char * json_array_get_string(const JSON_Array *array, size_t index) { + return json_value_get_string(json_array_get_value(array, index)); +} + +double json_array_get_number(const JSON_Array *array, size_t index) { + return json_value_get_number(json_array_get_value(array, index)); +} + +JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) { + return json_value_get_object(json_array_get_value(array, index)); +} + +JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) { + return json_value_get_array(json_array_get_value(array, index)); +} + +int json_array_get_boolean(const JSON_Array *array, size_t index) { + return json_value_get_boolean(json_array_get_value(array, index)); +} + +size_t json_array_get_count(const JSON_Array *array) { + return array ? array->count : 0; +} + +/* JSON Value API */ +JSON_Value_Type json_value_get_type(const JSON_Value *value) { + return value ? value->type : JSONError; +} + +JSON_Object * json_value_get_object(const JSON_Value *value) { + return json_value_get_type(value) == JSONObject ? value->value.object : NULL; +} + +JSON_Array * json_value_get_array(const JSON_Value *value) { + return json_value_get_type(value) == JSONArray ? value->value.array : NULL; +} + +const char * json_value_get_string(const JSON_Value *value) { + return json_value_get_type(value) == JSONString ? value->value.string : NULL; +} + +double json_value_get_number(const JSON_Value *value) { + return json_value_get_type(value) == JSONNumber ? value->value.number : 0; +} + +int json_value_get_boolean(const JSON_Value *value) { + return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; +} + +void json_value_free(JSON_Value *value) { + switch (json_value_get_type(value)) { + case JSONObject: + json_object_free(value->value.object); + break; + case JSONString: + if (value->value.string) { parson_free(value->value.string); } + break; + case JSONArray: + json_array_free(value->value.array); + break; + default: + break; + } + parson_free(value); +} diff --git a/loragw_spi_stress/LICENSE.TXT b/loragw_spi_stress/LICENSE.TXT new file mode 100644 index 0000000..e406dcb --- /dev/null +++ b/loragw_spi_stress/LICENSE.TXT @@ -0,0 +1,8 @@ +Copyright (C) 2013 SEMTECH S.A. + + THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND +(2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER. +CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR +CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT +OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION +CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. diff --git a/loragw_spi_stress/Makefile b/loragw_spi_stress/Makefile new file mode 100644 index 0000000..d2fe09d --- /dev/null +++ b/loragw_spi_stress/Makefile @@ -0,0 +1,34 @@ +### Application-specific constants + +APP_NAME=loragw_spi_stress + +### constant symbols + +CC=gcc +CFLAGS=-O2 -Wall -Wextra -Iinc +C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc +FLAG_AUX= + +### constants for Lora Gateway HAL library + +LGW_PATH=../loragw_hal +LGW_INC=-I$(LGW_PATH)/inc +#LGW_LNK=-lloragw -lrt +LGW_LNK=-lloragw -lrt -lmpsse +# add libmpsse or not, depending on what option you compiled the libloragw with + +### general build targets + +all: $(APP_NAME) + +clean: + rm -f obj/*.o + rm -f $(APP_NAME) + +### main program compilation and assembly + +obj/$(APP_NAME).o: src/$(APP_NAME).c + $(CC) -c $(C99FLAGS) -o obj/$(APP_NAME).o $(LGW_INC) src/$(APP_NAME).c $(FLAG_AUX) + +$(APP_NAME): $(LGW_PATH)/libloragw.a obj/$(APP_NAME).o + $(CC) -o $(APP_NAME) obj/$(APP_NAME).o -L$(LGW_PATH) $(LGW_LNK) diff --git a/loragw_spi_stress/README.TXT b/loragw_spi_stress/README.TXT new file mode 100644 index 0000000..fa73da1 --- /dev/null +++ b/loragw_spi_stress/README.TXT @@ -0,0 +1,64 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Lora Gateway SPI stress test +============================= + +1. Introduction +---------------- + +This software is used to check the reliability of the link between the host +platform (on which the program is run) and the Lora concentrator register file +that is the interface through which all interaction with the Lora concentrator +happens. + +2. Dependencies +---------------- + +This program only access the Lora gateway HAL library through its loragw_reg +"named registers" access sub-module. + +It was tested with beta8 of the libloragw library, and should be compatible +with any later version of the library and the hardware, assuming the registers +used for the tests are still present. + +The registers used are: +LGW_VERSION +LGW_IMPLICIT_PAYLOAD_LENGHT +LGW_FSK_REF_PATTERN_LSB +LGW_RX_DATA_BUF_ADDR +LGW_RX_DATA_BUF_DATA +A data buffer accessible through the 2 registers above must be implemented. + +3. Usage +--------- + +The tests run forever or until an error is detected. +Press Ctrl+C to stop the application. + +When an error is detected, diagnosis information are displayed. Please refer to +the source code for more details on what is displayed for diagnosis. + +All tests use pseudo-random data generated by the rand() function. The random +generator is not seeded, and the same sequence of data will be use each time the +program is launched. + +Basically, some random data is written, read back and then compared to the +initial written data. Some "useless" read on others registers might be inserted +to be sure that the data read back is coming from the hardware, and not from the +internal buffer(s) of the software driver(s). + +Test 1 > R/W on a simple 8-bit register +Test 2 > R/W on a simple 8-bit register with interstitial reads on VERSION +Test 3 > R/W on a 32-bit register (short SPI bursts access) +Test 4 > data buffer R/W (long SPI bursts access) + +4. Changelog +------------- + +2013-10-18, beta 1 +Initial version. diff --git a/loragw_spi_stress/obj/.gitkeep b/loragw_spi_stress/obj/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/loragw_spi_stress/obj/.gitkeep diff --git a/loragw_spi_stress/src/loragw_spi_stress.c b/loragw_spi_stress/src/loragw_spi_stress.c new file mode 100644 index 0000000..45d445f --- /dev/null +++ b/loragw_spi_stress/src/loragw_spi_stress.c @@ -0,0 +1,288 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + SPI stress test +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf sprintf fopen fputs */ + +#include <signal.h> /* sigaction */ +#include <unistd.h> /* getopt access */ +#include <stdlib.h> /* rand */ + +#include "loragw_reg.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define VERS 103 +#define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */ +#define BUFF_SIZE 1024 + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +/* describe command line options */ +void usage(void) { + MSG( "Available options:\n"); + MSG( " -h print this help\n"); + MSG( " -t <int> specify which test you want to run (1-4)\n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i; + int xi = 0; + + /* application option */ + int test_number = 1; + int cycle_number = 0; + int repeats_per_cycle = 1000; + bool error = false; + + /* in/out variables */ + int32_t test_value; + int32_t read_value; + int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */ + + /* data buffer */ + int32_t test_addr; + uint8_t test_buff[BUFF_SIZE]; + uint8_t read_buff[BUFF_SIZE]; + + /* parse command line options */ + while ((i = getopt (argc, argv, "ht:")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_FAILURE; + break; + + case 't': + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 1) || (xi > 4)) { + MSG("ERROR: invalid test number\n"); + return EXIT_FAILURE; + } else { + test_number = xi; + } + break; + + default: + MSG("ERROR: argument parsing use -h option for help\n"); + usage(); + return EXIT_FAILURE; + } + } + MSG("INFO: Starting Lora concentrator SPI stress-test number %i\n", test_number); + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* start SPI link */ + i = lgw_connect(); + if (i != LGW_REG_SUCCESS) { + MSG("ERROR: lgw_connect() did not return SUCCESS"); + return EXIT_FAILURE; + } + + if (test_number == 1) { + /* single 8b register R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() % 256); + lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + if (read_value != test_value) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write 0x%02X, read 0x%02X\n", i+1, test_value, read_value); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + printf(" 0x%02X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 2) { + /* single 8b register R/W with interstitial VERSION check stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() % 256); + lgw_reg_r(LGW_VERSION, &rb1); + lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); + lgw_reg_r(LGW_VERSION, &rb2); + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + lgw_reg_r(LGW_VERSION, &rb3); + if ((rb1 != VERS) || (rb2 != VERS) || (rb3 != VERS) || (read_value != test_value)) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write %02X, read %02X, version (%i, %i, %i)\n", i+1, test_value, read_value, rb1, rb2, rb3); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + printf(" 0x%02X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 3) { + /* 32b register R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + printf("Cycle %i > ", cycle_number); + for (i=0; i<repeats_per_cycle; ++i) { + test_value = (rand() & 0x0000FFFF); + test_value += (int32_t)(rand() & 0x0000FFFF) << 16; + lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, test_value); + lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); + if (read_value != test_value) { + error = true; + break; + } + } + if (error) { + printf("error during the %ith iteration: write 0x%08X, read 0x%08X\n", i+1, test_value, read_value); + printf("Repeat read of target register:"); + for (i=0; i<READS_WHEN_ERROR; ++i) { + lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); + printf(" 0x%08X", read_value); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did %i R/W on a 32 bits reg with no error\n", repeats_per_cycle); + ++cycle_number; + } + } + } else if (test_number == 4) { + /* databuffer R/W stress test */ + while ((quit_sig != 1) && (exit_sig != 1)) { + for (i=0; i<BUFF_SIZE; ++i) { + test_buff[i] = rand() & 0xFF; + } + printf("Cycle %i > ", cycle_number); + test_addr = rand() & 0xFFFF; + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */ + lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE); + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); + for (i=0; ((i<BUFF_SIZE) && (test_buff[i] == read_buff[i])); ++i); + if (i != BUFF_SIZE) { + printf("error during the buffer comparison\n"); + printf("Written values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", test_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + printf("Read values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", read_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); + printf("Re-read values:\n"); + for (i=0; i<BUFF_SIZE; ++i) { + printf(" %02X ", read_buff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + return EXIT_FAILURE; + } else { + printf("did a %i-byte R/W on a data buffer with no error\n", BUFF_SIZE); + ++cycle_number; + } + } + } else { + MSG("ERROR: invalid test number"); + usage(); + } + + /* close SPI link */ + i = lgw_disconnect(); + if (i != LGW_REG_SUCCESS) { + MSG("ERROR: lgw_disconnect() did not return SUCCESS"); + return EXIT_FAILURE; + } + + MSG("INFO: Exiting Lora concentrator SPI stress-test program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ + diff --git a/loragw_tx_test/LICENSE.TXT b/loragw_tx_test/LICENSE.TXT new file mode 100644 index 0000000..e406dcb --- /dev/null +++ b/loragw_tx_test/LICENSE.TXT @@ -0,0 +1,8 @@ +Copyright (C) 2013 SEMTECH S.A. + + THE FOLLOWING SOFTWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND +(2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER. +CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR +CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT +OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION +CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. diff --git a/loragw_tx_test/Makefile b/loragw_tx_test/Makefile new file mode 100644 index 0000000..5d07c6d --- /dev/null +++ b/loragw_tx_test/Makefile @@ -0,0 +1,34 @@ +### Application-specific constants + +APP_NAME=loragw_tx_test + +### constant symbols + +CC=gcc +CFLAGS=-O2 -Wall -Wextra -Iinc +C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc +FLAG_AUX= + +### constants for Lora Gateway HAL library + +LGW_PATH=../loragw_hal +LGW_INC=-I$(LGW_PATH)/inc +#LGW_LNK=-lloragw -lrt +LGW_LNK=-lloragw -lrt -lmpsse +# add libmpsse or not, depending on what option you compiled the libloragw with + +### general build targets + +all: $(APP_NAME) + +clean: + rm -f obj/*.o + rm -f $(APP_NAME) + +### main program compilation and assembly + +obj/$(APP_NAME).o: src/$(APP_NAME).c + $(CC) -c $(C99FLAGS) -o obj/$(APP_NAME).o $(LGW_INC) src/$(APP_NAME).c $(FLAG_AUX) + +$(APP_NAME): $(LGW_PATH)/libloragw.a obj/$(APP_NAME).o + $(CC) -o $(APP_NAME) obj/$(APP_NAME).o -L$(LGW_PATH) $(LGW_LNK) diff --git a/loragw_tx_test/README.TXT b/loragw_tx_test/README.TXT new file mode 100644 index 0000000..2f95735 --- /dev/null +++ b/loragw_tx_test/README.TXT @@ -0,0 +1,65 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Lora Gateway packet sender +=========================== + +1. Introduction +---------------- + +This software is used to send test packets with a Lora concentrator. The packets +contain little information, on no protocol (ie. MAC address) information but +can be used to assess the functionality of a gateway downlink using other +gateways as receivers. + +2. Dependencies +---------------- + +This program is a typical example of Lora Gateway HAL usage for sending packets. + +Only high-level functions are used (the ones contained in loragw_hal) so there +is no hardware dependencies assuming the HAL is matched with the proper version +of the hardware. +Data structures of the sent packets are accessed by name (ie. not at a +binary level) so new functionalities can be added to the API without affecting +that program at all. + +It was tested with beta8 of the libloragw library, and should be compatible +with any later version of the library assuming the API is downward-compatible. + +3. Usage +--------- + +The application runs until the specified number of packets have been send. +Press Ctrl+C to stop the application before that. + +Use the -f option followed by a real number (decimal point and scientific +'E notation' are OK) to specify the modulation central frequency. +Use the -s option to specify the Spreading Factor of Lora modulation (values 7 +to 12 are valid). +Use the -b option to set Lora modulation bandwidth in kHz (accepted values: 125, +250 or 500). +Use the -p option to set the concentrator TX power in dBm. Not all values are +supported by hardware (typically 14 et 20 dBm are supported, other values might +not give expected power). Check with a RF power meter before connecting any +sensitive equipment. +Use the -t option to specify the number of milliseconds of pause between +packets. Using zero will result in a quasi-continuous emission. +Use the -x to specify how many packets should be sent. + +The packets are 20 bytes long, and protected by the smallest supported ECC. + +The payload content is: +[T][E][S][T][packet counter MSB][packet counter MSB] followed by ASCII padding. +All Lora data is whitened, so the padding has no influence whatsoever on the +packet error rate. + +4. Changelog +------------- + +2013-10-18, beta 1 +Initial version. diff --git a/loragw_tx_test/obj/.gitkeep b/loragw_tx_test/obj/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/loragw_tx_test/obj/.gitkeep diff --git a/loragw_tx_test/src/loragw_tx_test.c b/loragw_tx_test/src/loragw_tx_test.c new file mode 100644 index 0000000..bb8fe2c --- /dev/null +++ b/loragw_tx_test/src/loragw_tx_test.c @@ -0,0 +1,290 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + Send a bunch of packets on a settable frequency +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf sprintf fopen fputs */ + +#include <string.h> /* memset */ +#include <signal.h> /* sigaction */ +#include <unistd.h> /* getopt access */ +#include <stdlib.h> /* exit codes */ + +#include "loragw_hal.h" +#include "loragw_aux.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define RF_CHAIN 0 /* we'll use radio A only */ + +const uint32_t lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ; +const uint32_t upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +/* describe command line options */ +void usage(void) { + MSG( "Available options:\n"); + MSG( " -h print this help\n"); + MSG( " -f <float> target frequency in MHz\n"); + MSG( " -s <int> Spreading Factor\n"); + MSG( " -b <int> Modulation bandwidth in kHz\n"); + MSG( " -p <int> RF power (dBm)\n"); + MSG( " -t <int> pause between packets (ms)\n"); + MSG( " -x <int> numbers of times the sequence is repeated\n"); + MSG( " -i send packet using inverted modulation polarity \n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i; + uint8_t status_var; + + /* user entry parameters */ + int xi = 0; + double xd = 0.0; + uint32_t f_min; + uint32_t f_max; + + /* application parameters */ + uint32_t f_target = lowfreq[RF_CHAIN]/2 + upfreq[RF_CHAIN]/2; /* target frequency */ + int sf = 10; /* SF10 by default */ + int bw = 125; /* 125kHz bandwidth by default */ + int pow = 14; /* 14 dBm by default */ + int delay = 1000; /* 1 second between packets by default */ + int repeat = 1; /* sweep only once by default */ + bool invert = false; + + /* RF configuration (TX fail if RF chain is not enabled) */ + const struct lgw_conf_rxrf_s rfconf = {true, lowfreq[RF_CHAIN]}; + + /* allocate memory for packet sending */ + struct lgw_pkt_tx_s txpkt; /* array containing 1 outbound packet + metadata */ + + /* loop variables (also use as counters in the packet payload) */ + uint16_t cycle_count = 0; + + /* parse command line options */ + while ((i = getopt (argc, argv, "hf:s:b:p:t:x:i")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_FAILURE; + break; + + case 'f': /* -f <float> target frequency in MHz */ + i = sscanf(optarg, "%lf", &xd); + if ((i != 1) || (xd < 30.0) || (xd > 3000.0)) { + MSG("ERROR: invalid TX frequency\n"); + return EXIT_FAILURE; + } else { + f_target = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ + } + break; + + case 's': /* -s <int> Spreading Factor */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 7) || (xi > 12)) { + MSG("ERROR: invalid spreading factor\n"); + return EXIT_FAILURE; + } else { + sf = xi; + } + break; + + case 'b': /* -b <int> Modulation bandwidth in kHz */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || ((xi != 125)&&(xi != 250)&&(xi != 500))) { + MSG("ERROR: invalid Lora bandwidth\n"); + return EXIT_FAILURE; + } else { + bw = xi; + } + break; + + case 'p': /* -p <int> RF power */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 0) || (xi > 20)) { + MSG("ERROR: invalid RF power\n"); + return EXIT_FAILURE; + } else { + pow = xi; + } + break; + + case 't': /* -t <int> pause between packets (ms) */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 0)) { + MSG("ERROR: invalid time between packets\n"); + return EXIT_FAILURE; + } else { + delay = xi; + } + break; + + case 'x': /* -x <int> numbers of times the sequence is repeated */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 1)) { + MSG("ERROR: invalid number of repeats\n"); + return EXIT_FAILURE; + } else { + repeat = xi; + } + break; + + case 'i': /* -i send packet using inverted modulation polarity */ + invert = true; + break; + + default: + MSG("ERROR: argument parsing use -h option for help\n"); + usage(); + return EXIT_FAILURE; + } + } + + /* check parameter sanity */ + f_min = lowfreq[RF_CHAIN] + (500 * bw); + f_max = upfreq[RF_CHAIN] - (500 * bw); + if ((f_target < f_min) || (f_target > f_max)) { + MSG("ERROR: frequency out of authorized band (accounting for modulation bandwidth)\n"); + return EXIT_FAILURE; + } + printf("Sending %u packets on %u Hz (BW %u kHz, SF %u, 20 bytes payload) at %i dBm, with %u ms between each\n", repeat, f_target, bw, sf, pow, delay); + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* starting the concentrator */ + lgw_rxrf_setconf(RF_CHAIN, rfconf); + i = lgw_start(); + if (i == LGW_HAL_SUCCESS) { + MSG("INFO: concentrator started, packet can be sent\n"); + } else { + MSG("ERROR: failed to start the concentrator\n"); + return EXIT_FAILURE; + } + + /* fill-up payload and parameters */ + memset(&txpkt, 0, sizeof(txpkt)); + txpkt.freq_hz = f_target; + txpkt.tx_mode = IMMEDIATE; + txpkt.rf_chain = RF_CHAIN; + txpkt.rf_power = pow; + txpkt.modulation = MOD_LORA; + switch (bw) { + case 125: txpkt.bandwidth = BW_125KHZ; break; + case 250: txpkt.bandwidth = BW_250KHZ; break; + case 500: txpkt.bandwidth = BW_500KHZ; break; + default: + MSG("ERROR: invalid 'bw' variable\n"); + return EXIT_FAILURE; + } + switch (sf) { + case 7: txpkt.datarate = DR_LORA_SF7; break; + case 8: txpkt.datarate = DR_LORA_SF8; break; + case 9: txpkt.datarate = DR_LORA_SF9; break; + case 10: txpkt.datarate = DR_LORA_SF10; break; + case 11: txpkt.datarate = DR_LORA_SF11; break; + case 12: txpkt.datarate = DR_LORA_SF12; break; + default: + MSG("ERROR: invalid 'sf' variable\n"); + return EXIT_FAILURE; + } + txpkt.coderate = CR_LORA_4_5; + txpkt.invert_pol = invert; + txpkt.preamble = 8; + txpkt.size = 20; /* should be close to typical payload length */ + strcpy((char *)txpkt.payload, "TEST**abcdefghijklmn" ); /* abc.. is for padding */ + + /* main loop */ + for (cycle_count = 0; cycle_count < repeat; ++cycle_count) { + /* refresh counters in payload (big endian, for readability) */ + txpkt.payload[4] = (uint8_t)(cycle_count >> 8); /* MSB */ + txpkt.payload[5] = (uint8_t)(cycle_count & 0x00FF); /* LSB */ + + /* send packet */ + printf("Sending packet number %u ...", cycle_count); + i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ + do { + wait_ms(5); + lgw_status(TX_STATUS, &status_var); /* get TX status */ + } while (status_var != TX_FREE); + printf("OK\n"); + + /* wait inter-packet delay */ + wait_ms(delay); + + /* exit loop on user signals */ + if ((quit_sig == 1) || (exit_sig == 1)) { + break; + } + } + + /* clean up before leaving */ + lgw_stop(); + + printf("Exiting Lora concentrator TX test program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ |